5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 Pekka Riikonen
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.
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.
21 #include "serverincludes.h"
22 #include "server_internal.h"
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;
34 /* Represents an SILC ID */
37 SilcIdType id_type; /* ID type */
38 SilcUInt16 ident; /* Command identifier */
41 /* Represents one error occurred during query */
44 SilcIdType id_type; /* ID type */
45 SilcUInt16 index; /* Index to IDs */
46 unsigned int from_cmd : 1; /* TRUE if `index' is from command args,
47 otherwise from query->ids */
48 unsigned int error : 7; /* The actual error (SilcStatus) */
49 } *SilcServerQueryError;
51 /* Query session context */
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 */
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 */
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,
86 void silc_server_query_add_error_id(SilcServer server,
87 SilcServerQuery query,
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,
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);
111 /* Free the query context structure and all allocated resources. */
113 void silc_server_query_free(SilcServerQuery query)
117 silc_server_command_free(query->cmd);
119 for (i = 0; i < query->queries_count; i++)
120 silc_free(query->queries[i].id);
121 silc_free(query->queries);
123 silc_free(query->nickname);
124 silc_free(query->nick_server);
125 silc_free(query->server_name);
126 silc_free(query->channel_name);
128 for (i = 0; i < query->ids_count; i++)
129 silc_free(query->ids[i].id);
130 silc_free(query->ids);
133 silc_attribute_payload_list_free(query->attrs);
135 for (i = 0; i < query->errors_count; i++)
136 silc_free(query->errors[i].id);
137 silc_free(query->errors);
139 memset(query, 'F', sizeof(*query));
143 /* Send error reply indicated by the `error' to the original sender of
146 void silc_server_query_send_error(SilcServer server,
147 SilcServerQuery query,
148 SilcStatus error, ...)
151 unsigned char *data = NULL;
152 SilcUInt32 data_len = 0, data_type = 0, argc = 0;
155 data_type = va_arg(va, SilcUInt32);
158 data = va_arg(va, unsigned char *);
159 data_len = va_arg(va, SilcUInt32);
162 SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
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);
172 /* Add error to error list. Multiple errors may occur during the query
173 processing and this function can be used to add one error. The
174 `index' is the index to the command context which includes the argument
175 which caused the error, or it is the index to query->ids, depending
176 on value of `from_cmd'. */
178 void silc_server_query_add_error(SilcServer server,
179 SilcServerQuery query,
184 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
185 (query->errors_count + 1));
188 query->errors[query->errors_count].index = index;
189 query->errors[query->errors_count].from_cmd = from_cmd;
190 query->errors[query->errors_count].error = error;
191 query->errors[query->errors_count].id = NULL;
192 query->errors[query->errors_count].id_type = 0;
193 query->errors_count++;
196 /* Same as silc_server_query_add_error but adds the ID data to be used
197 with error sending with this error type. */
199 void silc_server_query_add_error_id(SilcServer server,
200 SilcServerQuery query,
202 void *id, SilcIdType id_type)
204 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
205 (query->errors_count + 1));
208 query->errors[query->errors_count].index = 0;
209 query->errors[query->errors_count].from_cmd = FALSE;
210 query->errors[query->errors_count].error = error;
211 query->errors[query->errors_count].id = silc_id_dup(id, id_type);
212 query->errors[query->errors_count].id_type = id_type;
213 query->errors_count++;
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. */
223 bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
224 SilcServerCommandContext cmd)
226 SilcServerQuery query;
228 SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
230 query = silc_calloc(1, sizeof(*query));
231 query->querycmd = querycmd;
232 query->cmd = silc_server_command_dup(cmd);
236 case SILC_COMMAND_WHOIS:
237 /* If we are normal server and query contains nickname, send it
238 directly to router. */
239 if (server->server_type == SILC_SERVER && !server->standalone &&
240 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
241 silc_argument_get_arg_type(cmd->args, 1, NULL)) {
242 silc_server_query_send_router(server, query);
247 case SILC_COMMAND_WHOWAS:
248 /* WHOWAS query is always sent to router if we are normal server */
249 if (server->server_type == SILC_SERVER && !server->standalone &&
250 cmd->sock != SILC_PRIMARY_ROUTE(server)) {
251 silc_server_query_send_router(server, query);
256 case SILC_COMMAND_IDENTIFY:
257 /* If we are normal server and query does not contain IDs, send it
258 directly to router (it contains nickname, server name or channel
260 if (server->server_type == SILC_SERVER && !server->standalone &&
261 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
262 !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
263 silc_server_query_send_router(server, query);
269 SILC_LOG_ERROR(("Bad query using %d command", querycmd));
270 silc_server_query_free(query);
274 /* Now parse the request */
275 silc_server_query_parse(server, query);
280 /* Send the received query to our primary router since we could not
281 handle the query directly. We will reprocess the query after our
282 router replies back. */
284 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
287 SilcUInt16 old_ident;
289 SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
291 /* Send WHOIS command to our router */
292 old_ident = silc_command_get_ident(query->cmd->payload);
293 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
294 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
295 silc_server_packet_send(server,
296 SILC_PRIMARY_ROUTE(server),
297 SILC_PACKET_COMMAND, 0,
298 tmpbuf->data, tmpbuf->len, TRUE);
299 silc_command_set_ident(query->cmd->payload, old_ident);
300 silc_buffer_free(tmpbuf);
302 query->resolved = TRUE;
304 /* Continue parsing the query after received reply from router */
305 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
306 silc_server_query_send_router_reply, query);
309 /* Reply callback called after primary router has replied to our initial
310 sending of the query to it. We will proceed the query in this function. */
312 void silc_server_query_send_router_reply(void *context, void *reply)
314 SilcServerQuery query = context;
315 SilcServer server = query->cmd->server;
316 SilcServerCommandReplyContext cmdr = reply;
318 SILC_LOG_DEBUG(("Received reply from router to query"));
320 /* Check if router sent error reply */
321 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
324 SILC_LOG_DEBUG(("Sending error to original query"));
326 /* Send the same command reply payload which contains the error */
327 silc_command_set_command(cmdr->payload, query->querycmd);
328 silc_command_set_ident(cmdr->payload,
329 silc_command_get_ident(query->cmd->payload));
330 buffer = silc_command_payload_encode_payload(cmdr->payload);
331 silc_server_packet_send(server, query->cmd->sock,
332 SILC_PACKET_COMMAND_REPLY, 0,
333 buffer->data, buffer->len, FALSE);
334 silc_buffer_free(buffer);
335 silc_server_query_free(query);
339 /* Continue with parsing */
340 silc_server_query_parse(server, query);
343 /* Parse the command query and start processing the queries in detail. */
345 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
347 SilcServerCommandContext cmd = query->cmd;
349 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
354 SILC_LOG_DEBUG(("Parsing %s query",
355 silc_get_command_name(query->querycmd)));
357 switch (query->querycmd) {
359 case SILC_COMMAND_WHOIS:
360 /* Get Client IDs if present. Take IDs always instead of nickname. */
361 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
365 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
367 silc_server_query_send_error(server, query,
368 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
369 silc_server_query_free(query);
373 /* Get the nickname@server string and parse it */
375 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
376 silc_server_query_send_error(server, query,
377 SILC_STATUS_ERR_BAD_NICKNAME, 0);
378 silc_server_query_free(query);
383 /* Parse the IDs included in the query */
384 query->ids = silc_calloc(argc, sizeof(*query->ids));
386 for (i = 0; i < argc; i++) {
387 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
391 id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
393 silc_server_query_add_error(server, query, TRUE, i + 4,
394 SILC_STATUS_ERR_BAD_CLIENT_ID);
398 /* Normal server must check whether this ID exist, and if not then
399 send the query to router, unless done so already */
400 if (server->server_type == SILC_SERVER && !query->resolved) {
401 if (!silc_idlist_find_client_by_id(server->local_list,
403 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
404 !silc_idlist_find_client_by_id(server->global_list,
406 silc_server_query_send_router(server, query);
407 for (i = 0; i < query->ids_count; i++)
408 silc_free(query->ids[i].id);
409 silc_free(query->ids);
416 query->ids[query->ids_count].id = id;
417 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
422 /* Get the max count of reply messages allowed */
423 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
424 if (tmp && tmp_len == sizeof(SilcUInt32))
425 SILC_GET32_MSB(query->reply_count, tmp);
427 /* Get requested attributes if set */
428 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
429 if (tmp && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN)
430 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
433 case SILC_COMMAND_WHOWAS:
435 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
437 silc_server_query_send_error(server, query,
438 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
439 silc_server_query_free(query);
443 /* Get the nickname@server string and parse it */
445 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
446 silc_server_query_send_error(server, query,
447 SILC_STATUS_ERR_BAD_NICKNAME, 0);
448 silc_server_query_free(query);
452 /* Get the max count of reply messages allowed */
453 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
454 if (tmp && tmp_len == sizeof(SilcUInt32))
455 SILC_GET32_MSB(query->reply_count, tmp);
458 case SILC_COMMAND_IDENTIFY:
459 /* Get IDs if present. Take IDs always instead of names. */
460 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
463 /* Try get nickname */
464 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
466 /* Get the nickname@server string and parse it */
468 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
469 silc_server_query_add_error(server, query, TRUE, 1,
470 SILC_STATUS_ERR_BAD_NICKNAME);
473 /* Try get server name */
474 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
476 query->server_name = silc_memdup(tmp, tmp_len);
478 /* Get channel name */
479 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
480 if (tmp && tmp_len <= 256)
481 query->channel_name = silc_memdup(tmp, tmp_len);
483 if (!query->nickname && !query->server_name && !query->channel_name) {
484 silc_server_query_send_error(server, query,
485 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
486 silc_server_query_free(query);
491 /* Parse the IDs included in the query */
492 query->ids = silc_calloc(argc, sizeof(*query->ids));
494 for (i = 0; i < argc; i++) {
495 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
499 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
501 silc_server_query_add_error(server, query, TRUE, i + 5,
502 SILC_STATUS_ERR_BAD_CLIENT_ID);
506 /* Normal server must check whether this ID exist, and if not then
507 send the query to router, unless done so already */
508 if (server->server_type == SILC_SERVER && !query->resolved) {
509 if (!silc_idlist_find_client_by_id(server->local_list,
511 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
512 !silc_idlist_find_client_by_id(server->global_list,
514 silc_server_query_send_router(server, query);
515 for (i = 0; i < query->ids_count; i++)
516 silc_free(query->ids[i].id);
517 silc_free(query->ids);
524 query->ids[query->ids_count].id = id;
525 query->ids[query->ids_count].id_type = id_type;
530 /* Get the max count of reply messages allowed */
531 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
532 if (tmp && tmp_len == sizeof(SilcUInt32))
533 SILC_GET32_MSB(query->reply_count, tmp);
537 /* Start processing the query information */
538 silc_server_query_process(server, query, TRUE);
541 /* Processes the parsed query. This does the actual finding of the
542 queried information and prepares for sending reply to the original
543 sender of the query command. */
545 void silc_server_query_process(SilcServer server, SilcServerQuery query,
548 SilcServerCommandContext cmd = query->cmd;
549 bool check_global = FALSE;
551 SilcClientEntry *clients = NULL, client_entry;
552 SilcChannelEntry *channels = NULL;
553 SilcServerEntry *servers = NULL;
554 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
557 SILC_LOG_DEBUG(("Processing %s query",
558 silc_get_command_name(query->querycmd)));
560 /* Check global lists if query is coming from client or we are not
561 normal server (we know global information). */
562 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
564 else if (server->server_type != SILC_SERVER)
567 if (query->nickname) {
568 /* Get all clients matching nickname from local list */
569 if (!silc_idlist_get_clients_by_hash(server->local_list,
570 query->nickname, server->md5hash,
571 &clients, &clients_count))
572 silc_idlist_get_clients_by_nickname(server->local_list,
575 &clients, &clients_count);
577 /* Check global list as well */
579 if (!silc_idlist_get_clients_by_hash(server->global_list,
580 query->nickname, server->md5hash,
581 &clients, &clients_count))
582 silc_idlist_get_clients_by_nickname(server->global_list,
585 &clients, &clients_count);
589 silc_server_query_add_error(server, query, TRUE, 1,
590 SILC_STATUS_ERR_NO_SUCH_NICK);
593 if (query->server_name) {
594 /* Find server by name */
595 entry = silc_idlist_find_server_by_name(server->local_list,
596 query->server_name, TRUE, NULL);
597 if (!entry && check_global)
598 entry = silc_idlist_find_server_by_name(server->global_list,
599 query->server_name, TRUE, NULL);
601 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
602 servers[servers_count++] = (SilcServerEntry)entry;
606 silc_server_query_add_error(server, query, TRUE, 2,
607 SILC_STATUS_ERR_NO_SUCH_SERVER);
610 if (query->channel_name) {
611 /* Find channel by name */
612 entry = silc_idlist_find_channel_by_name(server->local_list,
613 query->channel_name, NULL);
614 if (!entry && check_global)
615 entry = silc_idlist_find_channel_by_name(server->global_list,
616 query->channel_name, NULL);
618 channels = silc_realloc(channels, sizeof(*channels) *
619 (channels_count + 1));
620 channels[channels_count++] = (SilcChannelEntry)entry;
624 silc_server_query_add_error(server, query, TRUE, 3,
625 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
628 if (query->ids_count) {
629 /* Find entries by the queried IDs */
630 for (i = 0; i < query->ids_count; i++) {
631 void *id = query->ids[i].id;
635 switch (query->ids[i].id_type) {
638 /* Get client entry */
639 entry = silc_idlist_find_client_by_id(server->local_list,
641 if (!entry && check_global)
642 entry = silc_idlist_find_client_by_id(server->global_list,
645 silc_server_query_add_error(server, query, FALSE, i,
646 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
650 clients = silc_realloc(clients, sizeof(*clients) *
651 (clients_count + 1));
652 clients[clients_count++] = (SilcClientEntry)entry;
656 /* Get server entry */
657 entry = silc_idlist_find_server_by_id(server->local_list,
659 if (!entry && check_global)
660 entry = silc_idlist_find_server_by_id(server->global_list,
663 silc_server_query_add_error(server, query, FALSE, i,
664 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
668 servers = silc_realloc(servers, sizeof(*servers) *
669 (servers_count + 1));
670 servers[servers_count++] = (SilcServerEntry)entry;
673 case SILC_ID_CHANNEL:
674 /* Get channel entry */
675 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
676 if (!entry && check_global)
677 entry = silc_idlist_find_channel_by_id(server->global_list, id,
680 silc_server_query_add_error(server, query, FALSE, i,
681 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
685 channels = silc_realloc(channels, sizeof(*channels) *
686 (channels_count + 1));
687 channels[channels_count++] = (SilcChannelEntry)entry;
696 /* If nothing was found, then just send the errors */
697 if (!clients && !channels && !servers) {
698 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
702 /* If caller does not want us to resolve anything (has resolved already)
703 then just continue with sending the reply */
705 silc_server_query_send_reply(server, query, clients, clients_count,
706 servers, servers_count, channels,
714 /* Now process all found information and if necessary do some more
716 switch (query->querycmd) {
718 case SILC_COMMAND_WHOIS:
719 for (i = 0; i < clients_count; i++) {
720 client_entry = clients[i];
722 /* Check if cannot query this anyway, so take next one */
724 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
727 /* If Requested Attributes is set then we always resolve the client
728 information, if not then check whether the entry is complete or not
729 and decide whether we need to resolve or not. */
732 /* Even if nickname and stuff are present, we may need to resolve
734 if (client_entry->nickname && client_entry->username &&
735 client_entry->userinfo) {
736 /* Check if cannot query this anyway, so take next one */
737 if (!client_entry->router)
740 /* If we are router, client is local to us, or client is on channel
741 we do not need to resolve the client information. */
742 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
743 || silc_hash_table_count(client_entry->channels) ||
749 /* Remove the NOATTR status periodically */
750 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
751 client_entry->updated + 600 < time(NULL))
752 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
754 /* When requested attributes is present and local client is detached
755 we cannot send the command to the client, we'll reply on behalf of
756 the client instead. */
757 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
758 (client_entry->mode & SILC_UMODE_DETACHED ||
759 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
762 /* Resolve the detailed client information. If client is local we
763 know that attributes were present and we will resolve directly
764 from the client. Otherwise resolve from client's owner. */
765 silc_server_query_resolve(server, query,
766 (SILC_IS_LOCAL(client_entry) ?
767 client_entry->connection :
768 client_entry->router->connection),
773 case SILC_COMMAND_WHOWAS:
774 for (i = 0; i < clients_count; i++) {
775 client_entry = clients[i];
777 /* Check if cannot query this anyway, so take next one */
778 if (!client_entry || !client_entry->router ||
779 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
782 /* If both nickname and username are present no resolving is needed */
783 if (client_entry->nickname && client_entry->username)
786 /* Resolve the detailed client information */
787 silc_server_query_resolve(server, query,
788 client_entry->router->connection,
793 case SILC_COMMAND_IDENTIFY:
794 for (i = 0; i < clients_count; i++) {
795 client_entry = clients[i];
797 /* Check if cannot query this anyway, so take next one */
798 if (!client_entry || !client_entry->router ||
799 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
802 /* Even if nickname is present, we may need to resolve the entry */
803 if (client_entry->nickname) {
805 /* If we are router, client is local to us, or client is on channel
806 we do not need to resolve the client information. */
807 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
808 || silc_hash_table_count(client_entry->channels) ||
813 /* Resolve the detailed client information */
814 silc_server_query_resolve(server, query,
815 client_entry->router->connection,
821 if (!query->queries_count)
822 /* If we didn't have to do any resolving, continue with sending the
823 command reply to the original sender. */
824 silc_server_query_send_reply(server, query, clients, clients_count,
825 servers, servers_count, channels,
828 /* Now actually send the resolvings we gathered earlier */
829 silc_server_query_resolve(server, query, NULL, NULL);
836 /* Resolve the detailed information for the `client_entry'. Only client
837 information needs to be resolved for being incomplete. Each incomplete
838 client entry calls this function to do the resolving. */
840 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
841 SilcSocketConnection sock,
842 SilcClientEntry client_entry)
844 SilcServerCommandContext cmd = query->cmd;
845 SilcServerQueryList r = NULL;
852 if (!sock && client_entry)
855 /* If arguments are NULL we will now actually send the resolvings
856 that earlier has been gathered by calling this function. */
857 if (!sock && !client_entry) {
860 SILC_LOG_DEBUG(("Sending the resolvings"));
862 /* WHOWAS resolving has been done at the same time this function
863 was called to add the resolving for WHOWAS, so just return. */
864 if (query->querycmd == SILC_COMMAND_WHOWAS)
867 for (i = 0; i < query->querylist_count; i++) {
868 r = &query->querylist[i];
870 /* Send WHOIS command */
871 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
872 r->argc, r->arg, r->arg_lens,
873 r->arg_types, r->ident);
874 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
875 res_cmd->data, res_cmd->len, FALSE);
876 silc_buffer_free(res_cmd);
878 /* Reprocess this packet after received reply */
879 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
881 silc_server_query_resolve_reply,
883 query->queries_left++;
886 /* Cleanup this temporary context */
887 for (i = 0; i < query->querylist_count; i++) {
889 for (k = 0; k < query->querylist[i].argc; k++)
890 silc_free(query->querylist[i].arg[k]);
891 silc_free(query->querylist[i].arg);
892 silc_free(query->querylist[i].arg_lens);
893 silc_free(query->querylist[i].arg_types);
895 silc_free(query->querylist);
896 query->querylist = NULL;
897 query->querylist_count = 0;
901 SILC_LOG_DEBUG(("Resolving client information"));
903 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
904 /* The entry is being resolved by some other external query already.
905 Attach to that query instead of resolving again. */
906 ident = client_entry->resolve_cmd_ident;
907 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
908 silc_server_query_resolve_reply, query))
909 query->queries_left++;
911 /* This entry will be resolved */
912 ident = ++server->cmd_ident;
914 switch (query->querycmd) {
916 case SILC_COMMAND_WHOIS:
917 case SILC_COMMAND_IDENTIFY:
918 /* Take existing query context if exist for this connection */
919 for (i = 0; i < query->queries_count; i++)
920 if (query->querylist[i].sock == sock) {
921 r = &query->querylist[i];
926 /* Allocate new temp query list context */
927 query->querylist = silc_realloc(query->querylist,
928 sizeof(*query->querylist) *
929 (query->querylist_count + 1));
930 r = &query->querylist[query->querylist_count];
931 query->querylist_count++;
932 memset(r, 0, sizeof(*r));
935 if (SILC_IS_LOCAL(client_entry))
939 /* If Requested Attributes were present put them to this resolving */
940 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
942 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
943 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
944 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
946 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
948 r->arg[r->argc] = silc_memdup(tmp, len);
949 r->arg_lens[r->argc] = len;
950 r->arg_types[r->argc] = 3;
955 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
956 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
957 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
959 /* Add the client entry to be resolved */
960 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
961 r->arg[r->argc] = silc_memdup(idp->data, idp->len);
962 r->arg_lens[r->argc] = idp->len;
963 r->arg_types[r->argc] = r->argc + 4;
965 silc_buffer_free(idp);
969 case SILC_COMMAND_WHOWAS:
970 /* We must send WHOWAS command since it's the only the way of
971 resolving clients that are not present in the network anymore. */
972 silc_server_send_command(server, sock, query->querycmd, ident, 1,
973 1, query->nickname, strlen(query->nickname));
974 if (silc_server_command_pending(server, query->querycmd, ident,
975 silc_server_query_resolve_reply, query))
976 query->queries_left++;
981 /* Mark the entry as being resolved */
982 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
983 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
984 client_entry->resolve_cmd_ident = ident;
985 client_entry->updated = time(NULL);
987 /* Save the queried ID, which we will reprocess after we get this and
988 all other queries back. */
989 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
990 (query->queries_count + 1));
991 if (query->queries) {
992 i = query->queries_count;
993 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
994 query->queries[i].id_type = SILC_ID_CLIENT;
995 query->queries[i].ident = ident;
996 query->queries_count++;
1000 /* Reply callback called after one resolving has been completed. If
1001 all resolvings has been received then we will continue with sending
1002 the command reply to the original sender of the query. */
1004 void silc_server_query_resolve_reply(void *context, void *reply)
1006 SilcServerQuery query = context;
1007 SilcServer server = query->cmd->server;
1008 SilcServerCommandReplyContext cmdr = reply;
1009 SilcUInt16 ident = cmdr->ident;
1010 SilcStatus error = SILC_STATUS_OK;
1011 SilcServerQueryID id = NULL;
1012 SilcClientEntry client_entry;
1015 /* One less query left */
1016 query->queries_left--;
1018 silc_command_get_status(cmdr->payload, NULL, &error);
1019 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1020 query->queries_left, error));
1022 /* If no error then skip to other stuff */
1023 if (error == SILC_STATUS_OK)
1026 /* Error occurred during resolving */
1028 /* Find the resolved client ID */
1029 for (i = 0; i < query->queries_count; i++) {
1030 if (query->queries[i].ident != ident)
1033 id = &query->queries[i];
1035 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1037 /* If timeout occurred for local entry when resolving attributes
1038 mark that this client doesn't support attributes in WHOIS. This
1039 assures we won't send the request again to the client. */
1040 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1041 client_entry = silc_idlist_find_client_by_id(server->local_list,
1042 id->id, TRUE, NULL);
1043 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1044 silc_id_render(id->id, SILC_ID_CLIENT)));
1045 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1046 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1047 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1052 /* Remove the RESOLVING status from the client entry */
1053 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1054 client_entry = silc_idlist_find_client_by_id(server->local_list,
1055 id->id, TRUE, NULL);
1057 client_entry = silc_idlist_find_client_by_id(server->global_list,
1058 id->id, TRUE, NULL);
1060 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1067 /* If there are queries left then wait for them */
1068 if (query->queries_left)
1071 SILC_LOG_DEBUG(("Reprocess the query"));
1073 /* We have received all queries. Now re-search all information required
1074 to complete this query. Reason we cannot save the values found in
1075 the first search is that SilcClientEntry, SilcServerEntry and
1076 SilcChannelEntry pointers may become invalid while we were waiting
1077 for these resolvings. */
1078 silc_server_query_process(server, query, FALSE);
1081 /* Send the reply to the original query. If arguments are NULL then this
1082 sends only the errors that has occurred during the processing of the
1083 query. This sends the errors always after sending all the found
1084 information. The query is over after this function returns and the
1085 `query' will become invalid. This is called only after all informations
1086 has been resolved. This means that if something is not found or is
1087 incomplete in this function we were unable to resolve the information
1088 or it does not exist at all. */
1090 void silc_server_query_send_reply(SilcServer server,
1091 SilcServerQuery query,
1092 SilcClientEntry *clients,
1093 SilcUInt32 clients_count,
1094 SilcServerEntry *servers,
1095 SilcUInt32 servers_count,
1096 SilcChannelEntry *channels,
1097 SilcUInt32 channels_count)
1099 SilcServerCommandContext cmd = query->cmd;
1100 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1105 int i, k, valid_count;
1106 char nh[256], uh[256];
1107 bool sent_reply = FALSE;
1109 SILC_LOG_DEBUG(("Sending reply to query"));
1111 status = SILC_STATUS_OK;
1114 if (clients_count) {
1115 SilcClientEntry entry;
1116 SilcSocketConnection hsock;
1118 /* Mark all invalid entries */
1119 for (i = 0, valid_count = 0; i < clients_count; i++) {
1121 switch (query->querycmd) {
1122 case SILC_COMMAND_WHOIS:
1123 if (!entry->nickname || !entry->username || !entry->userinfo ||
1124 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1125 /* When querying by ID, every "unfound" entry must cause error */
1127 silc_server_query_add_error_id(server, query,
1128 SILC_STATUS_ERR_TIMEDOUT,
1129 entry->id, SILC_ID_CLIENT);
1135 case SILC_COMMAND_IDENTIFY:
1136 if (!entry->nickname ||
1137 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1138 /* When querying by ID, every "unfound" entry must cause error */
1140 silc_server_query_add_error_id(server, query,
1141 SILC_STATUS_ERR_TIMEDOUT,
1142 entry->id, SILC_ID_CLIENT);
1148 case SILC_COMMAND_WHOWAS:
1149 if (!entry->nickname || !entry->username ||
1150 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1159 /* Start processing found clients */
1160 status = SILC_STATUS_OK;
1161 if (valid_count > 1)
1162 status = SILC_STATUS_LIST_START;
1164 /* Now do the sending of valid entries */
1166 for (i = 0; i < clients_count && valid_count; i++) {
1172 status = SILC_STATUS_LIST_ITEM;
1173 if (valid_count > 1 && k == valid_count - 1
1174 && !servers_count && !channels_count && !query->errors_count)
1175 status = SILC_STATUS_LIST_END;
1176 if (query->reply_count && k - 1 == query->reply_count)
1177 status = SILC_STATUS_LIST_END;
1179 SILC_LOG_DEBUG(("%s: client %s",
1180 (status == SILC_STATUS_OK ? " OK" :
1181 status == SILC_STATUS_LIST_START ? "START" :
1182 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1183 status == SILC_STATUS_LIST_END ? " END" :
1184 " : "), entry->nickname));
1186 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1187 memset(uh, 0, sizeof(uh));
1188 memset(nh, 0, sizeof(nh));
1190 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1191 if (!strchr(entry->nickname, '@')) {
1192 silc_strncat(nh, sizeof(nh), "@", 1);
1193 if (entry->servername) {
1194 silc_strncat(nh, sizeof(nh), entry->servername,
1195 strlen(entry->servername));
1197 len = entry->router ? strlen(entry->router->server_name) :
1198 strlen(server->server_name);
1199 silc_strncat(nh, sizeof(nh), entry->router ?
1200 entry->router->server_name :
1201 server->server_name, len);
1205 switch (query->querycmd) {
1207 case SILC_COMMAND_WHOIS:
1209 unsigned char idle[4], mode[4];
1210 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1211 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1213 memset(fempty, 0, sizeof(fempty));
1214 memset(idle, 0, sizeof(idle));
1215 silc_strncat(uh, sizeof(uh), entry->username,
1216 strlen(entry->username));
1217 if (!strchr(entry->username, '@') && entry->connection) {
1218 hsock = entry->connection;
1219 silc_strncat(uh, sizeof(uh), "@", 1);
1220 len = strlen(hsock->hostname);
1221 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1224 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1226 silc_server_get_client_channel_list(server, entry, FALSE,
1227 FALSE, &umode_list);
1230 silc_server_get_client_channel_list(server, entry, TRUE,
1233 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1234 fingerprint = entry->data.fingerprint;
1238 SILC_PUT32_MSB(entry->mode, mode);
1239 if (entry->connection)
1240 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1242 /* If Requested Attribute were present, and we do not have the
1243 attributes we will reply to them on behalf of the client. */
1246 if (!entry->attrs) {
1247 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1248 entry->attrs = silc_memdup(tmpattrs->data, tmpattrs->len);
1249 entry->attrs_len = tmpattrs->len;
1250 silc_buffer_free(tmpattrs);
1252 attrs = entry->attrs;
1253 len = entry->attrs_len;
1256 /* Send command reply */
1257 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1258 status, 0, ident, 10,
1259 2, idp->data, idp->len,
1263 strlen(entry->userinfo),
1264 6, channels ? channels->data : NULL,
1265 channels ? channels->len : 0,
1269 fingerprint ? 20 : 0,
1270 10, umode_list ? umode_list->data :
1271 NULL, umode_list ? umode_list->len :
1276 /* For now we always delete Requested Attributes, unless the client
1277 is detached, in which case we don't want to reconstruct the
1278 same data everytime */
1279 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1280 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1281 silc_free(entry->attrs);
1282 entry->attrs = NULL;
1286 silc_buffer_free(channels);
1288 silc_buffer_free(umode_list);
1294 case SILC_COMMAND_IDENTIFY:
1295 if (!entry->username) {
1296 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1297 status, 0, ident, 2,
1298 2, idp->data, idp->len,
1302 silc_strncat(uh, sizeof(uh), entry->username,
1303 strlen(entry->username));
1304 if (!strchr(entry->username, '@') && entry->connection) {
1305 hsock = entry->connection;
1306 silc_strncat(uh, sizeof(uh), "@", 1);
1307 len = strlen(hsock->hostname);
1308 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1311 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1312 status, 0, ident, 3,
1313 2, idp->data, idp->len,
1320 case SILC_COMMAND_WHOWAS:
1321 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1322 if (!strchr(entry->username, '@'))
1323 silc_strncat(uh, sizeof(uh), "@*private*", 10);
1325 /* Send command reply */
1326 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1327 status, 0, ident, 4,
1328 2, idp->data, idp->len,
1333 strlen(entry->userinfo) : 0);
1338 silc_buffer_free(idp);
1340 if (status == SILC_STATUS_LIST_END)
1346 /* Not one valid entry was found, send error. If nickname was used
1347 in query send error based on that, otherwise the query->errors
1348 already includes proper errors. */
1349 if (query->nickname)
1350 silc_server_query_add_error(server, query, TRUE, 1,
1351 SILC_STATUS_ERR_NO_SUCH_NICK);
1356 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1357 SilcServerEntry entry;
1359 if (status == SILC_STATUS_OK && servers_count > 1)
1360 status = SILC_STATUS_LIST_START;
1363 for (i = 0; i < servers_count; i++) {
1367 status = SILC_STATUS_LIST_ITEM;
1368 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1369 !query->errors_count)
1370 status = SILC_STATUS_LIST_END;
1371 if (query->reply_count && k - 1 == query->reply_count)
1372 status = SILC_STATUS_LIST_END;
1374 SILC_LOG_DEBUG(("%s: server %s",
1375 (status == SILC_STATUS_OK ? " OK" :
1376 status == SILC_STATUS_LIST_START ? "START" :
1377 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1378 status == SILC_STATUS_LIST_END ? " END" :
1380 entry->server_name ? entry->server_name : ""));
1382 /* Send command reply */
1383 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1384 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1385 status, 0, ident, 2,
1386 2, idp->data, idp->len,
1387 3, entry->server_name,
1388 entry->server_name ?
1389 strlen(entry->server_name) : 0);
1390 silc_buffer_free(idp);
1393 if (status == SILC_STATUS_LIST_END)
1400 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1401 SilcChannelEntry entry;
1403 if (status == SILC_STATUS_OK && channels_count > 1)
1404 status = SILC_STATUS_LIST_START;
1407 for (i = 0; i < channels_count; i++) {
1408 entry = channels[i];
1411 status = SILC_STATUS_LIST_ITEM;
1412 if (channels_count > 1 && k == channels_count - 1 &&
1413 !query->errors_count)
1414 status = SILC_STATUS_LIST_END;
1415 if (query->reply_count && k - 1 == query->reply_count)
1416 status = SILC_STATUS_LIST_END;
1418 SILC_LOG_DEBUG(("%s: channel %s",
1419 (status == SILC_STATUS_OK ? " OK" :
1420 status == SILC_STATUS_LIST_START ? "START" :
1421 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1422 status == SILC_STATUS_LIST_END ? " END" :
1424 entry->channel_name ? entry->channel_name : ""));
1426 /* Send command reply */
1427 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1428 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1429 status, 0, ident, 2,
1430 2, idp->data, idp->len,
1431 3, entry->channel_name,
1432 entry->channel_name ?
1433 strlen(entry->channel_name) : 0);
1434 silc_buffer_free(idp);
1437 if (status == SILC_STATUS_LIST_END)
1444 if (query->errors_count) {
1447 if (status == SILC_STATUS_OK && query->errors_count > 1)
1448 status = SILC_STATUS_LIST_START;
1451 for (i = 0; i < query->errors_count; i++) {
1454 /* Take error argument */
1455 if (query->errors[i].from_cmd) {
1457 tmp = silc_argument_get_arg_type(cmd->args,
1458 query->errors[i].index, &len);
1459 if (query->errors[i].index == 1)
1460 type = 3; /* Nickname */
1463 } else if (!query->errors[i].id) {
1465 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1466 query->ids[query->errors[k].index].id_type);
1471 idp = silc_id_payload_encode(query->errors[i].id,
1472 query->errors[k].id_type);
1479 status = SILC_STATUS_LIST_ITEM;
1480 if (query->errors_count > 1 && k == query->errors_count - 1)
1481 status = SILC_STATUS_LIST_END;
1482 if (query->reply_count && k - 1 == query->reply_count)
1483 status = SILC_STATUS_LIST_END;
1485 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1486 (status == SILC_STATUS_OK ? " OK" :
1487 status == SILC_STATUS_LIST_START ? "START" :
1488 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1489 status == SILC_STATUS_LIST_END ? " END" :
1491 silc_get_status_message(query->errors[i].error),
1492 query->errors[i].error));
1495 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1496 (status == SILC_STATUS_OK ?
1497 query->errors[i].error : status),
1498 (status == SILC_STATUS_OK ?
1499 0 : query->errors[i].error), ident, 1,
1501 silc_buffer_free(idp);
1504 if (status == SILC_STATUS_LIST_END)
1511 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1514 silc_server_query_free(query);
1517 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1518 of the client since we were unable to resolve them from the client.
1519 Either client does not support Requested Attributes or isn't replying
1520 to them like it should. */
1522 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1523 SilcServerQuery query,
1524 SilcClientEntry client_entry)
1526 SilcBuffer buffer = NULL;
1527 SilcAttribute attribute;
1528 SilcAttributePayload attr;
1529 SilcAttributeObjPk pk;
1530 SilcAttributeObjService service;
1532 unsigned char sign[2048];
1533 SilcUInt32 sign_len;
1535 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1537 /* Go through all requested attributes */
1538 silc_dlist_start(query->attrs);
1539 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1540 attribute = silc_attribute_get_attribute(attr);
1541 switch (attribute) {
1543 case SILC_ATTRIBUTE_SERVICE:
1544 /* Put SERVICE. Put only SILC service. */
1545 memset(&service, 0, sizeof(service));
1546 service.port = (server->config->server_info->primary ?
1547 server->config->server_info->primary->port : SILC_PORT);
1548 silc_strncat(service.address, sizeof(service.address),
1549 server->server_name, strlen(server->server_name));
1550 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1551 buffer = silc_attribute_payload_encode(buffer, attribute,
1552 SILC_ATTRIBUTE_FLAG_VALID,
1553 &service, sizeof(service));
1558 case SILC_ATTRIBUTE_STATUS_MOOD:
1559 /* Put STATUS_MOOD */
1560 buffer = silc_attribute_payload_encode(buffer, attribute,
1561 SILC_ATTRIBUTE_FLAG_VALID,
1563 SILC_ATTRIBUTE_MOOD_NORMAL,
1564 sizeof(SilcUInt32));
1569 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1570 /* Put STATUS_FREETEXT. We just tell in the message that we are
1571 replying on behalf of the client. */
1573 "This information was provided by the server on behalf of the user";
1574 buffer = silc_attribute_payload_encode(buffer, attribute,
1575 SILC_ATTRIBUTE_FLAG_VALID,
1581 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1582 /* Put PREFERRED_CONTACT */
1583 buffer = silc_attribute_payload_encode(buffer, attribute,
1584 SILC_ATTRIBUTE_FLAG_VALID,
1586 SILC_ATTRIBUTE_CONTACT_CHAT,
1587 sizeof(SilcUInt32));
1592 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1593 /* Put USER_PUBLIC_KEY */
1594 if (client_entry->data.public_key) {
1595 pk.type = "silc-rsa";
1596 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1598 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1599 SILC_ATTRIBUTE_FLAG_VALID :
1600 SILC_ATTRIBUTE_FLAG_INVALID,
1608 /* No public key available */
1609 buffer = silc_attribute_payload_encode(buffer, attribute,
1610 SILC_ATTRIBUTE_FLAG_INVALID,
1617 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1618 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1619 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1622 /* For other attributes we cannot reply so mark it invalid */
1623 buffer = silc_attribute_payload_encode(buffer, attribute,
1624 SILC_ATTRIBUTE_FLAG_INVALID,
1632 /* Always put our public key. This assures that we send at least
1633 something valid back always. */
1634 pk.type = "silc-rsa";
1635 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1636 buffer = silc_attribute_payload_encode(buffer,
1637 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1638 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1639 SILC_ATTRIBUTE_FLAG_INVALID,
1645 /* Finally compute the digital signature of all the data we provided
1646 as an indication that we provided rightfull information, and this
1647 also authenticates our public key. */
1648 if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
1649 silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1650 buffer->data, buffer->len,
1654 pk.data_len = sign_len;
1656 silc_attribute_payload_encode(buffer,
1657 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1658 SILC_ATTRIBUTE_FLAG_VALID,
1667 /* Find client by the Client ID indicated by the `client_id', and if not
1668 found then query it by using WHOIS command. The client information
1669 is also resolved if the cached information is incomplete or if the
1670 `always_resolve' is set to TRUE. The indication whether requested
1671 client was being resolved is saved into `resolved'. If the client
1672 is not being resolved its entry is returned by this function. NULL
1673 is returned if client is resolved. */
1675 SilcClientEntry silc_server_query_client(SilcServer server,
1676 const SilcClientID *client_id,
1677 bool always_resolve,
1680 SilcClientEntry client;
1682 SILC_LOG_DEBUG(("Resolving client by client ID"));
1687 client = silc_idlist_find_client_by_id(server->local_list,
1688 (SilcClientID *)client_id,
1691 client = silc_idlist_find_client_by_id(server->global_list,
1692 (SilcClientID *)client_id,
1694 if (!client && server->server_type == SILC_ROUTER)
1698 if (!client && server->standalone)
1701 if (!client || !client->nickname || !client->username ||
1703 SilcBuffer buffer, idp;
1706 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1707 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1708 client->resolve_cmd_ident = ++server->cmd_ident;
1711 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1712 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1713 server->cmd_ident, 1,
1714 4, idp->data, idp->len);
1715 silc_server_packet_send(server, client ? client->router->connection :
1716 SILC_PRIMARY_ROUTE(server),
1717 SILC_PACKET_COMMAND, 0,
1718 buffer->data, buffer->len, FALSE);
1719 silc_buffer_free(idp);
1720 silc_buffer_free(buffer);