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