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