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