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