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