Added dynamic server connection support with WHOIS and IDENTIFY
[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, 2007 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   SilcPacketStream sock;            /* Connection of this query */
26   unsigned char **arg;              /* Query argument */
27   SilcUInt32 *arg_lens;             /* Query argument lengths */
28   SilcUInt32 *arg_types;            /* Query argument types */
29   SilcUInt32 argc;                  /* Number of query arguments */
30   SilcUInt32 timeout;               /* Max timeout for query to complete */
31   SilcUInt16 ident;                 /* Query command identifier */
32 } *SilcServerQueryList;
33
34 /* Represents an SILC ID */
35 typedef struct {
36   void *id;                         /* ID */
37   SilcIdType id_type;               /* ID type */
38   SilcUInt16 ident;                 /* Command identifier */
39 } *SilcServerQueryID;
40
41 /* Represents one error occurred during query */
42 typedef struct {
43   void *id;                         /* ID */
44   SilcIdType id_type;               /* ID type */
45   unsigned int index : 15;          /* Index to IDs */
46   unsigned int type : 2;            /* 0 = take from query->ids, 1 = take
47                                        from args, 2 = no args in error. */
48   unsigned int error : 7;           /* The actual error (SilcStatus) */
49 } *SilcServerQueryError;
50
51 /* Query session context */
52 typedef struct {
53   /* Queried data */
54   char nickname[128 + 1];           /* Queried nickname, normalized */
55   char nick_server[128 + 1];        /* 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   SilcPacketStream router;          /* Router to send our query */
65   SilcServerCommandContext cmd;     /* Command context for query */
66   SilcServerQueryList querylist;    /* Temporary query list context */
67   SilcServerQueryID queries;        /* Ongoing queries */
68   SilcServerQueryError errors;      /* Query errors */
69   SilcUInt16 querylist_count;       /* Number of query lists */
70   SilcUInt16 queries_count;         /* Number of ongoing queries */
71   SilcUInt16 queries_left;          /* Number of ongoing queries left */
72   SilcUInt16 errors_count;          /* number of errors */
73   unsigned int querycmd      : 7;   /* Query command (SilcCommand) */
74   unsigned int resolved      : 1;   /* TRUE if normal server has resolved
75                                        information from router */
76   unsigned int dynamic_prim  : 1;   /* Dynamic connection attempt to primary */
77   unsigned int dynamic_retry : 1;   /* Primary returned error, send to
78                                        nick@serv server. */
79 } *SilcServerQuery;
80
81
82 void silc_server_query_free(SilcServerQuery query);
83 void silc_server_query_send_error(SilcServer server,
84                                   SilcServerQuery query,
85                                   SilcStatus error, ...);
86 void silc_server_query_add_error(SilcServer server,
87                                  SilcServerQuery query,
88                                  SilcUInt32 type,
89                                  SilcUInt32 index,
90                                  SilcStatus error);
91 void silc_server_query_add_error_id(SilcServer server,
92                                     SilcServerQuery query,
93                                     SilcStatus error,
94                                     void *id, SilcIdType id_type);
95 void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
96 void silc_server_query_send_router_reply(void *context, void *reply);
97 void silc_server_query_parse(SilcServer server, SilcServerQuery query);
98 void silc_server_query_process(SilcServer server, SilcServerQuery query,
99                                SilcBool resolve);
100 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
101                                SilcPacketStream sock,
102                                SilcClientEntry client_entry);
103 void silc_server_query_resolve_reply(void *context, void *reply);
104 void silc_server_query_send_reply(SilcServer server,
105                                   SilcServerQuery query,
106                                   SilcClientEntry *clients,
107                                   SilcUInt32 clients_count,
108                                   SilcServerEntry *servers,
109                                   SilcUInt32 servers_count,
110                                   SilcChannelEntry *channels,
111                                   SilcUInt32 channels_count);
112 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
113                                          SilcServerQuery query,
114                                          SilcClientEntry client_entry);
115
116 /* Free the query context structure and all allocated resources. */
117
118 void silc_server_query_free(SilcServerQuery query)
119 {
120   int i;
121
122   silc_server_command_free(query->cmd);
123
124   for (i = 0; i < query->queries_count; i++)
125     silc_free(query->queries[i].id);
126   silc_free(query->queries);
127
128   silc_free(query->server_name);
129   silc_free(query->channel_name);
130
131   for (i = 0; i < query->ids_count; i++)
132     silc_free(query->ids[i].id);
133   silc_free(query->ids);
134
135   if (query->attrs)
136     silc_attribute_payload_list_free(query->attrs);
137
138   for (i = 0; i < query->errors_count; i++)
139     silc_free(query->errors[i].id);
140   silc_free(query->errors);
141
142   memset(query, 'F', sizeof(*query));
143   silc_free(query);
144 }
145
146 /* Send error reply indicated by the `error' to the original sender of
147    the query. */
148
149 void silc_server_query_send_error(SilcServer server,
150                                   SilcServerQuery query,
151                                   SilcStatus error, ...)
152 {
153   va_list va;
154   unsigned char *data = NULL;
155   SilcUInt32 data_len = 0, data_type = 0, argc = 0;
156
157   va_start(va, error);
158   data_type = va_arg(va, SilcUInt32);
159   if (data_type) {
160     argc = 1;
161     data = va_arg(va, unsigned char *);
162     data_len = va_arg(va, SilcUInt32);
163   }
164
165   SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
166
167   /* Send the command reply with error */
168   silc_server_send_command_reply(server, query->cmd->sock,
169                                  query->querycmd, error, 0,
170                                  silc_command_get_ident(query->cmd->payload),
171                                  argc, data_type, data, data_len);
172   va_end(va);
173 }
174
175 /* Add error to error list.  Multiple errors may occur during the query
176    processing and this function can be used to add one error.  The
177    `index' is the index to the command context which includes the argument
178    which caused the error, or it is the index to query->ids, depending
179    on value of `type'.  If `type' is 0 the index is to query->ids, if
180    it is 1 it is index to the command context arguments, and if it is
181    2 the index is ignored and no argument is included in the error. */
182
183 void silc_server_query_add_error(SilcServer server,
184                                  SilcServerQuery query,
185                                  SilcUInt32 type,
186                                  SilcUInt32 index,
187                                  SilcStatus error)
188 {
189   query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
190                                (query->errors_count + 1));
191   if (!query->errors)
192     return;
193   query->errors[query->errors_count].index = index;
194   query->errors[query->errors_count].type = type;
195   query->errors[query->errors_count].error = error;
196   query->errors[query->errors_count].id = NULL;
197   query->errors[query->errors_count].id_type = 0;
198   query->errors_count++;
199 }
200
201 /* Same as silc_server_query_add_error but adds the ID data to be used
202    with error sending with this error type. */
203
204 void silc_server_query_add_error_id(SilcServer server,
205                                     SilcServerQuery query,
206                                     SilcStatus error,
207                                     void *id, SilcIdType id_type)
208 {
209   query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
210                                (query->errors_count + 1));
211   if (!query->errors)
212     return;
213   query->errors[query->errors_count].index = 0;
214   query->errors[query->errors_count].type = 0;
215   query->errors[query->errors_count].error = error;
216   query->errors[query->errors_count].id = silc_id_dup(id, id_type);
217   query->errors[query->errors_count].id_type = id_type;
218   query->errors_count++;
219 }
220
221 /* Processes query as command.  The `query' is the command that is
222    being processed indicated by the `cmd'.  The `query' can be one of
223    the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
224    SILC_COMMAND_IDENTIFY.  This function handles the reply sending
225    to the entity who sent this query to us automatically.  Returns
226    TRUE if the query is being processed or FALSE on error. */
227
228 SilcBool silc_server_query_command(SilcServer server,
229                                    SilcCommand querycmd,
230                                    SilcServerCommandContext cmd,
231                                    void *old_query)
232 {
233   SilcServerQuery query;
234
235   SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
236
237   if (!old_query) {
238     query = silc_calloc(1, sizeof(*query));
239     query->querycmd = querycmd;
240     query->cmd = silc_server_command_dup(cmd);
241     query->router = SILC_PRIMARY_ROUTE(server);
242   } else
243     query = old_query;
244
245   switch (querycmd) {
246
247   case SILC_COMMAND_WHOIS:
248     /* If we are normal server and query contains nickname OR query
249        doesn't contain nickname or ids BUT attributes, send it to the
250        router */
251     if (server->server_type != SILC_ROUTER && !server->standalone &&
252         cmd->sock != SILC_PRIMARY_ROUTE(server) &&
253          (silc_argument_get_arg_type(cmd->args, 1, NULL) ||
254          (!silc_argument_get_arg_type(cmd->args, 1, NULL) &&
255           !silc_argument_get_arg_type(cmd->args, 4, NULL) &&
256           silc_argument_get_arg_type(cmd->args, 3, NULL)))) {
257       silc_server_query_send_router(server, query);
258       return TRUE;
259     }
260     break;
261
262   case SILC_COMMAND_WHOWAS:
263     /* WHOWAS query is always sent to router if we are normal server */
264     if (server->server_type == SILC_SERVER && !server->standalone &&
265         cmd->sock != SILC_PRIMARY_ROUTE(server)) {
266       silc_server_query_send_router(server, query);
267       return TRUE;
268     }
269     break;
270
271   case SILC_COMMAND_IDENTIFY:
272     /* If we are normal server and query does not contain IDs, send it
273        directly to router (it contains nickname, server name or channel
274        name). */
275     if (server->server_type == SILC_SERVER && !server->standalone &&
276         cmd->sock != SILC_PRIMARY_ROUTE(server) &&
277         !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
278       silc_server_query_send_router(server, query);
279       return TRUE;
280     }
281     break;
282
283   default:
284     SILC_LOG_ERROR(("Bad query using %d command", querycmd));
285     silc_server_query_free(query);
286     return FALSE;
287   }
288
289   /* Now parse the request */
290   silc_server_query_parse(server, query);
291
292   return TRUE;
293 }
294
295 /* Remote server connected callback. */
296
297 void silc_server_query_connected(SilcServer server,
298                                  SilcServerEntry server_entry,
299                                  void *context)
300 {
301   SilcServerQuery query = context;
302
303   if (!server_entry) {
304     /* Connecting failed */
305
306     if (query->dynamic_prim /* && @serv != prim.host.name */ &&
307         !silc_server_num_sockets_by_remote(server, query->nick_server,
308                                            query->nick_server, 706)) {
309       /* Connection attempt to primary router failed, now try to the one
310          specified in nick@server. */
311       silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
312                                     706, silc_server_query_connected,
313                                     query);
314       query->dynamic_prim = FALSE;
315       return;
316     }
317
318     /* Process the query after failed connect.  This will send error back
319        because such nick was not found. */
320     SILC_LOG_DEBUG(("Process query, connecting failed"));
321     silc_server_query_process(server, query, TRUE);
322     return;
323   }
324
325   /* Reprocess the query */
326   SILC_LOG_DEBUG(("Reprocess query after creating connection to %s",
327                   server_entry->server_name));
328   query->router = server_entry->data.sconn->sock;
329   silc_server_query_command(server, query->querycmd, query->cmd, query);
330 }
331
332 /* Send the received query to our primary router since we could not
333    handle the query directly.  We will reprocess the query after our
334    router replies back. */
335
336 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
337 {
338   SilcBuffer tmpbuf;
339   SilcUInt16 old_ident;
340
341   SILC_LOG_DEBUG(("Forwarding the query to router %p for processing",
342                   query->router));
343
344   /* Statistics */
345   server->stat.commands_sent++;
346
347   /* Send WHOIS command to our router */
348   old_ident = silc_command_get_ident(query->cmd->payload);
349   silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
350   tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
351   silc_server_packet_send(server, query->router,
352                           SILC_PACKET_COMMAND, 0,
353                           tmpbuf->data, silc_buffer_len(tmpbuf));
354   silc_command_set_ident(query->cmd->payload, old_ident);
355   silc_buffer_free(tmpbuf);
356
357   query->resolved = TRUE;
358
359   /* Continue parsing the query after received reply from router */
360   silc_server_command_pending(server, query->querycmd, server->cmd_ident,
361                               silc_server_query_send_router_reply, query);
362 }
363
364 /* Reply callback called after primary router has replied to our initial
365    sending of the query to it.  We will proceed the query in this function. */
366
367 void silc_server_query_send_router_reply(void *context, void *reply)
368 {
369   SilcServerQuery query = context;
370   SilcServer server = query->cmd->server;
371   SilcServerCommandReplyContext cmdr = reply;
372
373   SILC_LOG_DEBUG(("Received reply from router to query"));
374
375   /* If the original command caller has gone away, just stop. */
376   if (!silc_packet_stream_is_valid(query->cmd->sock)) {
377     SILC_LOG_DEBUG(("Original command caller vanished"));
378     silc_server_query_free(query);
379     return;
380   }
381
382   /* Check if router sent error reply */
383   if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
384     SilcBuffer buffer;
385
386     /* If this was nick@server query, retry to @serv if the primary router
387        returned error. */
388     if (query->nick_server[0] && !query->dynamic_retry &&
389         !silc_server_num_sockets_by_remote(server, query->nick_server,
390                                            query->nick_server, 706)) {
391       SILC_LOG_DEBUG(("Retry query by connecting to %s:%d",
392                       query->nick_server, 706));
393       silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
394                                     706, silc_server_query_connected,
395                                     query);
396       query->dynamic_retry = TRUE;
397       query->resolved = FALSE;
398       return;
399     }
400
401     SILC_LOG_DEBUG(("Sending error to original query"));
402
403     /* Statistics */
404     server->stat.commands_sent++;
405
406     /* Send the same command reply payload which contains the error */
407     silc_command_set_command(cmdr->payload, query->querycmd);
408     silc_command_set_ident(cmdr->payload,
409                            silc_command_get_ident(query->cmd->payload));
410     buffer = silc_command_payload_encode_payload(cmdr->payload);
411     silc_server_packet_send(server, query->cmd->sock,
412                             SILC_PACKET_COMMAND_REPLY, 0,
413                             buffer->data, silc_buffer_len(buffer));
414     silc_buffer_free(buffer);
415     silc_server_query_free(query);
416     return;
417   }
418
419   /* Continue with parsing */
420   silc_server_query_parse(server, query);
421 }
422
423 /* Parse the command query and start processing the queries in detail. */
424
425 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
426 {
427   SilcServerCommandContext cmd = query->cmd;
428   SilcIDListData idata = silc_packet_get_context(cmd->sock);
429   unsigned char *tmp;
430   SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
431   SilcID id;
432   int i;
433
434   SILC_LOG_DEBUG(("Parsing %s query",
435                   silc_get_command_name(query->querycmd)));
436
437   switch (query->querycmd) {
438
439   case SILC_COMMAND_WHOIS:
440     /* Get requested attributes if set */
441     tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
442     if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
443       query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
444
445       /* When Requested Attributes is present we will assure that this
446          client cannot execute the WHOIS command too fast.  This would be
447          same as having SILC_CF_LAG_STRICT. */
448       if (idata && idata->conn_type == SILC_CONN_CLIENT)
449         ((SilcClientEntry)idata)->fast_command = 6;
450     }
451
452     /* Get Client IDs if present. Take IDs always instead of nickname. */
453     tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
454     if (!tmp) {
455
456       /* Get nickname */
457       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
458       if (!tmp && !query->attrs) {
459         /* No nickname, no ids and no attributes - send error */
460         silc_server_query_send_error(server, query,
461                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
462         silc_server_query_free(query);
463         return;
464       }
465
466       /* Get the nickname@server string and parse it */
467       if (tmp && ((tmp_len > 128) ||
468                   !silc_parse_userfqdn(tmp, query->nickname,
469                                        sizeof(query->nickname),
470                                        query->nick_server,
471                                        sizeof(query->nick_server)))) {
472         silc_server_query_send_error(server, query,
473                                      SILC_STATUS_ERR_BAD_NICKNAME, 0);
474         silc_server_query_free(query);
475         return;
476       }
477
478       /* Check nickname */
479       if (tmp) {
480         tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
481                                     SILC_STRING_UTF8, 128, &tmp_len);
482         if (!tmp) {
483           silc_server_query_send_error(server, query,
484                                        SILC_STATUS_ERR_BAD_NICKNAME, 0);
485           silc_server_query_free(query);
486           return;
487         }
488         memset(query->nickname, 0, sizeof(query->nickname));
489         silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
490         silc_free(tmp);
491       }
492
493       /* Check server name.  If we are open server and don't yet have
494          connection to remote router, create it now. */
495       if (query->nick_server[0] && server->config->open_server &&
496           !query->resolved) {
497         /* If primary router is specified, use that.  Otherwise connect
498            to the server in nick@server string. */
499         SilcServerConfigRouter *router;
500
501         router = silc_server_config_get_primary_router(server);
502         if (router && server->standalone) {
503           /* Create connection to primary router */
504           SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
505                           router->host, router->port));
506           query->dynamic_prim = TRUE;
507           silc_server_create_connection(server, FALSE, TRUE,
508                                         router->host, router->port,
509                                         silc_server_query_connected, query);
510           return;
511         } else if (!silc_server_num_sockets_by_remote(server,
512                                                       query->nick_server,
513                                                       query->nick_server,
514                                                       706)) {
515           /* Create connection and handle the query after connection */
516           SILC_LOG_DEBUG(("Create dynamic connection to %s:%d",
517                           query->nick_server, 706));
518           silc_server_create_connection(server, FALSE, TRUE,
519                                         query->nick_server, 706,
520                                         silc_server_query_connected, query);
521           return;
522         }
523       }
524
525     } else {
526       /* Parse the IDs included in the query */
527       query->ids = silc_calloc(argc, sizeof(*query->ids));
528
529       for (i = 0; i < argc; i++) {
530         tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
531         if (!tmp)
532           continue;
533
534         if (!silc_id_payload_parse_id(tmp, tmp_len, &id) ||
535             id.type != SILC_ID_CLIENT) {
536           silc_server_query_add_error(server, query, 1, i + 4,
537                                       SILC_STATUS_ERR_BAD_CLIENT_ID);
538           continue;
539         }
540
541         /* Normal server must check whether this ID exist, and if not then
542            send the query to router, unless done so already */
543         if (server->server_type == SILC_SERVER && !query->resolved) {
544           if (!silc_idlist_find_client_by_id(server->local_list,
545                                              &id.u.client_id, TRUE, NULL)) {
546             if (idata->conn_type != SILC_CONN_CLIENT ||
547                 !silc_idlist_find_client_by_id(server->global_list,
548                                                &id.u.client_id, TRUE, NULL)) {
549               silc_server_query_send_router(server, query);
550               for (i = 0; i < query->ids_count; i++)
551                 silc_free(query->ids[i].id);
552               silc_free(query->ids);
553               query->ids = NULL;
554               query->ids_count = 0;
555               return;
556             }
557           }
558         }
559
560         query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
561                                                       SILC_ID_CLIENT);
562         query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
563         query->ids_count++;
564       }
565     }
566
567     /* Get the max count of reply messages allowed */
568     tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
569     if (tmp && tmp_len == sizeof(SilcUInt32))
570       SILC_GET32_MSB(query->reply_count, tmp);
571    break;
572
573   case SILC_COMMAND_WHOWAS:
574     /* Get nickname */
575     tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
576     if (!tmp) {
577       silc_server_query_send_error(server, query,
578                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
579       silc_server_query_free(query);
580       return;
581     }
582
583     /* Get the nickname@server string and parse it */
584     if (tmp_len > 128 ||
585         !silc_parse_userfqdn(tmp, query->nickname, sizeof(query->nickname),
586                              query->nick_server, sizeof(query->nick_server))) {
587       silc_server_query_send_error(server, query,
588                                    SILC_STATUS_ERR_BAD_NICKNAME, 0);
589       silc_server_query_free(query);
590       return;
591     }
592
593     /* Check nickname */
594     tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
595                                 SILC_STRING_UTF8, 128, &tmp_len);
596     if (!tmp) {
597       silc_server_query_send_error(server, query,
598                                    SILC_STATUS_ERR_BAD_NICKNAME, 0);
599       silc_server_query_free(query);
600       return;
601     }
602     memset(query->nickname, 0, sizeof(query->nickname));
603     silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
604     silc_free(tmp);
605
606     /* Get the max count of reply messages allowed */
607     tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
608     if (tmp && tmp_len == sizeof(SilcUInt32))
609       SILC_GET32_MSB(query->reply_count, tmp);
610     break;
611
612   case SILC_COMMAND_IDENTIFY:
613     /* Get IDs if present. Take IDs always instead of names. */
614     tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
615     if (!tmp) {
616
617       /* Try get nickname */
618       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
619       if (tmp) {
620         /* Get the nickname@server string and parse it */
621         if (tmp_len > 128 ||
622             !silc_parse_userfqdn(tmp, query->nickname,
623                                  sizeof(query->nickname),
624                                  query->nick_server,
625                                  sizeof(query->nick_server)))
626           silc_server_query_add_error(server, query, 1, 1,
627                                       SILC_STATUS_ERR_BAD_NICKNAME);
628
629         /* Check nickname */
630         tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
631                                     SILC_STRING_UTF8, 128, &tmp_len);
632         if (!tmp) {
633           silc_server_query_send_error(server, query,
634                                        SILC_STATUS_ERR_BAD_NICKNAME, 0);
635           silc_server_query_free(query);
636           return;
637         }
638         memset(query->nickname, 0, sizeof(query->nickname));
639         silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
640         silc_free(tmp);
641       }
642
643       /* Try get server name */
644       tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
645       if (tmp) {
646         /* Check server name */
647         tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
648                                     256, &tmp_len);
649         if (!tmp) {
650           silc_server_query_send_error(server, query,
651                                        SILC_STATUS_ERR_BAD_SERVER, 0);
652           silc_server_query_free(query);
653           return;
654         }
655         query->server_name = tmp;
656       }
657
658       /* Get channel name */
659       tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
660       if (tmp && tmp_len <= 256) {
661         /* Check channel name */
662         tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
663                                     256, &tmp_len);
664         if (!tmp) {
665           silc_server_query_send_error(server, query,
666                                        SILC_STATUS_ERR_BAD_CHANNEL, 0);
667           silc_server_query_free(query);
668           return;
669         }
670         query->channel_name = tmp;
671       }
672
673       if (!query->nickname[0] && !query->server_name && !query->channel_name) {
674         silc_server_query_send_error(server, query,
675                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
676         silc_server_query_free(query);
677         return;
678       }
679
680       /* Check server name.  If we are open server and don't yet have
681          connection to remote router, create it now. */
682       if (query->nick_server[0] && server->config->open_server &&
683           !query->resolved) {
684         /* If primary router is specified, use that.  Otherwise connect
685            to the server in nick@server string. */
686         SilcServerConfigRouter *router;
687
688         router = silc_server_config_get_primary_router(server);
689         if (router && server->standalone) {
690           /* Create connection to primary router */
691           SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
692                           router->host, router->port));
693           query->dynamic_prim = TRUE;
694           silc_server_create_connection(server, FALSE, TRUE,
695                                         router->host, router->port,
696                                         silc_server_query_connected, query);
697           return;
698         } else if (!silc_server_num_sockets_by_remote(server,
699                                                       query->nick_server,
700                                                       query->nick_server,
701                                                       706)) {
702           /* Create connection and handle the query after connection */
703           SILC_LOG_DEBUG(("Create dynamic connection to %s:%d",
704                           query->nick_server, 706));
705           silc_server_create_connection(server, FALSE, TRUE,
706                                         query->nick_server, 706,
707                                         silc_server_query_connected, query);
708           return;
709         }
710       }
711
712     } else {
713       /* Parse the IDs included in the query */
714       query->ids = silc_calloc(argc, sizeof(*query->ids));
715
716       for (i = 0; i < argc; i++) {
717         tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
718         if (!tmp)
719           continue;
720
721         if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
722           silc_server_query_add_error(server, query, 1, i + 5,
723                                       SILC_STATUS_ERR_BAD_CLIENT_ID);
724           continue;
725         }
726
727         /* Normal server must check whether this ID exist, and if not then
728            send the query to router, unless done so already */
729         if (server->server_type == SILC_SERVER && !query->resolved) {
730           if (id.type == SILC_ID_CLIENT) {
731             if (!silc_idlist_find_client_by_id(server->local_list,
732                                                &id.u.client_id, TRUE, NULL)) {
733               if (idata->conn_type != SILC_CONN_CLIENT ||
734                   !silc_idlist_find_client_by_id(server->global_list,
735                                                  &id.u.client_id, TRUE,
736                                                  NULL)) {
737                 silc_server_query_send_router(server, query);
738                 for (i = 0; i < query->ids_count; i++)
739                   silc_free(query->ids[i].id);
740                 silc_free(query->ids);
741                 query->ids = NULL;
742                 query->ids_count = 0;
743                 return;
744               }
745             }
746           } else {
747             /* For now all other ID's except Client ID's are explicitly
748                sent to router for resolving. */
749             silc_server_query_send_router(server, query);
750             for (i = 0; i < query->ids_count; i++)
751               silc_free(query->ids[i].id);
752             silc_free(query->ids);
753             query->ids = NULL;
754             query->ids_count = 0;
755             return;
756           }
757         }
758
759         if (id.type == SILC_ID_CLIENT)
760           query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
761                                                         SILC_ID_CLIENT);
762         if (id.type == SILC_ID_SERVER)
763           query->ids[query->ids_count].id = silc_id_dup(&id.u.server_id,
764                                                         SILC_ID_SERVER);
765         if (id.type == SILC_ID_CHANNEL)
766           query->ids[query->ids_count].id = silc_id_dup(&id.u.channel_id,
767                                                         SILC_ID_CHANNEL);
768         query->ids[query->ids_count].id_type = id.type;
769         query->ids_count++;
770       }
771     }
772
773     /* Get the max count of reply messages allowed */
774     tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
775     if (tmp && tmp_len == sizeof(SilcUInt32))
776       SILC_GET32_MSB(query->reply_count, tmp);
777     break;
778   }
779
780   /* Start processing the query information */
781   silc_server_query_process(server, query, TRUE);
782 }
783
784 /* Context for holding clients searched by public key. */
785 typedef struct {
786   SilcClientEntry **clients;
787   SilcUInt32 *clients_count;
788   SilcBool found;
789 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
790
791 /* SKR find callbcak */
792
793 static void silc_server_query_skr_callback(SilcSKR skr,
794                                            SilcSKRFind find,
795                                            SilcSKRStatus status,
796                                            SilcDList keys,
797                                            void *context)
798 {
799   SilcServerPublicKeyUser uc = context;
800   SilcSKRKey key;
801
802   if (keys) {
803     (*uc->clients) = silc_realloc((*uc->clients),
804                                   sizeof((**uc->clients)) *
805                                   ((*uc->clients_count) +
806                                    silc_dlist_count(keys)));
807
808     silc_dlist_start(keys);
809     while ((key = silc_dlist_get(keys)))
810       (*uc->clients)[(*uc->clients_count)++] = key->key_context;
811
812     uc->found = TRUE;
813     silc_dlist_uninit(keys);
814   }
815
816   silc_skr_find_free(find);
817 }
818
819 /* If clients are set, limit the found clients using the attributes in
820    the query. If clients are not set, try to find some clients using
821    the attributes */
822
823 void silc_server_query_check_attributes(SilcServer server,
824                                         SilcServerQuery query,
825                                         SilcClientEntry **clients,
826                                         SilcUInt32 *clients_count) {
827   SilcClientEntry entry;
828   SilcAttributePayload attr;
829   SilcAttribute attribute;
830   SilcAttributeObjPk pk;
831   SilcPublicKey publickey, cmp_pubkey;
832   SilcPKCSType type;
833   SilcBool found = FALSE, no_clients = FALSE, search_pubkey = FALSE;
834   int i;
835
836   /* If no clients were found, we only check the attributes
837      if the user wasn't searching for nickname/ids */
838   if (!(*clients)) {
839     no_clients = TRUE;
840     if (query->nickname[0] || query->ids_count)
841       return;
842   }
843
844   silc_dlist_start(query->attrs);
845   while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
846     attribute = silc_attribute_get_attribute(attr);
847     switch (attribute) {
848
849       case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
850         SILC_LOG_DEBUG(("Finding clients by public key attribute"));
851
852         if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
853           continue;
854
855         if (!strcmp(pk.type, "silc-rsa"))
856           type = SILC_PKCS_SILC;
857         else if (!strcmp(pk.type, "ssh-rsa"))
858           type = SILC_PKCS_SSH2;
859         else if (!strcmp(pk.type, "x509v3-sign-rsa"))
860           type = SILC_PKCS_X509V3;
861         else if (!strcmp(pk.type, "pgp-sign-rsa"))
862           type = SILC_PKCS_OPENPGP;
863         else
864           continue;
865
866         if (!silc_pkcs_public_key_alloc(type, pk.data, pk.data_len,
867                                         &publickey)) {
868           silc_free(pk.type);
869           silc_free(pk.data);
870           continue;
871         }
872         search_pubkey = TRUE;
873
874         /* If no clients were set on calling this function, we just search
875            for clients, otherwise we try to limit the clients. */
876         if (no_clients) {
877           SilcServerPublicKeyUserStruct usercontext;
878           SilcSKRFind find;
879
880           usercontext.clients = clients;
881           usercontext.clients_count = clients_count;
882           usercontext.found = FALSE;
883
884           find = silc_skr_find_alloc();
885           if (!find)
886             continue;
887
888           silc_skr_find_set_public_key(find, publickey);
889           silc_skr_find_set_usage(find, SILC_SKR_USAGE_IDENTIFICATION);
890           silc_skr_find(server->repository, server->schedule,
891                         find, silc_server_query_skr_callback, &usercontext);
892
893           if (usercontext.found == TRUE)
894             found = TRUE;
895         } else {
896           for (i = 0; i < *clients_count; i++) {
897             entry = (*clients)[i];
898
899             if (!entry->data.public_key)
900               continue;
901
902             if (silc_server_get_public_key_by_client(server, entry,
903                                                      &cmp_pubkey)) {
904               if (silc_pkcs_public_key_compare(cmp_pubkey, publickey)) {
905                 found = TRUE;
906                 continue;
907               }
908             }
909
910             (*clients)[i] = NULL;
911           }
912         }
913         silc_free(pk.type);
914         silc_free(pk.data);
915         silc_pkcs_public_key_free(publickey);
916         break;
917     }
918   }
919
920   if (!found && !query->nickname[0] && !query->ids)
921     silc_server_query_add_error(server, query, 2, 0,
922                                 search_pubkey ?
923                                 SILC_STATUS_ERR_NO_SUCH_PUBLIC_KEY :
924                                 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
925 }
926
927 /* Processes the parsed query.  This does the actual finding of the
928    queried information and prepares for sending reply to the original
929    sender of the query command. */
930
931 void silc_server_query_process(SilcServer server, SilcServerQuery query,
932                                SilcBool resolve)
933 {
934   SilcServerCommandContext cmd = query->cmd;
935   SilcIDListData idata = silc_packet_get_context(cmd->sock);
936   SilcBool check_global = FALSE;
937   void *entry;
938   SilcClientEntry *clients = NULL, client_entry;
939   SilcChannelEntry *channels = NULL;
940   SilcServerEntry *servers = NULL;
941   SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
942   int i;
943
944   SILC_LOG_DEBUG(("Processing %s query",
945                   silc_get_command_name(query->querycmd)));
946
947   /* Check global lists if query is coming from client or we are not
948      normal server (we know global information). */
949   if (idata->conn_type == SILC_CONN_CLIENT)
950     check_global = TRUE;
951   else if (server->server_type != SILC_SERVER)
952     check_global = TRUE;
953
954   if (query->nickname[0]) {
955     /* Get all clients matching nickname from local list */
956     if (!silc_idlist_get_clients_by_hash(server->local_list,
957                                          query->nickname,
958                                          query->nick_server[0] ?
959                                          query->nick_server : NULL,
960                                          server->md5hash,
961                                          &clients, &clients_count))
962       silc_idlist_get_clients_by_nickname(server->local_list,
963                                           query->nickname,
964                                           query->nick_server[0] ?
965                                           query->nick_server : NULL,
966                                           &clients, &clients_count);
967
968     /* Check global list as well */
969     if (check_global) {
970       if (!silc_idlist_get_clients_by_hash(server->global_list,
971                                            query->nickname,
972                                            query->nick_server[0] ?
973                                            query->nick_server : NULL,
974                                            server->md5hash,
975                                            &clients, &clients_count))
976         silc_idlist_get_clients_by_nickname(server->global_list,
977                                             query->nickname,
978                                             query->nick_server[0] ?
979                                             query->nick_server : NULL,
980                                             &clients, &clients_count);
981     }
982
983     if (!clients)
984       silc_server_query_add_error(server, query, 1, 1,
985                                   SILC_STATUS_ERR_NO_SUCH_NICK);
986   }
987
988   if (query->server_name) {
989     /* Find server by name */
990     entry = silc_idlist_find_server_by_name(server->local_list,
991                                             query->server_name, TRUE, NULL);
992     if (!entry && check_global)
993       entry = silc_idlist_find_server_by_name(server->global_list,
994                                               query->server_name, TRUE, NULL);
995     if (entry) {
996       servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
997       servers[servers_count++] = (SilcServerEntry)entry;
998     }
999
1000     if (!servers)
1001       silc_server_query_add_error(server, query, 1, 2,
1002                                   SILC_STATUS_ERR_NO_SUCH_SERVER);
1003   }
1004
1005   if (query->channel_name) {
1006     /* Find channel by name */
1007     entry = silc_idlist_find_channel_by_name(server->local_list,
1008                                              query->channel_name, NULL);
1009     if (!entry && check_global)
1010       entry = silc_idlist_find_channel_by_name(server->global_list,
1011                                                query->channel_name, NULL);
1012     if (entry) {
1013       channels = silc_realloc(channels, sizeof(*channels) *
1014                               (channels_count + 1));
1015       channels[channels_count++] = (SilcChannelEntry)entry;
1016     }
1017
1018     if (!channels)
1019       silc_server_query_add_error(server, query, 1, 3,
1020                                   SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1021   }
1022
1023   if (query->ids_count) {
1024     /* Find entries by the queried IDs */
1025     for (i = 0; i < query->ids_count; i++) {
1026       void *id = query->ids[i].id;
1027       if (!id)
1028         continue;
1029
1030       switch (query->ids[i].id_type) {
1031
1032       case SILC_ID_CLIENT:
1033         /* Get client entry */
1034         entry = silc_idlist_find_client_by_id(server->local_list,
1035                                               id, TRUE, NULL);
1036         if (!entry && check_global)
1037           entry = silc_idlist_find_client_by_id(server->global_list,
1038                                                 id, TRUE, NULL);
1039         if (!entry) {
1040           silc_server_query_add_error(server, query, 0, i,
1041                                       SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
1042           continue;
1043         }
1044
1045         clients = silc_realloc(clients, sizeof(*clients) *
1046                                (clients_count + 1));
1047         clients[clients_count++] = (SilcClientEntry)entry;
1048         break;
1049
1050       case SILC_ID_SERVER:
1051         /* Get server entry */
1052         entry = silc_idlist_find_server_by_id(server->local_list,
1053                                               id, TRUE, NULL);
1054         if (!entry && check_global)
1055           entry = silc_idlist_find_server_by_id(server->global_list,
1056                                                 id, TRUE, NULL);
1057         if (!entry) {
1058           silc_server_query_add_error(server, query, 0, i,
1059                                       SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
1060           continue;
1061         }
1062
1063         servers = silc_realloc(servers, sizeof(*servers) *
1064                                (servers_count + 1));
1065         servers[servers_count++] = (SilcServerEntry)entry;
1066         break;
1067
1068       case SILC_ID_CHANNEL:
1069         /* Get channel entry */
1070         entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
1071         if (!entry && check_global)
1072           entry = silc_idlist_find_channel_by_id(server->global_list, id,
1073                                                  NULL);
1074         if (!entry) {
1075           silc_server_query_add_error(server, query, 0, i,
1076                                       SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
1077           continue;
1078         }
1079
1080         channels = silc_realloc(channels, sizeof(*channels) *
1081                                 (channels_count + 1));
1082         channels[channels_count++] = (SilcChannelEntry)entry;
1083         break;
1084
1085       default:
1086         break;
1087       }
1088     }
1089   }
1090
1091   /* Check the attributes to narrow down the search by using them. */
1092   if (query->attrs)
1093     silc_server_query_check_attributes(server, query, &clients,
1094                                        &clients_count);
1095
1096   SILC_LOG_DEBUG(("Querying %d clients", clients_count));
1097   SILC_LOG_DEBUG(("Querying %d servers", servers_count));
1098   SILC_LOG_DEBUG(("Querying %d channels", channels_count));
1099
1100   /* If nothing was found, then just send the errors */
1101   if (!clients && !channels && !servers) {
1102     silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
1103     return;
1104   }
1105
1106   /* If caller does not want us to resolve anything (has resolved already)
1107      then just continue with sending the reply */
1108   if (!resolve) {
1109     silc_server_query_send_reply(server, query, clients, clients_count,
1110                                  servers, servers_count, channels,
1111                                  channels_count);
1112     silc_free(clients);
1113     silc_free(servers);
1114     silc_free(channels);
1115     return;
1116   }
1117
1118   /* Now process all found information and if necessary do some more
1119      resolving. */
1120   switch (query->querycmd) {
1121
1122   case SILC_COMMAND_WHOIS:
1123     for (i = 0; i < clients_count; i++) {
1124       client_entry = clients[i];
1125
1126       /* Check if cannot query this anyway, so take next one */
1127       if (!client_entry ||
1128           !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1129         continue;
1130
1131       /* If Requested Attributes is set then we always resolve the client
1132          information, if not then check whether the entry is complete or not
1133          and decide whether we need to resolve or not. */
1134       if (!query->attrs) {
1135
1136         /* Even if nickname and stuff are present, we may need to resolve
1137            the entry */
1138         if (client_entry->nickname && client_entry->username &&
1139             client_entry->userinfo) {
1140           /* Check if cannot query this anyway, so take next one */
1141           if (!client_entry->router)
1142             continue;
1143
1144           /* If we are router, client is local to us, or client is on channel
1145              we do not need to resolve the client information. */
1146           if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1147               || silc_hash_table_count(client_entry->channels) ||
1148               query->resolved)
1149             continue;
1150         }
1151       }
1152
1153       /* Remove the NOATTR status periodically */
1154       if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
1155           client_entry->updated + 600 < time(NULL))
1156         client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
1157
1158       /* When requested attributes is present and local client is detached
1159          we cannot send the command to the client, we'll reply on behalf of
1160          the client instead. */
1161       if (query->attrs && SILC_IS_LOCAL(client_entry) &&
1162           (client_entry->mode & SILC_UMODE_DETACHED ||
1163            client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
1164         continue;
1165
1166       /* If attributes are present in query, and in the entry and we have
1167          done resolvings already we don't need to resolve anymore */
1168       if (query->resolved && query->attrs && client_entry->attrs)
1169         continue;
1170
1171       /* Resolve the detailed client information. If client is local we
1172          know that attributes were present and we will resolve directly
1173          from the client. Otherwise resolve from client's owner. */
1174       silc_server_query_resolve(server, query,
1175                                 (SILC_IS_LOCAL(client_entry) ?
1176                                  client_entry->connection :
1177                                  client_entry->router->connection),
1178                                 client_entry);
1179     }
1180     break;
1181
1182   case SILC_COMMAND_WHOWAS:
1183     for (i = 0; i < clients_count; i++) {
1184       client_entry = clients[i];
1185
1186       /* Check if cannot query this anyway, so take next one */
1187       if (!client_entry || !client_entry->router ||
1188           client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1189         continue;
1190
1191       /* If both nickname and username are present no resolving is needed */
1192       if (client_entry->nickname && client_entry->username)
1193         continue;
1194
1195       /* Resolve the detailed client information */
1196       silc_server_query_resolve(server, query,
1197                                 client_entry->router->connection,
1198                                 client_entry);
1199     }
1200     break;
1201
1202   case SILC_COMMAND_IDENTIFY:
1203     for (i = 0; i < clients_count; i++) {
1204       client_entry = clients[i];
1205
1206       /* Check if cannot query this anyway, so take next one */
1207       if (!client_entry || !client_entry->router ||
1208           !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1209         continue;
1210
1211       /* Even if nickname is present, we may need to resolve the entry */
1212       if (client_entry->nickname) {
1213
1214         /* If we are router, client is local to us, or client is on channel
1215            we do not need to resolve the client information. */
1216         if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1217             || silc_hash_table_count(client_entry->channels) ||
1218             query->resolved)
1219           continue;
1220       }
1221
1222       /* Resolve the detailed client information */
1223       silc_server_query_resolve(server, query,
1224                                 client_entry->router->connection,
1225                                 client_entry);
1226     }
1227     break;
1228   }
1229
1230   if (!query->queries_count)
1231     /* If we didn't have to do any resolving, continue with sending the
1232        command reply to the original sender. */
1233     silc_server_query_send_reply(server, query, clients, clients_count,
1234                                  servers, servers_count, channels,
1235                                  channels_count);
1236   else
1237     /* Now actually send the resolvings we gathered earlier */
1238     silc_server_query_resolve(server, query, NULL, NULL);
1239
1240   silc_free(clients);
1241   silc_free(servers);
1242   silc_free(channels);
1243 }
1244
1245 /* Resolve the detailed information for the `client_entry'.  Only client
1246    information needs to be resolved for being incomplete.  Each incomplete
1247    client entry calls this function to do the resolving. */
1248
1249 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1250                                SilcPacketStream sock,
1251                                SilcClientEntry client_entry)
1252 {
1253   SilcServerCommandContext cmd = query->cmd;
1254   SilcServerQueryList r = NULL;
1255   SilcBuffer idp;
1256   unsigned char *tmp;
1257   SilcUInt32 len;
1258   SilcUInt16 ident;
1259   int i;
1260
1261   if (!sock && client_entry)
1262     return;
1263
1264   /* If arguments are NULL we will now actually send the resolvings
1265      that earlier has been gathered by calling this function. */
1266   if (!sock && !client_entry) {
1267     SilcBuffer res_cmd;
1268
1269     SILC_LOG_DEBUG(("Sending the resolvings"));
1270
1271     /* WHOWAS resolving has been done at the same time this function
1272        was called to add the resolving for WHOWAS, so just return. */
1273     if (query->querycmd == SILC_COMMAND_WHOWAS)
1274       return;
1275
1276     for (i = 0; i < query->querylist_count; i++) {
1277       r = &query->querylist[i];
1278
1279       /* If Requested Attributes were present put them to this resolving */
1280       if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1281         len = r->argc + 1;
1282         r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1283         r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1284         r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1285
1286         tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1287         if (tmp)
1288           r->arg[r->argc] = silc_memdup(tmp, len);
1289         r->arg_lens[r->argc] = len;
1290         r->arg_types[r->argc] = 3;
1291         r->argc++;
1292       }
1293
1294       /* Statistics */
1295       server->stat.commands_sent++;
1296
1297       /* Send WHOIS command */
1298       res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1299                                             r->argc, r->arg, r->arg_lens,
1300                                             r->arg_types, r->ident);
1301       silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1302                               res_cmd->data, silc_buffer_len(res_cmd));
1303       silc_buffer_free(res_cmd);
1304
1305       /* Reprocess this packet after received reply */
1306       if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1307                                             r->ident,
1308                                             silc_server_query_resolve_reply,
1309                                             query, r->timeout))
1310         query->queries_left++;
1311     }
1312
1313     /* Cleanup this temporary context */
1314     for (i = 0; i < query->querylist_count; i++) {
1315       int k;
1316       for (k = 0; k < query->querylist[i].argc; k++)
1317         silc_free(query->querylist[i].arg[k]);
1318       silc_free(query->querylist[i].arg);
1319       silc_free(query->querylist[i].arg_lens);
1320       silc_free(query->querylist[i].arg_types);
1321     }
1322     silc_free(query->querylist);
1323     query->querylist = NULL;
1324     query->querylist_count = 0;
1325     return;
1326   }
1327
1328   SILC_LOG_DEBUG(("Resolving client information"));
1329
1330   if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1331     /* The entry is being resolved by some other external query already.
1332        Attach to that query instead of resolving again. */
1333     ident = client_entry->resolve_cmd_ident;
1334     if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1335                                     silc_server_query_resolve_reply, query))
1336       query->queries_left++;
1337   } else {
1338     /* This entry will be resolved */
1339     ident = ++server->cmd_ident;
1340
1341     switch (query->querycmd) {
1342
1343     case SILC_COMMAND_WHOIS:
1344     case SILC_COMMAND_IDENTIFY:
1345       /* Take existing query context if exist for this connection */
1346       for (i = 0; i < query->querylist_count; i++)
1347         if (query->querylist[i].sock == sock) {
1348           r = &query->querylist[i];
1349           break;
1350         }
1351
1352       if (!r) {
1353         /* Allocate new temp query list context */
1354         query->querylist = silc_realloc(query->querylist,
1355                                         sizeof(*query->querylist) *
1356                                         (query->querylist_count + 1));
1357         r = &query->querylist[query->querylist_count];
1358         query->querylist_count++;
1359         memset(r, 0, sizeof(*r));
1360         r->sock = sock;
1361         r->ident = ident;
1362         if (SILC_IS_LOCAL(client_entry))
1363           r->timeout = 3;
1364       }
1365
1366       len = r->argc + 1;
1367       r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1368       r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1369       r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1370
1371       /* Add the client entry to be resolved */
1372       idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1373       r->arg[r->argc] = silc_memdup(idp->data, silc_buffer_len(idp));
1374       r->arg_lens[r->argc] = silc_buffer_len(idp);
1375       r->arg_types[r->argc] = r->argc + 4;
1376       r->argc++;
1377       silc_buffer_free(idp);
1378
1379       break;
1380
1381     case SILC_COMMAND_WHOWAS:
1382       /* We must send WHOWAS command since it's the only the way of
1383          resolving clients that are not present in the network anymore. */
1384       silc_server_send_command(server, sock, query->querycmd, ident, 1,
1385                                1, query->nickname, strlen(query->nickname));
1386       if (silc_server_command_pending(server, query->querycmd, ident,
1387                                       silc_server_query_resolve_reply, query))
1388         query->queries_left++;
1389       break;
1390     }
1391   }
1392
1393   /* Mark the entry as being resolved */
1394   client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1395   client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1396   client_entry->resolve_cmd_ident = ident;
1397   client_entry->updated = time(NULL);
1398
1399   /* Save the queried ID, which we will reprocess after we get this and
1400      all other queries back. */
1401   query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1402                                 (query->queries_count + 1));
1403   if (query->queries) {
1404     i = query->queries_count;
1405     query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1406     query->queries[i].id_type = SILC_ID_CLIENT;
1407     query->queries[i].ident = ident;
1408     query->queries_count++;
1409   }
1410 }
1411
1412 /* Reply callback called after one resolving has been completed.  If
1413    all resolvings has been received then we will continue with sending
1414    the command reply to the original sender of the query. */
1415
1416 void silc_server_query_resolve_reply(void *context, void *reply)
1417 {
1418   SilcServerQuery query = context;
1419   SilcServer server = query->cmd->server;
1420   SilcServerCommandReplyContext cmdr = reply;
1421   SilcUInt16 ident = cmdr->ident;
1422   SilcStatus error = SILC_STATUS_OK;
1423   SilcServerQueryID id = NULL;
1424   SilcClientEntry client_entry;
1425   int i;
1426
1427   /* One less query left */
1428   query->queries_left--;
1429
1430   silc_command_get_status(cmdr->payload, NULL, &error);
1431   SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1432                   query->queries_left, error));
1433
1434   /* If no error then skip to other stuff */
1435   if (error == SILC_STATUS_OK)
1436     goto out;
1437
1438   /* Error occurred during resolving */
1439
1440   /* Find the resolved client ID */
1441   for (i = 0; i < query->queries_count; i++) {
1442     if (query->queries[i].ident != ident)
1443       continue;
1444
1445     id = &query->queries[i];
1446
1447     if (error == SILC_STATUS_ERR_TIMEDOUT) {
1448
1449       /* If timeout occurred for local entry when resolving attributes
1450          mark that this client doesn't support attributes in WHOIS. This
1451          assures we won't send the request again to the client. */
1452       if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1453         client_entry = silc_idlist_find_client_by_id(server->local_list,
1454                                                      id->id, TRUE, NULL);
1455         SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1456                         silc_id_render(id->id, SILC_ID_CLIENT)));
1457         if (client_entry && SILC_IS_LOCAL(client_entry)) {
1458           client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1459           client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1460           continue;
1461         }
1462       }
1463
1464       /* Remove the RESOLVING status from the client entry */
1465       if (query->querycmd != SILC_COMMAND_WHOWAS) {
1466         client_entry = silc_idlist_find_client_by_id(server->local_list,
1467                                                      id->id, TRUE, NULL);
1468         if (!client_entry)
1469           client_entry = silc_idlist_find_client_by_id(server->global_list,
1470                                                        id->id, TRUE, NULL);
1471         if (client_entry)
1472           client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1473       }
1474     }
1475   }
1476
1477  out:
1478
1479   /* If there are queries left then wait for them */
1480   if (query->queries_left)
1481     return;
1482
1483   SILC_LOG_DEBUG(("Reprocess the query"));
1484
1485   /* If the original command caller has gone away, just stop. */
1486   if (!silc_packet_stream_is_valid(query->cmd->sock)) {
1487     SILC_LOG_DEBUG(("Original command caller vanished"));
1488     silc_server_query_free(query);
1489     return;
1490   }
1491
1492   /* We have received all queries.  Now re-search all information required
1493      to complete this query.  Reason we cannot save the values found in
1494      the first search is that SilcClientEntry, SilcServerEntry and
1495      SilcChannelEntry pointers may become invalid while we were waiting
1496      for these resolvings. */
1497   silc_server_query_process(server, query, FALSE);
1498 }
1499
1500 /* Send the reply to the original query.  If arguments are NULL then this
1501    sends only the errors that has occurred during the processing of the
1502    query.  This sends the errors always after sending all the found
1503    information.  The query is over after this function returns and the
1504    `query' will become invalid.  This is called only after all informations
1505    has been resolved.  This means that if something is not found or is
1506    incomplete in this function we were unable to resolve the information
1507    or it does not exist at all. */
1508
1509 void silc_server_query_send_reply(SilcServer server,
1510                                   SilcServerQuery query,
1511                                   SilcClientEntry *clients,
1512                                   SilcUInt32 clients_count,
1513                                   SilcServerEntry *servers,
1514                                   SilcUInt32 servers_count,
1515                                   SilcChannelEntry *channels,
1516                                   SilcUInt32 channels_count)
1517 {
1518   SilcServerCommandContext cmd = query->cmd;
1519   SilcIDListData idata = silc_packet_get_context(cmd->sock);
1520   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1521   SilcStatus status;
1522   unsigned char *tmp;
1523   SilcUInt32 len;
1524   SilcBuffer idp;
1525   int i, k, valid_count;
1526   char nh[384], uh[384];
1527   SilcBool sent_reply = FALSE;
1528
1529   SILC_LOG_DEBUG(("Sending reply to query"));
1530   SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1531   SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1532   SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1533   SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1534
1535   status = SILC_STATUS_OK;
1536
1537   /* Send clients */
1538   if (clients_count) {
1539     SilcClientEntry entry;
1540     SilcPacketStream hsock;
1541
1542     /* Mark all invalid entries */
1543     for (i = 0, valid_count = 0; i < clients_count; i++) {
1544       entry = clients[i];
1545       if (!entry)
1546         continue;
1547
1548       switch (query->querycmd) {
1549       case SILC_COMMAND_WHOIS:
1550         if (!entry->nickname || !entry->username || !entry->userinfo ||
1551             !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1552           /* When querying by ID, every "unfound" entry must cause error */
1553           if (query->ids)
1554             silc_server_query_add_error_id(server, query,
1555                                            SILC_STATUS_ERR_TIMEDOUT,
1556                                            entry->id, SILC_ID_CLIENT);
1557           clients[i] = NULL;
1558           continue;
1559         }
1560         break;
1561
1562       case SILC_COMMAND_IDENTIFY:
1563         if (!entry->nickname ||
1564             !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1565           /* When querying by ID, every "unfound" entry must cause error */
1566           if (query->ids)
1567             silc_server_query_add_error_id(server, query,
1568                                            SILC_STATUS_ERR_TIMEDOUT,
1569                                            entry->id, SILC_ID_CLIENT);
1570           clients[i] = NULL;
1571           continue;
1572         }
1573         break;
1574
1575       case SILC_COMMAND_WHOWAS:
1576         if (!entry->nickname || !entry->username ||
1577             entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1578           clients[i] = NULL;
1579           continue;
1580         }
1581         break;
1582       }
1583       valid_count++;
1584     }
1585
1586     /* Start processing found clients */
1587     status = SILC_STATUS_OK;
1588     if (valid_count > 1)
1589       status = SILC_STATUS_LIST_START;
1590
1591     /* Now do the sending of valid entries */
1592     k = 0;
1593     for (i = 0; i < clients_count && valid_count; i++) {
1594       entry = clients[i];
1595       if (!entry)
1596         continue;
1597
1598       if (k >= 1)
1599         status = SILC_STATUS_LIST_ITEM;
1600       if (valid_count > 1 && k == valid_count - 1
1601           && !servers_count && !channels_count && !query->errors_count)
1602         status = SILC_STATUS_LIST_END;
1603       if (query->reply_count && k - 1 == query->reply_count)
1604         status = SILC_STATUS_LIST_END;
1605
1606       SILC_LOG_DEBUG(("%s: client %s",
1607                       (status == SILC_STATUS_OK ?         "   OK" :
1608                        status == SILC_STATUS_LIST_START ? "START" :
1609                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1610                        status == SILC_STATUS_LIST_END  ?  "  END" :
1611                        "      : "), entry->nickname));
1612
1613       idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1614       memset(nh, 0, sizeof(nh));
1615
1616       silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1617       if (!strchr(entry->nickname, '@')) {
1618         silc_strncat(nh, sizeof(nh), "@", 1);
1619         if (entry->servername) {
1620           silc_strncat(nh, sizeof(nh), entry->servername,
1621                        strlen(entry->servername));
1622         } else {
1623           len = entry->router ? strlen(entry->router->server_name) :
1624             strlen(server->server_name);
1625           silc_strncat(nh, sizeof(nh), entry->router ?
1626                        entry->router->server_name :
1627                        server->server_name, len);
1628         }
1629       }
1630
1631       switch (query->querycmd) {
1632
1633       case SILC_COMMAND_WHOIS:
1634         {
1635           unsigned char idle[4], mode[4];
1636           unsigned char *fingerprint, fempty[20], *attrs = NULL;
1637           SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1638
1639           memset(fempty, 0, sizeof(fempty));
1640           memset(idle, 0, sizeof(idle));
1641           memset(uh, 0, sizeof(uh));
1642
1643           silc_strncat(uh, sizeof(uh), entry->username,
1644                        strlen(entry->username));
1645           if (!strchr(entry->username, '@') && entry->connection) {
1646             hsock = entry->connection;
1647             silc_strncat(uh, sizeof(uh), "@", 1);
1648             silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1649                                         NULL, (const char **)&tmp, NULL, NULL);
1650             silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1651           }
1652
1653           if (idata->conn_type == SILC_CONN_CLIENT)
1654             channels =
1655               silc_server_get_client_channel_list(server, entry, FALSE,
1656                                                   FALSE, &umode_list);
1657           else
1658             channels =
1659               silc_server_get_client_channel_list(server, entry, TRUE,
1660                                                   TRUE, &umode_list);
1661
1662           if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1663             fingerprint = entry->data.fingerprint;
1664           else
1665             fingerprint = NULL;
1666
1667           SILC_PUT32_MSB(entry->mode, mode);
1668           if (entry->connection)
1669             SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1670
1671           /* If Requested Attribute were present, and we do not have the
1672              attributes we will reply to them on behalf of the client. */
1673           len = 0;
1674           if (query->attrs) {
1675             if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1676               tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1677               entry->attrs = silc_buffer_steal(tmpattrs, &len);
1678               entry->attrs_len = len;
1679               silc_buffer_free(tmpattrs);
1680             }
1681             attrs = entry->attrs;
1682             len = entry->attrs_len;
1683           }
1684
1685           /* Send command reply */
1686           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1687                                          status, 0, ident, 10,
1688                                          2, idp->data, silc_buffer_len(idp),
1689                                          3, nh, strlen(nh),
1690                                          4, uh, strlen(uh),
1691                                          5, entry->userinfo,
1692                                          strlen(entry->userinfo),
1693                                          6, channels ? channels->data : NULL,
1694                                          channels ? silc_buffer_len(channels)
1695                                          : 0,
1696                                          7, mode, 4,
1697                                          8, idle, 4,
1698                                          9, fingerprint,
1699                                          fingerprint ? 20 : 0,
1700                                          10, umode_list ? umode_list->data :
1701                                          NULL, umode_list ?
1702                                          silc_buffer_len(umode_list) :
1703                                          0, 11, attrs, len);
1704
1705           sent_reply = TRUE;
1706
1707           /* For now we always delete Requested Attributes, unless the client
1708              is detached, in which case we don't want to reconstruct the
1709              same data everytime */
1710           if (!(entry->mode & SILC_UMODE_DETACHED) &&
1711               !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1712             silc_free(entry->attrs);
1713             entry->attrs = NULL;
1714           }
1715
1716           if (channels)
1717             silc_buffer_free(channels);
1718           if (umode_list) {
1719             silc_buffer_free(umode_list);
1720             umode_list = NULL;
1721           }
1722         }
1723         break;
1724
1725       case SILC_COMMAND_IDENTIFY:
1726         if (!entry->username) {
1727           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1728                                          status, 0, ident, 2,
1729                                          2, idp->data, silc_buffer_len(idp),
1730                                          3, nh, strlen(nh));
1731           sent_reply = TRUE;
1732         } else {
1733           memset(uh, 0, sizeof(uh));
1734           silc_strncat(uh, sizeof(uh), entry->username,
1735                        strlen(entry->username));
1736           if (!strchr(entry->username, '@') && entry->connection) {
1737             hsock = entry->connection;
1738             silc_strncat(uh, sizeof(uh), "@", 1);
1739             silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1740                                         NULL, (const char **)&tmp,
1741                                         NULL, NULL);
1742             silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1743           }
1744
1745           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1746                                          status, 0, ident, 3,
1747                                          2, idp->data, silc_buffer_len(idp),
1748                                          3, nh, strlen(nh),
1749                                          4, uh, strlen(uh));
1750           sent_reply = TRUE;
1751         }
1752         break;
1753
1754       case SILC_COMMAND_WHOWAS:
1755         memset(uh, 0, sizeof(uh));
1756         silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1757         if (!strchr(entry->username, '@'))
1758           silc_strncat(uh, sizeof(uh), "@-private-", 10);
1759
1760         /* Send command reply */
1761         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1762                                        status, 0, ident, 4,
1763                                        2, idp->data, silc_buffer_len(idp),
1764                                        3, nh, strlen(nh),
1765                                        4, uh, strlen(uh),
1766                                        5, entry->userinfo,
1767                                        entry->userinfo ?
1768                                        strlen(entry->userinfo) : 0);
1769         sent_reply = TRUE;
1770         break;
1771       }
1772
1773       silc_buffer_free(idp);
1774
1775       if (status == SILC_STATUS_LIST_END)
1776         break;
1777       k++;
1778     }
1779
1780     if (k == 0) {
1781       /* Not one valid entry was found, send error.  If nickname was used
1782          in query send error based on that, otherwise the query->errors
1783          already includes proper errors. */
1784       if (query->nickname[0] || (!query->ids && query->attrs))
1785         silc_server_query_add_error(server, query, 1, 1,
1786                                     SILC_STATUS_ERR_NO_SUCH_NICK);
1787
1788       /* Make sure some error is sent */
1789       if (!query->errors_count && !servers_count && !channels_count)
1790         silc_server_query_add_error(server, query, 2, 0,
1791                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1792     }
1793   }
1794
1795   /* Send servers */
1796   if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1797     SilcServerEntry entry;
1798
1799     if (status == SILC_STATUS_OK && servers_count > 1)
1800       status = SILC_STATUS_LIST_START;
1801
1802     k = 0;
1803     for (i = 0; i < servers_count; i++) {
1804       entry = servers[i];
1805
1806       if (k >= 1)
1807         status = SILC_STATUS_LIST_ITEM;
1808       if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1809           !query->errors_count)
1810         status = SILC_STATUS_LIST_END;
1811       if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1812           !query->errors_count)
1813         status = SILC_STATUS_LIST_END;
1814       if (query->reply_count && k - 1 == query->reply_count)
1815         status = SILC_STATUS_LIST_END;
1816
1817       SILC_LOG_DEBUG(("%s: server %s",
1818                       (status == SILC_STATUS_OK ?         "   OK" :
1819                        status == SILC_STATUS_LIST_START ? "START" :
1820                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1821                        status == SILC_STATUS_LIST_END  ?  "  END" :
1822                        "      : "),
1823                       entry->server_name ? entry->server_name : ""));
1824
1825       /* Send command reply */
1826       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1827       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1828                                      status, 0, ident, 2,
1829                                      2, idp->data, silc_buffer_len(idp),
1830                                      3, entry->server_name,
1831                                      entry->server_name ?
1832                                      strlen(entry->server_name) : 0);
1833       silc_buffer_free(idp);
1834       sent_reply = TRUE;
1835
1836       if (status == SILC_STATUS_LIST_END)
1837         break;
1838       k++;
1839     }
1840   }
1841
1842   /* Send channels */
1843   if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1844     SilcChannelEntry entry;
1845
1846     if (status == SILC_STATUS_OK && channels_count > 1)
1847       status = SILC_STATUS_LIST_START;
1848
1849     k = 0;
1850     for (i = 0; i < channels_count; i++) {
1851       entry = channels[i];
1852
1853       if (k >= 1)
1854         status = SILC_STATUS_LIST_ITEM;
1855       if (channels_count == 1 && status != SILC_STATUS_OK &&
1856           !query->errors_count)
1857         status = SILC_STATUS_LIST_END;
1858       if (channels_count > 1 && k == channels_count - 1 &&
1859           !query->errors_count)
1860         status = SILC_STATUS_LIST_END;
1861       if (query->reply_count && k - 1 == query->reply_count)
1862         status = SILC_STATUS_LIST_END;
1863
1864       SILC_LOG_DEBUG(("%s: channel %s",
1865                       (status == SILC_STATUS_OK ?         "   OK" :
1866                        status == SILC_STATUS_LIST_START ? "START" :
1867                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1868                        status == SILC_STATUS_LIST_END  ?  "  END" :
1869                        "      : "),
1870                       entry->channel_name ? entry->channel_name : ""));
1871
1872       /* Send command reply */
1873       idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1874       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1875                                      status, 0, ident, 2,
1876                                      2, idp->data, silc_buffer_len(idp),
1877                                      3, entry->channel_name,
1878                                      entry->channel_name ?
1879                                      strlen(entry->channel_name) : 0);
1880       silc_buffer_free(idp);
1881       sent_reply = TRUE;
1882
1883       if (status == SILC_STATUS_LIST_END)
1884         break;
1885       k++;
1886     }
1887   }
1888
1889   /* Send errors */
1890   if (query->errors_count) {
1891     int type;
1892
1893     if (status == SILC_STATUS_OK && query->errors_count > 1)
1894       status = SILC_STATUS_LIST_START;
1895
1896     k = 0;
1897     for (i = 0; i < query->errors_count; i++) {
1898       idp = NULL;
1899
1900       /* Take error argument */
1901       if (query->errors[i].type == 1) {
1902         /* Take from sent arguments */
1903         len = 0;
1904         tmp = silc_argument_get_arg_type(cmd->args,
1905                                          query->errors[i].index, &len);
1906         type = 2;
1907       } else if (query->errors[i].type == 2) {
1908         /* No argument */
1909         len = 0;
1910         tmp = NULL;
1911         type = 0;
1912       } else if (!query->errors[i].id) {
1913         /* Take from query->ids */
1914         idp =
1915           silc_id_payload_encode(query->ids[query->errors[i].index].id,
1916                                  query->ids[query->errors[k].index].id_type);
1917         tmp = idp->data;
1918         len = silc_buffer_len(idp);
1919         type = 2;
1920       } else {
1921         /* Take added ID. */
1922         idp = silc_id_payload_encode(query->errors[i].id,
1923                                      query->errors[k].id_type);
1924         tmp = idp->data;
1925         len = silc_buffer_len(idp);
1926         type = 2;
1927       }
1928
1929       if (k >= 1)
1930         status = SILC_STATUS_LIST_ITEM;
1931       if (query->errors_count == 1 && status != SILC_STATUS_OK)
1932         status = SILC_STATUS_LIST_END;
1933       if (query->errors_count > 1 && k == query->errors_count - 1)
1934         status = SILC_STATUS_LIST_END;
1935       if (query->reply_count && k - 1 == query->reply_count)
1936         status = SILC_STATUS_LIST_END;
1937
1938       SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1939                       (status == SILC_STATUS_OK ?         "   OK" :
1940                        status == SILC_STATUS_LIST_START ? "START" :
1941                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1942                        status == SILC_STATUS_LIST_END  ?  "  END" :
1943                        "      : "),
1944                       silc_get_status_message(query->errors[i].error),
1945                       query->errors[i].error));
1946
1947 #if 1 /* XXX Backwards compatibility.  Remove in 1.0. */
1948       if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1949         /* Send error */
1950         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1951                                        (status == SILC_STATUS_OK ?
1952                                         query->errors[i].error : status),
1953                                        (status == SILC_STATUS_OK ?
1954                                         0 : query->errors[i].error), ident, 2,
1955                                        type, tmp, len,
1956                                        3, tmp, len);
1957       else
1958 #endif
1959       /* Send error */
1960       silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1961                                      (status == SILC_STATUS_OK ?
1962                                       query->errors[i].error : status),
1963                                      (status == SILC_STATUS_OK ?
1964                                       0 : query->errors[i].error), ident, 1,
1965                                      type, tmp, len);
1966
1967       silc_buffer_free(idp);
1968       sent_reply = TRUE;
1969
1970       if (status == SILC_STATUS_LIST_END)
1971         break;
1972       k++;
1973     }
1974   }
1975
1976   if (!sent_reply)
1977     SILC_LOG_ERROR(("BUG: Query did not send anything"));
1978
1979   /* Cleanup */
1980   silc_server_query_free(query);
1981 }
1982
1983 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1984    of the client since we were unable to resolve them from the client.
1985    Either client does not support Requested Attributes or isn't replying
1986    to them like it should. */
1987
1988 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1989                                          SilcServerQuery query,
1990                                          SilcClientEntry client_entry)
1991 {
1992   SilcBuffer buffer = NULL;
1993   SilcAttribute attribute;
1994   SilcAttributePayload attr;
1995   SilcAttributeObjPk pk;
1996   SilcAttributeObjService service;
1997   unsigned char *tmp;
1998   unsigned char sign[2048 + 1];
1999   SilcUInt32 sign_len;
2000
2001   SILC_LOG_DEBUG(("Constructing Requested Attributes"));
2002
2003   /* Go through all requested attributes */
2004   silc_dlist_start(query->attrs);
2005   while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
2006     attribute = silc_attribute_get_attribute(attr);
2007     switch (attribute) {
2008
2009     case SILC_ATTRIBUTE_SERVICE:
2010       /* Put SERVICE.  Put only SILC service. */
2011       memset(&service, 0, sizeof(service));
2012       service.port = (server->config->server_info->primary ?
2013                       server->config->server_info->primary->port : SILC_PORT);
2014       silc_strncat(service.address, sizeof(service.address),
2015                    server->server_name, strlen(server->server_name));
2016       service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
2017       if (client_entry->connection)
2018         service.idle = time(NULL) - client_entry->data.last_receive;
2019       buffer = silc_attribute_payload_encode(buffer, attribute,
2020                                              SILC_ATTRIBUTE_FLAG_VALID,
2021                                              &service, sizeof(service));
2022       if (!buffer)
2023         return NULL;
2024       break;
2025
2026     case SILC_ATTRIBUTE_STATUS_MOOD:
2027       /* Put STATUS_MOOD */
2028       buffer = silc_attribute_payload_encode(buffer, attribute,
2029                                              SILC_ATTRIBUTE_FLAG_VALID,
2030                                              (void *)
2031                                              SILC_ATTRIBUTE_MOOD_NORMAL,
2032                                              sizeof(SilcUInt32));
2033       if (!buffer)
2034         return NULL;
2035       break;
2036
2037     case SILC_ATTRIBUTE_STATUS_FREETEXT:
2038       /* Put STATUS_FREETEXT.  We just tell in the message that we are
2039          replying on behalf of the client. */
2040       tmp =
2041         "This information was provided by the server on behalf of the user";
2042       buffer = silc_attribute_payload_encode(buffer, attribute,
2043                                              SILC_ATTRIBUTE_FLAG_VALID,
2044                                              tmp, strlen(tmp));
2045       if (!buffer)
2046         return NULL;
2047       break;
2048
2049     case SILC_ATTRIBUTE_PREFERRED_CONTACT:
2050       /* Put PREFERRED_CONTACT */
2051       buffer = silc_attribute_payload_encode(buffer, attribute,
2052                                              SILC_ATTRIBUTE_FLAG_VALID,
2053                                              (void *)
2054                                              SILC_ATTRIBUTE_CONTACT_CHAT,
2055                                              sizeof(SilcUInt32));
2056       if (!buffer)
2057         return NULL;
2058       break;
2059
2060     case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
2061       /* Put USER_PUBLIC_KEY */
2062       if (client_entry->data.public_key) {
2063         pk.type = "silc-rsa";
2064         pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
2065                                               &pk.data_len);
2066         buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
2067                                                SILC_ATTRIBUTE_FLAG_VALID :
2068                                                SILC_ATTRIBUTE_FLAG_INVALID,
2069                                                &pk, sizeof(pk));
2070         silc_free(pk.data);
2071         if (!buffer)
2072           return NULL;
2073         break;
2074       }
2075
2076       /* No public key available */
2077       buffer = silc_attribute_payload_encode(buffer, attribute,
2078                                              SILC_ATTRIBUTE_FLAG_INVALID,
2079                                              NULL, 0);
2080       if (!buffer)
2081         return NULL;
2082       break;
2083
2084     default:
2085       /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
2086       if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
2087           attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
2088         break;
2089
2090       /* For other attributes we cannot reply so mark it invalid */
2091       buffer = silc_attribute_payload_encode(buffer, attribute,
2092                                              SILC_ATTRIBUTE_FLAG_INVALID,
2093                                              NULL, 0);
2094       if (!buffer)
2095         return NULL;
2096       break;
2097     }
2098   }
2099
2100   /* Always put our public key.  This assures that we send at least
2101      something valid back always. */
2102   pk.type = "silc-rsa";
2103   pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
2104   buffer = silc_attribute_payload_encode(buffer,
2105                                          SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
2106                                          pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
2107                                          SILC_ATTRIBUTE_FLAG_INVALID,
2108                                          &pk, sizeof(pk));
2109   silc_free(pk.data);
2110   if (!buffer)
2111     return NULL;
2112
2113   /* Finally compute the digital signature of all the data we provided
2114      as an indication that we provided rightfull information, and this
2115      also authenticates our public key. */
2116   if (silc_pkcs_private_key_get_len(server->private_key) / 8 <=
2117       sizeof(sign) -1  &&
2118       silc_pkcs_sign(server->private_key, buffer->data,
2119                      silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
2120                      TRUE, server->sha1hash)) {
2121     pk.type = NULL;
2122     pk.data = sign;
2123     pk.data_len = sign_len;
2124     buffer =
2125       silc_attribute_payload_encode(buffer,
2126                                     SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
2127                                     SILC_ATTRIBUTE_FLAG_VALID,
2128                                     &pk, sizeof(pk));
2129   }
2130   if (!buffer)
2131     return NULL;
2132
2133   return buffer;
2134 }
2135
2136 /* Find client by the Client ID indicated by the `client_id', and if not
2137    found then query it by using WHOIS command.  The client information
2138    is also resolved if the cached information is incomplete or if the
2139    `always_resolve' is set to TRUE.  The indication whether requested
2140    client was being resolved is saved into `resolved'.  If the client
2141    is not being resolved its entry is returned by this function.  NULL
2142    is returned if client is resolved. */
2143
2144 SilcClientEntry silc_server_query_client(SilcServer server,
2145                                          const SilcClientID *client_id,
2146                                          SilcBool always_resolve,
2147                                          SilcBool *resolved)
2148 {
2149   SilcClientEntry client;
2150
2151   SILC_LOG_DEBUG(("Resolving client by client ID"));
2152
2153   if (resolved)
2154     *resolved = FALSE;
2155
2156   client = silc_idlist_find_client_by_id(server->local_list,
2157                                          (SilcClientID *)client_id,
2158                                          TRUE, NULL);
2159   if (!client) {
2160     client = silc_idlist_find_client_by_id(server->global_list,
2161                                            (SilcClientID *)client_id,
2162                                            TRUE, NULL);
2163     if (!client && server->server_type == SILC_ROUTER)
2164       return NULL;
2165   }
2166
2167   if (!client && server->standalone)
2168     return NULL;
2169
2170   if (!client || !client->nickname || !client->username ||
2171       always_resolve) {
2172     SilcBuffer buffer, idp;
2173
2174     /* Statistics */
2175     server->stat.commands_sent++;
2176
2177     if (client) {
2178       client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
2179       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
2180       client->resolve_cmd_ident = ++server->cmd_ident;
2181     }
2182
2183     idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
2184     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
2185                                             server->cmd_ident, 1,
2186                                             4, idp->data,
2187                                             silc_buffer_len(idp));
2188     silc_server_packet_send(server, client ? client->router->connection :
2189                             SILC_PRIMARY_ROUTE(server),
2190                             SILC_PACKET_COMMAND, 0,
2191                             buffer->data, silc_buffer_len(buffer));
2192     silc_buffer_free(idp);
2193     silc_buffer_free(buffer);
2194
2195     if (resolved)
2196       *resolved = TRUE;
2197
2198     return NULL;
2199   }
2200
2201   return client;
2202 }