bcce80c91efa20ca74843cc108b96adbf48aff02
[silc.git] / apps / silcd / server_query.c
1 /*
2
3   server_query.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 - 2005 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "serverincludes.h"
22 #include "server_internal.h"
23
24 typedef struct {
25   SilcSocketConnection sock;        /* Connection of this query */
26   unsigned char **arg;              /* Query argument */
27   SilcUInt32 *arg_lens;             /* Query argument lengths */
28   SilcUInt32 *arg_types;            /* Query argument types */
29   SilcUInt32 argc;                  /* Number of query arguments */
30   SilcUInt32 timeout;               /* Max timeout for query to complete */
31   SilcUInt16 ident;                 /* Query command identifier */
32 } *SilcServerQueryList;
33
34 /* Represents an SILC ID */
35 typedef struct {
36   void *id;                         /* ID */
37   SilcIdType id_type;               /* ID type */
38   SilcUInt16 ident;                 /* Command identifier */
39 } *SilcServerQueryID;
40
41 /* Represents one error occurred during query */
42 typedef struct {
43   void *id;                         /* ID */
44   SilcIdType id_type;               /* ID type */
45   unsigned int index : 15;          /* Index to IDs */
46   unsigned int type : 2;            /* 0 = take from query->ids, 1 = take
47                                        from args, 2 = no args in error. */
48   unsigned int error : 7;           /* The actual error (SilcStatus) */
49 } *SilcServerQueryError;
50
51 /* Query session context */
52 typedef struct {
53   /* Queried data */
54   char *nickname;                   /* Queried nickname, normalized */
55   char *nick_server;                /* Queried nickname's server */
56   char *server_name;                /* Queried server name, normalized */
57   char *channel_name;               /* Queried channel name, normalized */
58   SilcServerQueryID ids;            /* Queried IDs */
59   SilcUInt32 ids_count;             /* number of queried IDs */
60   SilcUInt32 reply_count;           /* Requested reply count */
61   SilcDList attrs;                  /* Requested Attributes in WHOIS */
62
63   /* Query session data */
64   SilcServerCommandContext cmd;     /* Command context for query */
65   SilcServerQueryList querylist;    /* Temporary query list context */
66   SilcServerQueryID queries;        /* Ongoing queries */
67   SilcServerQueryError errors;      /* Query errors */
68   SilcUInt16 querylist_count;       /* Number of query lists */
69   SilcUInt16 queries_count;         /* Number of ongoing queries */
70   SilcUInt16 queries_left;          /* Number of ongoing queries left */
71   SilcUInt16 errors_count;          /* number of errors */
72   unsigned int querycmd : 7;        /* Query command (SilcCommand) */
73   unsigned int resolved : 1;        /* TRUE if normal server has resolved
74                                        information from router */
75 } *SilcServerQuery;
76
77 void silc_server_query_free(SilcServerQuery query);
78 void silc_server_query_send_error(SilcServer server,
79                                   SilcServerQuery query,
80                                   SilcStatus error, ...);
81 void silc_server_query_add_error(SilcServer server,
82                                  SilcServerQuery query,
83                                  SilcUInt32 type,
84                                  SilcUInt32 index,
85                                  SilcStatus error);
86 void silc_server_query_add_error_id(SilcServer server,
87                                     SilcServerQuery query,
88                                     SilcStatus error,
89                                     void *id, SilcIdType id_type);
90 void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
91 void silc_server_query_send_router_reply(void *context, void *reply);
92 void silc_server_query_parse(SilcServer server, SilcServerQuery query);
93 void silc_server_query_process(SilcServer server, SilcServerQuery query,
94                                bool resolve);
95 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
96                                SilcSocketConnection sock,
97                                SilcClientEntry client_entry);
98 void silc_server_query_resolve_reply(void *context, void *reply);
99 void silc_server_query_send_reply(SilcServer server,
100                                   SilcServerQuery query,
101                                   SilcClientEntry *clients,
102                                   SilcUInt32 clients_count,
103                                   SilcServerEntry *servers,
104                                   SilcUInt32 servers_count,
105                                   SilcChannelEntry *channels,
106                                   SilcUInt32 channels_count);
107 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
108                                          SilcServerQuery query,
109                                          SilcClientEntry client_entry);
110
111 /* Free the query context structure and all allocated resources. */
112
113 void silc_server_query_free(SilcServerQuery query)
114 {
115   int i;
116
117   silc_server_command_free(query->cmd);
118
119   for (i = 0; i < query->queries_count; i++)
120     silc_free(query->queries[i].id);
121   silc_free(query->queries);
122
123   silc_free(query->nickname);
124   silc_free(query->nick_server);
125   silc_free(query->server_name);
126   silc_free(query->channel_name);
127
128   for (i = 0; i < query->ids_count; i++)
129     silc_free(query->ids[i].id);
130   silc_free(query->ids);
131
132   if (query->attrs)
133     silc_attribute_payload_list_free(query->attrs);
134
135   for (i = 0; i < query->errors_count; i++)
136     silc_free(query->errors[i].id);
137   silc_free(query->errors);
138
139   memset(query, 'F', sizeof(*query));
140   silc_free(query);
141 }
142
143 /* Send error reply indicated by the `error' to the original sender of
144    the query. */
145
146 void silc_server_query_send_error(SilcServer server,
147                                   SilcServerQuery query,
148                                   SilcStatus error, ...)
149 {
150   va_list va;
151   unsigned char *data = NULL;
152   SilcUInt32 data_len = 0, data_type = 0, argc = 0;
153
154   va_start(va, error);
155   data_type = va_arg(va, SilcUInt32);
156   if (data_type) {
157     argc = 1;
158     data = va_arg(va, unsigned char *);
159     data_len = va_arg(va, SilcUInt32);
160   }
161
162   SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
163
164   /* Send the command reply with error */
165   silc_server_send_command_reply(server, query->cmd->sock,
166                                  query->querycmd, error, 0,
167                                  silc_command_get_ident(query->cmd->payload),
168                                  argc, data_type, data, data_len);
169   va_end(va);
170 }
171
172 /* Add error to error list.  Multiple errors may occur during the query
173    processing and this function can be used to add one error.  The
174    `index' is the index to the command context which includes the argument
175    which caused the error, or it is the index to query->ids, depending
176    on value of `type'.  If `type' is 0 the index is to query->ids, if
177    it is 1 it is index to the command context arguments, and if it is
178    2 the index is ignored and no argument is included in the error. */
179
180 void silc_server_query_add_error(SilcServer server,
181                                  SilcServerQuery query,
182                                  SilcUInt32 type,
183                                  SilcUInt32 index,
184                                  SilcStatus error)
185 {
186   query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
187                                (query->errors_count + 1));
188   if (!query->errors)
189     return;
190   query->errors[query->errors_count].index = index;
191   query->errors[query->errors_count].type = type;
192   query->errors[query->errors_count].error = error;
193   query->errors[query->errors_count].id = NULL;
194   query->errors[query->errors_count].id_type = 0;
195   query->errors_count++;
196 }
197
198 /* Same as silc_server_query_add_error but adds the ID data to be used
199    with error sending with this error type. */
200
201 void silc_server_query_add_error_id(SilcServer server,
202                                     SilcServerQuery query,
203                                     SilcStatus error,
204                                     void *id, SilcIdType id_type)
205 {
206   query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
207                                (query->errors_count + 1));
208   if (!query->errors)
209     return;
210   query->errors[query->errors_count].index = 0;
211   query->errors[query->errors_count].type = 0;
212   query->errors[query->errors_count].error = error;
213   query->errors[query->errors_count].id = silc_id_dup(id, id_type);
214   query->errors[query->errors_count].id_type = id_type;
215   query->errors_count++;
216 }
217
218 /* Processes query as command.  The `query' is the command that is
219    being processed indicated by the `cmd'.  The `query' can be one of
220    the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
221    SILC_COMMAND_IDENTIFY.  This function handles the reply sending
222    to the entity who sent this query to us automatically.  Returns
223    TRUE if the query is being processed or FALSE on error. */
224
225 bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
226                                SilcServerCommandContext cmd)
227 {
228   SilcServerQuery query;
229
230   SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
231
232   query = silc_calloc(1, sizeof(*query));
233   query->querycmd = querycmd;
234   query->cmd = silc_server_command_dup(cmd);
235
236   switch (querycmd) {
237
238   case SILC_COMMAND_WHOIS:
239     /* If we are normal server and query contains nickname OR query
240        doesn't contain nickname or ids BUT attributes, send it to the
241        router */
242     if (server->server_type != SILC_ROUTER && !server->standalone &&
243         cmd->sock != SILC_PRIMARY_ROUTE(server) &&
244          (silc_argument_get_arg_type(cmd->args, 1, NULL) ||
245          (!silc_argument_get_arg_type(cmd->args, 1, NULL) &&
246           !silc_argument_get_arg_type(cmd->args, 4, NULL) &&
247           silc_argument_get_arg_type(cmd->args, 3, NULL)))) {
248       silc_server_query_send_router(server, query);
249       return TRUE;
250     }
251     break;
252
253   case SILC_COMMAND_WHOWAS:
254     /* WHOWAS query is always sent to router if we are normal server */
255     if (server->server_type == SILC_SERVER && !server->standalone &&
256         cmd->sock != SILC_PRIMARY_ROUTE(server)) {
257       silc_server_query_send_router(server, query);
258       return TRUE;
259     }
260     break;
261
262   case SILC_COMMAND_IDENTIFY:
263     /* If we are normal server and query does not contain IDs, send it
264        directly to router (it contains nickname, server name or channel
265        name). */
266     if (server->server_type == SILC_SERVER && !server->standalone &&
267         cmd->sock != SILC_PRIMARY_ROUTE(server) &&
268         !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
269       silc_server_query_send_router(server, query);
270       return TRUE;
271     }
272     break;
273
274   default:
275     SILC_LOG_ERROR(("Bad query using %d command", querycmd));
276     silc_server_query_free(query);
277     return FALSE;
278   }
279
280   /* Now parse the request */
281   silc_server_query_parse(server, query);
282
283   return TRUE;
284 }
285
286 /* Send the received query to our primary router since we could not
287    handle the query directly.  We will reprocess the query after our
288    router replies back. */
289
290 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
291 {
292   SilcBuffer tmpbuf;
293   SilcUInt16 old_ident;
294
295   SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
296
297   /* Statistics */
298   server->stat.commands_sent++;
299
300   /* Send WHOIS command to our router */
301   old_ident = silc_command_get_ident(query->cmd->payload);
302   silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
303   tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
304   silc_server_packet_send(server,
305                           SILC_PRIMARY_ROUTE(server),
306                           SILC_PACKET_COMMAND, 0,
307                           tmpbuf->data, tmpbuf->len, TRUE);
308   silc_command_set_ident(query->cmd->payload, old_ident);
309   silc_buffer_free(tmpbuf);
310
311   query->resolved = TRUE;
312
313   /* Continue parsing the query after received reply from router */
314   silc_server_command_pending(server, query->querycmd, server->cmd_ident,
315                               silc_server_query_send_router_reply, query);
316 }
317
318 /* Reply callback called after primary router has replied to our initial
319    sending of the query to it.  We will proceed the query in this function. */
320
321 void silc_server_query_send_router_reply(void *context, void *reply)
322 {
323   SilcServerQuery query = context;
324   SilcServer server = query->cmd->server;
325   SilcServerCommandReplyContext cmdr = reply;
326
327   SILC_LOG_DEBUG(("Received reply from router to query"));
328
329   /* If the original command caller has gone away, just stop. */
330   if (query->cmd->sock->users == 1) {
331     SILC_LOG_DEBUG(("Original command caller vanished"));
332     silc_server_query_free(query);
333     return;
334   }
335
336   /* Check if router sent error reply */
337   if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
338     SilcBuffer buffer;
339
340     SILC_LOG_DEBUG(("Sending error to original query"));
341
342     /* Statistics */
343     server->stat.commands_sent++;
344
345     /* Send the same command reply payload which contains the error */
346     silc_command_set_command(cmdr->payload, query->querycmd);
347     silc_command_set_ident(cmdr->payload,
348                            silc_command_get_ident(query->cmd->payload));
349     buffer = silc_command_payload_encode_payload(cmdr->payload);
350     silc_server_packet_send(server, query->cmd->sock,
351                             SILC_PACKET_COMMAND_REPLY, 0,
352                             buffer->data, buffer->len, FALSE);
353     silc_buffer_free(buffer);
354     silc_server_query_free(query);
355     return;
356   }
357
358   /* Continue with parsing */
359   silc_server_query_parse(server, query);
360 }
361
362 /* Parse the command query and start processing the queries in detail. */
363
364 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
365 {
366   SilcServerCommandContext cmd = query->cmd;
367   unsigned char *tmp;
368   SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
369   void *id;
370   SilcIdType id_type;
371   int i;
372
373   SILC_LOG_DEBUG(("Parsing %s query",
374                   silc_get_command_name(query->querycmd)));
375
376   switch (query->querycmd) {
377
378   case SILC_COMMAND_WHOIS:
379     /* Get requested attributes if set */
380     tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
381     if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
382       query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
383
384       /* When Requested Attributes is present we will assure that this
385          client cannot execute the WHOIS command too fast.  This would be
386          same as having SILC_CF_LAG_STRICT. */
387       if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
388           cmd->sock->user_data)
389         ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
390     }
391
392     /* Get Client IDs if present. Take IDs always instead of nickname. */
393     tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
394     if (!tmp) {
395
396       /* Get nickname */
397       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
398       if (!tmp && !query->attrs) {
399         /* No nickname, no ids and no attributes - send error */
400         silc_server_query_send_error(server, query,
401                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
402         silc_server_query_free(query);
403         return;
404       }
405
406       /* Get the nickname@server string and parse it */
407       if (tmp && ((tmp_len > 128) ||
408           !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))) {
409         silc_server_query_send_error(server, query,
410                                      SILC_STATUS_ERR_BAD_NICKNAME, 0);
411         silc_server_query_free(query);
412         return;
413       }
414
415       /* Check nickname */
416       tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
417                                   SILC_STRING_UTF8, 128, &tmp_len);
418       if (!tmp) {
419         silc_server_query_send_error(server, query,
420                                      SILC_STATUS_ERR_BAD_NICKNAME, 0);
421         silc_server_query_free(query);
422         return;
423       }
424       silc_free(query->nickname);
425       query->nickname = tmp;
426
427     } else {
428       /* Parse the IDs included in the query */
429       query->ids = silc_calloc(argc, sizeof(*query->ids));
430
431       for (i = 0; i < argc; i++) {
432         tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
433         if (!tmp)
434           continue;
435
436         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
437         if (!id || id_type != SILC_ID_CLIENT) {
438           silc_server_query_add_error(server, query, 1, i + 4,
439                                       SILC_STATUS_ERR_BAD_CLIENT_ID);
440           continue;
441         }
442
443         /* Normal server must check whether this ID exist, and if not then
444            send the query to router, unless done so already */
445         if (server->server_type == SILC_SERVER && !query->resolved) {
446           if (!silc_idlist_find_client_by_id(server->local_list,
447                                              id, TRUE, NULL)) {
448             if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
449                 !silc_idlist_find_client_by_id(server->global_list,
450                                                id, TRUE, NULL)) {
451               silc_server_query_send_router(server, query);
452               for (i = 0; i < query->ids_count; i++)
453                 silc_free(query->ids[i].id);
454               silc_free(query->ids);
455               query->ids = NULL;
456               query->ids_count = 0;
457               silc_free(id);
458               return;
459             }
460           }
461         }
462
463         query->ids[query->ids_count].id = id;
464         query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
465         query->ids_count++;
466       }
467     }
468
469     /* Get the max count of reply messages allowed */
470     tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
471     if (tmp && tmp_len == sizeof(SilcUInt32))
472       SILC_GET32_MSB(query->reply_count, tmp);
473    break;
474
475   case SILC_COMMAND_WHOWAS:
476     /* Get nickname */
477     tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
478     if (!tmp) {
479       silc_server_query_send_error(server, query,
480                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
481       silc_server_query_free(query);
482       return;
483     }
484
485     /* Get the nickname@server string and parse it */
486     if (tmp_len > 128 ||
487         !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
488       silc_server_query_send_error(server, query,
489                                    SILC_STATUS_ERR_BAD_NICKNAME, 0);
490       silc_server_query_free(query);
491       return;
492     }
493
494     /* Check nickname */
495     tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
496                                 SILC_STRING_UTF8, 128, &tmp_len);
497     if (!tmp) {
498       silc_server_query_send_error(server, query,
499                                    SILC_STATUS_ERR_BAD_NICKNAME, 0);
500       silc_server_query_free(query);
501       return;
502     }
503     silc_free(query->nickname);
504     query->nickname = tmp;
505
506     /* Get the max count of reply messages allowed */
507     tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
508     if (tmp && tmp_len == sizeof(SilcUInt32))
509       SILC_GET32_MSB(query->reply_count, tmp);
510     break;
511
512   case SILC_COMMAND_IDENTIFY:
513     /* Get IDs if present. Take IDs always instead of names. */
514     tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
515     if (!tmp) {
516
517       /* Try get nickname */
518       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
519       if (tmp) {
520         /* Get the nickname@server string and parse it */
521         if (tmp_len > 128 ||
522             !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
523           silc_server_query_add_error(server, query, 1, 1,
524                                       SILC_STATUS_ERR_BAD_NICKNAME);
525
526         /* Check nickname */
527         tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
528                                     SILC_STRING_UTF8, 128, &tmp_len);
529         if (!tmp) {
530           silc_server_query_send_error(server, query,
531                                        SILC_STATUS_ERR_BAD_NICKNAME, 0);
532           silc_server_query_free(query);
533           return;
534         }
535         silc_free(query->nickname);
536         query->nickname = tmp;
537       }
538
539       /* Try get server name */
540       tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
541       if (tmp) {
542         /* Check server name */
543         tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
544                                     256, &tmp_len);
545         if (!tmp) {
546           silc_server_query_send_error(server, query,
547                                        SILC_STATUS_ERR_BAD_SERVER, 0);
548           silc_server_query_free(query);
549           return;
550         }
551         query->server_name = tmp;
552       }
553
554       /* Get channel name */
555       tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
556       if (tmp && tmp_len <= 256) {
557         /* Check channel name */
558         tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
559                                     256, &tmp_len);
560         if (!tmp) {
561           silc_server_query_send_error(server, query,
562                                        SILC_STATUS_ERR_BAD_CHANNEL, 0);
563           silc_server_query_free(query);
564           return;
565         }
566         query->channel_name = tmp;
567       }
568
569       if (!query->nickname && !query->server_name && !query->channel_name) {
570         silc_server_query_send_error(server, query,
571                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
572         silc_server_query_free(query);
573         return;
574       }
575
576     } else {
577       /* Parse the IDs included in the query */
578       query->ids = silc_calloc(argc, sizeof(*query->ids));
579
580       for (i = 0; i < argc; i++) {
581         tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
582         if (!tmp)
583           continue;
584
585         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
586         if (!id) {
587           silc_server_query_add_error(server, query, 1, i + 5,
588                                       SILC_STATUS_ERR_BAD_CLIENT_ID);
589           continue;
590         }
591
592         /* Normal server must check whether this ID exist, and if not then
593            send the query to router, unless done so already */
594         if (server->server_type == SILC_SERVER && !query->resolved) {
595           if (id_type == SILC_ID_CLIENT) {
596             if (!silc_idlist_find_client_by_id(server->local_list,
597                                                id, TRUE, NULL)) {
598               if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
599                   !silc_idlist_find_client_by_id(server->global_list,
600                                                  id, TRUE, NULL)) {
601                 silc_server_query_send_router(server, query);
602                 for (i = 0; i < query->ids_count; i++)
603                   silc_free(query->ids[i].id);
604                 silc_free(query->ids);
605                 query->ids = NULL;
606                 query->ids_count = 0;
607                 silc_free(id);
608                 return;
609               }
610             }
611           } else {
612             /* For now all other ID's except Client ID's are explicitly
613                sent to router for resolving. */
614             silc_server_query_send_router(server, query);
615             for (i = 0; i < query->ids_count; i++)
616               silc_free(query->ids[i].id);
617             silc_free(query->ids);
618             query->ids = NULL;
619             query->ids_count = 0;
620             silc_free(id);
621             return;
622           }
623         }
624
625         query->ids[query->ids_count].id = id;
626         query->ids[query->ids_count].id_type = id_type;
627         query->ids_count++;
628       }
629     }
630
631     /* Get the max count of reply messages allowed */
632     tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
633     if (tmp && tmp_len == sizeof(SilcUInt32))
634       SILC_GET32_MSB(query->reply_count, tmp);
635     break;
636   }
637
638   /* Start processing the query information */
639   silc_server_query_process(server, query, TRUE);
640 }
641
642 /* Context for holding clients searched by public key. */
643 typedef struct {
644   SilcClientEntry **clients;
645   SilcUInt32 *clients_count;
646   bool found;
647 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
648
649 void silc_server_public_key_hash_foreach(void *key, void *context,
650                                          void *user_context)
651 {
652   SilcServerPublicKeyUser uc = user_context;
653   SilcClientEntry entry = context;
654
655   /* Nothing was found, just return */
656   if (!context)
657     return;
658
659   uc->found = TRUE;
660
661   (*uc->clients) = silc_realloc((*uc->clients),
662                                 sizeof((**uc->clients)) *
663                                 ((*uc->clients_count) + 1));
664   (*uc->clients)[(*uc->clients_count)++] = entry;
665 }
666
667 /* If clients are set, limit the found clients using the attributes in
668    the query. If clients are not set, try to find some clients using
669    the attributes */
670
671 void silc_server_query_check_attributes(SilcServer server,
672                                         SilcServerQuery query,
673                                         SilcClientEntry **clients,
674                                         SilcUInt32 *clients_count) {
675   SilcClientEntry entry;
676   SilcAttributePayload attr;
677   SilcAttribute attribute;
678   SilcAttributeObjPk pk;
679   SilcPublicKey publickey;
680   int i;
681   bool found = FALSE, no_clients = FALSE;
682
683   /* If no clients were found, we only check the attributes
684      if the user wasn't searching for nickname/ids */
685   if (!(*clients)) {
686     no_clients = TRUE;
687     if (query->nickname || query->ids_count)
688       return;
689   }
690
691   silc_dlist_start(query->attrs);
692   while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
693     attribute = silc_attribute_get_attribute(attr);
694     switch (attribute) {
695
696       case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
697         SILC_LOG_DEBUG(("Finding clients by public key attribute"));
698
699         if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
700           continue;
701
702         if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
703                                          &publickey)) {
704           silc_free(pk.type);
705           silc_free(pk.data);
706           continue;
707         }
708
709         /* If no clients were set on calling this function, we
710            just search for clients, otherwise we try to limit
711            the clients */
712         if (no_clients) {
713           SilcServerPublicKeyUserStruct usercontext;
714
715           usercontext.clients = clients;
716           usercontext.clients_count = clients_count;
717           usercontext.found = FALSE;
718
719           silc_hash_table_find_foreach(server->pk_hash, publickey,
720                                        silc_server_public_key_hash_foreach,
721                                        &usercontext);
722
723           if (usercontext.found == TRUE)
724             found = TRUE;
725         } else {
726           for (i = 0; i < *clients_count; i++) {
727             entry = (*clients)[i];
728
729             if (!entry->data.public_key)
730               continue;
731
732             if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
733                                                  entry, NULL))
734               (*clients)[i] = NULL;
735             else
736               found = TRUE;
737           }
738         }
739         silc_free(pk.type);
740         silc_free(pk.data);
741         silc_pkcs_public_key_free(publickey);
742         break;
743     }
744   }
745
746   if (!found && !query->nickname && !query->ids)
747     silc_server_query_add_error(server, query, 2, 0,
748                                 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
749 }
750
751 /* Processes the parsed query.  This does the actual finding of the
752    queried information and prepares for sending reply to the original
753    sender of the query command. */
754
755 void silc_server_query_process(SilcServer server, SilcServerQuery query,
756                                bool resolve)
757 {
758   SilcServerCommandContext cmd = query->cmd;
759   bool check_global = FALSE;
760   void *entry;
761   SilcClientEntry *clients = NULL, client_entry;
762   SilcChannelEntry *channels = NULL;
763   SilcServerEntry *servers = NULL;
764   SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
765   int i;
766
767   SILC_LOG_DEBUG(("Processing %s query",
768                   silc_get_command_name(query->querycmd)));
769
770   /* Check global lists if query is coming from client or we are not
771      normal server (we know global information). */
772   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
773     check_global = TRUE;
774   else if (server->server_type != SILC_SERVER)
775     check_global = TRUE;
776
777   if (query->nickname) {
778     /* Get all clients matching nickname from local list */
779     if (!silc_idlist_get_clients_by_hash(server->local_list,
780                                          query->nickname, server->md5hash,
781                                          &clients, &clients_count))
782       silc_idlist_get_clients_by_nickname(server->local_list,
783                                           query->nickname,
784                                           query->nick_server,
785                                           &clients, &clients_count);
786
787     /* Check global list as well */
788     if (check_global) {
789       if (!silc_idlist_get_clients_by_hash(server->global_list,
790                                            query->nickname, server->md5hash,
791                                            &clients, &clients_count))
792         silc_idlist_get_clients_by_nickname(server->global_list,
793                                             query->nickname,
794                                             query->nick_server,
795                                             &clients, &clients_count);
796     }
797
798     if (!clients)
799       silc_server_query_add_error(server, query, 1, 1,
800                                   SILC_STATUS_ERR_NO_SUCH_NICK);
801   }
802
803   if (query->server_name) {
804     /* Find server by name */
805     entry = silc_idlist_find_server_by_name(server->local_list,
806                                             query->server_name, TRUE, NULL);
807     if (!entry && check_global)
808       entry = silc_idlist_find_server_by_name(server->global_list,
809                                               query->server_name, TRUE, NULL);
810     if (entry) {
811       servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
812       servers[servers_count++] = (SilcServerEntry)entry;
813     }
814
815     if (!servers)
816       silc_server_query_add_error(server, query, 1, 2,
817                                   SILC_STATUS_ERR_NO_SUCH_SERVER);
818   }
819
820   if (query->channel_name) {
821     /* Find channel by name */
822     entry = silc_idlist_find_channel_by_name(server->local_list,
823                                              query->channel_name, NULL);
824     if (!entry && check_global)
825       entry = silc_idlist_find_channel_by_name(server->global_list,
826                                                query->channel_name, NULL);
827     if (entry) {
828       channels = silc_realloc(channels, sizeof(*channels) *
829                               (channels_count + 1));
830       channels[channels_count++] = (SilcChannelEntry)entry;
831     }
832
833     if (!channels)
834       silc_server_query_add_error(server, query, 1, 3,
835                                   SILC_STATUS_ERR_NO_SUCH_CHANNEL);
836   }
837
838   if (query->ids_count) {
839     /* Find entries by the queried IDs */
840     for (i = 0; i < query->ids_count; i++) {
841       void *id = query->ids[i].id;
842       if (!id)
843         continue;
844
845       switch (query->ids[i].id_type) {
846
847       case SILC_ID_CLIENT:
848         /* Get client entry */
849         entry = silc_idlist_find_client_by_id(server->local_list,
850                                               id, TRUE, NULL);
851         if (!entry && check_global)
852           entry = silc_idlist_find_client_by_id(server->global_list,
853                                                 id, TRUE, NULL);
854         if (!entry) {
855           silc_server_query_add_error(server, query, 0, i,
856                                       SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
857           continue;
858         }
859
860         clients = silc_realloc(clients, sizeof(*clients) *
861                                (clients_count + 1));
862         clients[clients_count++] = (SilcClientEntry)entry;
863         break;
864
865       case SILC_ID_SERVER:
866         /* Get server entry */
867         entry = silc_idlist_find_server_by_id(server->local_list,
868                                               id, TRUE, NULL);
869         if (!entry && check_global)
870           entry = silc_idlist_find_server_by_id(server->global_list,
871                                                 id, TRUE, NULL);
872         if (!entry) {
873           silc_server_query_add_error(server, query, 0, i,
874                                       SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
875           continue;
876         }
877
878         servers = silc_realloc(servers, sizeof(*servers) *
879                                (servers_count + 1));
880         servers[servers_count++] = (SilcServerEntry)entry;
881         break;
882
883       case SILC_ID_CHANNEL:
884         /* Get channel entry */
885         entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
886         if (!entry && check_global)
887           entry = silc_idlist_find_channel_by_id(server->global_list, id,
888                                                  NULL);
889         if (!entry) {
890           silc_server_query_add_error(server, query, 0, i,
891                                       SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
892           continue;
893         }
894
895         channels = silc_realloc(channels, sizeof(*channels) *
896                                 (channels_count + 1));
897         channels[channels_count++] = (SilcChannelEntry)entry;
898         break;
899
900       default:
901         break;
902       }
903     }
904   }
905
906   /* Check the attributes to narrow down the search by using them. */
907   if (query->attrs)
908     silc_server_query_check_attributes(server, query, &clients,
909                                        &clients_count);
910
911   SILC_LOG_DEBUG(("Querying %d clients", clients_count));
912   SILC_LOG_DEBUG(("Querying %d servers", servers_count));
913   SILC_LOG_DEBUG(("Querying %d channels", channels_count));
914
915   /* If nothing was found, then just send the errors */
916   if (!clients && !channels && !servers) {
917     silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
918     return;
919   }
920
921   /* If caller does not want us to resolve anything (has resolved already)
922      then just continue with sending the reply */
923   if (!resolve) {
924     silc_server_query_send_reply(server, query, clients, clients_count,
925                                  servers, servers_count, channels,
926                                  channels_count);
927     silc_free(clients);
928     silc_free(servers);
929     silc_free(channels);
930     return;
931   }
932
933   /* Now process all found information and if necessary do some more
934      resolving. */
935   switch (query->querycmd) {
936
937   case SILC_COMMAND_WHOIS:
938     for (i = 0; i < clients_count; i++) {
939       client_entry = clients[i];
940
941       /* Check if cannot query this anyway, so take next one */
942       if (!client_entry ||
943           !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
944         continue;
945
946       /* If Requested Attributes is set then we always resolve the client
947          information, if not then check whether the entry is complete or not
948          and decide whether we need to resolve or not. */
949       if (!query->attrs) {
950
951         /* Even if nickname and stuff are present, we may need to resolve
952            the entry */
953         if (client_entry->nickname && client_entry->username &&
954             client_entry->userinfo) {
955           /* Check if cannot query this anyway, so take next one */
956           if (!client_entry->router)
957             continue;
958
959           /* If we are router, client is local to us, or client is on channel
960              we do not need to resolve the client information. */
961           if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
962               || silc_hash_table_count(client_entry->channels) ||
963               query->resolved)
964             continue;
965         }
966       }
967
968       /* Remove the NOATTR status periodically */
969       if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
970           client_entry->updated + 600 < time(NULL))
971         client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
972
973       /* When requested attributes is present and local client is detached
974          we cannot send the command to the client, we'll reply on behalf of
975          the client instead. */
976       if (query->attrs && SILC_IS_LOCAL(client_entry) &&
977           (client_entry->mode & SILC_UMODE_DETACHED ||
978            client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
979         continue;
980
981       /* If attributes are present in query, and in the entry and we have
982          done resolvings already we don't need to resolve anymore */
983       if (query->resolved && query->attrs && client_entry->attrs)
984         continue;
985
986       /* Resolve the detailed client information. If client is local we
987          know that attributes were present and we will resolve directly
988          from the client. Otherwise resolve from client's owner. */
989       silc_server_query_resolve(server, query,
990                                 (SILC_IS_LOCAL(client_entry) ?
991                                  client_entry->connection :
992                                  client_entry->router->connection),
993                                 client_entry);
994     }
995     break;
996
997   case SILC_COMMAND_WHOWAS:
998     for (i = 0; i < clients_count; i++) {
999       client_entry = clients[i];
1000
1001       /* Check if cannot query this anyway, so take next one */
1002       if (!client_entry || !client_entry->router ||
1003           client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1004         continue;
1005
1006       /* If both nickname and username are present no resolving is needed */
1007       if (client_entry->nickname && client_entry->username)
1008         continue;
1009
1010       /* Resolve the detailed client information */
1011       silc_server_query_resolve(server, query,
1012                                 client_entry->router->connection,
1013                                 client_entry);
1014     }
1015     break;
1016
1017   case SILC_COMMAND_IDENTIFY:
1018     for (i = 0; i < clients_count; i++) {
1019       client_entry = clients[i];
1020
1021       /* Check if cannot query this anyway, so take next one */
1022       if (!client_entry || !client_entry->router ||
1023           !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1024         continue;
1025
1026       /* Even if nickname is present, we may need to resolve the entry */
1027       if (client_entry->nickname) {
1028
1029         /* If we are router, client is local to us, or client is on channel
1030            we do not need to resolve the client information. */
1031         if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1032             || silc_hash_table_count(client_entry->channels) ||
1033             query->resolved)
1034           continue;
1035       }
1036
1037       /* Resolve the detailed client information */
1038       silc_server_query_resolve(server, query,
1039                                 client_entry->router->connection,
1040                                 client_entry);
1041     }
1042     break;
1043   }
1044
1045   if (!query->queries_count)
1046     /* If we didn't have to do any resolving, continue with sending the
1047        command reply to the original sender. */
1048     silc_server_query_send_reply(server, query, clients, clients_count,
1049                                  servers, servers_count, channels,
1050                                  channels_count);
1051   else
1052     /* Now actually send the resolvings we gathered earlier */
1053     silc_server_query_resolve(server, query, NULL, NULL);
1054
1055   silc_free(clients);
1056   silc_free(servers);
1057   silc_free(channels);
1058 }
1059
1060 /* Resolve the detailed information for the `client_entry'.  Only client
1061    information needs to be resolved for being incomplete.  Each incomplete
1062    client entry calls this function to do the resolving. */
1063
1064 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1065                                SilcSocketConnection sock,
1066                                SilcClientEntry client_entry)
1067 {
1068   SilcServerCommandContext cmd = query->cmd;
1069   SilcServerQueryList r = NULL;
1070   SilcBuffer idp;
1071   unsigned char *tmp;
1072   SilcUInt32 len;
1073   SilcUInt16 ident;
1074   int i;
1075
1076   if (!sock && client_entry)
1077     return;
1078
1079   /* If arguments are NULL we will now actually send the resolvings
1080      that earlier has been gathered by calling this function. */
1081   if (!sock && !client_entry) {
1082     SilcBuffer res_cmd;
1083
1084     SILC_LOG_DEBUG(("Sending the resolvings"));
1085
1086     /* WHOWAS resolving has been done at the same time this function
1087        was called to add the resolving for WHOWAS, so just return. */
1088     if (query->querycmd == SILC_COMMAND_WHOWAS)
1089       return;
1090
1091     for (i = 0; i < query->querylist_count; i++) {
1092       r = &query->querylist[i];
1093
1094       /* If Requested Attributes were present put them to this resolving */
1095       if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1096         len = r->argc + 1;
1097         r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1098         r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1099         r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1100
1101         tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1102         if (tmp)
1103           r->arg[r->argc] = silc_memdup(tmp, len);
1104         r->arg_lens[r->argc] = len;
1105         r->arg_types[r->argc] = 3;
1106         r->argc++;
1107       }
1108
1109       /* Statistics */
1110       server->stat.commands_sent++;
1111
1112       /* Send WHOIS command */
1113       res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1114                                             r->argc, r->arg, r->arg_lens,
1115                                             r->arg_types, r->ident);
1116       silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1117                               res_cmd->data, res_cmd->len, FALSE);
1118       silc_buffer_free(res_cmd);
1119
1120       /* Reprocess this packet after received reply */
1121       if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1122                                             r->ident,
1123                                             silc_server_query_resolve_reply,
1124                                             query, r->timeout))
1125         query->queries_left++;
1126     }
1127
1128     /* Cleanup this temporary context */
1129     for (i = 0; i < query->querylist_count; i++) {
1130       int k;
1131       for (k = 0; k < query->querylist[i].argc; k++)
1132         silc_free(query->querylist[i].arg[k]);
1133       silc_free(query->querylist[i].arg);
1134       silc_free(query->querylist[i].arg_lens);
1135       silc_free(query->querylist[i].arg_types);
1136     }
1137     silc_free(query->querylist);
1138     query->querylist = NULL;
1139     query->querylist_count = 0;
1140     return;
1141   }
1142
1143   SILC_LOG_DEBUG(("Resolving client information"));
1144
1145   if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1146     /* The entry is being resolved by some other external query already.
1147        Attach to that query instead of resolving again. */
1148     ident = client_entry->resolve_cmd_ident;
1149     if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1150                                     silc_server_query_resolve_reply, query))
1151       query->queries_left++;
1152   } else {
1153     /* This entry will be resolved */
1154     ident = ++server->cmd_ident;
1155
1156     switch (query->querycmd) {
1157
1158     case SILC_COMMAND_WHOIS:
1159     case SILC_COMMAND_IDENTIFY:
1160       /* Take existing query context if exist for this connection */
1161       for (i = 0; i < query->querylist_count; i++)
1162         if (query->querylist[i].sock == sock) {
1163           r = &query->querylist[i];
1164           break;
1165         }
1166
1167       if (!r) {
1168         /* Allocate new temp query list context */
1169         query->querylist = silc_realloc(query->querylist,
1170                                         sizeof(*query->querylist) *
1171                                         (query->querylist_count + 1));
1172         r = &query->querylist[query->querylist_count];
1173         query->querylist_count++;
1174         memset(r, 0, sizeof(*r));
1175         r->sock = sock;
1176         r->ident = ident;
1177         if (SILC_IS_LOCAL(client_entry))
1178           r->timeout = 3;
1179       }
1180
1181       len = r->argc + 1;
1182       r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1183       r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1184       r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1185
1186       /* Add the client entry to be resolved */
1187       idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1188       r->arg[r->argc] = silc_memdup(idp->data, idp->len);
1189       r->arg_lens[r->argc] = idp->len;
1190       r->arg_types[r->argc] = r->argc + 4;
1191       r->argc++;
1192       silc_buffer_free(idp);
1193
1194       break;
1195
1196     case SILC_COMMAND_WHOWAS:
1197       /* We must send WHOWAS command since it's the only the way of
1198          resolving clients that are not present in the network anymore. */
1199       silc_server_send_command(server, sock, query->querycmd, ident, 1,
1200                                1, query->nickname, strlen(query->nickname));
1201       if (silc_server_command_pending(server, query->querycmd, ident,
1202                                       silc_server_query_resolve_reply, query))
1203         query->queries_left++;
1204       break;
1205     }
1206   }
1207
1208   /* Mark the entry as being resolved */
1209   client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1210   client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1211   client_entry->resolve_cmd_ident = ident;
1212   client_entry->updated = time(NULL);
1213
1214   /* Save the queried ID, which we will reprocess after we get this and
1215      all other queries back. */
1216   query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1217                                 (query->queries_count + 1));
1218   if (query->queries) {
1219     i = query->queries_count;
1220     query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1221     query->queries[i].id_type = SILC_ID_CLIENT;
1222     query->queries[i].ident = ident;
1223     query->queries_count++;
1224   }
1225 }
1226
1227 /* Reply callback called after one resolving has been completed.  If
1228    all resolvings has been received then we will continue with sending
1229    the command reply to the original sender of the query. */
1230
1231 void silc_server_query_resolve_reply(void *context, void *reply)
1232 {
1233   SilcServerQuery query = context;
1234   SilcServer server = query->cmd->server;
1235   SilcServerCommandReplyContext cmdr = reply;
1236   SilcUInt16 ident = cmdr->ident;
1237   SilcStatus error = SILC_STATUS_OK;
1238   SilcServerQueryID id = NULL;
1239   SilcClientEntry client_entry;
1240   int i;
1241
1242   /* One less query left */
1243   query->queries_left--;
1244
1245   silc_command_get_status(cmdr->payload, NULL, &error);
1246   SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1247                   query->queries_left, error));
1248
1249   /* If no error then skip to other stuff */
1250   if (error == SILC_STATUS_OK)
1251     goto out;
1252
1253   /* Error occurred during resolving */
1254
1255   /* Find the resolved client ID */
1256   for (i = 0; i < query->queries_count; i++) {
1257     if (query->queries[i].ident != ident)
1258       continue;
1259
1260     id = &query->queries[i];
1261
1262     if (error == SILC_STATUS_ERR_TIMEDOUT) {
1263
1264       /* If timeout occurred for local entry when resolving attributes
1265          mark that this client doesn't support attributes in WHOIS. This
1266          assures we won't send the request again to the client. */
1267       if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1268         client_entry = silc_idlist_find_client_by_id(server->local_list,
1269                                                      id->id, TRUE, NULL);
1270         SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1271                         silc_id_render(id->id, SILC_ID_CLIENT)));
1272         if (client_entry && SILC_IS_LOCAL(client_entry)) {
1273           client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1274           client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1275           continue;
1276         }
1277       }
1278
1279       /* Remove the RESOLVING status from the client entry */
1280       if (query->querycmd != SILC_COMMAND_WHOWAS) {
1281         client_entry = silc_idlist_find_client_by_id(server->local_list,
1282                                                      id->id, TRUE, NULL);
1283         if (!client_entry)
1284           client_entry = silc_idlist_find_client_by_id(server->global_list,
1285                                                        id->id, TRUE, NULL);
1286         if (client_entry)
1287           client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1288       }
1289     }
1290   }
1291
1292  out:
1293
1294   /* If there are queries left then wait for them */
1295   if (query->queries_left)
1296     return;
1297
1298   SILC_LOG_DEBUG(("Reprocess the query"));
1299
1300   /* If the original command caller has gone away, just stop. */
1301   if (query->cmd->sock->users == 1) {
1302     SILC_LOG_DEBUG(("Original command caller vanished"));
1303     silc_server_query_free(query);
1304     return;
1305   }
1306
1307   /* We have received all queries.  Now re-search all information required
1308      to complete this query.  Reason we cannot save the values found in
1309      the first search is that SilcClientEntry, SilcServerEntry and
1310      SilcChannelEntry pointers may become invalid while we were waiting
1311      for these resolvings. */
1312   silc_server_query_process(server, query, FALSE);
1313 }
1314
1315 /* Send the reply to the original query.  If arguments are NULL then this
1316    sends only the errors that has occurred during the processing of the
1317    query.  This sends the errors always after sending all the found
1318    information.  The query is over after this function returns and the
1319    `query' will become invalid.  This is called only after all informations
1320    has been resolved.  This means that if something is not found or is
1321    incomplete in this function we were unable to resolve the information
1322    or it does not exist at all. */
1323
1324 void silc_server_query_send_reply(SilcServer server,
1325                                   SilcServerQuery query,
1326                                   SilcClientEntry *clients,
1327                                   SilcUInt32 clients_count,
1328                                   SilcServerEntry *servers,
1329                                   SilcUInt32 servers_count,
1330                                   SilcChannelEntry *channels,
1331                                   SilcUInt32 channels_count)
1332 {
1333   SilcServerCommandContext cmd = query->cmd;
1334   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1335   SilcStatus status;
1336   unsigned char *tmp;
1337   SilcUInt32 len;
1338   SilcBuffer idp;
1339   int i, k, valid_count;
1340   char nh[384], uh[384];
1341   bool sent_reply = FALSE;
1342
1343   SILC_LOG_DEBUG(("Sending reply to query"));
1344   SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1345   SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1346   SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1347   SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1348
1349   status = SILC_STATUS_OK;
1350
1351   /* Send clients */
1352   if (clients_count) {
1353     SilcClientEntry entry;
1354     SilcSocketConnection hsock;
1355
1356     /* Mark all invalid entries */
1357     for (i = 0, valid_count = 0; i < clients_count; i++) {
1358       entry = clients[i];
1359       if (!entry)
1360         continue;
1361
1362       switch (query->querycmd) {
1363       case SILC_COMMAND_WHOIS:
1364         if (!entry->nickname || !entry->username || !entry->userinfo ||
1365             !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1366           /* When querying by ID, every "unfound" entry must cause error */
1367           if (query->ids)
1368             silc_server_query_add_error_id(server, query,
1369                                            SILC_STATUS_ERR_TIMEDOUT,
1370                                            entry->id, SILC_ID_CLIENT);
1371           clients[i] = NULL;
1372           continue;
1373         }
1374         break;
1375
1376       case SILC_COMMAND_IDENTIFY:
1377         if (!entry->nickname ||
1378             !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1379           /* When querying by ID, every "unfound" entry must cause error */
1380           if (query->ids)
1381             silc_server_query_add_error_id(server, query,
1382                                            SILC_STATUS_ERR_TIMEDOUT,
1383                                            entry->id, SILC_ID_CLIENT);
1384           clients[i] = NULL;
1385           continue;
1386         }
1387         break;
1388
1389       case SILC_COMMAND_WHOWAS:
1390         if (!entry->nickname || !entry->username ||
1391             entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1392           clients[i] = NULL;
1393           continue;
1394         }
1395         break;
1396       }
1397       valid_count++;
1398     }
1399
1400     /* Start processing found clients */
1401     status = SILC_STATUS_OK;
1402     if (valid_count > 1)
1403       status = SILC_STATUS_LIST_START;
1404
1405     /* Now do the sending of valid entries */
1406     k = 0;
1407     for (i = 0; i < clients_count && valid_count; i++) {
1408       entry = clients[i];
1409       if (!entry)
1410         continue;
1411
1412       if (k >= 1)
1413         status = SILC_STATUS_LIST_ITEM;
1414       if (valid_count > 1 && k == valid_count - 1
1415           && !servers_count && !channels_count && !query->errors_count)
1416         status = SILC_STATUS_LIST_END;
1417       if (query->reply_count && k - 1 == query->reply_count)
1418         status = SILC_STATUS_LIST_END;
1419
1420       SILC_LOG_DEBUG(("%s: client %s",
1421                       (status == SILC_STATUS_OK ?         "   OK" :
1422                        status == SILC_STATUS_LIST_START ? "START" :
1423                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1424                        status == SILC_STATUS_LIST_END  ?  "  END" :
1425                        "      : "), entry->nickname));
1426
1427       idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1428       memset(nh, 0, sizeof(nh));
1429
1430       silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1431       if (!strchr(entry->nickname, '@')) {
1432         silc_strncat(nh, sizeof(nh), "@", 1);
1433         if (entry->servername) {
1434           silc_strncat(nh, sizeof(nh), entry->servername,
1435                        strlen(entry->servername));
1436         } else {
1437           len = entry->router ? strlen(entry->router->server_name) :
1438             strlen(server->server_name);
1439           silc_strncat(nh, sizeof(nh), entry->router ?
1440                        entry->router->server_name :
1441                        server->server_name, len);
1442         }
1443       }
1444
1445       switch (query->querycmd) {
1446
1447       case SILC_COMMAND_WHOIS:
1448         {
1449           unsigned char idle[4], mode[4];
1450           unsigned char *fingerprint, fempty[20], *attrs = NULL;
1451           SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1452
1453           memset(fempty, 0, sizeof(fempty));
1454           memset(idle, 0, sizeof(idle));
1455           memset(uh, 0, sizeof(uh));
1456
1457           silc_strncat(uh, sizeof(uh), entry->username,
1458                        strlen(entry->username));
1459           if (!strchr(entry->username, '@') && entry->connection) {
1460             hsock = entry->connection;
1461             silc_strncat(uh, sizeof(uh), "@", 1);
1462             len = strlen(hsock->hostname);
1463             silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1464           }
1465
1466           if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1467             channels =
1468               silc_server_get_client_channel_list(server, entry, FALSE,
1469                                                   FALSE, &umode_list);
1470           else
1471             channels =
1472               silc_server_get_client_channel_list(server, entry, TRUE,
1473                                                   TRUE, &umode_list);
1474
1475           if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1476             fingerprint = entry->data.fingerprint;
1477           else
1478             fingerprint = NULL;
1479
1480           SILC_PUT32_MSB(entry->mode, mode);
1481           if (entry->connection)
1482             SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1483
1484           /* If Requested Attribute were present, and we do not have the
1485              attributes we will reply to them on behalf of the client. */
1486           len = 0;
1487           if (query->attrs) {
1488             if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1489               tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1490               entry->attrs = silc_buffer_steal(tmpattrs, &len);
1491               entry->attrs_len = len;
1492               silc_buffer_free(tmpattrs);
1493             }
1494             attrs = entry->attrs;
1495             len = entry->attrs_len;
1496           }
1497
1498           /* Send command reply */
1499           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1500                                          status, 0, ident, 10,
1501                                          2, idp->data, idp->len,
1502                                          3, nh, strlen(nh),
1503                                          4, uh, strlen(uh),
1504                                          5, entry->userinfo,
1505                                          strlen(entry->userinfo),
1506                                          6, channels ? channels->data : NULL,
1507                                          channels ? channels->len : 0,
1508                                          7, mode, 4,
1509                                          8, idle, 4,
1510                                          9, fingerprint,
1511                                          fingerprint ? 20 : 0,
1512                                          10, umode_list ? umode_list->data :
1513                                          NULL, umode_list ? umode_list->len :
1514                                          0, 11, attrs, len);
1515
1516           sent_reply = TRUE;
1517
1518           /* For now we always delete Requested Attributes, unless the client
1519              is detached, in which case we don't want to reconstruct the
1520              same data everytime */
1521           if (!(entry->mode & SILC_UMODE_DETACHED) &&
1522               !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1523             silc_free(entry->attrs);
1524             entry->attrs = NULL;
1525           }
1526
1527           if (channels)
1528             silc_buffer_free(channels);
1529           if (umode_list) {
1530             silc_buffer_free(umode_list);
1531             umode_list = NULL;
1532           }
1533         }
1534         break;
1535
1536       case SILC_COMMAND_IDENTIFY:
1537         if (!entry->username) {
1538           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1539                                          status, 0, ident, 2,
1540                                          2, idp->data, idp->len,
1541                                          3, nh, strlen(nh));
1542           sent_reply = TRUE;
1543         } else {
1544           silc_strncat(uh, sizeof(uh), entry->username,
1545                        strlen(entry->username));
1546           if (!strchr(entry->username, '@') && entry->connection) {
1547             hsock = entry->connection;
1548             silc_strncat(uh, sizeof(uh), "@", 1);
1549             len = strlen(hsock->hostname);
1550             silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1551           }
1552
1553           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1554                                          status, 0, ident, 3,
1555                                          2, idp->data, idp->len,
1556                                          3, nh, strlen(nh),
1557                                          4, uh, strlen(uh));
1558           sent_reply = TRUE;
1559         }
1560         break;
1561
1562       case SILC_COMMAND_WHOWAS:
1563         silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1564         if (!strchr(entry->username, '@'))
1565           silc_strncat(uh, sizeof(uh), "@-private-", 10);
1566
1567         /* Send command reply */
1568         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1569                                        status, 0, ident, 4,
1570                                        2, idp->data, idp->len,
1571                                        3, nh, strlen(nh),
1572                                        4, uh, strlen(uh),
1573                                        5, entry->userinfo,
1574                                        entry->userinfo ?
1575                                        strlen(entry->userinfo) : 0);
1576         sent_reply = TRUE;
1577         break;
1578       }
1579
1580       silc_buffer_free(idp);
1581
1582       if (status == SILC_STATUS_LIST_END)
1583         break;
1584       k++;
1585     }
1586
1587     if (k == 0) {
1588       /* Not one valid entry was found, send error.  If nickname was used
1589          in query send error based on that, otherwise the query->errors
1590          already includes proper errors. */
1591       if (query->nickname || (!query->ids && query->attrs))
1592         silc_server_query_add_error(server, query, 1, 1,
1593                                     SILC_STATUS_ERR_NO_SUCH_NICK);
1594
1595       /* Make sure some error is sent */
1596       if (!query->errors_count && !servers_count && !channels_count)
1597         silc_server_query_add_error(server, query, 2, 0,
1598                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1599     }
1600   }
1601
1602   /* Send servers */
1603   if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1604     SilcServerEntry entry;
1605
1606     if (status == SILC_STATUS_OK && servers_count > 1)
1607       status = SILC_STATUS_LIST_START;
1608
1609     k = 0;
1610     for (i = 0; i < servers_count; i++) {
1611       entry = servers[i];
1612
1613       if (k >= 1)
1614         status = SILC_STATUS_LIST_ITEM;
1615       if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1616           !query->errors_count)
1617         status = SILC_STATUS_LIST_END;
1618       if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1619           !query->errors_count)
1620         status = SILC_STATUS_LIST_END;
1621       if (query->reply_count && k - 1 == query->reply_count)
1622         status = SILC_STATUS_LIST_END;
1623
1624       SILC_LOG_DEBUG(("%s: server %s",
1625                       (status == SILC_STATUS_OK ?         "   OK" :
1626                        status == SILC_STATUS_LIST_START ? "START" :
1627                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1628                        status == SILC_STATUS_LIST_END  ?  "  END" :
1629                        "      : "),
1630                       entry->server_name ? entry->server_name : ""));
1631
1632       /* Send command reply */
1633       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1634       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1635                                      status, 0, ident, 2,
1636                                      2, idp->data, idp->len,
1637                                      3, entry->server_name,
1638                                      entry->server_name ?
1639                                      strlen(entry->server_name) : 0);
1640       silc_buffer_free(idp);
1641       sent_reply = TRUE;
1642
1643       if (status == SILC_STATUS_LIST_END)
1644         break;
1645       k++;
1646     }
1647   }
1648
1649   /* Send channels */
1650   if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1651     SilcChannelEntry entry;
1652
1653     if (status == SILC_STATUS_OK && channels_count > 1)
1654       status = SILC_STATUS_LIST_START;
1655
1656     k = 0;
1657     for (i = 0; i < channels_count; i++) {
1658       entry = channels[i];
1659
1660       if (k >= 1)
1661         status = SILC_STATUS_LIST_ITEM;
1662       if (channels_count == 1 && status != SILC_STATUS_OK &&
1663           !query->errors_count)
1664         status = SILC_STATUS_LIST_END;
1665       if (channels_count > 1 && k == channels_count - 1 &&
1666           !query->errors_count)
1667         status = SILC_STATUS_LIST_END;
1668       if (query->reply_count && k - 1 == query->reply_count)
1669         status = SILC_STATUS_LIST_END;
1670
1671       SILC_LOG_DEBUG(("%s: channel %s",
1672                       (status == SILC_STATUS_OK ?         "   OK" :
1673                        status == SILC_STATUS_LIST_START ? "START" :
1674                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1675                        status == SILC_STATUS_LIST_END  ?  "  END" :
1676                        "      : "),
1677                       entry->channel_name ? entry->channel_name : ""));
1678
1679       /* Send command reply */
1680       idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1681       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1682                                      status, 0, ident, 2,
1683                                      2, idp->data, idp->len,
1684                                      3, entry->channel_name,
1685                                      entry->channel_name ?
1686                                      strlen(entry->channel_name) : 0);
1687       silc_buffer_free(idp);
1688       sent_reply = TRUE;
1689
1690       if (status == SILC_STATUS_LIST_END)
1691         break;
1692       k++;
1693     }
1694   }
1695
1696   /* Send errors */
1697   if (query->errors_count) {
1698     int type;
1699
1700     if (status == SILC_STATUS_OK && query->errors_count > 1)
1701       status = SILC_STATUS_LIST_START;
1702
1703     k = 0;
1704     for (i = 0; i < query->errors_count; i++) {
1705       idp = NULL;
1706
1707       /* Take error argument */
1708       if (query->errors[i].type == 1) {
1709         /* Take from sent arguments */
1710         len = 0;
1711         tmp = silc_argument_get_arg_type(cmd->args,
1712                                          query->errors[i].index, &len);
1713         type = 2;
1714       } else if (query->errors[i].type == 2) {
1715         /* No argument */
1716         len = 0;
1717         tmp = NULL;
1718         type = 0;
1719       } else if (!query->errors[i].id) {
1720         /* Take from query->ids */
1721         idp =
1722           silc_id_payload_encode(query->ids[query->errors[i].index].id,
1723                                  query->ids[query->errors[k].index].id_type);
1724         tmp = idp->data;
1725         len = idp->len;
1726         type = 2;
1727       } else {
1728         /* Take added ID. */
1729         idp = silc_id_payload_encode(query->errors[i].id,
1730                                      query->errors[k].id_type);
1731         tmp = idp->data;
1732         len = idp->len;
1733         type = 2;
1734       }
1735
1736       if (k >= 1)
1737         status = SILC_STATUS_LIST_ITEM;
1738       if (query->errors_count == 1 && status != SILC_STATUS_OK)
1739         status = SILC_STATUS_LIST_END;
1740       if (query->errors_count > 1 && k == query->errors_count - 1)
1741         status = SILC_STATUS_LIST_END;
1742       if (query->reply_count && k - 1 == query->reply_count)
1743         status = SILC_STATUS_LIST_END;
1744
1745       SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1746                       (status == SILC_STATUS_OK ?         "   OK" :
1747                        status == SILC_STATUS_LIST_START ? "START" :
1748                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1749                        status == SILC_STATUS_LIST_END  ?  "  END" :
1750                        "      : "),
1751                       silc_get_status_message(query->errors[i].error),
1752                       query->errors[i].error));
1753
1754 #if 1 /* XXX Backwards compatibility.  Remove in 1.0. */
1755       if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1756         /* Send error */
1757         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1758                                        (status == SILC_STATUS_OK ?
1759                                         query->errors[i].error : status),
1760                                        (status == SILC_STATUS_OK ?
1761                                         0 : query->errors[i].error), ident, 2,
1762                                        type, tmp, len,
1763                                        3, tmp, len);
1764       else
1765 #endif
1766       /* Send error */
1767       silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1768                                      (status == SILC_STATUS_OK ?
1769                                       query->errors[i].error : status),
1770                                      (status == SILC_STATUS_OK ?
1771                                       0 : query->errors[i].error), ident, 1,
1772                                      type, tmp, len);
1773
1774       silc_buffer_free(idp);
1775       sent_reply = TRUE;
1776
1777       if (status == SILC_STATUS_LIST_END)
1778         break;
1779       k++;
1780     }
1781   }
1782
1783   if (!sent_reply)
1784     SILC_LOG_ERROR(("BUG: Query did not send anything"));
1785
1786   /* Cleanup */
1787   silc_server_query_free(query);
1788 }
1789
1790 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1791    of the client since we were unable to resolve them from the client.
1792    Either client does not support Requested Attributes or isn't replying
1793    to them like it should. */
1794
1795 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1796                                          SilcServerQuery query,
1797                                          SilcClientEntry client_entry)
1798 {
1799   SilcBuffer buffer = NULL;
1800   SilcAttribute attribute;
1801   SilcAttributePayload attr;
1802   SilcAttributeObjPk pk;
1803   SilcAttributeObjService service;
1804   unsigned char *tmp;
1805   unsigned char sign[2048 + 1];
1806   SilcUInt32 sign_len;
1807
1808   SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1809
1810   /* Go through all requested attributes */
1811   silc_dlist_start(query->attrs);
1812   while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1813     attribute = silc_attribute_get_attribute(attr);
1814     switch (attribute) {
1815
1816     case SILC_ATTRIBUTE_SERVICE:
1817       /* Put SERVICE.  Put only SILC service. */
1818       memset(&service, 0, sizeof(service));
1819       service.port = (server->config->server_info->primary ?
1820                       server->config->server_info->primary->port : SILC_PORT);
1821       silc_strncat(service.address, sizeof(service.address),
1822                    server->server_name, strlen(server->server_name));
1823       service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1824       if (client_entry->connection)
1825         service.idle = time(NULL) - client_entry->data.last_receive;
1826       buffer = silc_attribute_payload_encode(buffer, attribute,
1827                                              SILC_ATTRIBUTE_FLAG_VALID,
1828                                              &service, sizeof(service));
1829       if (!buffer)
1830         return NULL;
1831       break;
1832
1833     case SILC_ATTRIBUTE_STATUS_MOOD:
1834       /* Put STATUS_MOOD */
1835       buffer = silc_attribute_payload_encode(buffer, attribute,
1836                                              SILC_ATTRIBUTE_FLAG_VALID,
1837                                              (void *)
1838                                              SILC_ATTRIBUTE_MOOD_NORMAL,
1839                                              sizeof(SilcUInt32));
1840       if (!buffer)
1841         return NULL;
1842       break;
1843
1844     case SILC_ATTRIBUTE_STATUS_FREETEXT:
1845       /* Put STATUS_FREETEXT.  We just tell in the message that we are
1846          replying on behalf of the client. */
1847       tmp =
1848         "This information was provided by the server on behalf of the user";
1849       buffer = silc_attribute_payload_encode(buffer, attribute,
1850                                              SILC_ATTRIBUTE_FLAG_VALID,
1851                                              tmp, strlen(tmp));
1852       if (!buffer)
1853         return NULL;
1854       break;
1855
1856     case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1857       /* Put PREFERRED_CONTACT */
1858       buffer = silc_attribute_payload_encode(buffer, attribute,
1859                                              SILC_ATTRIBUTE_FLAG_VALID,
1860                                              (void *)
1861                                              SILC_ATTRIBUTE_CONTACT_CHAT,
1862                                              sizeof(SilcUInt32));
1863       if (!buffer)
1864         return NULL;
1865       break;
1866
1867     case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1868       /* Put USER_PUBLIC_KEY */
1869       if (client_entry->data.public_key) {
1870         pk.type = "silc-rsa";
1871         pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1872                                               &pk.data_len);
1873         buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1874                                                SILC_ATTRIBUTE_FLAG_VALID :
1875                                                SILC_ATTRIBUTE_FLAG_INVALID,
1876                                                &pk, sizeof(pk));
1877         silc_free(pk.data);
1878         if (!buffer)
1879           return NULL;
1880         break;
1881       }
1882
1883       /* No public key available */
1884       buffer = silc_attribute_payload_encode(buffer, attribute,
1885                                              SILC_ATTRIBUTE_FLAG_INVALID,
1886                                              NULL, 0);
1887       if (!buffer)
1888         return NULL;
1889       break;
1890
1891     default:
1892       /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1893       if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1894           attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1895         break;
1896
1897       /* For other attributes we cannot reply so mark it invalid */
1898       buffer = silc_attribute_payload_encode(buffer, attribute,
1899                                              SILC_ATTRIBUTE_FLAG_INVALID,
1900                                              NULL, 0);
1901       if (!buffer)
1902         return NULL;
1903       break;
1904     }
1905   }
1906
1907   /* Always put our public key.  This assures that we send at least
1908      something valid back always. */
1909   pk.type = "silc-rsa";
1910   pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1911   buffer = silc_attribute_payload_encode(buffer,
1912                                          SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1913                                          pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1914                                          SILC_ATTRIBUTE_FLAG_INVALID,
1915                                          &pk, sizeof(pk));
1916   silc_free(pk.data);
1917   if (!buffer)
1918     return NULL;
1919
1920   /* Finally compute the digital signature of all the data we provided
1921      as an indication that we provided rightfull information, and this
1922      also authenticates our public key. */
1923   if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1  &&
1924       silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1925                                buffer->data, buffer->len,
1926                                sign, &sign_len)) {
1927     pk.type = NULL;
1928     pk.data = sign;
1929     pk.data_len = sign_len;
1930     buffer =
1931       silc_attribute_payload_encode(buffer,
1932                                     SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1933                                     SILC_ATTRIBUTE_FLAG_VALID,
1934                                     &pk, sizeof(pk));
1935   }
1936   if (!buffer)
1937     return NULL;
1938
1939   return buffer;
1940 }
1941
1942 /* Find client by the Client ID indicated by the `client_id', and if not
1943    found then query it by using WHOIS command.  The client information
1944    is also resolved if the cached information is incomplete or if the
1945    `always_resolve' is set to TRUE.  The indication whether requested
1946    client was being resolved is saved into `resolved'.  If the client
1947    is not being resolved its entry is returned by this function.  NULL
1948    is returned if client is resolved. */
1949
1950 SilcClientEntry silc_server_query_client(SilcServer server,
1951                                          const SilcClientID *client_id,
1952                                          bool always_resolve,
1953                                          bool *resolved)
1954 {
1955   SilcClientEntry client;
1956
1957   SILC_LOG_DEBUG(("Resolving client by client ID"));
1958
1959   if (resolved)
1960     *resolved = FALSE;
1961
1962   client = silc_idlist_find_client_by_id(server->local_list,
1963                                          (SilcClientID *)client_id,
1964                                          TRUE, NULL);
1965   if (!client) {
1966     client = silc_idlist_find_client_by_id(server->global_list,
1967                                            (SilcClientID *)client_id,
1968                                            TRUE, NULL);
1969     if (!client && server->server_type == SILC_ROUTER)
1970       return NULL;
1971   }
1972
1973   if (!client && server->standalone)
1974     return NULL;
1975
1976   if (!client || !client->nickname || !client->username ||
1977       always_resolve) {
1978     SilcBuffer buffer, idp;
1979
1980     /* Statistics */
1981     server->stat.commands_sent++;
1982
1983     if (client) {
1984       client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1985       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1986       client->resolve_cmd_ident = ++server->cmd_ident;
1987     }
1988
1989     idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1990     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1991                                             server->cmd_ident, 1,
1992                                             4, idp->data, idp->len);
1993     silc_server_packet_send(server, client ? client->router->connection :
1994                             SILC_PRIMARY_ROUTE(server),
1995                             SILC_PACKET_COMMAND, 0,
1996                             buffer->data, buffer->len, FALSE);
1997     silc_buffer_free(idp);
1998     silc_buffer_free(buffer);
1999
2000     if (resolved)
2001       *resolved = TRUE;
2002
2003     return NULL;
2004   }
2005
2006   return client;
2007 }