More SILC Server 1.1 porting. Added HTTP statistics access.
[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 - 2005, 2007 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   SilcPacketStream 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   unsigned int index : 15;          /* Index to IDs */
46   unsigned int type : 2;            /* 0 = take from query->ids, 1 = take
47                                        from args, 2 = no args in error. */
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[128 + 1];           /* Queried nickname, normalized */
55   char nick_server[128 + 1];        /* Queried nickname's server */
56   char *server_name;                /* Queried server name, normalized */
57   char *channel_name;               /* Queried channel name, normalized */
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                                  SilcUInt32 type,
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                                SilcBool resolve);
95 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
96                                SilcPacketStream 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->server_name);
124   silc_free(query->channel_name);
125
126   for (i = 0; i < query->ids_count; i++)
127     silc_free(query->ids[i].id);
128   silc_free(query->ids);
129
130   if (query->attrs)
131     silc_attribute_payload_list_free(query->attrs);
132
133   for (i = 0; i < query->errors_count; i++)
134     silc_free(query->errors[i].id);
135   silc_free(query->errors);
136
137   memset(query, 'F', sizeof(*query));
138   silc_free(query);
139 }
140
141 /* Send error reply indicated by the `error' to the original sender of
142    the query. */
143
144 void silc_server_query_send_error(SilcServer server,
145                                   SilcServerQuery query,
146                                   SilcStatus error, ...)
147 {
148   va_list va;
149   unsigned char *data = NULL;
150   SilcUInt32 data_len = 0, data_type = 0, argc = 0;
151
152   va_start(va, error);
153   data_type = va_arg(va, SilcUInt32);
154   if (data_type) {
155     argc = 1;
156     data = va_arg(va, unsigned char *);
157     data_len = va_arg(va, SilcUInt32);
158   }
159
160   SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
161
162   /* Send the command reply with error */
163   silc_server_send_command_reply(server, query->cmd->sock,
164                                  query->querycmd, error, 0,
165                                  silc_command_get_ident(query->cmd->payload),
166                                  argc, data_type, data, data_len);
167   va_end(va);
168 }
169
170 /* Add error to error list.  Multiple errors may occur during the query
171    processing and this function can be used to add one error.  The
172    `index' is the index to the command context which includes the argument
173    which caused the error, or it is the index to query->ids, depending
174    on value of `type'.  If `type' is 0 the index is to query->ids, if
175    it is 1 it is index to the command context arguments, and if it is
176    2 the index is ignored and no argument is included in the error. */
177
178 void silc_server_query_add_error(SilcServer server,
179                                  SilcServerQuery query,
180                                  SilcUInt32 type,
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].type = type;
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].type = 0;
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 SilcBool 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 OR query
238        doesn't contain nickname or ids BUT attributes, send it to the
239        router */
240     if (server->server_type != SILC_ROUTER && !server->standalone &&
241         cmd->sock != SILC_PRIMARY_ROUTE(server) &&
242          (silc_argument_get_arg_type(cmd->args, 1, NULL) ||
243          (!silc_argument_get_arg_type(cmd->args, 1, NULL) &&
244           !silc_argument_get_arg_type(cmd->args, 4, NULL) &&
245           silc_argument_get_arg_type(cmd->args, 3, NULL)))) {
246       silc_server_query_send_router(server, query);
247       return TRUE;
248     }
249     break;
250
251   case SILC_COMMAND_WHOWAS:
252     /* WHOWAS query is always sent to router if we are normal server */
253     if (server->server_type == SILC_SERVER && !server->standalone &&
254         cmd->sock != SILC_PRIMARY_ROUTE(server)) {
255       silc_server_query_send_router(server, query);
256       return TRUE;
257     }
258     break;
259
260   case SILC_COMMAND_IDENTIFY:
261     /* If we are normal server and query does not contain IDs, send it
262        directly to router (it contains nickname, server name or channel
263        name). */
264     if (server->server_type == SILC_SERVER && !server->standalone &&
265         cmd->sock != SILC_PRIMARY_ROUTE(server) &&
266         !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
267       silc_server_query_send_router(server, query);
268       return TRUE;
269     }
270     break;
271
272   default:
273     SILC_LOG_ERROR(("Bad query using %d command", querycmd));
274     silc_server_query_free(query);
275     return FALSE;
276   }
277
278   /* Now parse the request */
279   silc_server_query_parse(server, query);
280
281   return TRUE;
282 }
283
284 /* Send the received query to our primary router since we could not
285    handle the query directly.  We will reprocess the query after our
286    router replies back. */
287
288 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
289 {
290   SilcBuffer tmpbuf;
291   SilcUInt16 old_ident;
292
293   SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
294
295   /* Statistics */
296   server->stat.commands_sent++;
297
298   /* Send WHOIS command to our router */
299   old_ident = silc_command_get_ident(query->cmd->payload);
300   silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
301   tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
302   silc_server_packet_send(server,
303                           SILC_PRIMARY_ROUTE(server),
304                           SILC_PACKET_COMMAND, 0,
305                           tmpbuf->data, silc_buffer_len(tmpbuf));
306   silc_command_set_ident(query->cmd->payload, old_ident);
307   silc_buffer_free(tmpbuf);
308
309   query->resolved = TRUE;
310
311   /* Continue parsing the query after received reply from router */
312   silc_server_command_pending(server, query->querycmd, server->cmd_ident,
313                               silc_server_query_send_router_reply, query);
314 }
315
316 /* Reply callback called after primary router has replied to our initial
317    sending of the query to it.  We will proceed the query in this function. */
318
319 void silc_server_query_send_router_reply(void *context, void *reply)
320 {
321   SilcServerQuery query = context;
322   SilcServer server = query->cmd->server;
323   SilcServerCommandReplyContext cmdr = reply;
324
325   SILC_LOG_DEBUG(("Received reply from router to query"));
326
327   /* If the original command caller has gone away, just stop. */
328   if (!silc_packet_stream_is_valid(query->cmd->sock)) {
329     SILC_LOG_DEBUG(("Original command caller vanished"));
330     silc_server_query_free(query);
331     return;
332   }
333
334   /* Check if router sent error reply */
335   if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
336     SilcBuffer buffer;
337
338     SILC_LOG_DEBUG(("Sending error to original query"));
339
340     /* Statistics */
341     server->stat.commands_sent++;
342
343     /* Send the same command reply payload which contains the error */
344     silc_command_set_command(cmdr->payload, query->querycmd);
345     silc_command_set_ident(cmdr->payload,
346                            silc_command_get_ident(query->cmd->payload));
347     buffer = silc_command_payload_encode_payload(cmdr->payload);
348     silc_server_packet_send(server, query->cmd->sock,
349                             SILC_PACKET_COMMAND_REPLY, 0,
350                             buffer->data, silc_buffer_len(buffer));
351     silc_buffer_free(buffer);
352     silc_server_query_free(query);
353     return;
354   }
355
356   /* Continue with parsing */
357   silc_server_query_parse(server, query);
358 }
359
360 /* Parse the command query and start processing the queries in detail. */
361
362 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
363 {
364   SilcServerCommandContext cmd = query->cmd;
365   SilcIDListData idata = silc_packet_get_context(cmd->sock);
366   unsigned char *tmp;
367   SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
368   SilcID id;
369   int i;
370
371   SILC_LOG_DEBUG(("Parsing %s query",
372                   silc_get_command_name(query->querycmd)));
373
374   switch (query->querycmd) {
375
376   case SILC_COMMAND_WHOIS:
377     /* Get requested attributes if set */
378     tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
379     if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
380       query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
381
382       /* When Requested Attributes is present we will assure that this
383          client cannot execute the WHOIS command too fast.  This would be
384          same as having SILC_CF_LAG_STRICT. */
385       if (idata && idata->conn_type == SILC_CONN_CLIENT)
386         ((SilcClientEntry)idata)->fast_command = 6;
387     }
388
389     /* Get Client IDs if present. Take IDs always instead of nickname. */
390     tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
391     if (!tmp) {
392
393       /* Get nickname */
394       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
395       if (!tmp && !query->attrs) {
396         /* No nickname, no ids and no attributes - send error */
397         silc_server_query_send_error(server, query,
398                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
399         silc_server_query_free(query);
400         return;
401       }
402
403       /* Get the nickname@server string and parse it */
404       if (tmp && ((tmp_len > 128) ||
405                   !silc_parse_userfqdn(tmp, query->nickname,
406                                        sizeof(query->nickname),
407                                        query->nick_server,
408                                        sizeof(query->nick_server)))) {
409         silc_server_query_send_error(server, query,
410                                      SILC_STATUS_ERR_BAD_NICKNAME, 0);
411         silc_server_query_free(query);
412         return;
413       }
414
415       /* Check nickname */
416       if (tmp) {
417         tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
418                                     SILC_STRING_UTF8, 128, &tmp_len);
419         if (!tmp) {
420           silc_server_query_send_error(server, query,
421                                        SILC_STATUS_ERR_BAD_NICKNAME, 0);
422           silc_server_query_free(query);
423           return;
424         }
425         memset(query->nickname, 0, sizeof(query->nickname));
426         silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
427         silc_free(tmp);
428       }
429
430     } else {
431       /* Parse the IDs included in the query */
432       query->ids = silc_calloc(argc, sizeof(*query->ids));
433
434       for (i = 0; i < argc; i++) {
435         tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
436         if (!tmp)
437           continue;
438
439         if (!silc_id_payload_parse_id(tmp, tmp_len, &id) ||
440             id.type != SILC_ID_CLIENT) {
441           silc_server_query_add_error(server, query, 1, i + 4,
442                                       SILC_STATUS_ERR_BAD_CLIENT_ID);
443           continue;
444         }
445
446         /* Normal server must check whether this ID exist, and if not then
447            send the query to router, unless done so already */
448         if (server->server_type == SILC_SERVER && !query->resolved) {
449           if (!silc_idlist_find_client_by_id(server->local_list,
450                                              &id.u.client_id, TRUE, NULL)) {
451             if (idata->conn_type != SILC_CONN_CLIENT ||
452                 !silc_idlist_find_client_by_id(server->global_list,
453                                                &id.u.client_id, TRUE, NULL)) {
454               silc_server_query_send_router(server, query);
455               for (i = 0; i < query->ids_count; i++)
456                 silc_free(query->ids[i].id);
457               silc_free(query->ids);
458               query->ids = NULL;
459               query->ids_count = 0;
460               return;
461             }
462           }
463         }
464
465         query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
466                                                       SILC_ID_CLIENT);
467         query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
468         query->ids_count++;
469       }
470     }
471
472     /* Get the max count of reply messages allowed */
473     tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
474     if (tmp && tmp_len == sizeof(SilcUInt32))
475       SILC_GET32_MSB(query->reply_count, tmp);
476    break;
477
478   case SILC_COMMAND_WHOWAS:
479     /* Get nickname */
480     tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
481     if (!tmp) {
482       silc_server_query_send_error(server, query,
483                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
484       silc_server_query_free(query);
485       return;
486     }
487
488     /* Get the nickname@server string and parse it */
489     if (tmp_len > 128 ||
490         !silc_parse_userfqdn(tmp, query->nickname, sizeof(query->nickname),
491                              query->nick_server, sizeof(query->nick_server))) {
492       silc_server_query_send_error(server, query,
493                                    SILC_STATUS_ERR_BAD_NICKNAME, 0);
494       silc_server_query_free(query);
495       return;
496     }
497
498     /* Check nickname */
499     tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
500                                 SILC_STRING_UTF8, 128, &tmp_len);
501     if (!tmp) {
502       silc_server_query_send_error(server, query,
503                                    SILC_STATUS_ERR_BAD_NICKNAME, 0);
504       silc_server_query_free(query);
505       return;
506     }
507     memset(query->nickname, 0, sizeof(query->nickname));
508     silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
509     silc_free(tmp);
510
511     /* Get the max count of reply messages allowed */
512     tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
513     if (tmp && tmp_len == sizeof(SilcUInt32))
514       SILC_GET32_MSB(query->reply_count, tmp);
515     break;
516
517   case SILC_COMMAND_IDENTIFY:
518     /* Get IDs if present. Take IDs always instead of names. */
519     tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
520     if (!tmp) {
521
522       /* Try get nickname */
523       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
524       if (tmp) {
525         /* Get the nickname@server string and parse it */
526         if (tmp_len > 128 ||
527             !silc_parse_userfqdn(tmp, query->nickname,
528                                  sizeof(query->nickname),
529                                  query->nick_server,
530                                  sizeof(query->nick_server)))
531           silc_server_query_add_error(server, query, 1, 1,
532                                       SILC_STATUS_ERR_BAD_NICKNAME);
533
534         /* Check nickname */
535         tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
536                                     SILC_STRING_UTF8, 128, &tmp_len);
537         if (!tmp) {
538           silc_server_query_send_error(server, query,
539                                        SILC_STATUS_ERR_BAD_NICKNAME, 0);
540           silc_server_query_free(query);
541           return;
542         }
543         memset(query->nickname, 0, sizeof(query->nickname));
544         silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
545         silc_free(tmp);
546       }
547
548       /* Try get server name */
549       tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
550       if (tmp) {
551         /* Check server name */
552         tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
553                                     256, &tmp_len);
554         if (!tmp) {
555           silc_server_query_send_error(server, query,
556                                        SILC_STATUS_ERR_BAD_SERVER, 0);
557           silc_server_query_free(query);
558           return;
559         }
560         query->server_name = tmp;
561       }
562
563       /* Get channel name */
564       tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
565       if (tmp && tmp_len <= 256) {
566         /* Check channel name */
567         tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
568                                     256, &tmp_len);
569         if (!tmp) {
570           silc_server_query_send_error(server, query,
571                                        SILC_STATUS_ERR_BAD_CHANNEL, 0);
572           silc_server_query_free(query);
573           return;
574         }
575         query->channel_name = tmp;
576       }
577
578       if (!query->nickname[0] && !query->server_name && !query->channel_name) {
579         silc_server_query_send_error(server, query,
580                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
581         silc_server_query_free(query);
582         return;
583       }
584
585     } else {
586       /* Parse the IDs included in the query */
587       query->ids = silc_calloc(argc, sizeof(*query->ids));
588
589       for (i = 0; i < argc; i++) {
590         tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
591         if (!tmp)
592           continue;
593
594         if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
595           silc_server_query_add_error(server, query, 1, i + 5,
596                                       SILC_STATUS_ERR_BAD_CLIENT_ID);
597           continue;
598         }
599
600         /* Normal server must check whether this ID exist, and if not then
601            send the query to router, unless done so already */
602         if (server->server_type == SILC_SERVER && !query->resolved) {
603           if (id.type == SILC_ID_CLIENT) {
604             if (!silc_idlist_find_client_by_id(server->local_list,
605                                                &id.u.client_id, TRUE, NULL)) {
606               if (idata->conn_type != SILC_CONN_CLIENT ||
607                   !silc_idlist_find_client_by_id(server->global_list,
608                                                  &id.u.client_id, TRUE,
609                                                  NULL)) {
610                 silc_server_query_send_router(server, query);
611                 for (i = 0; i < query->ids_count; i++)
612                   silc_free(query->ids[i].id);
613                 silc_free(query->ids);
614                 query->ids = NULL;
615                 query->ids_count = 0;
616                 return;
617               }
618             }
619           } else {
620             /* For now all other ID's except Client ID's are explicitly
621                sent to router for resolving. */
622             silc_server_query_send_router(server, query);
623             for (i = 0; i < query->ids_count; i++)
624               silc_free(query->ids[i].id);
625             silc_free(query->ids);
626             query->ids = NULL;
627             query->ids_count = 0;
628             return;
629           }
630         }
631
632         if (id.type == SILC_ID_CLIENT)
633           query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
634                                                         SILC_ID_CLIENT);
635         if (id.type == SILC_ID_SERVER)
636           query->ids[query->ids_count].id = silc_id_dup(&id.u.server_id,
637                                                         SILC_ID_SERVER);
638         if (id.type == SILC_ID_CHANNEL)
639           query->ids[query->ids_count].id = silc_id_dup(&id.u.channel_id,
640                                                         SILC_ID_CHANNEL);
641         query->ids[query->ids_count].id_type = id.type;
642         query->ids_count++;
643       }
644     }
645
646     /* Get the max count of reply messages allowed */
647     tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
648     if (tmp && tmp_len == sizeof(SilcUInt32))
649       SILC_GET32_MSB(query->reply_count, tmp);
650     break;
651   }
652
653   /* Start processing the query information */
654   silc_server_query_process(server, query, TRUE);
655 }
656
657 /* Context for holding clients searched by public key. */
658 typedef struct {
659   SilcClientEntry **clients;
660   SilcUInt32 *clients_count;
661   SilcBool found;
662 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
663
664 /* SKR find callbcak */
665
666 static void silc_server_query_skr_callback(SilcSKR skr,
667                                            SilcSKRFind find,
668                                            SilcSKRStatus status,
669                                            SilcDList keys,
670                                            void *context)
671 {
672   SilcServerPublicKeyUser uc = context;
673   SilcSKRKey key;
674
675   if (keys) {
676     (*uc->clients) = silc_realloc((*uc->clients),
677                                   sizeof((**uc->clients)) *
678                                   ((*uc->clients_count) +
679                                    silc_dlist_count(keys)));
680
681     silc_dlist_start(keys);
682     while ((key = silc_dlist_get(keys)))
683       (*uc->clients)[(*uc->clients_count)++] = key->key_context;
684
685     uc->found = TRUE;
686     silc_dlist_uninit(keys);
687   }
688
689   silc_skr_find_free(find);
690 }
691
692 /* If clients are set, limit the found clients using the attributes in
693    the query. If clients are not set, try to find some clients using
694    the attributes */
695
696 void silc_server_query_check_attributes(SilcServer server,
697                                         SilcServerQuery query,
698                                         SilcClientEntry **clients,
699                                         SilcUInt32 *clients_count) {
700   SilcClientEntry entry;
701   SilcAttributePayload attr;
702   SilcAttribute attribute;
703   SilcAttributeObjPk pk;
704   SilcPublicKey publickey, cmp_pubkey;
705   SilcPKCSType type;
706   SilcBool found = FALSE, no_clients = FALSE;
707   int i;
708
709   /* If no clients were found, we only check the attributes
710      if the user wasn't searching for nickname/ids */
711   if (!(*clients)) {
712     no_clients = TRUE;
713     if (query->nickname[0] || query->ids_count)
714       return;
715   }
716
717   silc_dlist_start(query->attrs);
718   while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
719     attribute = silc_attribute_get_attribute(attr);
720     switch (attribute) {
721
722       case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
723         SILC_LOG_DEBUG(("Finding clients by public key attribute"));
724
725         if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
726           continue;
727
728         if (!strcmp(pk.type, "silc-rsa"))
729           type = SILC_PKCS_SILC;
730         else if (!strcmp(pk.type, "ssh-rsa"))
731           type = SILC_PKCS_SSH2;
732         else if (!strcmp(pk.type, "x509v3-sign-rsa"))
733           type = SILC_PKCS_X509V3;
734         else if (!strcmp(pk.type, "pgp-sign-rsa"))
735           type = SILC_PKCS_OPENPGP;
736         else
737           continue;
738
739         if (!silc_pkcs_public_key_alloc(type, pk.data, pk.data_len,
740                                         &publickey)) {
741           silc_free(pk.type);
742           silc_free(pk.data);
743           continue;
744         }
745
746         /* If no clients were set on calling this function, we just search
747            for clients, otherwise we try to limit the clients. */
748         if (no_clients) {
749           SilcServerPublicKeyUserStruct usercontext;
750           SilcSKRFind find;
751
752           usercontext.clients = clients;
753           usercontext.clients_count = clients_count;
754           usercontext.found = FALSE;
755
756           find = silc_skr_find_alloc();
757           if (!find)
758             continue;
759
760           silc_skr_find_set_public_key(find, publickey);
761           silc_skr_find_set_usage(find, SILC_SKR_USAGE_IDENTIFICATION);
762           silc_skr_find(server->repository, server->schedule,
763                         find, silc_server_query_skr_callback, &usercontext);
764
765           if (usercontext.found == TRUE)
766             found = TRUE;
767         } else {
768           for (i = 0; i < *clients_count; i++) {
769             entry = (*clients)[i];
770
771             if (!entry->data.public_key)
772               continue;
773
774             if (silc_server_get_public_key_by_client(server, entry,
775                                                      &cmp_pubkey)) {
776               if (silc_pkcs_public_key_compare(cmp_pubkey, publickey)) {
777                 found = TRUE;
778                 continue;
779               }
780             }
781
782             (*clients)[i] = NULL;
783           }
784         }
785         silc_free(pk.type);
786         silc_free(pk.data);
787         silc_pkcs_public_key_free(publickey);
788         break;
789     }
790   }
791
792   if (!found && !query->nickname[0] && !query->ids)
793     silc_server_query_add_error(server, query, 2, 0,
794                                 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
795 }
796
797 /* Processes the parsed query.  This does the actual finding of the
798    queried information and prepares for sending reply to the original
799    sender of the query command. */
800
801 void silc_server_query_process(SilcServer server, SilcServerQuery query,
802                                SilcBool resolve)
803 {
804   SilcServerCommandContext cmd = query->cmd;
805   SilcIDListData idata = silc_packet_get_context(cmd->sock);
806   SilcBool check_global = FALSE;
807   void *entry;
808   SilcClientEntry *clients = NULL, client_entry;
809   SilcChannelEntry *channels = NULL;
810   SilcServerEntry *servers = NULL;
811   SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
812   int i;
813
814   SILC_LOG_DEBUG(("Processing %s query",
815                   silc_get_command_name(query->querycmd)));
816
817   /* Check global lists if query is coming from client or we are not
818      normal server (we know global information). */
819   if (idata->conn_type == SILC_CONN_CLIENT)
820     check_global = TRUE;
821   else if (server->server_type != SILC_SERVER)
822     check_global = TRUE;
823
824   if (query->nickname[0]) {
825     /* Get all clients matching nickname from local list */
826     if (!silc_idlist_get_clients_by_hash(server->local_list,
827                                          query->nickname, server->md5hash,
828                                          &clients, &clients_count))
829       silc_idlist_get_clients_by_nickname(server->local_list,
830                                           query->nickname,
831                                           query->nick_server,
832                                          /* XXX nick_server may not be set */
833                                           &clients, &clients_count);
834
835     /* Check global list as well */
836     if (check_global) {
837       if (!silc_idlist_get_clients_by_hash(server->global_list,
838                                            query->nickname, server->md5hash,
839                                            &clients, &clients_count))
840         silc_idlist_get_clients_by_nickname(server->global_list,
841                                             query->nickname,
842                                             query->nick_server,
843                                          /* XXX nick_server may not be set */
844                                             &clients, &clients_count);
845     }
846
847     if (!clients)
848       silc_server_query_add_error(server, query, 1, 1,
849                                   SILC_STATUS_ERR_NO_SUCH_NICK);
850   }
851
852   if (query->server_name) {
853     /* Find server by name */
854     entry = silc_idlist_find_server_by_name(server->local_list,
855                                             query->server_name, TRUE, NULL);
856     if (!entry && check_global)
857       entry = silc_idlist_find_server_by_name(server->global_list,
858                                               query->server_name, TRUE, NULL);
859     if (entry) {
860       servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
861       servers[servers_count++] = (SilcServerEntry)entry;
862     }
863
864     if (!servers)
865       silc_server_query_add_error(server, query, 1, 2,
866                                   SILC_STATUS_ERR_NO_SUCH_SERVER);
867   }
868
869   if (query->channel_name) {
870     /* Find channel by name */
871     entry = silc_idlist_find_channel_by_name(server->local_list,
872                                              query->channel_name, NULL);
873     if (!entry && check_global)
874       entry = silc_idlist_find_channel_by_name(server->global_list,
875                                                query->channel_name, NULL);
876     if (entry) {
877       channels = silc_realloc(channels, sizeof(*channels) *
878                               (channels_count + 1));
879       channels[channels_count++] = (SilcChannelEntry)entry;
880     }
881
882     if (!channels)
883       silc_server_query_add_error(server, query, 1, 3,
884                                   SILC_STATUS_ERR_NO_SUCH_CHANNEL);
885   }
886
887   if (query->ids_count) {
888     /* Find entries by the queried IDs */
889     for (i = 0; i < query->ids_count; i++) {
890       void *id = query->ids[i].id;
891       if (!id)
892         continue;
893
894       switch (query->ids[i].id_type) {
895
896       case SILC_ID_CLIENT:
897         /* Get client entry */
898         entry = silc_idlist_find_client_by_id(server->local_list,
899                                               id, TRUE, NULL);
900         if (!entry && check_global)
901           entry = silc_idlist_find_client_by_id(server->global_list,
902                                                 id, TRUE, NULL);
903         if (!entry) {
904           silc_server_query_add_error(server, query, 0, i,
905                                       SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
906           continue;
907         }
908
909         clients = silc_realloc(clients, sizeof(*clients) *
910                                (clients_count + 1));
911         clients[clients_count++] = (SilcClientEntry)entry;
912         break;
913
914       case SILC_ID_SERVER:
915         /* Get server entry */
916         entry = silc_idlist_find_server_by_id(server->local_list,
917                                               id, TRUE, NULL);
918         if (!entry && check_global)
919           entry = silc_idlist_find_server_by_id(server->global_list,
920                                                 id, TRUE, NULL);
921         if (!entry) {
922           silc_server_query_add_error(server, query, 0, i,
923                                       SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
924           continue;
925         }
926
927         servers = silc_realloc(servers, sizeof(*servers) *
928                                (servers_count + 1));
929         servers[servers_count++] = (SilcServerEntry)entry;
930         break;
931
932       case SILC_ID_CHANNEL:
933         /* Get channel entry */
934         entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
935         if (!entry && check_global)
936           entry = silc_idlist_find_channel_by_id(server->global_list, id,
937                                                  NULL);
938         if (!entry) {
939           silc_server_query_add_error(server, query, 0, i,
940                                       SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
941           continue;
942         }
943
944         channels = silc_realloc(channels, sizeof(*channels) *
945                                 (channels_count + 1));
946         channels[channels_count++] = (SilcChannelEntry)entry;
947         break;
948
949       default:
950         break;
951       }
952     }
953   }
954
955   /* Check the attributes to narrow down the search by using them. */
956   if (query->attrs)
957     silc_server_query_check_attributes(server, query, &clients,
958                                        &clients_count);
959
960   SILC_LOG_DEBUG(("Querying %d clients", clients_count));
961   SILC_LOG_DEBUG(("Querying %d servers", servers_count));
962   SILC_LOG_DEBUG(("Querying %d channels", channels_count));
963
964   /* If nothing was found, then just send the errors */
965   if (!clients && !channels && !servers) {
966     silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
967     return;
968   }
969
970   /* If caller does not want us to resolve anything (has resolved already)
971      then just continue with sending the reply */
972   if (!resolve) {
973     silc_server_query_send_reply(server, query, clients, clients_count,
974                                  servers, servers_count, channels,
975                                  channels_count);
976     silc_free(clients);
977     silc_free(servers);
978     silc_free(channels);
979     return;
980   }
981
982   /* Now process all found information and if necessary do some more
983      resolving. */
984   switch (query->querycmd) {
985
986   case SILC_COMMAND_WHOIS:
987     for (i = 0; i < clients_count; i++) {
988       client_entry = clients[i];
989
990       /* Check if cannot query this anyway, so take next one */
991       if (!client_entry ||
992           !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
993         continue;
994
995       /* If Requested Attributes is set then we always resolve the client
996          information, if not then check whether the entry is complete or not
997          and decide whether we need to resolve or not. */
998       if (!query->attrs) {
999
1000         /* Even if nickname and stuff are present, we may need to resolve
1001            the entry */
1002         if (client_entry->nickname && client_entry->username &&
1003             client_entry->userinfo) {
1004           /* Check if cannot query this anyway, so take next one */
1005           if (!client_entry->router)
1006             continue;
1007
1008           /* If we are router, client is local to us, or client is on channel
1009              we do not need to resolve the client information. */
1010           if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1011               || silc_hash_table_count(client_entry->channels) ||
1012               query->resolved)
1013             continue;
1014         }
1015       }
1016
1017       /* Remove the NOATTR status periodically */
1018       if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
1019           client_entry->updated + 600 < time(NULL))
1020         client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
1021
1022       /* When requested attributes is present and local client is detached
1023          we cannot send the command to the client, we'll reply on behalf of
1024          the client instead. */
1025       if (query->attrs && SILC_IS_LOCAL(client_entry) &&
1026           (client_entry->mode & SILC_UMODE_DETACHED ||
1027            client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
1028         continue;
1029
1030       /* If attributes are present in query, and in the entry and we have
1031          done resolvings already we don't need to resolve anymore */
1032       if (query->resolved && query->attrs && client_entry->attrs)
1033         continue;
1034
1035       /* Resolve the detailed client information. If client is local we
1036          know that attributes were present and we will resolve directly
1037          from the client. Otherwise resolve from client's owner. */
1038       silc_server_query_resolve(server, query,
1039                                 (SILC_IS_LOCAL(client_entry) ?
1040                                  client_entry->connection :
1041                                  client_entry->router->connection),
1042                                 client_entry);
1043     }
1044     break;
1045
1046   case SILC_COMMAND_WHOWAS:
1047     for (i = 0; i < clients_count; i++) {
1048       client_entry = clients[i];
1049
1050       /* Check if cannot query this anyway, so take next one */
1051       if (!client_entry || !client_entry->router ||
1052           client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1053         continue;
1054
1055       /* If both nickname and username are present no resolving is needed */
1056       if (client_entry->nickname && client_entry->username)
1057         continue;
1058
1059       /* Resolve the detailed client information */
1060       silc_server_query_resolve(server, query,
1061                                 client_entry->router->connection,
1062                                 client_entry);
1063     }
1064     break;
1065
1066   case SILC_COMMAND_IDENTIFY:
1067     for (i = 0; i < clients_count; i++) {
1068       client_entry = clients[i];
1069
1070       /* Check if cannot query this anyway, so take next one */
1071       if (!client_entry || !client_entry->router ||
1072           !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1073         continue;
1074
1075       /* Even if nickname is present, we may need to resolve the entry */
1076       if (client_entry->nickname) {
1077
1078         /* If we are router, client is local to us, or client is on channel
1079            we do not need to resolve the client information. */
1080         if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1081             || silc_hash_table_count(client_entry->channels) ||
1082             query->resolved)
1083           continue;
1084       }
1085
1086       /* Resolve the detailed client information */
1087       silc_server_query_resolve(server, query,
1088                                 client_entry->router->connection,
1089                                 client_entry);
1090     }
1091     break;
1092   }
1093
1094   if (!query->queries_count)
1095     /* If we didn't have to do any resolving, continue with sending the
1096        command reply to the original sender. */
1097     silc_server_query_send_reply(server, query, clients, clients_count,
1098                                  servers, servers_count, channels,
1099                                  channels_count);
1100   else
1101     /* Now actually send the resolvings we gathered earlier */
1102     silc_server_query_resolve(server, query, NULL, NULL);
1103
1104   silc_free(clients);
1105   silc_free(servers);
1106   silc_free(channels);
1107 }
1108
1109 /* Resolve the detailed information for the `client_entry'.  Only client
1110    information needs to be resolved for being incomplete.  Each incomplete
1111    client entry calls this function to do the resolving. */
1112
1113 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1114                                SilcPacketStream sock,
1115                                SilcClientEntry client_entry)
1116 {
1117   SilcServerCommandContext cmd = query->cmd;
1118   SilcServerQueryList r = NULL;
1119   SilcBuffer idp;
1120   unsigned char *tmp;
1121   SilcUInt32 len;
1122   SilcUInt16 ident;
1123   int i;
1124
1125   if (!sock && client_entry)
1126     return;
1127
1128   /* If arguments are NULL we will now actually send the resolvings
1129      that earlier has been gathered by calling this function. */
1130   if (!sock && !client_entry) {
1131     SilcBuffer res_cmd;
1132
1133     SILC_LOG_DEBUG(("Sending the resolvings"));
1134
1135     /* WHOWAS resolving has been done at the same time this function
1136        was called to add the resolving for WHOWAS, so just return. */
1137     if (query->querycmd == SILC_COMMAND_WHOWAS)
1138       return;
1139
1140     for (i = 0; i < query->querylist_count; i++) {
1141       r = &query->querylist[i];
1142
1143       /* If Requested Attributes were present put them to this resolving */
1144       if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1145         len = r->argc + 1;
1146         r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1147         r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1148         r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1149
1150         tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1151         if (tmp)
1152           r->arg[r->argc] = silc_memdup(tmp, len);
1153         r->arg_lens[r->argc] = len;
1154         r->arg_types[r->argc] = 3;
1155         r->argc++;
1156       }
1157
1158       /* Statistics */
1159       server->stat.commands_sent++;
1160
1161       /* Send WHOIS command */
1162       res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1163                                             r->argc, r->arg, r->arg_lens,
1164                                             r->arg_types, r->ident);
1165       silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1166                               res_cmd->data, silc_buffer_len(res_cmd));
1167       silc_buffer_free(res_cmd);
1168
1169       /* Reprocess this packet after received reply */
1170       if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1171                                             r->ident,
1172                                             silc_server_query_resolve_reply,
1173                                             query, r->timeout))
1174         query->queries_left++;
1175     }
1176
1177     /* Cleanup this temporary context */
1178     for (i = 0; i < query->querylist_count; i++) {
1179       int k;
1180       for (k = 0; k < query->querylist[i].argc; k++)
1181         silc_free(query->querylist[i].arg[k]);
1182       silc_free(query->querylist[i].arg);
1183       silc_free(query->querylist[i].arg_lens);
1184       silc_free(query->querylist[i].arg_types);
1185     }
1186     silc_free(query->querylist);
1187     query->querylist = NULL;
1188     query->querylist_count = 0;
1189     return;
1190   }
1191
1192   SILC_LOG_DEBUG(("Resolving client information"));
1193
1194   if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1195     /* The entry is being resolved by some other external query already.
1196        Attach to that query instead of resolving again. */
1197     ident = client_entry->resolve_cmd_ident;
1198     if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1199                                     silc_server_query_resolve_reply, query))
1200       query->queries_left++;
1201   } else {
1202     /* This entry will be resolved */
1203     ident = ++server->cmd_ident;
1204
1205     switch (query->querycmd) {
1206
1207     case SILC_COMMAND_WHOIS:
1208     case SILC_COMMAND_IDENTIFY:
1209       /* Take existing query context if exist for this connection */
1210       for (i = 0; i < query->querylist_count; i++)
1211         if (query->querylist[i].sock == sock) {
1212           r = &query->querylist[i];
1213           break;
1214         }
1215
1216       if (!r) {
1217         /* Allocate new temp query list context */
1218         query->querylist = silc_realloc(query->querylist,
1219                                         sizeof(*query->querylist) *
1220                                         (query->querylist_count + 1));
1221         r = &query->querylist[query->querylist_count];
1222         query->querylist_count++;
1223         memset(r, 0, sizeof(*r));
1224         r->sock = sock;
1225         r->ident = ident;
1226         if (SILC_IS_LOCAL(client_entry))
1227           r->timeout = 3;
1228       }
1229
1230       len = r->argc + 1;
1231       r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1232       r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1233       r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1234
1235       /* Add the client entry to be resolved */
1236       idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1237       r->arg[r->argc] = silc_memdup(idp->data, silc_buffer_len(idp));
1238       r->arg_lens[r->argc] = silc_buffer_len(idp);
1239       r->arg_types[r->argc] = r->argc + 4;
1240       r->argc++;
1241       silc_buffer_free(idp);
1242
1243       break;
1244
1245     case SILC_COMMAND_WHOWAS:
1246       /* We must send WHOWAS command since it's the only the way of
1247          resolving clients that are not present in the network anymore. */
1248       silc_server_send_command(server, sock, query->querycmd, ident, 1,
1249                                1, query->nickname, strlen(query->nickname));
1250       if (silc_server_command_pending(server, query->querycmd, ident,
1251                                       silc_server_query_resolve_reply, query))
1252         query->queries_left++;
1253       break;
1254     }
1255   }
1256
1257   /* Mark the entry as being resolved */
1258   client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1259   client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1260   client_entry->resolve_cmd_ident = ident;
1261   client_entry->updated = time(NULL);
1262
1263   /* Save the queried ID, which we will reprocess after we get this and
1264      all other queries back. */
1265   query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1266                                 (query->queries_count + 1));
1267   if (query->queries) {
1268     i = query->queries_count;
1269     query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1270     query->queries[i].id_type = SILC_ID_CLIENT;
1271     query->queries[i].ident = ident;
1272     query->queries_count++;
1273   }
1274 }
1275
1276 /* Reply callback called after one resolving has been completed.  If
1277    all resolvings has been received then we will continue with sending
1278    the command reply to the original sender of the query. */
1279
1280 void silc_server_query_resolve_reply(void *context, void *reply)
1281 {
1282   SilcServerQuery query = context;
1283   SilcServer server = query->cmd->server;
1284   SilcServerCommandReplyContext cmdr = reply;
1285   SilcUInt16 ident = cmdr->ident;
1286   SilcStatus error = SILC_STATUS_OK;
1287   SilcServerQueryID id = NULL;
1288   SilcClientEntry client_entry;
1289   int i;
1290
1291   /* One less query left */
1292   query->queries_left--;
1293
1294   silc_command_get_status(cmdr->payload, NULL, &error);
1295   SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1296                   query->queries_left, error));
1297
1298   /* If no error then skip to other stuff */
1299   if (error == SILC_STATUS_OK)
1300     goto out;
1301
1302   /* Error occurred during resolving */
1303
1304   /* Find the resolved client ID */
1305   for (i = 0; i < query->queries_count; i++) {
1306     if (query->queries[i].ident != ident)
1307       continue;
1308
1309     id = &query->queries[i];
1310
1311     if (error == SILC_STATUS_ERR_TIMEDOUT) {
1312
1313       /* If timeout occurred for local entry when resolving attributes
1314          mark that this client doesn't support attributes in WHOIS. This
1315          assures we won't send the request again to the client. */
1316       if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1317         client_entry = silc_idlist_find_client_by_id(server->local_list,
1318                                                      id->id, TRUE, NULL);
1319         SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1320                         silc_id_render(id->id, SILC_ID_CLIENT)));
1321         if (client_entry && SILC_IS_LOCAL(client_entry)) {
1322           client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1323           client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1324           continue;
1325         }
1326       }
1327
1328       /* Remove the RESOLVING status from the client entry */
1329       if (query->querycmd != SILC_COMMAND_WHOWAS) {
1330         client_entry = silc_idlist_find_client_by_id(server->local_list,
1331                                                      id->id, TRUE, NULL);
1332         if (!client_entry)
1333           client_entry = silc_idlist_find_client_by_id(server->global_list,
1334                                                        id->id, TRUE, NULL);
1335         if (client_entry)
1336           client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1337       }
1338     }
1339   }
1340
1341  out:
1342
1343   /* If there are queries left then wait for them */
1344   if (query->queries_left)
1345     return;
1346
1347   SILC_LOG_DEBUG(("Reprocess the query"));
1348
1349   /* If the original command caller has gone away, just stop. */
1350   if (!silc_packet_stream_is_valid(query->cmd->sock)) {
1351     SILC_LOG_DEBUG(("Original command caller vanished"));
1352     silc_server_query_free(query);
1353     return;
1354   }
1355
1356   /* We have received all queries.  Now re-search all information required
1357      to complete this query.  Reason we cannot save the values found in
1358      the first search is that SilcClientEntry, SilcServerEntry and
1359      SilcChannelEntry pointers may become invalid while we were waiting
1360      for these resolvings. */
1361   silc_server_query_process(server, query, FALSE);
1362 }
1363
1364 /* Send the reply to the original query.  If arguments are NULL then this
1365    sends only the errors that has occurred during the processing of the
1366    query.  This sends the errors always after sending all the found
1367    information.  The query is over after this function returns and the
1368    `query' will become invalid.  This is called only after all informations
1369    has been resolved.  This means that if something is not found or is
1370    incomplete in this function we were unable to resolve the information
1371    or it does not exist at all. */
1372
1373 void silc_server_query_send_reply(SilcServer server,
1374                                   SilcServerQuery query,
1375                                   SilcClientEntry *clients,
1376                                   SilcUInt32 clients_count,
1377                                   SilcServerEntry *servers,
1378                                   SilcUInt32 servers_count,
1379                                   SilcChannelEntry *channels,
1380                                   SilcUInt32 channels_count)
1381 {
1382   SilcServerCommandContext cmd = query->cmd;
1383   SilcIDListData idata = silc_packet_get_context(cmd->sock);
1384   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1385   SilcStatus status;
1386   unsigned char *tmp;
1387   SilcUInt32 len;
1388   SilcBuffer idp;
1389   int i, k, valid_count;
1390   char nh[384], uh[384];
1391   SilcBool sent_reply = FALSE;
1392
1393   SILC_LOG_DEBUG(("Sending reply to query"));
1394   SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1395   SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1396   SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1397   SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1398
1399   status = SILC_STATUS_OK;
1400
1401   /* Send clients */
1402   if (clients_count) {
1403     SilcClientEntry entry;
1404     SilcPacketStream hsock;
1405
1406     /* Mark all invalid entries */
1407     for (i = 0, valid_count = 0; i < clients_count; i++) {
1408       entry = clients[i];
1409       if (!entry)
1410         continue;
1411
1412       switch (query->querycmd) {
1413       case SILC_COMMAND_WHOIS:
1414         if (!entry->nickname || !entry->username || !entry->userinfo ||
1415             !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1416           /* When querying by ID, every "unfound" entry must cause error */
1417           if (query->ids)
1418             silc_server_query_add_error_id(server, query,
1419                                            SILC_STATUS_ERR_TIMEDOUT,
1420                                            entry->id, SILC_ID_CLIENT);
1421           clients[i] = NULL;
1422           continue;
1423         }
1424         break;
1425
1426       case SILC_COMMAND_IDENTIFY:
1427         if (!entry->nickname ||
1428             !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1429           /* When querying by ID, every "unfound" entry must cause error */
1430           if (query->ids)
1431             silc_server_query_add_error_id(server, query,
1432                                            SILC_STATUS_ERR_TIMEDOUT,
1433                                            entry->id, SILC_ID_CLIENT);
1434           clients[i] = NULL;
1435           continue;
1436         }
1437         break;
1438
1439       case SILC_COMMAND_WHOWAS:
1440         if (!entry->nickname || !entry->username ||
1441             entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1442           clients[i] = NULL;
1443           continue;
1444         }
1445         break;
1446       }
1447       valid_count++;
1448     }
1449
1450     /* Start processing found clients */
1451     status = SILC_STATUS_OK;
1452     if (valid_count > 1)
1453       status = SILC_STATUS_LIST_START;
1454
1455     /* Now do the sending of valid entries */
1456     k = 0;
1457     for (i = 0; i < clients_count && valid_count; i++) {
1458       entry = clients[i];
1459       if (!entry)
1460         continue;
1461
1462       if (k >= 1)
1463         status = SILC_STATUS_LIST_ITEM;
1464       if (valid_count > 1 && k == valid_count - 1
1465           && !servers_count && !channels_count && !query->errors_count)
1466         status = SILC_STATUS_LIST_END;
1467       if (query->reply_count && k - 1 == query->reply_count)
1468         status = SILC_STATUS_LIST_END;
1469
1470       SILC_LOG_DEBUG(("%s: client %s",
1471                       (status == SILC_STATUS_OK ?         "   OK" :
1472                        status == SILC_STATUS_LIST_START ? "START" :
1473                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1474                        status == SILC_STATUS_LIST_END  ?  "  END" :
1475                        "      : "), entry->nickname));
1476
1477       idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1478       memset(nh, 0, sizeof(nh));
1479
1480       silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1481       if (!strchr(entry->nickname, '@')) {
1482         silc_strncat(nh, sizeof(nh), "@", 1);
1483         if (entry->servername) {
1484           silc_strncat(nh, sizeof(nh), entry->servername,
1485                        strlen(entry->servername));
1486         } else {
1487           len = entry->router ? strlen(entry->router->server_name) :
1488             strlen(server->server_name);
1489           silc_strncat(nh, sizeof(nh), entry->router ?
1490                        entry->router->server_name :
1491                        server->server_name, len);
1492         }
1493       }
1494
1495       switch (query->querycmd) {
1496
1497       case SILC_COMMAND_WHOIS:
1498         {
1499           unsigned char idle[4], mode[4];
1500           unsigned char *fingerprint, fempty[20], *attrs = NULL;
1501           SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1502
1503           memset(fempty, 0, sizeof(fempty));
1504           memset(idle, 0, sizeof(idle));
1505           memset(uh, 0, sizeof(uh));
1506
1507           silc_strncat(uh, sizeof(uh), entry->username,
1508                        strlen(entry->username));
1509           if (!strchr(entry->username, '@') && entry->connection) {
1510             hsock = entry->connection;
1511             silc_strncat(uh, sizeof(uh), "@", 1);
1512             silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1513                                         NULL, (const char **)&tmp, NULL, NULL);
1514             silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1515           }
1516
1517           if (idata->conn_type == SILC_CONN_CLIENT)
1518             channels =
1519               silc_server_get_client_channel_list(server, entry, FALSE,
1520                                                   FALSE, &umode_list);
1521           else
1522             channels =
1523               silc_server_get_client_channel_list(server, entry, TRUE,
1524                                                   TRUE, &umode_list);
1525
1526           if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1527             fingerprint = entry->data.fingerprint;
1528           else
1529             fingerprint = NULL;
1530
1531           SILC_PUT32_MSB(entry->mode, mode);
1532           if (entry->connection)
1533             SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1534
1535           /* If Requested Attribute were present, and we do not have the
1536              attributes we will reply to them on behalf of the client. */
1537           len = 0;
1538           if (query->attrs) {
1539             if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1540               tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1541               entry->attrs = silc_buffer_steal(tmpattrs, &len);
1542               entry->attrs_len = len;
1543               silc_buffer_free(tmpattrs);
1544             }
1545             attrs = entry->attrs;
1546             len = entry->attrs_len;
1547           }
1548
1549           /* Send command reply */
1550           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1551                                          status, 0, ident, 10,
1552                                          2, idp->data, silc_buffer_len(idp),
1553                                          3, nh, strlen(nh),
1554                                          4, uh, strlen(uh),
1555                                          5, entry->userinfo,
1556                                          strlen(entry->userinfo),
1557                                          6, channels ? channels->data : NULL,
1558                                          channels ? silc_buffer_len(channels)
1559                                          : 0,
1560                                          7, mode, 4,
1561                                          8, idle, 4,
1562                                          9, fingerprint,
1563                                          fingerprint ? 20 : 0,
1564                                          10, umode_list ? umode_list->data :
1565                                          NULL, umode_list ?
1566                                          silc_buffer_len(umode_list) :
1567                                          0, 11, attrs, len);
1568
1569           sent_reply = TRUE;
1570
1571           /* For now we always delete Requested Attributes, unless the client
1572              is detached, in which case we don't want to reconstruct the
1573              same data everytime */
1574           if (!(entry->mode & SILC_UMODE_DETACHED) &&
1575               !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1576             silc_free(entry->attrs);
1577             entry->attrs = NULL;
1578           }
1579
1580           if (channels)
1581             silc_buffer_free(channels);
1582           if (umode_list) {
1583             silc_buffer_free(umode_list);
1584             umode_list = NULL;
1585           }
1586         }
1587         break;
1588
1589       case SILC_COMMAND_IDENTIFY:
1590         if (!entry->username) {
1591           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1592                                          status, 0, ident, 2,
1593                                          2, idp->data, silc_buffer_len(idp),
1594                                          3, nh, strlen(nh));
1595           sent_reply = TRUE;
1596         } else {
1597           memset(uh, 0, sizeof(uh));
1598           silc_strncat(uh, sizeof(uh), entry->username,
1599                        strlen(entry->username));
1600           if (!strchr(entry->username, '@') && entry->connection) {
1601             hsock = entry->connection;
1602             silc_strncat(uh, sizeof(uh), "@", 1);
1603             silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1604                                         NULL, (const char **)&tmp,
1605                                         NULL, NULL);
1606             silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1607           }
1608
1609           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1610                                          status, 0, ident, 3,
1611                                          2, idp->data, silc_buffer_len(idp),
1612                                          3, nh, strlen(nh),
1613                                          4, uh, strlen(uh));
1614           sent_reply = TRUE;
1615         }
1616         break;
1617
1618       case SILC_COMMAND_WHOWAS:
1619         memset(uh, 0, sizeof(uh));
1620         silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1621         if (!strchr(entry->username, '@'))
1622           silc_strncat(uh, sizeof(uh), "@-private-", 10);
1623
1624         /* Send command reply */
1625         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1626                                        status, 0, ident, 4,
1627                                        2, idp->data, silc_buffer_len(idp),
1628                                        3, nh, strlen(nh),
1629                                        4, uh, strlen(uh),
1630                                        5, entry->userinfo,
1631                                        entry->userinfo ?
1632                                        strlen(entry->userinfo) : 0);
1633         sent_reply = TRUE;
1634         break;
1635       }
1636
1637       silc_buffer_free(idp);
1638
1639       if (status == SILC_STATUS_LIST_END)
1640         break;
1641       k++;
1642     }
1643
1644     if (k == 0) {
1645       /* Not one valid entry was found, send error.  If nickname was used
1646          in query send error based on that, otherwise the query->errors
1647          already includes proper errors. */
1648       if (query->nickname[0] || (!query->ids && query->attrs))
1649         silc_server_query_add_error(server, query, 1, 1,
1650                                     SILC_STATUS_ERR_NO_SUCH_NICK);
1651
1652       /* Make sure some error is sent */
1653       if (!query->errors_count && !servers_count && !channels_count)
1654         silc_server_query_add_error(server, query, 2, 0,
1655                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1656     }
1657   }
1658
1659   /* Send servers */
1660   if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1661     SilcServerEntry entry;
1662
1663     if (status == SILC_STATUS_OK && servers_count > 1)
1664       status = SILC_STATUS_LIST_START;
1665
1666     k = 0;
1667     for (i = 0; i < servers_count; i++) {
1668       entry = servers[i];
1669
1670       if (k >= 1)
1671         status = SILC_STATUS_LIST_ITEM;
1672       if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1673           !query->errors_count)
1674         status = SILC_STATUS_LIST_END;
1675       if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1676           !query->errors_count)
1677         status = SILC_STATUS_LIST_END;
1678       if (query->reply_count && k - 1 == query->reply_count)
1679         status = SILC_STATUS_LIST_END;
1680
1681       SILC_LOG_DEBUG(("%s: server %s",
1682                       (status == SILC_STATUS_OK ?         "   OK" :
1683                        status == SILC_STATUS_LIST_START ? "START" :
1684                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1685                        status == SILC_STATUS_LIST_END  ?  "  END" :
1686                        "      : "),
1687                       entry->server_name ? entry->server_name : ""));
1688
1689       /* Send command reply */
1690       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1691       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1692                                      status, 0, ident, 2,
1693                                      2, idp->data, silc_buffer_len(idp),
1694                                      3, entry->server_name,
1695                                      entry->server_name ?
1696                                      strlen(entry->server_name) : 0);
1697       silc_buffer_free(idp);
1698       sent_reply = TRUE;
1699
1700       if (status == SILC_STATUS_LIST_END)
1701         break;
1702       k++;
1703     }
1704   }
1705
1706   /* Send channels */
1707   if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1708     SilcChannelEntry entry;
1709
1710     if (status == SILC_STATUS_OK && channels_count > 1)
1711       status = SILC_STATUS_LIST_START;
1712
1713     k = 0;
1714     for (i = 0; i < channels_count; i++) {
1715       entry = channels[i];
1716
1717       if (k >= 1)
1718         status = SILC_STATUS_LIST_ITEM;
1719       if (channels_count == 1 && status != SILC_STATUS_OK &&
1720           !query->errors_count)
1721         status = SILC_STATUS_LIST_END;
1722       if (channels_count > 1 && k == channels_count - 1 &&
1723           !query->errors_count)
1724         status = SILC_STATUS_LIST_END;
1725       if (query->reply_count && k - 1 == query->reply_count)
1726         status = SILC_STATUS_LIST_END;
1727
1728       SILC_LOG_DEBUG(("%s: channel %s",
1729                       (status == SILC_STATUS_OK ?         "   OK" :
1730                        status == SILC_STATUS_LIST_START ? "START" :
1731                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1732                        status == SILC_STATUS_LIST_END  ?  "  END" :
1733                        "      : "),
1734                       entry->channel_name ? entry->channel_name : ""));
1735
1736       /* Send command reply */
1737       idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1738       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1739                                      status, 0, ident, 2,
1740                                      2, idp->data, silc_buffer_len(idp),
1741                                      3, entry->channel_name,
1742                                      entry->channel_name ?
1743                                      strlen(entry->channel_name) : 0);
1744       silc_buffer_free(idp);
1745       sent_reply = TRUE;
1746
1747       if (status == SILC_STATUS_LIST_END)
1748         break;
1749       k++;
1750     }
1751   }
1752
1753   /* Send errors */
1754   if (query->errors_count) {
1755     int type;
1756
1757     if (status == SILC_STATUS_OK && query->errors_count > 1)
1758       status = SILC_STATUS_LIST_START;
1759
1760     k = 0;
1761     for (i = 0; i < query->errors_count; i++) {
1762       idp = NULL;
1763
1764       /* Take error argument */
1765       if (query->errors[i].type == 1) {
1766         /* Take from sent arguments */
1767         len = 0;
1768         tmp = silc_argument_get_arg_type(cmd->args,
1769                                          query->errors[i].index, &len);
1770         type = 2;
1771       } else if (query->errors[i].type == 2) {
1772         /* No argument */
1773         len = 0;
1774         tmp = NULL;
1775         type = 0;
1776       } else if (!query->errors[i].id) {
1777         /* Take from query->ids */
1778         idp =
1779           silc_id_payload_encode(query->ids[query->errors[i].index].id,
1780                                  query->ids[query->errors[k].index].id_type);
1781         tmp = idp->data;
1782         len = silc_buffer_len(idp);
1783         type = 2;
1784       } else {
1785         /* Take added ID. */
1786         idp = silc_id_payload_encode(query->errors[i].id,
1787                                      query->errors[k].id_type);
1788         tmp = idp->data;
1789         len = silc_buffer_len(idp);
1790         type = 2;
1791       }
1792
1793       if (k >= 1)
1794         status = SILC_STATUS_LIST_ITEM;
1795       if (query->errors_count == 1 && status != SILC_STATUS_OK)
1796         status = SILC_STATUS_LIST_END;
1797       if (query->errors_count > 1 && k == query->errors_count - 1)
1798         status = SILC_STATUS_LIST_END;
1799       if (query->reply_count && k - 1 == query->reply_count)
1800         status = SILC_STATUS_LIST_END;
1801
1802       SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1803                       (status == SILC_STATUS_OK ?         "   OK" :
1804                        status == SILC_STATUS_LIST_START ? "START" :
1805                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1806                        status == SILC_STATUS_LIST_END  ?  "  END" :
1807                        "      : "),
1808                       silc_get_status_message(query->errors[i].error),
1809                       query->errors[i].error));
1810
1811 #if 1 /* XXX Backwards compatibility.  Remove in 1.0. */
1812       if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1813         /* Send error */
1814         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1815                                        (status == SILC_STATUS_OK ?
1816                                         query->errors[i].error : status),
1817                                        (status == SILC_STATUS_OK ?
1818                                         0 : query->errors[i].error), ident, 2,
1819                                        type, tmp, len,
1820                                        3, tmp, len);
1821       else
1822 #endif
1823       /* Send error */
1824       silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1825                                      (status == SILC_STATUS_OK ?
1826                                       query->errors[i].error : status),
1827                                      (status == SILC_STATUS_OK ?
1828                                       0 : query->errors[i].error), ident, 1,
1829                                      type, tmp, len);
1830
1831       silc_buffer_free(idp);
1832       sent_reply = TRUE;
1833
1834       if (status == SILC_STATUS_LIST_END)
1835         break;
1836       k++;
1837     }
1838   }
1839
1840   if (!sent_reply)
1841     SILC_LOG_ERROR(("BUG: Query did not send anything"));
1842
1843   /* Cleanup */
1844   silc_server_query_free(query);
1845 }
1846
1847 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1848    of the client since we were unable to resolve them from the client.
1849    Either client does not support Requested Attributes or isn't replying
1850    to them like it should. */
1851
1852 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1853                                          SilcServerQuery query,
1854                                          SilcClientEntry client_entry)
1855 {
1856   SilcBuffer buffer = NULL;
1857   SilcAttribute attribute;
1858   SilcAttributePayload attr;
1859   SilcAttributeObjPk pk;
1860   SilcAttributeObjService service;
1861   unsigned char *tmp;
1862   unsigned char sign[2048 + 1];
1863   SilcUInt32 sign_len;
1864
1865   SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1866
1867   /* Go through all requested attributes */
1868   silc_dlist_start(query->attrs);
1869   while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1870     attribute = silc_attribute_get_attribute(attr);
1871     switch (attribute) {
1872
1873     case SILC_ATTRIBUTE_SERVICE:
1874       /* Put SERVICE.  Put only SILC service. */
1875       memset(&service, 0, sizeof(service));
1876       service.port = (server->config->server_info->primary ?
1877                       server->config->server_info->primary->port : SILC_PORT);
1878       silc_strncat(service.address, sizeof(service.address),
1879                    server->server_name, strlen(server->server_name));
1880       service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1881       if (client_entry->connection)
1882         service.idle = time(NULL) - client_entry->data.last_receive;
1883       buffer = silc_attribute_payload_encode(buffer, attribute,
1884                                              SILC_ATTRIBUTE_FLAG_VALID,
1885                                              &service, sizeof(service));
1886       if (!buffer)
1887         return NULL;
1888       break;
1889
1890     case SILC_ATTRIBUTE_STATUS_MOOD:
1891       /* Put STATUS_MOOD */
1892       buffer = silc_attribute_payload_encode(buffer, attribute,
1893                                              SILC_ATTRIBUTE_FLAG_VALID,
1894                                              (void *)
1895                                              SILC_ATTRIBUTE_MOOD_NORMAL,
1896                                              sizeof(SilcUInt32));
1897       if (!buffer)
1898         return NULL;
1899       break;
1900
1901     case SILC_ATTRIBUTE_STATUS_FREETEXT:
1902       /* Put STATUS_FREETEXT.  We just tell in the message that we are
1903          replying on behalf of the client. */
1904       tmp =
1905         "This information was provided by the server on behalf of the user";
1906       buffer = silc_attribute_payload_encode(buffer, attribute,
1907                                              SILC_ATTRIBUTE_FLAG_VALID,
1908                                              tmp, strlen(tmp));
1909       if (!buffer)
1910         return NULL;
1911       break;
1912
1913     case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1914       /* Put PREFERRED_CONTACT */
1915       buffer = silc_attribute_payload_encode(buffer, attribute,
1916                                              SILC_ATTRIBUTE_FLAG_VALID,
1917                                              (void *)
1918                                              SILC_ATTRIBUTE_CONTACT_CHAT,
1919                                              sizeof(SilcUInt32));
1920       if (!buffer)
1921         return NULL;
1922       break;
1923
1924     case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1925       /* Put USER_PUBLIC_KEY */
1926       if (client_entry->data.public_key) {
1927         pk.type = "silc-rsa";
1928         pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1929                                               &pk.data_len);
1930         buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1931                                                SILC_ATTRIBUTE_FLAG_VALID :
1932                                                SILC_ATTRIBUTE_FLAG_INVALID,
1933                                                &pk, sizeof(pk));
1934         silc_free(pk.data);
1935         if (!buffer)
1936           return NULL;
1937         break;
1938       }
1939
1940       /* No public key available */
1941       buffer = silc_attribute_payload_encode(buffer, attribute,
1942                                              SILC_ATTRIBUTE_FLAG_INVALID,
1943                                              NULL, 0);
1944       if (!buffer)
1945         return NULL;
1946       break;
1947
1948     default:
1949       /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1950       if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1951           attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1952         break;
1953
1954       /* For other attributes we cannot reply so mark it invalid */
1955       buffer = silc_attribute_payload_encode(buffer, attribute,
1956                                              SILC_ATTRIBUTE_FLAG_INVALID,
1957                                              NULL, 0);
1958       if (!buffer)
1959         return NULL;
1960       break;
1961     }
1962   }
1963
1964   /* Always put our public key.  This assures that we send at least
1965      something valid back always. */
1966   pk.type = "silc-rsa";
1967   pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1968   buffer = silc_attribute_payload_encode(buffer,
1969                                          SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1970                                          pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1971                                          SILC_ATTRIBUTE_FLAG_INVALID,
1972                                          &pk, sizeof(pk));
1973   silc_free(pk.data);
1974   if (!buffer)
1975     return NULL;
1976
1977   /* Finally compute the digital signature of all the data we provided
1978      as an indication that we provided rightfull information, and this
1979      also authenticates our public key. */
1980   if (silc_pkcs_private_key_get_len(server->private_key) / 8 <=
1981       sizeof(sign) -1  &&
1982       silc_pkcs_sign(server->private_key, buffer->data,
1983                      silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
1984                      TRUE, server->sha1hash)) {
1985     pk.type = NULL;
1986     pk.data = sign;
1987     pk.data_len = sign_len;
1988     buffer =
1989       silc_attribute_payload_encode(buffer,
1990                                     SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1991                                     SILC_ATTRIBUTE_FLAG_VALID,
1992                                     &pk, sizeof(pk));
1993   }
1994   if (!buffer)
1995     return NULL;
1996
1997   return buffer;
1998 }
1999
2000 /* Find client by the Client ID indicated by the `client_id', and if not
2001    found then query it by using WHOIS command.  The client information
2002    is also resolved if the cached information is incomplete or if the
2003    `always_resolve' is set to TRUE.  The indication whether requested
2004    client was being resolved is saved into `resolved'.  If the client
2005    is not being resolved its entry is returned by this function.  NULL
2006    is returned if client is resolved. */
2007
2008 SilcClientEntry silc_server_query_client(SilcServer server,
2009                                          const SilcClientID *client_id,
2010                                          SilcBool always_resolve,
2011                                          SilcBool *resolved)
2012 {
2013   SilcClientEntry client;
2014
2015   SILC_LOG_DEBUG(("Resolving client by client ID"));
2016
2017   if (resolved)
2018     *resolved = FALSE;
2019
2020   client = silc_idlist_find_client_by_id(server->local_list,
2021                                          (SilcClientID *)client_id,
2022                                          TRUE, NULL);
2023   if (!client) {
2024     client = silc_idlist_find_client_by_id(server->global_list,
2025                                            (SilcClientID *)client_id,
2026                                            TRUE, NULL);
2027     if (!client && server->server_type == SILC_ROUTER)
2028       return NULL;
2029   }
2030
2031   if (!client && server->standalone)
2032     return NULL;
2033
2034   if (!client || !client->nickname || !client->username ||
2035       always_resolve) {
2036     SilcBuffer buffer, idp;
2037
2038     /* Statistics */
2039     server->stat.commands_sent++;
2040
2041     if (client) {
2042       client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
2043       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
2044       client->resolve_cmd_ident = ++server->cmd_ident;
2045     }
2046
2047     idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
2048     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
2049                                             server->cmd_ident, 1,
2050                                             4, idp->data,
2051                                             silc_buffer_len(idp));
2052     silc_server_packet_send(server, client ? client->router->connection :
2053                             SILC_PRIMARY_ROUTE(server),
2054                             SILC_PACKET_COMMAND, 0,
2055                             buffer->data, silc_buffer_len(buffer));
2056     silc_buffer_free(idp);
2057     silc_buffer_free(buffer);
2058
2059     if (resolved)
2060       *resolved = TRUE;
2061
2062     return NULL;
2063   }
2064
2065   return client;
2066 }