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