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, &id_type);
392 if (!id || id_type != SILC_ID_CLIENT) {
393 silc_server_query_add_error(server, query, TRUE, i + 4,
394 SILC_STATUS_ERR_BAD_CLIENT_ID);
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);
432 /* When Requested Attributes is present we will assure that this
433 client cannot execute the WHOIS command too fast. This would be
434 same as having SILC_CF_LAG_STRICT. */
435 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
436 cmd->sock->user_data)
437 ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
441 case SILC_COMMAND_WHOWAS:
443 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
445 silc_server_query_send_error(server, query,
446 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
447 silc_server_query_free(query);
451 /* Get the nickname@server string and parse it */
453 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
454 silc_server_query_send_error(server, query,
455 SILC_STATUS_ERR_BAD_NICKNAME, 0);
456 silc_server_query_free(query);
460 /* Get the max count of reply messages allowed */
461 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
462 if (tmp && tmp_len == sizeof(SilcUInt32))
463 SILC_GET32_MSB(query->reply_count, tmp);
466 case SILC_COMMAND_IDENTIFY:
467 /* Get IDs if present. Take IDs always instead of names. */
468 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
471 /* Try get nickname */
472 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
474 /* Get the nickname@server string and parse it */
476 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
477 silc_server_query_add_error(server, query, TRUE, 1,
478 SILC_STATUS_ERR_BAD_NICKNAME);
481 /* Try get server name */
482 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
484 query->server_name = silc_memdup(tmp, tmp_len);
486 /* Get channel name */
487 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
488 if (tmp && tmp_len <= 256)
489 query->channel_name = silc_memdup(tmp, tmp_len);
491 if (!query->nickname && !query->server_name && !query->channel_name) {
492 silc_server_query_send_error(server, query,
493 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
494 silc_server_query_free(query);
499 /* Parse the IDs included in the query */
500 query->ids = silc_calloc(argc, sizeof(*query->ids));
502 for (i = 0; i < argc; i++) {
503 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
507 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
509 silc_server_query_add_error(server, query, TRUE, i + 5,
510 SILC_STATUS_ERR_BAD_CLIENT_ID);
514 /* Normal server must check whether this ID exist, and if not then
515 send the query to router, unless done so already */
516 if (server->server_type == SILC_SERVER && !query->resolved) {
517 if (id_type == SILC_ID_CLIENT) {
518 if (!silc_idlist_find_client_by_id(server->local_list,
520 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
521 !silc_idlist_find_client_by_id(server->global_list,
523 silc_server_query_send_router(server, query);
524 for (i = 0; i < query->ids_count; i++)
525 silc_free(query->ids[i].id);
526 silc_free(query->ids);
532 /* For now all other ID's except Client ID's are explicitly
533 sent to router for resolving. */
534 silc_server_query_send_router(server, query);
535 for (i = 0; i < query->ids_count; i++)
536 silc_free(query->ids[i].id);
537 silc_free(query->ids);
543 query->ids[query->ids_count].id = id;
544 query->ids[query->ids_count].id_type = id_type;
549 /* Get the max count of reply messages allowed */
550 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
551 if (tmp && tmp_len == sizeof(SilcUInt32))
552 SILC_GET32_MSB(query->reply_count, tmp);
556 /* Start processing the query information */
557 silc_server_query_process(server, query, TRUE);
560 /* Processes the parsed query. This does the actual finding of the
561 queried information and prepares for sending reply to the original
562 sender of the query command. */
564 void silc_server_query_process(SilcServer server, SilcServerQuery query,
567 SilcServerCommandContext cmd = query->cmd;
568 bool check_global = FALSE;
570 SilcClientEntry *clients = NULL, client_entry;
571 SilcChannelEntry *channels = NULL;
572 SilcServerEntry *servers = NULL;
573 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
576 SILC_LOG_DEBUG(("Processing %s query",
577 silc_get_command_name(query->querycmd)));
579 /* Check global lists if query is coming from client or we are not
580 normal server (we know global information). */
581 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
583 else if (server->server_type != SILC_SERVER)
586 if (query->nickname) {
587 /* Get all clients matching nickname from local list */
588 if (!silc_idlist_get_clients_by_hash(server->local_list,
589 query->nickname, server->md5hash,
590 &clients, &clients_count))
591 silc_idlist_get_clients_by_nickname(server->local_list,
594 &clients, &clients_count);
596 /* Check global list as well */
598 if (!silc_idlist_get_clients_by_hash(server->global_list,
599 query->nickname, server->md5hash,
600 &clients, &clients_count))
601 silc_idlist_get_clients_by_nickname(server->global_list,
604 &clients, &clients_count);
608 silc_server_query_add_error(server, query, TRUE, 1,
609 SILC_STATUS_ERR_NO_SUCH_NICK);
612 if (query->server_name) {
613 /* Find server by name */
614 entry = silc_idlist_find_server_by_name(server->local_list,
615 query->server_name, TRUE, NULL);
616 if (!entry && check_global)
617 entry = silc_idlist_find_server_by_name(server->global_list,
618 query->server_name, TRUE, NULL);
620 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
621 servers[servers_count++] = (SilcServerEntry)entry;
625 silc_server_query_add_error(server, query, TRUE, 2,
626 SILC_STATUS_ERR_NO_SUCH_SERVER);
629 if (query->channel_name) {
630 /* Find channel by name */
631 entry = silc_idlist_find_channel_by_name(server->local_list,
632 query->channel_name, NULL);
633 if (!entry && check_global)
634 entry = silc_idlist_find_channel_by_name(server->global_list,
635 query->channel_name, NULL);
637 channels = silc_realloc(channels, sizeof(*channels) *
638 (channels_count + 1));
639 channels[channels_count++] = (SilcChannelEntry)entry;
643 silc_server_query_add_error(server, query, TRUE, 3,
644 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
647 if (query->ids_count) {
648 /* Find entries by the queried IDs */
649 for (i = 0; i < query->ids_count; i++) {
650 void *id = query->ids[i].id;
654 switch (query->ids[i].id_type) {
657 /* Get client entry */
658 entry = silc_idlist_find_client_by_id(server->local_list,
660 if (!entry && check_global)
661 entry = silc_idlist_find_client_by_id(server->global_list,
664 silc_server_query_add_error(server, query, FALSE, i,
665 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
669 clients = silc_realloc(clients, sizeof(*clients) *
670 (clients_count + 1));
671 clients[clients_count++] = (SilcClientEntry)entry;
675 /* Get server entry */
676 entry = silc_idlist_find_server_by_id(server->local_list,
678 if (!entry && check_global)
679 entry = silc_idlist_find_server_by_id(server->global_list,
682 silc_server_query_add_error(server, query, FALSE, i,
683 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
687 servers = silc_realloc(servers, sizeof(*servers) *
688 (servers_count + 1));
689 servers[servers_count++] = (SilcServerEntry)entry;
692 case SILC_ID_CHANNEL:
693 /* Get channel entry */
694 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
695 if (!entry && check_global)
696 entry = silc_idlist_find_channel_by_id(server->global_list, id,
699 silc_server_query_add_error(server, query, FALSE, i,
700 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
704 channels = silc_realloc(channels, sizeof(*channels) *
705 (channels_count + 1));
706 channels[channels_count++] = (SilcChannelEntry)entry;
715 /* If nothing was found, then just send the errors */
716 if (!clients && !channels && !servers) {
717 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
721 /* If caller does not want us to resolve anything (has resolved already)
722 then just continue with sending the reply */
724 silc_server_query_send_reply(server, query, clients, clients_count,
725 servers, servers_count, channels,
733 /* Now process all found information and if necessary do some more
735 switch (query->querycmd) {
737 case SILC_COMMAND_WHOIS:
738 for (i = 0; i < clients_count; i++) {
739 client_entry = clients[i];
741 /* Check if cannot query this anyway, so take next one */
743 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
746 /* If Requested Attributes is set then we always resolve the client
747 information, if not then check whether the entry is complete or not
748 and decide whether we need to resolve or not. */
751 /* Even if nickname and stuff are present, we may need to resolve
753 if (client_entry->nickname && client_entry->username &&
754 client_entry->userinfo) {
755 /* Check if cannot query this anyway, so take next one */
756 if (!client_entry->router)
759 /* If we are router, client is local to us, or client is on channel
760 we do not need to resolve the client information. */
761 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
762 || silc_hash_table_count(client_entry->channels) ||
768 /* Remove the NOATTR status periodically */
769 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
770 client_entry->updated + 600 < time(NULL))
771 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
773 /* When requested attributes is present and local client is detached
774 we cannot send the command to the client, we'll reply on behalf of
775 the client instead. */
776 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
777 (client_entry->mode & SILC_UMODE_DETACHED ||
778 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
781 /* Resolve the detailed client information. If client is local we
782 know that attributes were present and we will resolve directly
783 from the client. Otherwise resolve from client's owner. */
784 silc_server_query_resolve(server, query,
785 (SILC_IS_LOCAL(client_entry) ?
786 client_entry->connection :
787 client_entry->router->connection),
792 case SILC_COMMAND_WHOWAS:
793 for (i = 0; i < clients_count; i++) {
794 client_entry = clients[i];
796 /* Check if cannot query this anyway, so take next one */
797 if (!client_entry || !client_entry->router ||
798 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
801 /* If both nickname and username are present no resolving is needed */
802 if (client_entry->nickname && client_entry->username)
805 /* Resolve the detailed client information */
806 silc_server_query_resolve(server, query,
807 client_entry->router->connection,
812 case SILC_COMMAND_IDENTIFY:
813 for (i = 0; i < clients_count; i++) {
814 client_entry = clients[i];
816 /* Check if cannot query this anyway, so take next one */
817 if (!client_entry || !client_entry->router ||
818 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
821 /* Even if nickname is present, we may need to resolve the entry */
822 if (client_entry->nickname) {
824 /* If we are router, client is local to us, or client is on channel
825 we do not need to resolve the client information. */
826 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
827 || silc_hash_table_count(client_entry->channels) ||
832 /* Resolve the detailed client information */
833 silc_server_query_resolve(server, query,
834 client_entry->router->connection,
840 if (!query->queries_count)
841 /* If we didn't have to do any resolving, continue with sending the
842 command reply to the original sender. */
843 silc_server_query_send_reply(server, query, clients, clients_count,
844 servers, servers_count, channels,
847 /* Now actually send the resolvings we gathered earlier */
848 silc_server_query_resolve(server, query, NULL, NULL);
855 /* Resolve the detailed information for the `client_entry'. Only client
856 information needs to be resolved for being incomplete. Each incomplete
857 client entry calls this function to do the resolving. */
859 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
860 SilcSocketConnection sock,
861 SilcClientEntry client_entry)
863 SilcServerCommandContext cmd = query->cmd;
864 SilcServerQueryList r = NULL;
871 if (!sock && client_entry)
874 /* If arguments are NULL we will now actually send the resolvings
875 that earlier has been gathered by calling this function. */
876 if (!sock && !client_entry) {
879 SILC_LOG_DEBUG(("Sending the resolvings"));
881 /* WHOWAS resolving has been done at the same time this function
882 was called to add the resolving for WHOWAS, so just return. */
883 if (query->querycmd == SILC_COMMAND_WHOWAS)
886 for (i = 0; i < query->querylist_count; i++) {
887 r = &query->querylist[i];
889 /* If Requested Attributes were present put them to this resolving */
890 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
892 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
893 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
894 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
896 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
898 r->arg[r->argc] = silc_memdup(tmp, len);
899 r->arg_lens[r->argc] = len;
900 r->arg_types[r->argc] = 3;
904 /* Send WHOIS command */
905 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
906 r->argc, r->arg, r->arg_lens,
907 r->arg_types, r->ident);
908 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
909 res_cmd->data, res_cmd->len, FALSE);
910 silc_buffer_free(res_cmd);
912 /* Reprocess this packet after received reply */
913 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
915 silc_server_query_resolve_reply,
917 query->queries_left++;
920 /* Cleanup this temporary context */
921 for (i = 0; i < query->querylist_count; i++) {
923 for (k = 0; k < query->querylist[i].argc; k++)
924 silc_free(query->querylist[i].arg[k]);
925 silc_free(query->querylist[i].arg);
926 silc_free(query->querylist[i].arg_lens);
927 silc_free(query->querylist[i].arg_types);
929 silc_free(query->querylist);
930 query->querylist = NULL;
931 query->querylist_count = 0;
935 SILC_LOG_DEBUG(("Resolving client information"));
937 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
938 /* The entry is being resolved by some other external query already.
939 Attach to that query instead of resolving again. */
940 ident = client_entry->resolve_cmd_ident;
941 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
942 silc_server_query_resolve_reply, query))
943 query->queries_left++;
945 /* This entry will be resolved */
946 ident = ++server->cmd_ident;
948 switch (query->querycmd) {
950 case SILC_COMMAND_WHOIS:
951 case SILC_COMMAND_IDENTIFY:
952 /* Take existing query context if exist for this connection */
953 for (i = 0; i < query->querylist_count; i++)
954 if (query->querylist[i].sock == sock) {
955 r = &query->querylist[i];
960 /* Allocate new temp query list context */
961 query->querylist = silc_realloc(query->querylist,
962 sizeof(*query->querylist) *
963 (query->querylist_count + 1));
964 r = &query->querylist[query->querylist_count];
965 query->querylist_count++;
966 memset(r, 0, sizeof(*r));
969 if (SILC_IS_LOCAL(client_entry))
974 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
975 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
976 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
978 /* Add the client entry to be resolved */
979 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
980 r->arg[r->argc] = silc_memdup(idp->data, idp->len);
981 r->arg_lens[r->argc] = idp->len;
982 r->arg_types[r->argc] = r->argc + 4;
984 silc_buffer_free(idp);
988 case SILC_COMMAND_WHOWAS:
989 /* We must send WHOWAS command since it's the only the way of
990 resolving clients that are not present in the network anymore. */
991 silc_server_send_command(server, sock, query->querycmd, ident, 1,
992 1, query->nickname, strlen(query->nickname));
993 if (silc_server_command_pending(server, query->querycmd, ident,
994 silc_server_query_resolve_reply, query))
995 query->queries_left++;
1000 /* Mark the entry as being resolved */
1001 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1002 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1003 client_entry->resolve_cmd_ident = ident;
1004 client_entry->updated = time(NULL);
1006 /* Save the queried ID, which we will reprocess after we get this and
1007 all other queries back. */
1008 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1009 (query->queries_count + 1));
1010 if (query->queries) {
1011 i = query->queries_count;
1012 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1013 query->queries[i].id_type = SILC_ID_CLIENT;
1014 query->queries[i].ident = ident;
1015 query->queries_count++;
1019 /* Reply callback called after one resolving has been completed. If
1020 all resolvings has been received then we will continue with sending
1021 the command reply to the original sender of the query. */
1023 void silc_server_query_resolve_reply(void *context, void *reply)
1025 SilcServerQuery query = context;
1026 SilcServer server = query->cmd->server;
1027 SilcServerCommandReplyContext cmdr = reply;
1028 SilcUInt16 ident = cmdr->ident;
1029 SilcStatus error = SILC_STATUS_OK;
1030 SilcServerQueryID id = NULL;
1031 SilcClientEntry client_entry;
1034 /* One less query left */
1035 query->queries_left--;
1037 silc_command_get_status(cmdr->payload, NULL, &error);
1038 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1039 query->queries_left, error));
1041 /* If no error then skip to other stuff */
1042 if (error == SILC_STATUS_OK)
1045 /* Error occurred during resolving */
1047 /* Find the resolved client ID */
1048 for (i = 0; i < query->queries_count; i++) {
1049 if (query->queries[i].ident != ident)
1052 id = &query->queries[i];
1054 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1056 /* If timeout occurred for local entry when resolving attributes
1057 mark that this client doesn't support attributes in WHOIS. This
1058 assures we won't send the request again to the client. */
1059 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1060 client_entry = silc_idlist_find_client_by_id(server->local_list,
1061 id->id, TRUE, NULL);
1062 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1063 silc_id_render(id->id, SILC_ID_CLIENT)));
1064 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1065 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1066 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1071 /* Remove the RESOLVING status from the client entry */
1072 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1073 client_entry = silc_idlist_find_client_by_id(server->local_list,
1074 id->id, TRUE, NULL);
1076 client_entry = silc_idlist_find_client_by_id(server->global_list,
1077 id->id, TRUE, NULL);
1079 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1086 /* If there are queries left then wait for them */
1087 if (query->queries_left)
1090 SILC_LOG_DEBUG(("Reprocess the query"));
1092 /* We have received all queries. Now re-search all information required
1093 to complete this query. Reason we cannot save the values found in
1094 the first search is that SilcClientEntry, SilcServerEntry and
1095 SilcChannelEntry pointers may become invalid while we were waiting
1096 for these resolvings. */
1097 silc_server_query_process(server, query, FALSE);
1100 /* Send the reply to the original query. If arguments are NULL then this
1101 sends only the errors that has occurred during the processing of the
1102 query. This sends the errors always after sending all the found
1103 information. The query is over after this function returns and the
1104 `query' will become invalid. This is called only after all informations
1105 has been resolved. This means that if something is not found or is
1106 incomplete in this function we were unable to resolve the information
1107 or it does not exist at all. */
1109 void silc_server_query_send_reply(SilcServer server,
1110 SilcServerQuery query,
1111 SilcClientEntry *clients,
1112 SilcUInt32 clients_count,
1113 SilcServerEntry *servers,
1114 SilcUInt32 servers_count,
1115 SilcChannelEntry *channels,
1116 SilcUInt32 channels_count)
1118 SilcServerCommandContext cmd = query->cmd;
1119 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1124 int i, k, valid_count;
1125 char nh[256], uh[256];
1126 bool sent_reply = FALSE;
1128 SILC_LOG_DEBUG(("Sending reply to query"));
1130 status = SILC_STATUS_OK;
1133 if (clients_count) {
1134 SilcClientEntry entry;
1135 SilcSocketConnection hsock;
1137 /* Mark all invalid entries */
1138 for (i = 0, valid_count = 0; i < clients_count; i++) {
1140 switch (query->querycmd) {
1141 case SILC_COMMAND_WHOIS:
1142 if (!entry->nickname || !entry->username || !entry->userinfo ||
1143 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1144 /* When querying by ID, every "unfound" entry must cause error */
1146 silc_server_query_add_error_id(server, query,
1147 SILC_STATUS_ERR_TIMEDOUT,
1148 entry->id, SILC_ID_CLIENT);
1154 case SILC_COMMAND_IDENTIFY:
1155 if (!entry->nickname ||
1156 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1157 /* When querying by ID, every "unfound" entry must cause error */
1159 silc_server_query_add_error_id(server, query,
1160 SILC_STATUS_ERR_TIMEDOUT,
1161 entry->id, SILC_ID_CLIENT);
1167 case SILC_COMMAND_WHOWAS:
1168 if (!entry->nickname || !entry->username ||
1169 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1178 /* Start processing found clients */
1179 status = SILC_STATUS_OK;
1180 if (valid_count > 1)
1181 status = SILC_STATUS_LIST_START;
1183 /* Now do the sending of valid entries */
1185 for (i = 0; i < clients_count && valid_count; i++) {
1191 status = SILC_STATUS_LIST_ITEM;
1192 if (valid_count > 1 && k == valid_count - 1
1193 && !servers_count && !channels_count && !query->errors_count)
1194 status = SILC_STATUS_LIST_END;
1195 if (query->reply_count && k - 1 == query->reply_count)
1196 status = SILC_STATUS_LIST_END;
1198 SILC_LOG_DEBUG(("%s: client %s",
1199 (status == SILC_STATUS_OK ? " OK" :
1200 status == SILC_STATUS_LIST_START ? "START" :
1201 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1202 status == SILC_STATUS_LIST_END ? " END" :
1203 " : "), entry->nickname));
1205 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1206 memset(uh, 0, sizeof(uh));
1207 memset(nh, 0, sizeof(nh));
1209 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1210 if (!strchr(entry->nickname, '@')) {
1211 silc_strncat(nh, sizeof(nh), "@", 1);
1212 if (entry->servername) {
1213 silc_strncat(nh, sizeof(nh), entry->servername,
1214 strlen(entry->servername));
1216 len = entry->router ? strlen(entry->router->server_name) :
1217 strlen(server->server_name);
1218 silc_strncat(nh, sizeof(nh), entry->router ?
1219 entry->router->server_name :
1220 server->server_name, len);
1224 switch (query->querycmd) {
1226 case SILC_COMMAND_WHOIS:
1228 unsigned char idle[4], mode[4];
1229 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1230 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1232 memset(fempty, 0, sizeof(fempty));
1233 memset(idle, 0, sizeof(idle));
1234 silc_strncat(uh, sizeof(uh), entry->username,
1235 strlen(entry->username));
1236 if (!strchr(entry->username, '@') && entry->connection) {
1237 hsock = entry->connection;
1238 silc_strncat(uh, sizeof(uh), "@", 1);
1239 len = strlen(hsock->hostname);
1240 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1243 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1245 silc_server_get_client_channel_list(server, entry, FALSE,
1246 FALSE, &umode_list);
1249 silc_server_get_client_channel_list(server, entry, TRUE,
1252 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1253 fingerprint = entry->data.fingerprint;
1257 SILC_PUT32_MSB(entry->mode, mode);
1258 if (entry->connection)
1259 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1261 /* If Requested Attribute were present, and we do not have the
1262 attributes we will reply to them on behalf of the client. */
1265 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1266 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1267 entry->attrs = silc_memdup(tmpattrs->data, tmpattrs->len);
1268 entry->attrs_len = tmpattrs->len;
1269 silc_buffer_free(tmpattrs);
1271 attrs = entry->attrs;
1272 len = entry->attrs_len;
1275 /* Send command reply */
1276 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1277 status, 0, ident, 10,
1278 2, idp->data, idp->len,
1282 strlen(entry->userinfo),
1283 6, channels ? channels->data : NULL,
1284 channels ? channels->len : 0,
1288 fingerprint ? 20 : 0,
1289 10, umode_list ? umode_list->data :
1290 NULL, umode_list ? umode_list->len :
1295 /* For now we always delete Requested Attributes, unless the client
1296 is detached, in which case we don't want to reconstruct the
1297 same data everytime */
1298 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1299 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1300 silc_free(entry->attrs);
1301 entry->attrs = NULL;
1305 silc_buffer_free(channels);
1307 silc_buffer_free(umode_list);
1313 case SILC_COMMAND_IDENTIFY:
1314 if (!entry->username) {
1315 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1316 status, 0, ident, 2,
1317 2, idp->data, idp->len,
1321 silc_strncat(uh, sizeof(uh), entry->username,
1322 strlen(entry->username));
1323 if (!strchr(entry->username, '@') && entry->connection) {
1324 hsock = entry->connection;
1325 silc_strncat(uh, sizeof(uh), "@", 1);
1326 len = strlen(hsock->hostname);
1327 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1330 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1331 status, 0, ident, 3,
1332 2, idp->data, idp->len,
1339 case SILC_COMMAND_WHOWAS:
1340 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1341 if (!strchr(entry->username, '@'))
1342 silc_strncat(uh, sizeof(uh), "@*private*", 10);
1344 /* Send command reply */
1345 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1346 status, 0, ident, 4,
1347 2, idp->data, idp->len,
1352 strlen(entry->userinfo) : 0);
1357 silc_buffer_free(idp);
1359 if (status == SILC_STATUS_LIST_END)
1365 /* Not one valid entry was found, send error. If nickname was used
1366 in query send error based on that, otherwise the query->errors
1367 already includes proper errors. */
1368 if (query->nickname)
1369 silc_server_query_add_error(server, query, TRUE, 1,
1370 SILC_STATUS_ERR_NO_SUCH_NICK);
1375 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1376 SilcServerEntry entry;
1378 if (status == SILC_STATUS_OK && servers_count > 1)
1379 status = SILC_STATUS_LIST_START;
1382 for (i = 0; i < servers_count; i++) {
1386 status = SILC_STATUS_LIST_ITEM;
1387 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1388 !query->errors_count)
1389 status = SILC_STATUS_LIST_END;
1390 if (query->reply_count && k - 1 == query->reply_count)
1391 status = SILC_STATUS_LIST_END;
1393 SILC_LOG_DEBUG(("%s: server %s",
1394 (status == SILC_STATUS_OK ? " OK" :
1395 status == SILC_STATUS_LIST_START ? "START" :
1396 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1397 status == SILC_STATUS_LIST_END ? " END" :
1399 entry->server_name ? entry->server_name : ""));
1401 /* Send command reply */
1402 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1403 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1404 status, 0, ident, 2,
1405 2, idp->data, idp->len,
1406 3, entry->server_name,
1407 entry->server_name ?
1408 strlen(entry->server_name) : 0);
1409 silc_buffer_free(idp);
1412 if (status == SILC_STATUS_LIST_END)
1419 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1420 SilcChannelEntry entry;
1422 if (status == SILC_STATUS_OK && channels_count > 1)
1423 status = SILC_STATUS_LIST_START;
1426 for (i = 0; i < channels_count; i++) {
1427 entry = channels[i];
1430 status = SILC_STATUS_LIST_ITEM;
1431 if (channels_count > 1 && k == channels_count - 1 &&
1432 !query->errors_count)
1433 status = SILC_STATUS_LIST_END;
1434 if (query->reply_count && k - 1 == query->reply_count)
1435 status = SILC_STATUS_LIST_END;
1437 SILC_LOG_DEBUG(("%s: channel %s",
1438 (status == SILC_STATUS_OK ? " OK" :
1439 status == SILC_STATUS_LIST_START ? "START" :
1440 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1441 status == SILC_STATUS_LIST_END ? " END" :
1443 entry->channel_name ? entry->channel_name : ""));
1445 /* Send command reply */
1446 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1447 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1448 status, 0, ident, 2,
1449 2, idp->data, idp->len,
1450 3, entry->channel_name,
1451 entry->channel_name ?
1452 strlen(entry->channel_name) : 0);
1453 silc_buffer_free(idp);
1456 if (status == SILC_STATUS_LIST_END)
1463 if (query->errors_count) {
1466 if (status == SILC_STATUS_OK && query->errors_count > 1)
1467 status = SILC_STATUS_LIST_START;
1470 for (i = 0; i < query->errors_count; i++) {
1473 /* Take error argument */
1474 if (query->errors[i].from_cmd) {
1476 tmp = silc_argument_get_arg_type(cmd->args,
1477 query->errors[i].index, &len);
1478 if (query->errors[i].index == 1)
1479 type = 3; /* Nickname */
1482 } else if (!query->errors[i].id) {
1484 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1485 query->ids[query->errors[k].index].id_type);
1490 idp = silc_id_payload_encode(query->errors[i].id,
1491 query->errors[k].id_type);
1498 status = SILC_STATUS_LIST_ITEM;
1499 if (query->errors_count > 1 && k == query->errors_count - 1)
1500 status = SILC_STATUS_LIST_END;
1501 if (query->reply_count && k - 1 == query->reply_count)
1502 status = SILC_STATUS_LIST_END;
1504 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1505 (status == SILC_STATUS_OK ? " OK" :
1506 status == SILC_STATUS_LIST_START ? "START" :
1507 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1508 status == SILC_STATUS_LIST_END ? " END" :
1510 silc_get_status_message(query->errors[i].error),
1511 query->errors[i].error));
1514 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1515 (status == SILC_STATUS_OK ?
1516 query->errors[i].error : status),
1517 (status == SILC_STATUS_OK ?
1518 0 : query->errors[i].error), ident, 1,
1520 silc_buffer_free(idp);
1523 if (status == SILC_STATUS_LIST_END)
1530 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1533 silc_server_query_free(query);
1536 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1537 of the client since we were unable to resolve them from the client.
1538 Either client does not support Requested Attributes or isn't replying
1539 to them like it should. */
1541 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1542 SilcServerQuery query,
1543 SilcClientEntry client_entry)
1545 SilcBuffer buffer = NULL;
1546 SilcAttribute attribute;
1547 SilcAttributePayload attr;
1548 SilcAttributeObjPk pk;
1549 SilcAttributeObjService service;
1551 unsigned char sign[2048];
1552 SilcUInt32 sign_len;
1554 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1556 /* Go through all requested attributes */
1557 silc_dlist_start(query->attrs);
1558 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1559 attribute = silc_attribute_get_attribute(attr);
1560 switch (attribute) {
1562 case SILC_ATTRIBUTE_SERVICE:
1563 /* Put SERVICE. Put only SILC service. */
1564 memset(&service, 0, sizeof(service));
1565 service.port = (server->config->server_info->primary ?
1566 server->config->server_info->primary->port : SILC_PORT);
1567 silc_strncat(service.address, sizeof(service.address),
1568 server->server_name, strlen(server->server_name));
1569 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1570 buffer = silc_attribute_payload_encode(buffer, attribute,
1571 SILC_ATTRIBUTE_FLAG_VALID,
1572 &service, sizeof(service));
1577 case SILC_ATTRIBUTE_STATUS_MOOD:
1578 /* Put STATUS_MOOD */
1579 buffer = silc_attribute_payload_encode(buffer, attribute,
1580 SILC_ATTRIBUTE_FLAG_VALID,
1582 SILC_ATTRIBUTE_MOOD_NORMAL,
1583 sizeof(SilcUInt32));
1588 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1589 /* Put STATUS_FREETEXT. We just tell in the message that we are
1590 replying on behalf of the client. */
1592 "This information was provided by the server on behalf of the user";
1593 buffer = silc_attribute_payload_encode(buffer, attribute,
1594 SILC_ATTRIBUTE_FLAG_VALID,
1600 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1601 /* Put PREFERRED_CONTACT */
1602 buffer = silc_attribute_payload_encode(buffer, attribute,
1603 SILC_ATTRIBUTE_FLAG_VALID,
1605 SILC_ATTRIBUTE_CONTACT_CHAT,
1606 sizeof(SilcUInt32));
1611 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1612 /* Put USER_PUBLIC_KEY */
1613 if (client_entry->data.public_key) {
1614 pk.type = "silc-rsa";
1615 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1617 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1618 SILC_ATTRIBUTE_FLAG_VALID :
1619 SILC_ATTRIBUTE_FLAG_INVALID,
1627 /* No public key available */
1628 buffer = silc_attribute_payload_encode(buffer, attribute,
1629 SILC_ATTRIBUTE_FLAG_INVALID,
1636 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1637 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1638 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1641 /* For other attributes we cannot reply so mark it invalid */
1642 buffer = silc_attribute_payload_encode(buffer, attribute,
1643 SILC_ATTRIBUTE_FLAG_INVALID,
1651 /* Always put our public key. This assures that we send at least
1652 something valid back always. */
1653 pk.type = "silc-rsa";
1654 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1655 buffer = silc_attribute_payload_encode(buffer,
1656 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1657 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1658 SILC_ATTRIBUTE_FLAG_INVALID,
1664 /* Finally compute the digital signature of all the data we provided
1665 as an indication that we provided rightfull information, and this
1666 also authenticates our public key. */
1667 if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
1668 silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1669 buffer->data, buffer->len,
1673 pk.data_len = sign_len;
1675 silc_attribute_payload_encode(buffer,
1676 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1677 SILC_ATTRIBUTE_FLAG_VALID,
1686 /* Find client by the Client ID indicated by the `client_id', and if not
1687 found then query it by using WHOIS command. The client information
1688 is also resolved if the cached information is incomplete or if the
1689 `always_resolve' is set to TRUE. The indication whether requested
1690 client was being resolved is saved into `resolved'. If the client
1691 is not being resolved its entry is returned by this function. NULL
1692 is returned if client is resolved. */
1694 SilcClientEntry silc_server_query_client(SilcServer server,
1695 const SilcClientID *client_id,
1696 bool always_resolve,
1699 SilcClientEntry client;
1701 SILC_LOG_DEBUG(("Resolving client by client ID"));
1706 client = silc_idlist_find_client_by_id(server->local_list,
1707 (SilcClientID *)client_id,
1710 client = silc_idlist_find_client_by_id(server->global_list,
1711 (SilcClientID *)client_id,
1713 if (!client && server->server_type == SILC_ROUTER)
1717 if (!client && server->standalone)
1720 if (!client || !client->nickname || !client->username ||
1722 SilcBuffer buffer, idp;
1725 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1726 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1727 client->resolve_cmd_ident = ++server->cmd_ident;
1730 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1731 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1732 server->cmd_ident, 1,
1733 4, idp->data, idp->len);
1734 silc_server_packet_send(server, client ? client->router->connection :
1735 SILC_PRIMARY_ROUTE(server),
1736 SILC_PACKET_COMMAND, 0,
1737 buffer->data, buffer->len, FALSE);
1738 silc_buffer_free(idp);
1739 silc_buffer_free(buffer);