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