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