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