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