f54145da589c2cd00c4601e13bc4d36101bde079
[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           silc_strncat(uh, sizeof(uh), entry->username,
1547                        strlen(entry->username));
1548           if (!strchr(entry->username, '@') && entry->connection) {
1549             hsock = entry->connection;
1550             silc_strncat(uh, sizeof(uh), "@", 1);
1551             len = strlen(hsock->hostname);
1552             silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1553           }
1554
1555           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1556                                          status, 0, ident, 3,
1557                                          2, idp->data, idp->len,
1558                                          3, nh, strlen(nh),
1559                                          4, uh, strlen(uh));
1560           sent_reply = TRUE;
1561         }
1562         break;
1563
1564       case SILC_COMMAND_WHOWAS:
1565         silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1566         if (!strchr(entry->username, '@'))
1567           silc_strncat(uh, sizeof(uh), "@-private-", 10);
1568
1569         /* Send command reply */
1570         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1571                                        status, 0, ident, 4,
1572                                        2, idp->data, idp->len,
1573                                        3, nh, strlen(nh),
1574                                        4, uh, strlen(uh),
1575                                        5, entry->userinfo,
1576                                        entry->userinfo ?
1577                                        strlen(entry->userinfo) : 0);
1578         sent_reply = TRUE;
1579         break;
1580       }
1581
1582       silc_buffer_free(idp);
1583
1584       if (status == SILC_STATUS_LIST_END)
1585         break;
1586       k++;
1587     }
1588
1589     if (k == 0) {
1590       /* Not one valid entry was found, send error.  If nickname was used
1591          in query send error based on that, otherwise the query->errors
1592          already includes proper errors. */
1593       if (query->nickname || (!query->ids && query->attrs))
1594         silc_server_query_add_error(server, query, 1, 1,
1595                                     SILC_STATUS_ERR_NO_SUCH_NICK);
1596
1597       /* Make sure some error is sent */
1598       if (!query->errors_count && !servers_count && !channels_count)
1599         silc_server_query_add_error(server, query, 2, 0,
1600                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1601     }
1602   }
1603
1604   /* Send servers */
1605   if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1606     SilcServerEntry entry;
1607
1608     if (status == SILC_STATUS_OK && servers_count > 1)
1609       status = SILC_STATUS_LIST_START;
1610
1611     k = 0;
1612     for (i = 0; i < servers_count; i++) {
1613       entry = servers[i];
1614
1615       if (k >= 1)
1616         status = SILC_STATUS_LIST_ITEM;
1617       if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1618           !query->errors_count)
1619         status = SILC_STATUS_LIST_END;
1620       if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1621           !query->errors_count)
1622         status = SILC_STATUS_LIST_END;
1623       if (query->reply_count && k - 1 == query->reply_count)
1624         status = SILC_STATUS_LIST_END;
1625
1626       SILC_LOG_DEBUG(("%s: server %s",
1627                       (status == SILC_STATUS_OK ?         "   OK" :
1628                        status == SILC_STATUS_LIST_START ? "START" :
1629                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1630                        status == SILC_STATUS_LIST_END  ?  "  END" :
1631                        "      : "),
1632                       entry->server_name ? entry->server_name : ""));
1633
1634       /* Send command reply */
1635       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1636       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1637                                      status, 0, ident, 2,
1638                                      2, idp->data, idp->len,
1639                                      3, entry->server_name,
1640                                      entry->server_name ?
1641                                      strlen(entry->server_name) : 0);
1642       silc_buffer_free(idp);
1643       sent_reply = TRUE;
1644
1645       if (status == SILC_STATUS_LIST_END)
1646         break;
1647       k++;
1648     }
1649   }
1650
1651   /* Send channels */
1652   if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1653     SilcChannelEntry entry;
1654
1655     if (status == SILC_STATUS_OK && channels_count > 1)
1656       status = SILC_STATUS_LIST_START;
1657
1658     k = 0;
1659     for (i = 0; i < channels_count; i++) {
1660       entry = channels[i];
1661
1662       if (k >= 1)
1663         status = SILC_STATUS_LIST_ITEM;
1664       if (channels_count == 1 && status != SILC_STATUS_OK &&
1665           !query->errors_count)
1666         status = SILC_STATUS_LIST_END;
1667       if (channels_count > 1 && k == channels_count - 1 &&
1668           !query->errors_count)
1669         status = SILC_STATUS_LIST_END;
1670       if (query->reply_count && k - 1 == query->reply_count)
1671         status = SILC_STATUS_LIST_END;
1672
1673       SILC_LOG_DEBUG(("%s: channel %s",
1674                       (status == SILC_STATUS_OK ?         "   OK" :
1675                        status == SILC_STATUS_LIST_START ? "START" :
1676                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1677                        status == SILC_STATUS_LIST_END  ?  "  END" :
1678                        "      : "),
1679                       entry->channel_name ? entry->channel_name : ""));
1680
1681       /* Send command reply */
1682       idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1683       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1684                                      status, 0, ident, 2,
1685                                      2, idp->data, idp->len,
1686                                      3, entry->channel_name,
1687                                      entry->channel_name ?
1688                                      strlen(entry->channel_name) : 0);
1689       silc_buffer_free(idp);
1690       sent_reply = TRUE;
1691
1692       if (status == SILC_STATUS_LIST_END)
1693         break;
1694       k++;
1695     }
1696   }
1697
1698   /* Send errors */
1699   if (query->errors_count) {
1700     int type;
1701
1702     if (status == SILC_STATUS_OK && query->errors_count > 1)
1703       status = SILC_STATUS_LIST_START;
1704
1705     k = 0;
1706     for (i = 0; i < query->errors_count; i++) {
1707       idp = NULL;
1708
1709       /* Take error argument */
1710       if (query->errors[i].type == 1) {
1711         /* Take from sent arguments */
1712         len = 0;
1713         tmp = silc_argument_get_arg_type(cmd->args,
1714                                          query->errors[i].index, &len);
1715         type = 2;
1716       } else if (query->errors[i].type == 2) {
1717         /* No argument */
1718         len = 0;
1719         tmp = NULL;
1720         type = 0;
1721       } else if (!query->errors[i].id) {
1722         /* Take from query->ids */
1723         idp =
1724           silc_id_payload_encode(query->ids[query->errors[i].index].id,
1725                                  query->ids[query->errors[k].index].id_type);
1726         tmp = idp->data;
1727         len = idp->len;
1728         type = 2;
1729       } else {
1730         /* Take added ID. */
1731         idp = silc_id_payload_encode(query->errors[i].id,
1732                                      query->errors[k].id_type);
1733         tmp = idp->data;
1734         len = idp->len;
1735         type = 2;
1736       }
1737
1738       if (k >= 1)
1739         status = SILC_STATUS_LIST_ITEM;
1740       if (query->errors_count == 1 && status != SILC_STATUS_OK)
1741         status = SILC_STATUS_LIST_END;
1742       if (query->errors_count > 1 && k == query->errors_count - 1)
1743         status = SILC_STATUS_LIST_END;
1744       if (query->reply_count && k - 1 == query->reply_count)
1745         status = SILC_STATUS_LIST_END;
1746
1747       SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1748                       (status == SILC_STATUS_OK ?         "   OK" :
1749                        status == SILC_STATUS_LIST_START ? "START" :
1750                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1751                        status == SILC_STATUS_LIST_END  ?  "  END" :
1752                        "      : "),
1753                       silc_get_status_message(query->errors[i].error),
1754                       query->errors[i].error));
1755
1756 #if 1 /* XXX Backwards compatibility.  Remove in 1.0. */
1757       if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1758         /* Send error */
1759         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1760                                        (status == SILC_STATUS_OK ?
1761                                         query->errors[i].error : status),
1762                                        (status == SILC_STATUS_OK ?
1763                                         0 : query->errors[i].error), ident, 2,
1764                                        type, tmp, len,
1765                                        3, tmp, len);
1766       else
1767 #endif
1768       /* Send error */
1769       silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1770                                      (status == SILC_STATUS_OK ?
1771                                       query->errors[i].error : status),
1772                                      (status == SILC_STATUS_OK ?
1773                                       0 : query->errors[i].error), ident, 1,
1774                                      type, tmp, len);
1775
1776       silc_buffer_free(idp);
1777       sent_reply = TRUE;
1778
1779       if (status == SILC_STATUS_LIST_END)
1780         break;
1781       k++;
1782     }
1783   }
1784
1785   if (!sent_reply)
1786     SILC_LOG_ERROR(("BUG: Query did not send anything"));
1787
1788   /* Cleanup */
1789   silc_server_query_free(query);
1790 }
1791
1792 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1793    of the client since we were unable to resolve them from the client.
1794    Either client does not support Requested Attributes or isn't replying
1795    to them like it should. */
1796
1797 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1798                                          SilcServerQuery query,
1799                                          SilcClientEntry client_entry)
1800 {
1801   SilcBuffer buffer = NULL;
1802   SilcAttribute attribute;
1803   SilcAttributePayload attr;
1804   SilcAttributeObjPk pk;
1805   SilcAttributeObjService service;
1806   unsigned char *tmp;
1807   unsigned char sign[2048 + 1];
1808   SilcUInt32 sign_len;
1809
1810   SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1811
1812   /* Go through all requested attributes */
1813   silc_dlist_start(query->attrs);
1814   while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1815     attribute = silc_attribute_get_attribute(attr);
1816     switch (attribute) {
1817
1818     case SILC_ATTRIBUTE_SERVICE:
1819       /* Put SERVICE.  Put only SILC service. */
1820       memset(&service, 0, sizeof(service));
1821       service.port = (server->config->server_info->primary ?
1822                       server->config->server_info->primary->port : SILC_PORT);
1823       silc_strncat(service.address, sizeof(service.address),
1824                    server->server_name, strlen(server->server_name));
1825       service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1826       if (client_entry->connection)
1827         service.idle = time(NULL) - client_entry->data.last_receive;
1828       buffer = silc_attribute_payload_encode(buffer, attribute,
1829                                              SILC_ATTRIBUTE_FLAG_VALID,
1830                                              &service, sizeof(service));
1831       if (!buffer)
1832         return NULL;
1833       break;
1834
1835     case SILC_ATTRIBUTE_STATUS_MOOD:
1836       /* Put STATUS_MOOD */
1837       buffer = silc_attribute_payload_encode(buffer, attribute,
1838                                              SILC_ATTRIBUTE_FLAG_VALID,
1839                                              (void *)
1840                                              SILC_ATTRIBUTE_MOOD_NORMAL,
1841                                              sizeof(SilcUInt32));
1842       if (!buffer)
1843         return NULL;
1844       break;
1845
1846     case SILC_ATTRIBUTE_STATUS_FREETEXT:
1847       /* Put STATUS_FREETEXT.  We just tell in the message that we are
1848          replying on behalf of the client. */
1849       tmp =
1850         "This information was provided by the server on behalf of the user";
1851       buffer = silc_attribute_payload_encode(buffer, attribute,
1852                                              SILC_ATTRIBUTE_FLAG_VALID,
1853                                              tmp, strlen(tmp));
1854       if (!buffer)
1855         return NULL;
1856       break;
1857
1858     case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1859       /* Put PREFERRED_CONTACT */
1860       buffer = silc_attribute_payload_encode(buffer, attribute,
1861                                              SILC_ATTRIBUTE_FLAG_VALID,
1862                                              (void *)
1863                                              SILC_ATTRIBUTE_CONTACT_CHAT,
1864                                              sizeof(SilcUInt32));
1865       if (!buffer)
1866         return NULL;
1867       break;
1868
1869     case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1870       /* Put USER_PUBLIC_KEY */
1871       if (client_entry->data.public_key) {
1872         pk.type = "silc-rsa";
1873         pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1874                                               &pk.data_len);
1875         buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1876                                                SILC_ATTRIBUTE_FLAG_VALID :
1877                                                SILC_ATTRIBUTE_FLAG_INVALID,
1878                                                &pk, sizeof(pk));
1879         silc_free(pk.data);
1880         if (!buffer)
1881           return NULL;
1882         break;
1883       }
1884
1885       /* No public key available */
1886       buffer = silc_attribute_payload_encode(buffer, attribute,
1887                                              SILC_ATTRIBUTE_FLAG_INVALID,
1888                                              NULL, 0);
1889       if (!buffer)
1890         return NULL;
1891       break;
1892
1893     default:
1894       /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1895       if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1896           attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1897         break;
1898
1899       /* For other attributes we cannot reply so mark it invalid */
1900       buffer = silc_attribute_payload_encode(buffer, attribute,
1901                                              SILC_ATTRIBUTE_FLAG_INVALID,
1902                                              NULL, 0);
1903       if (!buffer)
1904         return NULL;
1905       break;
1906     }
1907   }
1908
1909   /* Always put our public key.  This assures that we send at least
1910      something valid back always. */
1911   pk.type = "silc-rsa";
1912   pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1913   buffer = silc_attribute_payload_encode(buffer,
1914                                          SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1915                                          pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1916                                          SILC_ATTRIBUTE_FLAG_INVALID,
1917                                          &pk, sizeof(pk));
1918   silc_free(pk.data);
1919   if (!buffer)
1920     return NULL;
1921
1922   /* Finally compute the digital signature of all the data we provided
1923      as an indication that we provided rightfull information, and this
1924      also authenticates our public key. */
1925   if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1  &&
1926       silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1927                                buffer->data, buffer->len,
1928                                sign, &sign_len)) {
1929     pk.type = NULL;
1930     pk.data = sign;
1931     pk.data_len = sign_len;
1932     buffer =
1933       silc_attribute_payload_encode(buffer,
1934                                     SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1935                                     SILC_ATTRIBUTE_FLAG_VALID,
1936                                     &pk, sizeof(pk));
1937   }
1938   if (!buffer)
1939     return NULL;
1940
1941   return buffer;
1942 }
1943
1944 /* Find client by the Client ID indicated by the `client_id', and if not
1945    found then query it by using WHOIS command.  The client information
1946    is also resolved if the cached information is incomplete or if the
1947    `always_resolve' is set to TRUE.  The indication whether requested
1948    client was being resolved is saved into `resolved'.  If the client
1949    is not being resolved its entry is returned by this function.  NULL
1950    is returned if client is resolved. */
1951
1952 SilcClientEntry silc_server_query_client(SilcServer server,
1953                                          const SilcClientID *client_id,
1954                                          bool always_resolve,
1955                                          bool *resolved)
1956 {
1957   SilcClientEntry client;
1958
1959   SILC_LOG_DEBUG(("Resolving client by client ID"));
1960
1961   if (resolved)
1962     *resolved = FALSE;
1963
1964   client = silc_idlist_find_client_by_id(server->local_list,
1965                                          (SilcClientID *)client_id,
1966                                          TRUE, NULL);
1967   if (!client) {
1968     client = silc_idlist_find_client_by_id(server->global_list,
1969                                            (SilcClientID *)client_id,
1970                                            TRUE, NULL);
1971     if (!client && server->server_type == SILC_ROUTER)
1972       return NULL;
1973   }
1974
1975   if (!client && server->standalone)
1976     return NULL;
1977
1978   if (!client || !client->nickname || !client->username ||
1979       always_resolve) {
1980     SilcBuffer buffer, idp;
1981
1982     /* Statistics */
1983     server->stat.commands_sent++;
1984
1985     if (client) {
1986       client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1987       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1988       client->resolve_cmd_ident = ++server->cmd_ident;
1989     }
1990
1991     idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1992     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1993                                             server->cmd_ident, 1,
1994                                             4, idp->data, idp->len);
1995     silc_server_packet_send(server, client ? client->router->connection :
1996                             SILC_PRIMARY_ROUTE(server),
1997                             SILC_PACKET_COMMAND, 0,
1998                             buffer->data, buffer->len, FALSE);
1999     silc_buffer_free(idp);
2000     silc_buffer_free(buffer);
2001
2002     if (resolved)
2003       *resolved = TRUE;
2004
2005     return NULL;
2006   }
2007
2008   return client;
2009 }