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