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