In IDENTIFY command parsing, send all other IDs except
[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 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   SilcSocketConnection 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   SilcUInt16 index;                 /* Index to IDs */
46   unsigned int from_cmd : 1;        /* TRUE if `index' is from command args,
47                                        otherwise from query->ids */
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;                   /* Queried nickname */
55   char *nick_server;                /* Queried nickname's server */
56   char *server_name;                /* Queried server name */
57   char *channel_name;               /* Queried channel name */
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   SilcServerCommandContext cmd;     /* Command context for query */
65   SilcServerQueryList querylist;    /* Temporary query list context */
66   SilcServerQueryID queries;        /* Ongoing queries */
67   SilcServerQueryError errors;      /* Query errors */
68   SilcUInt16 querylist_count;       /* Number of query lists */
69   SilcUInt16 queries_count;         /* Number of ongoing queries */
70   SilcUInt16 queries_left;          /* Number of ongoing queries left */
71   SilcUInt16 errors_count;          /* number of errors */
72   unsigned int querycmd : 7;        /* Query command (SilcCommand) */
73   unsigned int resolved : 1;        /* TRUE if normal server has resolved
74                                        information from router */
75 } *SilcServerQuery;
76
77 void silc_server_query_free(SilcServerQuery query);
78 void silc_server_query_send_error(SilcServer server,
79                                   SilcServerQuery query,
80                                   SilcStatus error, ...);
81 void silc_server_query_add_error(SilcServer server,
82                                  SilcServerQuery query,
83                                  bool from_cmd,
84                                  SilcUInt32 index,
85                                  SilcStatus error);
86 void silc_server_query_add_error_id(SilcServer server,
87                                     SilcServerQuery query,
88                                     SilcStatus error,
89                                     void *id, SilcIdType id_type);
90 void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
91 void silc_server_query_send_router_reply(void *context, void *reply);
92 void silc_server_query_parse(SilcServer server, SilcServerQuery query);
93 void silc_server_query_process(SilcServer server, SilcServerQuery query,
94                                bool resolve);
95 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
96                                SilcSocketConnection sock,
97                                SilcClientEntry client_entry);
98 void silc_server_query_resolve_reply(void *context, void *reply);
99 void silc_server_query_send_reply(SilcServer server,
100                                   SilcServerQuery query,
101                                   SilcClientEntry *clients,
102                                   SilcUInt32 clients_count,
103                                   SilcServerEntry *servers,
104                                   SilcUInt32 servers_count,
105                                   SilcChannelEntry *channels,
106                                   SilcUInt32 channels_count);
107 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
108                                          SilcServerQuery query,
109                                          SilcClientEntry client_entry);
110
111 /* Free the query context structure and all allocated resources. */
112
113 void silc_server_query_free(SilcServerQuery query)
114 {
115   int i;
116
117   silc_server_command_free(query->cmd);
118
119   for (i = 0; i < query->queries_count; i++)
120     silc_free(query->queries[i].id);
121   silc_free(query->queries);
122
123   silc_free(query->nickname);
124   silc_free(query->nick_server);
125   silc_free(query->server_name);
126   silc_free(query->channel_name);
127
128   for (i = 0; i < query->ids_count; i++)
129     silc_free(query->ids[i].id);
130   silc_free(query->ids);
131
132   if (query->attrs)
133     silc_attribute_payload_list_free(query->attrs);
134
135   for (i = 0; i < query->errors_count; i++)
136     silc_free(query->errors[i].id);
137   silc_free(query->errors);
138
139   memset(query, 'F', sizeof(*query));
140   silc_free(query);
141 }
142
143 /* Send error reply indicated by the `error' to the original sender of
144    the query. */
145
146 void silc_server_query_send_error(SilcServer server,
147                                   SilcServerQuery query,
148                                   SilcStatus error, ...)
149 {
150   va_list va;
151   unsigned char *data = NULL;
152   SilcUInt32 data_len = 0, data_type = 0, argc = 0;
153
154   va_start(va, error);
155   data_type = va_arg(va, SilcUInt32);
156   if (data_type) {
157     argc = 1;
158     data = va_arg(va, unsigned char *);
159     data_len = va_arg(va, SilcUInt32);
160   }
161
162   SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
163
164   /* Send the command reply with error */
165   silc_server_send_command_reply(server, query->cmd->sock,
166                                  query->querycmd, error, 0, 
167                                  silc_command_get_ident(query->cmd->payload),
168                                  argc, data_type, data, data_len);
169   va_end(va);
170 }
171
172 /* Add error to error list.  Multiple errors may occur during the query
173    processing and this function can be used to add one error.  The
174    `index' is the index to the command context which includes the argument
175    which caused the error, or it is the index to query->ids, depending
176    on value of `from_cmd'. */
177
178 void silc_server_query_add_error(SilcServer server,
179                                  SilcServerQuery query,
180                                  bool from_cmd,
181                                  SilcUInt32 index,
182                                  SilcStatus error)
183 {
184   query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
185                                (query->errors_count + 1));
186   if (!query->errors)
187     return;
188   query->errors[query->errors_count].index = index;
189   query->errors[query->errors_count].from_cmd = from_cmd;
190   query->errors[query->errors_count].error = error;
191   query->errors[query->errors_count].id = NULL;
192   query->errors[query->errors_count].id_type = 0;
193   query->errors_count++;
194 }
195
196 /* Same as silc_server_query_add_error but adds the ID data to be used
197    with error sending with this error type. */
198
199 void silc_server_query_add_error_id(SilcServer server,
200                                     SilcServerQuery query,
201                                     SilcStatus error,
202                                     void *id, SilcIdType id_type)
203 {
204   query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
205                                (query->errors_count + 1));
206   if (!query->errors)
207     return;
208   query->errors[query->errors_count].index = 0;
209   query->errors[query->errors_count].from_cmd = FALSE;
210   query->errors[query->errors_count].error = error;
211   query->errors[query->errors_count].id = silc_id_dup(id, id_type);
212   query->errors[query->errors_count].id_type = id_type;
213   query->errors_count++;
214 }
215
216 /* Processes query as command.  The `query' is the command that is
217    being processed indicated by the `cmd'.  The `query' can be one of
218    the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
219    SILC_COMMAND_IDENTIFY.  This function handles the reply sending
220    to the entity who sent this query to us automatically.  Returns
221    TRUE if the query is being processed or FALSE on error. */
222
223 bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
224                                SilcServerCommandContext cmd)
225 {
226   SilcServerQuery query;
227
228   SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
229
230   query = silc_calloc(1, sizeof(*query));
231   query->querycmd = querycmd;
232   query->cmd = silc_server_command_dup(cmd);
233
234   switch (querycmd) {
235
236   case SILC_COMMAND_WHOIS:
237     /* If we are normal server and query contains nickname, send it
238        directly to router. */
239     if (server->server_type == SILC_SERVER && !server->standalone &&
240         cmd->sock != SILC_PRIMARY_ROUTE(server) &&
241         silc_argument_get_arg_type(cmd->args, 1, NULL)) {
242       silc_server_query_send_router(server, query);
243       return TRUE;
244     }
245     break;
246
247   case SILC_COMMAND_WHOWAS:
248     /* WHOWAS query is always sent to router if we are normal server */
249     if (server->server_type == SILC_SERVER && !server->standalone &&
250         cmd->sock != SILC_PRIMARY_ROUTE(server)) {
251       silc_server_query_send_router(server, query);
252       return TRUE;
253     }
254     break;
255
256   case SILC_COMMAND_IDENTIFY:
257     /* If we are normal server and query does not contain IDs, send it
258        directly to router (it contains nickname, server name or channel
259        name). */
260     if (server->server_type == SILC_SERVER && !server->standalone &&
261         cmd->sock != SILC_PRIMARY_ROUTE(server) &&
262         !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
263       silc_server_query_send_router(server, query);
264       return TRUE;
265     }
266     break;
267
268   default:
269     SILC_LOG_ERROR(("Bad query using %d command", querycmd));
270     silc_server_query_free(query);
271     return FALSE;
272   }
273
274   /* Now parse the request */
275   silc_server_query_parse(server, query);
276
277   return TRUE;
278 }
279
280 /* Send the received query to our primary router since we could not
281    handle the query directly.  We will reprocess the query after our
282    router replies back. */
283
284 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
285 {
286   SilcBuffer tmpbuf;
287   SilcUInt16 old_ident;
288
289   SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
290
291   /* Send WHOIS command to our router */
292   old_ident = silc_command_get_ident(query->cmd->payload);
293   silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
294   tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
295   silc_server_packet_send(server, 
296                           SILC_PRIMARY_ROUTE(server),
297                           SILC_PACKET_COMMAND, 0,
298                           tmpbuf->data, tmpbuf->len, TRUE);
299   silc_command_set_ident(query->cmd->payload, old_ident);
300   silc_buffer_free(tmpbuf);
301
302   query->resolved = TRUE;
303
304   /* Continue parsing the query after received reply from router */
305   silc_server_command_pending(server, query->querycmd, server->cmd_ident,
306                               silc_server_query_send_router_reply, query);
307 }
308
309 /* Reply callback called after primary router has replied to our initial
310    sending of the query to it.  We will proceed the query in this function. */
311
312 void silc_server_query_send_router_reply(void *context, void *reply)
313 {
314   SilcServerQuery query = context;
315   SilcServer server = query->cmd->server;
316   SilcServerCommandReplyContext cmdr = reply;
317
318   SILC_LOG_DEBUG(("Received reply from router to query"));
319
320   /* Check if router sent error reply */
321   if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
322     SilcBuffer buffer;
323
324     SILC_LOG_DEBUG(("Sending error to original query"));
325
326     /* Send the same command reply payload which contains the error */
327     silc_command_set_command(cmdr->payload, query->querycmd);
328     silc_command_set_ident(cmdr->payload,
329                            silc_command_get_ident(query->cmd->payload));
330     buffer = silc_command_payload_encode_payload(cmdr->payload);
331     silc_server_packet_send(server, query->cmd->sock,
332                             SILC_PACKET_COMMAND_REPLY, 0, 
333                             buffer->data, buffer->len, FALSE);
334     silc_buffer_free(buffer);
335     silc_server_query_free(query);
336     return;
337   }
338
339   /* Continue with parsing */
340   silc_server_query_parse(server, query);
341 }
342
343 /* Parse the command query and start processing the queries in detail. */
344
345 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
346 {
347   SilcServerCommandContext cmd = query->cmd;
348   unsigned char *tmp;
349   SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
350   void *id;
351   SilcIdType id_type;
352   int i;
353
354   SILC_LOG_DEBUG(("Parsing %s query",
355                   silc_get_command_name(query->querycmd)));
356
357   switch (query->querycmd) {
358
359   case SILC_COMMAND_WHOIS:
360     /* Get Client IDs if present. Take IDs always instead of nickname. */
361     tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
362     if (!tmp) {
363
364       /* Get nickname */
365       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
366       if (!tmp) {
367         silc_server_query_send_error(server, query,
368                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
369         silc_server_query_free(query);
370         return;
371       }
372
373       /* Get the nickname@server string and parse it */
374       if (tmp_len > 128 ||
375           !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
376         silc_server_query_send_error(server, query,
377                                      SILC_STATUS_ERR_BAD_NICKNAME, 0);
378         silc_server_query_free(query);
379         return;
380       }
381
382     } else {
383       /* Parse the IDs included in the query */
384       query->ids = silc_calloc(argc, sizeof(*query->ids));
385
386       for (i = 0; i < argc; i++) {
387         tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
388         if (!tmp)
389           continue;
390
391         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
392         if (!id || id_type != SILC_ID_CLIENT) {
393           silc_server_query_add_error(server, query, TRUE, i + 4,
394                                       SILC_STATUS_ERR_BAD_CLIENT_ID);
395           continue;
396         }
397
398         /* Normal server must check whether this ID exist, and if not then
399            send the query to router, unless done so already */
400         if (server->server_type == SILC_SERVER && !query->resolved) {
401           if (!silc_idlist_find_client_by_id(server->local_list,
402                                              id, TRUE, NULL)) {
403             if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
404                 !silc_idlist_find_client_by_id(server->global_list,
405                                                id, TRUE, NULL)) {
406               silc_server_query_send_router(server, query);
407               for (i = 0; i < query->ids_count; i++)
408                 silc_free(query->ids[i].id);
409               silc_free(query->ids);
410               silc_free(id);
411               return;
412             }
413           }
414         }
415
416         query->ids[query->ids_count].id = id;
417         query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
418         query->ids_count++;
419       }
420     }
421
422     /* Get the max count of reply messages allowed */
423     tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
424     if (tmp && tmp_len == sizeof(SilcUInt32))
425       SILC_GET32_MSB(query->reply_count, tmp);
426
427     /* Get requested attributes if set */
428     tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
429     if (tmp && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
430       query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
431
432       /* When Requested Attributes is present we will assure that this
433          client cannot execute the WHOIS command too fast.  This would be
434          same as having SILC_CF_LAG_STRICT. */
435       if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
436           cmd->sock->user_data)
437         ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
438     }
439     break;
440
441   case SILC_COMMAND_WHOWAS:
442     /* Get nickname */
443     tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
444     if (!tmp) {
445       silc_server_query_send_error(server, query,
446                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
447       silc_server_query_free(query);
448       return;
449     }
450
451     /* Get the nickname@server string and parse it */
452     if (tmp_len > 128 ||
453         !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
454       silc_server_query_send_error(server, query,
455                                    SILC_STATUS_ERR_BAD_NICKNAME, 0);
456       silc_server_query_free(query);
457       return;
458     }
459
460     /* Get the max count of reply messages allowed */
461     tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
462     if (tmp && tmp_len == sizeof(SilcUInt32))
463       SILC_GET32_MSB(query->reply_count, tmp);
464     break;
465
466   case SILC_COMMAND_IDENTIFY:
467     /* Get IDs if present. Take IDs always instead of names. */
468     tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
469     if (!tmp) {
470
471       /* Try get nickname */
472       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
473       if (tmp) {
474         /* Get the nickname@server string and parse it */
475         if (tmp_len > 128 ||
476             !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
477           silc_server_query_add_error(server, query, TRUE, 1,
478                                       SILC_STATUS_ERR_BAD_NICKNAME);
479       }
480
481       /* Try get server name */
482       tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
483       if (tmp)
484         query->server_name = silc_memdup(tmp, tmp_len);
485
486       /* Get channel name */
487       tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
488       if (tmp && tmp_len <= 256)
489         query->channel_name = silc_memdup(tmp, tmp_len);
490
491       if (!query->nickname && !query->server_name && !query->channel_name) {
492         silc_server_query_send_error(server, query,
493                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
494         silc_server_query_free(query);
495         return;
496       }
497
498     } else {
499       /* Parse the IDs included in the query */
500       query->ids = silc_calloc(argc, sizeof(*query->ids));
501
502       for (i = 0; i < argc; i++) {
503         tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
504         if (!tmp)
505           continue;
506
507         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
508         if (!id) {
509           silc_server_query_add_error(server, query, TRUE, i + 5,
510                                       SILC_STATUS_ERR_BAD_CLIENT_ID);
511           continue;
512         }
513
514         /* Normal server must check whether this ID exist, and if not then
515            send the query to router, unless done so already */
516         if (server->server_type == SILC_SERVER && !query->resolved) {
517           if (id_type == SILC_ID_CLIENT) {
518             if (!silc_idlist_find_client_by_id(server->local_list,
519                                                id, TRUE, NULL)) {
520               if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
521                   !silc_idlist_find_client_by_id(server->global_list,
522                                                  id, TRUE, NULL)) {
523                 silc_server_query_send_router(server, query);
524                 for (i = 0; i < query->ids_count; i++)
525                   silc_free(query->ids[i].id);
526                 silc_free(query->ids);
527                 silc_free(id);
528                 return;
529               }
530             }
531           } else {
532             /* For now all other ID's except Client ID's are explicitly
533                sent to router for resolving. */
534             silc_server_query_send_router(server, query);
535             for (i = 0; i < query->ids_count; i++)
536               silc_free(query->ids[i].id);
537             silc_free(query->ids);
538             silc_free(id);
539             return;
540           }
541         }
542
543         query->ids[query->ids_count].id = id;
544         query->ids[query->ids_count].id_type = id_type;
545         query->ids_count++;
546       }
547     }
548
549     /* Get the max count of reply messages allowed */
550     tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
551     if (tmp && tmp_len == sizeof(SilcUInt32))
552       SILC_GET32_MSB(query->reply_count, tmp);
553     break;
554   }
555
556   /* Start processing the query information */
557   silc_server_query_process(server, query, TRUE);
558 }
559
560 /* Processes the parsed query.  This does the actual finding of the
561    queried information and prepares for sending reply to the original
562    sender of the query command. */
563
564 void silc_server_query_process(SilcServer server, SilcServerQuery query,
565                                bool resolve)
566 {
567   SilcServerCommandContext cmd = query->cmd;
568   bool check_global = FALSE;
569   void *entry;
570   SilcClientEntry *clients = NULL, client_entry;
571   SilcChannelEntry *channels = NULL;
572   SilcServerEntry *servers = NULL;
573   SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
574   int i;
575
576   SILC_LOG_DEBUG(("Processing %s query",
577                   silc_get_command_name(query->querycmd)));
578
579   /* Check global lists if query is coming from client or we are not
580      normal server (we know global information). */
581   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
582     check_global = TRUE;
583   else if (server->server_type != SILC_SERVER)
584     check_global = TRUE;
585
586   if (query->nickname) {
587     /* Get all clients matching nickname from local list */
588     if (!silc_idlist_get_clients_by_hash(server->local_list, 
589                                          query->nickname, server->md5hash,
590                                          &clients, &clients_count))
591       silc_idlist_get_clients_by_nickname(server->local_list, 
592                                           query->nickname,
593                                           query->nick_server,
594                                           &clients, &clients_count);
595
596     /* Check global list as well */
597     if (check_global) {
598       if (!silc_idlist_get_clients_by_hash(server->global_list, 
599                                            query->nickname, server->md5hash,
600                                            &clients, &clients_count))
601         silc_idlist_get_clients_by_nickname(server->global_list, 
602                                             query->nickname,
603                                             query->nick_server,
604                                             &clients, &clients_count);
605     }
606
607     if (!clients)
608       silc_server_query_add_error(server, query, TRUE, 1,
609                                   SILC_STATUS_ERR_NO_SUCH_NICK);
610   }
611
612   if (query->server_name) {
613     /* Find server by name */
614     entry = silc_idlist_find_server_by_name(server->local_list,
615                                             query->server_name, TRUE, NULL);
616     if (!entry && check_global)
617       entry = silc_idlist_find_server_by_name(server->global_list,
618                                               query->server_name, TRUE, NULL);
619     if (entry) {
620       servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
621       servers[servers_count++] = (SilcServerEntry)entry;
622     }
623
624     if (!servers)
625       silc_server_query_add_error(server, query, TRUE, 2,
626                                   SILC_STATUS_ERR_NO_SUCH_SERVER);
627   }
628
629   if (query->channel_name) {
630     /* Find channel by name */
631     entry = silc_idlist_find_channel_by_name(server->local_list,
632                                              query->channel_name, NULL);
633     if (!entry && check_global)
634       entry = silc_idlist_find_channel_by_name(server->global_list,
635                                                query->channel_name, NULL);
636     if (entry) {
637       channels = silc_realloc(channels, sizeof(*channels) *
638                               (channels_count + 1));
639       channels[channels_count++] = (SilcChannelEntry)entry;
640     }
641
642     if (!channels)
643       silc_server_query_add_error(server, query, TRUE, 3,
644                                   SILC_STATUS_ERR_NO_SUCH_CHANNEL);
645   }
646
647   if (query->ids_count) {
648     /* Find entries by the queried IDs */
649     for (i = 0; i < query->ids_count; i++) {
650       void *id = query->ids[i].id;
651       if (!id)
652         continue;
653
654       switch (query->ids[i].id_type) {
655
656       case SILC_ID_CLIENT:
657         /* Get client entry */
658         entry = silc_idlist_find_client_by_id(server->local_list,
659                                               id, TRUE, NULL);
660         if (!entry && check_global)
661           entry = silc_idlist_find_client_by_id(server->global_list,
662                                                 id, TRUE, NULL);
663         if (!entry) {
664           silc_server_query_add_error(server, query, FALSE, i,
665                                       SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
666           continue;
667         }
668
669         clients = silc_realloc(clients, sizeof(*clients) *
670                                (clients_count + 1));
671         clients[clients_count++] = (SilcClientEntry)entry;
672         break;
673
674       case SILC_ID_SERVER:
675         /* Get server entry */
676         entry = silc_idlist_find_server_by_id(server->local_list,
677                                               id, TRUE, NULL);
678         if (!entry && check_global)
679           entry = silc_idlist_find_server_by_id(server->global_list,
680                                                 id, TRUE, NULL);
681         if (!entry) {
682           silc_server_query_add_error(server, query, FALSE, i,
683                                       SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
684           continue;
685         }
686
687         servers = silc_realloc(servers, sizeof(*servers) *
688                                (servers_count + 1));
689         servers[servers_count++] = (SilcServerEntry)entry;
690         break;
691
692       case SILC_ID_CHANNEL:
693         /* Get channel entry */
694         entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
695         if (!entry && check_global)
696           entry = silc_idlist_find_channel_by_id(server->global_list, id,
697                                                  NULL);
698         if (!entry) {
699           silc_server_query_add_error(server, query, FALSE, i,
700                                       SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
701           continue;
702         }
703
704         channels = silc_realloc(channels, sizeof(*channels) *
705                                 (channels_count + 1));
706         channels[channels_count++] = (SilcChannelEntry)entry;
707         break;
708
709       default:
710         break;
711       }
712     }
713   }
714
715   /* If nothing was found, then just send the errors */
716   if (!clients && !channels && !servers) {
717     silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
718     return;
719   }
720
721   /* If caller does not want us to resolve anything (has resolved already)
722      then just continue with sending the reply */
723   if (!resolve) {
724     silc_server_query_send_reply(server, query, clients, clients_count,
725                                  servers, servers_count, channels,
726                                  channels_count);
727     silc_free(clients);
728     silc_free(servers);
729     silc_free(channels);
730     return;
731   }
732
733   /* Now process all found information and if necessary do some more
734      resolving. */
735   switch (query->querycmd) {
736
737   case SILC_COMMAND_WHOIS:
738     for (i = 0; i < clients_count; i++) {
739       client_entry = clients[i];
740
741       /* Check if cannot query this anyway, so take next one */
742       if (!client_entry ||
743           !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
744         continue;
745
746       /* If Requested Attributes is set then we always resolve the client
747          information, if not then check whether the entry is complete or not
748          and decide whether we need to resolve or not. */
749       if (!query->attrs) {
750
751         /* Even if nickname and stuff are present, we may need to resolve
752            the entry */
753         if (client_entry->nickname && client_entry->username &&
754             client_entry->userinfo) {
755           /* Check if cannot query this anyway, so take next one */
756           if (!client_entry->router)
757             continue;
758
759           /* If we are router, client is local to us, or client is on channel
760              we do not need to resolve the client information. */
761           if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
762               || silc_hash_table_count(client_entry->channels) ||
763               query->resolved)
764             continue;
765         }
766       }
767
768       /* Remove the NOATTR status periodically */
769       if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
770           client_entry->updated + 600 < time(NULL))
771         client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
772
773       /* When requested attributes is present and local client is detached
774          we cannot send the command to the client, we'll reply on behalf of
775          the client instead. */
776       if (query->attrs && SILC_IS_LOCAL(client_entry) &&
777           (client_entry->mode & SILC_UMODE_DETACHED ||
778            client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
779         continue;
780
781       /* Resolve the detailed client information. If client is local we
782          know that attributes were present and we will resolve directly
783          from the client. Otherwise resolve from client's owner. */
784       silc_server_query_resolve(server, query,
785                                 (SILC_IS_LOCAL(client_entry) ?
786                                  client_entry->connection :
787                                  client_entry->router->connection),
788                                 client_entry);
789     }
790     break;
791
792   case SILC_COMMAND_WHOWAS:
793     for (i = 0; i < clients_count; i++) {
794       client_entry = clients[i];
795
796       /* Check if cannot query this anyway, so take next one */
797       if (!client_entry || !client_entry->router ||
798           client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
799         continue;
800
801       /* If both nickname and username are present no resolving is needed */
802       if (client_entry->nickname && client_entry->username)
803         continue;
804
805       /* Resolve the detailed client information */
806       silc_server_query_resolve(server, query,
807                                 client_entry->router->connection,
808                                 client_entry);
809     }
810     break;
811
812   case SILC_COMMAND_IDENTIFY:
813     for (i = 0; i < clients_count; i++) {
814       client_entry = clients[i];
815
816       /* Check if cannot query this anyway, so take next one */
817       if (!client_entry || !client_entry->router ||
818           !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
819         continue;
820
821       /* Even if nickname is present, we may need to resolve the entry */
822       if (client_entry->nickname) {
823
824         /* If we are router, client is local to us, or client is on channel
825            we do not need to resolve the client information. */
826         if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
827             || silc_hash_table_count(client_entry->channels) ||
828             query->resolved)
829           continue;
830       }
831
832       /* Resolve the detailed client information */
833       silc_server_query_resolve(server, query,
834                                 client_entry->router->connection,
835                                 client_entry);
836     }
837     break;
838   }
839
840   if (!query->queries_count)
841     /* If we didn't have to do any resolving, continue with sending the
842        command reply to the original sender. */
843     silc_server_query_send_reply(server, query, clients, clients_count,
844                                  servers, servers_count, channels,
845                                  channels_count);
846   else
847     /* Now actually send the resolvings we gathered earlier */
848     silc_server_query_resolve(server, query, NULL, NULL);
849
850   silc_free(clients);
851   silc_free(servers);
852   silc_free(channels);
853 }
854
855 /* Resolve the detailed information for the `client_entry'.  Only client
856    information needs to be resolved for being incomplete.  Each incomplete
857    client entry calls this function to do the resolving. */
858
859 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
860                                SilcSocketConnection sock,
861                                SilcClientEntry client_entry)
862 {
863   SilcServerCommandContext cmd = query->cmd;
864   SilcServerQueryList r = NULL;
865   SilcBuffer idp;
866   unsigned char *tmp;
867   SilcUInt32 len;
868   SilcUInt16 ident;
869   int i;
870
871   if (!sock && client_entry)
872     return;
873
874   /* If arguments are NULL we will now actually send the resolvings
875      that earlier has been gathered by calling this function. */
876   if (!sock && !client_entry) {
877     SilcBuffer res_cmd;
878
879     SILC_LOG_DEBUG(("Sending the resolvings"));
880
881     /* WHOWAS resolving has been done at the same time this function
882        was called to add the resolving for WHOWAS, so just return. */
883     if (query->querycmd == SILC_COMMAND_WHOWAS)
884       return;
885
886     for (i = 0; i < query->querylist_count; i++) {
887       r = &query->querylist[i];
888
889       /* If Requested Attributes were present put them to this resolving */
890       if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
891         len = r->argc + 1;
892         r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
893         r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
894         r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
895
896         tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
897         if (tmp)
898           r->arg[r->argc] = silc_memdup(tmp, len);
899         r->arg_lens[r->argc] = len;
900         r->arg_types[r->argc] = 3;
901         r->argc++;
902       }
903
904       /* Send WHOIS command */
905       res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
906                                             r->argc, r->arg, r->arg_lens,
907                                             r->arg_types, r->ident);
908       silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
909                               res_cmd->data, res_cmd->len, FALSE);
910       silc_buffer_free(res_cmd);
911
912       /* Reprocess this packet after received reply */
913       if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
914                                             r->ident,
915                                             silc_server_query_resolve_reply,
916                                             query, r->timeout))
917         query->queries_left++;
918     }
919
920     /* Cleanup this temporary context */
921     for (i = 0; i < query->querylist_count; i++) {
922       int k;
923       for (k = 0; k < query->querylist[i].argc; k++)
924         silc_free(query->querylist[i].arg[k]);
925       silc_free(query->querylist[i].arg);
926       silc_free(query->querylist[i].arg_lens);
927       silc_free(query->querylist[i].arg_types);
928     }
929     silc_free(query->querylist);
930     query->querylist = NULL;
931     query->querylist_count = 0;
932     return;
933   }
934
935   SILC_LOG_DEBUG(("Resolving client information"));
936
937   if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
938     /* The entry is being resolved by some other external query already.
939        Attach to that query instead of resolving again. */
940     ident = client_entry->resolve_cmd_ident;
941     if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
942                                     silc_server_query_resolve_reply, query))
943       query->queries_left++;
944   } else {
945     /* This entry will be resolved */
946     ident = ++server->cmd_ident;
947
948     switch (query->querycmd) {
949
950     case SILC_COMMAND_WHOIS:
951     case SILC_COMMAND_IDENTIFY:
952       /* Take existing query context if exist for this connection */
953       for (i = 0; i < query->querylist_count; i++)
954         if (query->querylist[i].sock == sock) {
955           r = &query->querylist[i];
956           break;
957         }
958
959       if (!r) {
960         /* Allocate new temp query list context */
961         query->querylist = silc_realloc(query->querylist,
962                                         sizeof(*query->querylist) * 
963                                         (query->querylist_count + 1));
964         r = &query->querylist[query->querylist_count];
965         query->querylist_count++;
966         memset(r, 0, sizeof(*r));
967         r->sock = sock;
968         r->ident = ident;
969         if (SILC_IS_LOCAL(client_entry))
970           r->timeout = 3;
971       }
972
973       len = r->argc + 1;
974       r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
975       r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
976       r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
977
978       /* Add the client entry to be resolved */
979       idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
980       r->arg[r->argc] = silc_memdup(idp->data, idp->len);
981       r->arg_lens[r->argc] = idp->len;
982       r->arg_types[r->argc] = r->argc + 4;
983       r->argc++;
984       silc_buffer_free(idp);
985
986       break;
987
988     case SILC_COMMAND_WHOWAS:
989       /* We must send WHOWAS command since it's the only the way of
990          resolving clients that are not present in the network anymore. */
991       silc_server_send_command(server, sock, query->querycmd, ident, 1,
992                                1, query->nickname, strlen(query->nickname));
993       if (silc_server_command_pending(server, query->querycmd, ident,
994                                       silc_server_query_resolve_reply, query))
995         query->queries_left++;
996       break;
997     }
998   }
999
1000   /* Mark the entry as being resolved */
1001   client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1002   client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1003   client_entry->resolve_cmd_ident = ident;
1004   client_entry->updated = time(NULL);
1005
1006   /* Save the queried ID, which we will reprocess after we get this and
1007      all other queries back. */
1008   query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1009                                 (query->queries_count + 1));
1010   if (query->queries) {
1011     i = query->queries_count;
1012     query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1013     query->queries[i].id_type = SILC_ID_CLIENT;
1014     query->queries[i].ident = ident;
1015     query->queries_count++;
1016   }
1017 }
1018
1019 /* Reply callback called after one resolving has been completed.  If
1020    all resolvings has been received then we will continue with sending
1021    the command reply to the original sender of the query. */
1022
1023 void silc_server_query_resolve_reply(void *context, void *reply)
1024 {
1025   SilcServerQuery query = context;
1026   SilcServer server = query->cmd->server;
1027   SilcServerCommandReplyContext cmdr = reply;
1028   SilcUInt16 ident = cmdr->ident;
1029   SilcStatus error = SILC_STATUS_OK;
1030   SilcServerQueryID id = NULL;
1031   SilcClientEntry client_entry;
1032   int i;
1033
1034   /* One less query left */
1035   query->queries_left--;
1036
1037   silc_command_get_status(cmdr->payload, NULL, &error);
1038   SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1039                   query->queries_left, error));
1040
1041   /* If no error then skip to other stuff */
1042   if (error == SILC_STATUS_OK)
1043     goto out;
1044
1045   /* Error occurred during resolving */
1046
1047   /* Find the resolved client ID */
1048   for (i = 0; i < query->queries_count; i++) {
1049     if (query->queries[i].ident != ident)
1050       continue;
1051
1052     id = &query->queries[i];
1053
1054     if (error == SILC_STATUS_ERR_TIMEDOUT) {
1055
1056       /* If timeout occurred for local entry when resolving attributes
1057          mark that this client doesn't support attributes in WHOIS. This
1058          assures we won't send the request again to the client. */
1059       if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1060         client_entry = silc_idlist_find_client_by_id(server->local_list,
1061                                                      id->id, TRUE, NULL);
1062         SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1063                         silc_id_render(id->id, SILC_ID_CLIENT)));
1064         if (client_entry && SILC_IS_LOCAL(client_entry)) {
1065           client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1066           client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1067           continue;
1068         }
1069       }
1070
1071       /* Remove the RESOLVING status from the client entry */
1072       if (query->querycmd != SILC_COMMAND_WHOWAS) {
1073         client_entry = silc_idlist_find_client_by_id(server->local_list,
1074                                                      id->id, TRUE, NULL);
1075         if (!client_entry)
1076           client_entry = silc_idlist_find_client_by_id(server->global_list,
1077                                                        id->id, TRUE, NULL);
1078         if (client_entry)
1079           client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1080       }
1081     }
1082   }
1083
1084  out:
1085
1086   /* If there are queries left then wait for them */
1087   if (query->queries_left)
1088     return;
1089
1090   SILC_LOG_DEBUG(("Reprocess the query"));
1091
1092   /* We have received all queries.  Now re-search all information required
1093      to complete this query.  Reason we cannot save the values found in
1094      the first search is that SilcClientEntry, SilcServerEntry and
1095      SilcChannelEntry pointers may become invalid while we were waiting
1096      for these resolvings. */
1097   silc_server_query_process(server, query, FALSE);
1098 }
1099
1100 /* Send the reply to the original query.  If arguments are NULL then this
1101    sends only the errors that has occurred during the processing of the
1102    query.  This sends the errors always after sending all the found
1103    information.  The query is over after this function returns and the
1104    `query' will become invalid.  This is called only after all informations
1105    has been resolved.  This means that if something is not found or is
1106    incomplete in this function we were unable to resolve the information
1107    or it does not exist at all. */
1108
1109 void silc_server_query_send_reply(SilcServer server,
1110                                   SilcServerQuery query,
1111                                   SilcClientEntry *clients,
1112                                   SilcUInt32 clients_count,
1113                                   SilcServerEntry *servers,
1114                                   SilcUInt32 servers_count,
1115                                   SilcChannelEntry *channels,
1116                                   SilcUInt32 channels_count)
1117 {
1118   SilcServerCommandContext cmd = query->cmd;
1119   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1120   SilcStatus status;
1121   unsigned char *tmp;
1122   SilcUInt32 len;
1123   SilcBuffer idp;
1124   int i, k, valid_count;
1125   char nh[256], uh[256];
1126   bool sent_reply = FALSE;
1127
1128   SILC_LOG_DEBUG(("Sending reply to query"));
1129
1130   status = SILC_STATUS_OK;
1131
1132   /* Send clients */
1133   if (clients_count) {
1134     SilcClientEntry entry;
1135     SilcSocketConnection hsock;
1136
1137     /* Mark all invalid entries */
1138     for (i = 0, valid_count = 0; i < clients_count; i++) {
1139       entry = clients[i];
1140       switch (query->querycmd) {
1141       case SILC_COMMAND_WHOIS:
1142         if (!entry->nickname || !entry->username || !entry->userinfo ||
1143             !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1144           /* When querying by ID, every "unfound" entry must cause error */
1145           if (query->ids)
1146             silc_server_query_add_error_id(server, query,
1147                                            SILC_STATUS_ERR_TIMEDOUT,
1148                                            entry->id, SILC_ID_CLIENT);
1149           clients[i] = NULL;
1150           continue;
1151         }
1152         break;
1153
1154       case SILC_COMMAND_IDENTIFY:
1155         if (!entry->nickname ||
1156             !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1157           /* When querying by ID, every "unfound" entry must cause error */
1158           if (query->ids)
1159             silc_server_query_add_error_id(server, query,
1160                                            SILC_STATUS_ERR_TIMEDOUT,
1161                                            entry->id, SILC_ID_CLIENT);
1162           clients[i] = NULL;
1163           continue;
1164         }
1165         break;
1166
1167       case SILC_COMMAND_WHOWAS:
1168         if (!entry->nickname || !entry->username ||
1169             entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1170           clients[i] = NULL;
1171           continue;
1172         }
1173         break;
1174       }
1175       valid_count++;
1176     }
1177
1178     /* Start processing found clients */
1179     status = SILC_STATUS_OK;
1180     if (valid_count > 1)
1181       status = SILC_STATUS_LIST_START;
1182
1183     /* Now do the sending of valid entries */
1184     k = 0;
1185     for (i = 0; i < clients_count && valid_count; i++) {
1186       entry = clients[i];
1187       if (!entry)
1188         continue;
1189
1190       if (k >= 1)
1191         status = SILC_STATUS_LIST_ITEM;
1192       if (valid_count > 1 && k == valid_count - 1 
1193           && !servers_count && !channels_count && !query->errors_count)
1194         status = SILC_STATUS_LIST_END;
1195       if (query->reply_count && k - 1 == query->reply_count)
1196         status = SILC_STATUS_LIST_END;
1197
1198       SILC_LOG_DEBUG(("%s: client %s",
1199                       (status == SILC_STATUS_OK ?         "   OK" :
1200                        status == SILC_STATUS_LIST_START ? "START" :
1201                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1202                        status == SILC_STATUS_LIST_END  ?  "  END" :
1203                        "      : "), entry->nickname));
1204
1205       idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1206       memset(uh, 0, sizeof(uh));
1207       memset(nh, 0, sizeof(nh));
1208
1209       silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1210       if (!strchr(entry->nickname, '@')) {
1211         silc_strncat(nh, sizeof(nh), "@", 1);
1212         if (entry->servername) {
1213           silc_strncat(nh, sizeof(nh), entry->servername,
1214                        strlen(entry->servername));
1215         } else {
1216           len = entry->router ? strlen(entry->router->server_name) :
1217             strlen(server->server_name);
1218           silc_strncat(nh, sizeof(nh), entry->router ?
1219                        entry->router->server_name :
1220                        server->server_name, len);
1221         }
1222       }
1223       
1224       switch (query->querycmd) {
1225         
1226       case SILC_COMMAND_WHOIS:
1227         {
1228           unsigned char idle[4], mode[4];
1229           unsigned char *fingerprint, fempty[20], *attrs = NULL;
1230           SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1231
1232           memset(fempty, 0, sizeof(fempty));
1233           memset(idle, 0, sizeof(idle));
1234           silc_strncat(uh, sizeof(uh), entry->username,
1235                        strlen(entry->username));
1236           if (!strchr(entry->username, '@') && entry->connection) {
1237             hsock = entry->connection;
1238             silc_strncat(uh, sizeof(uh), "@", 1);
1239             len = strlen(hsock->hostname);
1240             silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1241           }
1242
1243           if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1244             channels =
1245               silc_server_get_client_channel_list(server, entry, FALSE, 
1246                                                   FALSE, &umode_list);
1247           else
1248             channels =
1249               silc_server_get_client_channel_list(server, entry, TRUE, 
1250                                                   TRUE, &umode_list);
1251
1252           if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1253             fingerprint = entry->data.fingerprint;
1254           else
1255             fingerprint = NULL;
1256
1257           SILC_PUT32_MSB(entry->mode, mode);
1258           if (entry->connection)
1259             SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1260
1261           /* If Requested Attribute were present, and we do not have the
1262              attributes we will reply to them on behalf of the client. */
1263           len = 0;
1264           if (query->attrs) {
1265             if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1266               tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1267               entry->attrs = silc_memdup(tmpattrs->data, tmpattrs->len);
1268               entry->attrs_len = tmpattrs->len;
1269               silc_buffer_free(tmpattrs);
1270             }
1271             attrs = entry->attrs;
1272             len = entry->attrs_len;
1273           }
1274
1275           /* Send command reply */
1276           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1277                                          status, 0, ident, 10,
1278                                          2, idp->data, idp->len,
1279                                          3, nh, strlen(nh),
1280                                          4, uh, strlen(uh),
1281                                          5, entry->userinfo, 
1282                                          strlen(entry->userinfo),
1283                                          6, channels ? channels->data : NULL,
1284                                          channels ? channels->len : 0,
1285                                          7, mode, 4,
1286                                          8, idle, 4,
1287                                          9, fingerprint,
1288                                          fingerprint ? 20 : 0,
1289                                          10, umode_list ? umode_list->data :
1290                                          NULL, umode_list ? umode_list->len :
1291                                          0, 11, attrs, len);
1292
1293           sent_reply = TRUE;
1294
1295           /* For now we always delete Requested Attributes, unless the client
1296              is detached, in which case we don't want to reconstruct the
1297              same data everytime */
1298           if (!(entry->mode & SILC_UMODE_DETACHED) &&
1299               !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1300             silc_free(entry->attrs);
1301             entry->attrs = NULL;
1302           }
1303
1304           if (channels)
1305             silc_buffer_free(channels);
1306           if (umode_list) {
1307             silc_buffer_free(umode_list);
1308             umode_list = NULL;
1309           }
1310         }
1311         break;
1312
1313       case SILC_COMMAND_IDENTIFY:
1314         if (!entry->username) {
1315           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1316                                          status, 0, ident, 2,
1317                                          2, idp->data, idp->len,
1318                                          3, nh, strlen(nh));
1319           sent_reply = TRUE;
1320         } else {
1321           silc_strncat(uh, sizeof(uh), entry->username,
1322                        strlen(entry->username));
1323           if (!strchr(entry->username, '@') && entry->connection) {
1324             hsock = entry->connection;
1325             silc_strncat(uh, sizeof(uh), "@", 1);
1326             len = strlen(hsock->hostname);
1327             silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1328           }
1329
1330           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1331                                          status, 0, ident, 3,
1332                                          2, idp->data, idp->len,
1333                                          3, nh, strlen(nh),
1334                                          4, uh, strlen(uh));
1335           sent_reply = TRUE;
1336         }
1337         break;
1338
1339       case SILC_COMMAND_WHOWAS:
1340         silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1341         if (!strchr(entry->username, '@'))
1342           silc_strncat(uh, sizeof(uh), "@*private*", 10);
1343
1344         /* Send command reply */
1345         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1346                                        status, 0, ident, 4,
1347                                        2, idp->data, idp->len,
1348                                        3, nh, strlen(nh),
1349                                        4, uh, strlen(uh),
1350                                        5, entry->userinfo, 
1351                                        entry->userinfo ? 
1352                                        strlen(entry->userinfo) : 0);
1353         sent_reply = TRUE;
1354         break;
1355       }
1356
1357       silc_buffer_free(idp);
1358
1359       if (status == SILC_STATUS_LIST_END)
1360         break;
1361       k++;
1362     }
1363
1364     if (k == 0) {
1365       /* Not one valid entry was found, send error.  If nickname was used
1366          in query send error based on that, otherwise the query->errors
1367          already includes proper errors. */
1368       if (query->nickname)
1369         silc_server_query_add_error(server, query, TRUE, 1,
1370                                     SILC_STATUS_ERR_NO_SUCH_NICK);
1371     }
1372   }
1373
1374   /* Send servers */
1375   if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1376     SilcServerEntry entry;
1377
1378     if (status == SILC_STATUS_OK && servers_count > 1)
1379       status = SILC_STATUS_LIST_START;
1380
1381     k = 0;
1382     for (i = 0; i < servers_count; i++) {
1383       entry = servers[i];
1384       
1385       if (k >= 1)
1386         status = SILC_STATUS_LIST_ITEM;
1387       if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1388           !query->errors_count)
1389         status = SILC_STATUS_LIST_END;
1390       if (query->reply_count && k - 1 == query->reply_count)
1391         status = SILC_STATUS_LIST_END;
1392       
1393       SILC_LOG_DEBUG(("%s: server %s",
1394                       (status == SILC_STATUS_OK ?         "   OK" :
1395                        status == SILC_STATUS_LIST_START ? "START" :
1396                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1397                        status == SILC_STATUS_LIST_END  ?  "  END" :
1398                        "      : "),
1399                       entry->server_name ? entry->server_name : ""));
1400
1401       /* Send command reply */
1402       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1403       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1404                                      status, 0, ident, 2,
1405                                      2, idp->data, idp->len, 
1406                                      3, entry->server_name, 
1407                                      entry->server_name ? 
1408                                      strlen(entry->server_name) : 0);
1409       silc_buffer_free(idp);
1410       sent_reply = TRUE;
1411       
1412       if (status == SILC_STATUS_LIST_END)
1413         break;
1414       k++;
1415     }
1416   }
1417
1418   /* Send channels */
1419   if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1420     SilcChannelEntry entry;
1421
1422     if (status == SILC_STATUS_OK && channels_count > 1)
1423       status = SILC_STATUS_LIST_START;
1424
1425     k = 0;
1426     for (i = 0; i < channels_count; i++) {
1427       entry = channels[i];
1428       
1429       if (k >= 1)
1430         status = SILC_STATUS_LIST_ITEM;
1431       if (channels_count > 1 && k == channels_count - 1 &&
1432           !query->errors_count)
1433         status = SILC_STATUS_LIST_END;
1434       if (query->reply_count && k - 1 == query->reply_count)
1435         status = SILC_STATUS_LIST_END;
1436       
1437       SILC_LOG_DEBUG(("%s: channel %s",
1438                       (status == SILC_STATUS_OK ?         "   OK" :
1439                        status == SILC_STATUS_LIST_START ? "START" :
1440                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1441                        status == SILC_STATUS_LIST_END  ?  "  END" :
1442                        "      : "),
1443                       entry->channel_name ? entry->channel_name : ""));
1444
1445       /* Send command reply */
1446       idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1447       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1448                                      status, 0, ident, 2,
1449                                      2, idp->data, idp->len, 
1450                                      3, entry->channel_name, 
1451                                      entry->channel_name ? 
1452                                      strlen(entry->channel_name) : 0);
1453       silc_buffer_free(idp);
1454       sent_reply = TRUE;
1455       
1456       if (status == SILC_STATUS_LIST_END)
1457         break;
1458       k++;
1459     }
1460   }
1461
1462   /* Send errors */
1463   if (query->errors_count) {
1464     int type;
1465
1466     if (status == SILC_STATUS_OK && query->errors_count > 1)
1467       status = SILC_STATUS_LIST_START;
1468
1469     k = 0;
1470     for (i = 0; i < query->errors_count; i++) {
1471       idp = NULL;
1472
1473       /* Take error argument */
1474       if (query->errors[i].from_cmd) {
1475         len = 0;
1476         tmp = silc_argument_get_arg_type(cmd->args,
1477                                          query->errors[i].index, &len);
1478         if (query->errors[i].index == 1)
1479           type = 3;                 /* Nickname */
1480         else
1481           type = 2;                 /* ID */
1482       } else if (!query->errors[i].id) {
1483         idp =
1484           silc_id_payload_encode(query->ids[query->errors[i].index].id,
1485                                  query->ids[query->errors[k].index].id_type);
1486         tmp = idp->data;
1487         len = idp->len;
1488         type = 2;
1489       } else {
1490         idp = silc_id_payload_encode(query->errors[i].id,
1491                                      query->errors[k].id_type);
1492         tmp = idp->data;
1493         len = idp->len;
1494         type = 2;
1495       }
1496
1497       if (k >= 1)
1498         status = SILC_STATUS_LIST_ITEM;
1499       if (query->errors_count > 1 && k == query->errors_count - 1)
1500         status = SILC_STATUS_LIST_END;
1501       if (query->reply_count && k - 1 == query->reply_count)
1502         status = SILC_STATUS_LIST_END;
1503
1504       SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1505                       (status == SILC_STATUS_OK ?         "   OK" :
1506                        status == SILC_STATUS_LIST_START ? "START" :
1507                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1508                        status == SILC_STATUS_LIST_END  ?  "  END" :
1509                        "      : "), 
1510                       silc_get_status_message(query->errors[i].error),
1511                       query->errors[i].error));
1512
1513       /* Send error */
1514       silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1515                                      (status == SILC_STATUS_OK ?
1516                                       query->errors[i].error : status),
1517                                      (status == SILC_STATUS_OK ?
1518                                       0 : query->errors[i].error), ident, 1,
1519                                      type, tmp, len);
1520       silc_buffer_free(idp);
1521       sent_reply = TRUE;
1522
1523       if (status == SILC_STATUS_LIST_END)
1524         break;
1525       k++;
1526     }
1527   }
1528
1529   if (!sent_reply)
1530     SILC_LOG_ERROR(("BUG: Query did not send anything"));
1531
1532   /* Cleanup */
1533   silc_server_query_free(query);
1534 }
1535
1536 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1537    of the client since we were unable to resolve them from the client.
1538    Either client does not support Requested Attributes or isn't replying
1539    to them like it should. */
1540
1541 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1542                                          SilcServerQuery query,
1543                                          SilcClientEntry client_entry)
1544 {
1545   SilcBuffer buffer = NULL;
1546   SilcAttribute attribute;
1547   SilcAttributePayload attr;
1548   SilcAttributeObjPk pk;
1549   SilcAttributeObjService service;
1550   unsigned char *tmp;
1551   unsigned char sign[2048];
1552   SilcUInt32 sign_len;
1553
1554   SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1555
1556   /* Go through all requested attributes */
1557   silc_dlist_start(query->attrs);
1558   while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1559     attribute = silc_attribute_get_attribute(attr);
1560     switch (attribute) {
1561
1562     case SILC_ATTRIBUTE_SERVICE:
1563       /* Put SERVICE.  Put only SILC service. */
1564       memset(&service, 0, sizeof(service));
1565       service.port = (server->config->server_info->primary ?
1566                       server->config->server_info->primary->port : SILC_PORT);
1567       silc_strncat(service.address, sizeof(service.address),
1568                    server->server_name, strlen(server->server_name));
1569       service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1570       buffer = silc_attribute_payload_encode(buffer, attribute,
1571                                              SILC_ATTRIBUTE_FLAG_VALID,
1572                                              &service, sizeof(service));
1573       if (!buffer)
1574         return NULL;
1575       break;
1576
1577     case SILC_ATTRIBUTE_STATUS_MOOD:
1578       /* Put STATUS_MOOD */
1579       buffer = silc_attribute_payload_encode(buffer, attribute,
1580                                              SILC_ATTRIBUTE_FLAG_VALID,
1581                                              (void *)
1582                                              SILC_ATTRIBUTE_MOOD_NORMAL,
1583                                              sizeof(SilcUInt32));
1584       if (!buffer)
1585         return NULL;
1586       break;
1587
1588     case SILC_ATTRIBUTE_STATUS_FREETEXT:
1589       /* Put STATUS_FREETEXT.  We just tell in the message that we are
1590          replying on behalf of the client. */
1591       tmp = 
1592         "This information was provided by the server on behalf of the user";
1593       buffer = silc_attribute_payload_encode(buffer, attribute,
1594                                              SILC_ATTRIBUTE_FLAG_VALID,
1595                                              tmp, strlen(tmp));
1596       if (!buffer)
1597         return NULL;
1598       break;
1599
1600     case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1601       /* Put PREFERRED_CONTACT */
1602       buffer = silc_attribute_payload_encode(buffer, attribute,
1603                                              SILC_ATTRIBUTE_FLAG_VALID,
1604                                              (void *)
1605                                              SILC_ATTRIBUTE_CONTACT_CHAT,
1606                                              sizeof(SilcUInt32));
1607       if (!buffer)
1608         return NULL;
1609       break;
1610
1611     case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1612       /* Put USER_PUBLIC_KEY */
1613       if (client_entry->data.public_key) {
1614         pk.type = "silc-rsa";
1615         pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1616                                               &pk.data_len);
1617         buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1618                                                SILC_ATTRIBUTE_FLAG_VALID :
1619                                                SILC_ATTRIBUTE_FLAG_INVALID,
1620                                                &pk, sizeof(pk));
1621         silc_free(pk.data);
1622         if (!buffer)
1623           return NULL;
1624         break;
1625       }
1626
1627       /* No public key available */
1628       buffer = silc_attribute_payload_encode(buffer, attribute,
1629                                              SILC_ATTRIBUTE_FLAG_INVALID,
1630                                              NULL, 0);
1631       if (!buffer)
1632         return NULL;
1633       break;
1634
1635     default:
1636       /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1637       if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1638           attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1639         break;
1640       
1641       /* For other attributes we cannot reply so mark it invalid */
1642       buffer = silc_attribute_payload_encode(buffer, attribute,
1643                                              SILC_ATTRIBUTE_FLAG_INVALID,
1644                                              NULL, 0);
1645       if (!buffer)
1646         return NULL;
1647       break;
1648     }
1649   }
1650
1651   /* Always put our public key.  This assures that we send at least
1652      something valid back always. */
1653   pk.type = "silc-rsa";
1654   pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1655   buffer = silc_attribute_payload_encode(buffer,
1656                                          SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1657                                          pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1658                                          SILC_ATTRIBUTE_FLAG_INVALID,
1659                                          &pk, sizeof(pk));
1660   silc_free(pk.data);
1661   if (!buffer)
1662     return NULL;
1663
1664   /* Finally compute the digital signature of all the data we provided
1665      as an indication that we provided rightfull information, and this
1666      also authenticates our public key. */
1667   if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1  &&
1668       silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1669                                buffer->data, buffer->len,
1670                                sign, &sign_len)) {
1671     pk.type = NULL;
1672     pk.data = sign;
1673     pk.data_len = sign_len;
1674     buffer =
1675       silc_attribute_payload_encode(buffer,
1676                                     SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1677                                     SILC_ATTRIBUTE_FLAG_VALID,
1678                                     &pk, sizeof(pk));
1679   }
1680   if (!buffer)
1681     return NULL;
1682
1683   return buffer;
1684 }
1685
1686 /* Find client by the Client ID indicated by the `client_id', and if not
1687    found then query it by using WHOIS command.  The client information
1688    is also resolved if the cached information is incomplete or if the
1689    `always_resolve' is set to TRUE.  The indication whether requested
1690    client was being resolved is saved into `resolved'.  If the client
1691    is not being resolved its entry is returned by this function.  NULL
1692    is returned if client is resolved. */
1693
1694 SilcClientEntry silc_server_query_client(SilcServer server,
1695                                          const SilcClientID *client_id,
1696                                          bool always_resolve,
1697                                          bool *resolved)
1698 {
1699   SilcClientEntry client;
1700
1701   SILC_LOG_DEBUG(("Resolving client by client ID"));
1702
1703   if (resolved)
1704     *resolved = FALSE;
1705
1706   client = silc_idlist_find_client_by_id(server->local_list,
1707                                          (SilcClientID *)client_id,
1708                                          TRUE, NULL);
1709   if (!client) {
1710     client = silc_idlist_find_client_by_id(server->global_list,
1711                                            (SilcClientID *)client_id,
1712                                            TRUE, NULL);
1713     if (!client && server->server_type == SILC_ROUTER)
1714       return NULL;
1715   }
1716
1717   if (!client && server->standalone)
1718     return NULL;
1719
1720   if (!client || !client->nickname || !client->username ||
1721       always_resolve) {
1722     SilcBuffer buffer, idp;
1723
1724     if (client) {
1725       client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1726       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1727       client->resolve_cmd_ident = ++server->cmd_ident;
1728     }
1729
1730     idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1731     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1732                                             server->cmd_ident, 1,
1733                                             4, idp->data, idp->len);
1734     silc_server_packet_send(server, client ? client->router->connection :
1735                             SILC_PRIMARY_ROUTE(server),
1736                             SILC_PACKET_COMMAND, 0,
1737                             buffer->data, buffer->len, FALSE);
1738     silc_buffer_free(idp);
1739     silc_buffer_free(buffer);
1740
1741     if (resolved)
1742       *resolved = TRUE;
1743
1744     return NULL;
1745   }
1746
1747   return client;
1748 }