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