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