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);
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 (!silc_idlist_find_client_by_id(server->local_list,
519 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
520 !silc_idlist_find_client_by_id(server->global_list,
522 silc_server_query_send_router(server, query);
523 for (i = 0; i < query->ids_count; i++)
524 silc_free(query->ids[i].id);
525 silc_free(query->ids);
532 query->ids[query->ids_count].id = id;
533 query->ids[query->ids_count].id_type = id_type;
538 /* Get the max count of reply messages allowed */
539 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
540 if (tmp && tmp_len == sizeof(SilcUInt32))
541 SILC_GET32_MSB(query->reply_count, tmp);
545 /* Start processing the query information */
546 silc_server_query_process(server, query, TRUE);
549 /* Processes the parsed query. This does the actual finding of the
550 queried information and prepares for sending reply to the original
551 sender of the query command. */
553 void silc_server_query_process(SilcServer server, SilcServerQuery query,
556 SilcServerCommandContext cmd = query->cmd;
557 bool check_global = FALSE;
559 SilcClientEntry *clients = NULL, client_entry;
560 SilcChannelEntry *channels = NULL;
561 SilcServerEntry *servers = NULL;
562 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
565 SILC_LOG_DEBUG(("Processing %s query",
566 silc_get_command_name(query->querycmd)));
568 /* Check global lists if query is coming from client or we are not
569 normal server (we know global information). */
570 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
572 else if (server->server_type != SILC_SERVER)
575 if (query->nickname) {
576 /* Get all clients matching nickname from local list */
577 if (!silc_idlist_get_clients_by_hash(server->local_list,
578 query->nickname, server->md5hash,
579 &clients, &clients_count))
580 silc_idlist_get_clients_by_nickname(server->local_list,
583 &clients, &clients_count);
585 /* Check global list as well */
587 if (!silc_idlist_get_clients_by_hash(server->global_list,
588 query->nickname, server->md5hash,
589 &clients, &clients_count))
590 silc_idlist_get_clients_by_nickname(server->global_list,
593 &clients, &clients_count);
597 silc_server_query_add_error(server, query, TRUE, 1,
598 SILC_STATUS_ERR_NO_SUCH_NICK);
601 if (query->server_name) {
602 /* Find server by name */
603 entry = silc_idlist_find_server_by_name(server->local_list,
604 query->server_name, TRUE, NULL);
605 if (!entry && check_global)
606 entry = silc_idlist_find_server_by_name(server->global_list,
607 query->server_name, TRUE, NULL);
609 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
610 servers[servers_count++] = (SilcServerEntry)entry;
614 silc_server_query_add_error(server, query, TRUE, 2,
615 SILC_STATUS_ERR_NO_SUCH_SERVER);
618 if (query->channel_name) {
619 /* Find channel by name */
620 entry = silc_idlist_find_channel_by_name(server->local_list,
621 query->channel_name, NULL);
622 if (!entry && check_global)
623 entry = silc_idlist_find_channel_by_name(server->global_list,
624 query->channel_name, NULL);
626 channels = silc_realloc(channels, sizeof(*channels) *
627 (channels_count + 1));
628 channels[channels_count++] = (SilcChannelEntry)entry;
632 silc_server_query_add_error(server, query, TRUE, 3,
633 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
636 if (query->ids_count) {
637 /* Find entries by the queried IDs */
638 for (i = 0; i < query->ids_count; i++) {
639 void *id = query->ids[i].id;
643 switch (query->ids[i].id_type) {
646 /* Get client entry */
647 entry = silc_idlist_find_client_by_id(server->local_list,
649 if (!entry && check_global)
650 entry = silc_idlist_find_client_by_id(server->global_list,
653 silc_server_query_add_error(server, query, FALSE, i,
654 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
658 clients = silc_realloc(clients, sizeof(*clients) *
659 (clients_count + 1));
660 clients[clients_count++] = (SilcClientEntry)entry;
664 /* Get server entry */
665 entry = silc_idlist_find_server_by_id(server->local_list,
667 if (!entry && check_global)
668 entry = silc_idlist_find_server_by_id(server->global_list,
671 silc_server_query_add_error(server, query, FALSE, i,
672 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
676 servers = silc_realloc(servers, sizeof(*servers) *
677 (servers_count + 1));
678 servers[servers_count++] = (SilcServerEntry)entry;
681 case SILC_ID_CHANNEL:
682 /* Get channel entry */
683 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
684 if (!entry && check_global)
685 entry = silc_idlist_find_channel_by_id(server->global_list, id,
688 silc_server_query_add_error(server, query, FALSE, i,
689 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
693 channels = silc_realloc(channels, sizeof(*channels) *
694 (channels_count + 1));
695 channels[channels_count++] = (SilcChannelEntry)entry;
704 /* If nothing was found, then just send the errors */
705 if (!clients && !channels && !servers) {
706 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
710 /* If caller does not want us to resolve anything (has resolved already)
711 then just continue with sending the reply */
713 silc_server_query_send_reply(server, query, clients, clients_count,
714 servers, servers_count, channels,
722 /* Now process all found information and if necessary do some more
724 switch (query->querycmd) {
726 case SILC_COMMAND_WHOIS:
727 for (i = 0; i < clients_count; i++) {
728 client_entry = clients[i];
730 /* Check if cannot query this anyway, so take next one */
732 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
735 /* If Requested Attributes is set then we always resolve the client
736 information, if not then check whether the entry is complete or not
737 and decide whether we need to resolve or not. */
740 /* Even if nickname and stuff are present, we may need to resolve
742 if (client_entry->nickname && client_entry->username &&
743 client_entry->userinfo) {
744 /* Check if cannot query this anyway, so take next one */
745 if (!client_entry->router)
748 /* If we are router, client is local to us, or client is on channel
749 we do not need to resolve the client information. */
750 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
751 || silc_hash_table_count(client_entry->channels) ||
757 /* Remove the NOATTR status periodically */
758 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
759 client_entry->updated + 600 < time(NULL))
760 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
762 /* When requested attributes is present and local client is detached
763 we cannot send the command to the client, we'll reply on behalf of
764 the client instead. */
765 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
766 (client_entry->mode & SILC_UMODE_DETACHED ||
767 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
770 /* Resolve the detailed client information. If client is local we
771 know that attributes were present and we will resolve directly
772 from the client. Otherwise resolve from client's owner. */
773 silc_server_query_resolve(server, query,
774 (SILC_IS_LOCAL(client_entry) ?
775 client_entry->connection :
776 client_entry->router->connection),
781 case SILC_COMMAND_WHOWAS:
782 for (i = 0; i < clients_count; i++) {
783 client_entry = clients[i];
785 /* Check if cannot query this anyway, so take next one */
786 if (!client_entry || !client_entry->router ||
787 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
790 /* If both nickname and username are present no resolving is needed */
791 if (client_entry->nickname && client_entry->username)
794 /* Resolve the detailed client information */
795 silc_server_query_resolve(server, query,
796 client_entry->router->connection,
801 case SILC_COMMAND_IDENTIFY:
802 for (i = 0; i < clients_count; i++) {
803 client_entry = clients[i];
805 /* Check if cannot query this anyway, so take next one */
806 if (!client_entry || !client_entry->router ||
807 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
810 /* Even if nickname is present, we may need to resolve the entry */
811 if (client_entry->nickname) {
813 /* If we are router, client is local to us, or client is on channel
814 we do not need to resolve the client information. */
815 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
816 || silc_hash_table_count(client_entry->channels) ||
821 /* Resolve the detailed client information */
822 silc_server_query_resolve(server, query,
823 client_entry->router->connection,
829 if (!query->queries_count)
830 /* If we didn't have to do any resolving, continue with sending the
831 command reply to the original sender. */
832 silc_server_query_send_reply(server, query, clients, clients_count,
833 servers, servers_count, channels,
836 /* Now actually send the resolvings we gathered earlier */
837 silc_server_query_resolve(server, query, NULL, NULL);
844 /* Resolve the detailed information for the `client_entry'. Only client
845 information needs to be resolved for being incomplete. Each incomplete
846 client entry calls this function to do the resolving. */
848 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
849 SilcSocketConnection sock,
850 SilcClientEntry client_entry)
852 SilcServerCommandContext cmd = query->cmd;
853 SilcServerQueryList r = NULL;
860 if (!sock && client_entry)
863 /* If arguments are NULL we will now actually send the resolvings
864 that earlier has been gathered by calling this function. */
865 if (!sock && !client_entry) {
868 SILC_LOG_DEBUG(("Sending the resolvings"));
870 /* WHOWAS resolving has been done at the same time this function
871 was called to add the resolving for WHOWAS, so just return. */
872 if (query->querycmd == SILC_COMMAND_WHOWAS)
875 for (i = 0; i < query->querylist_count; i++) {
876 r = &query->querylist[i];
878 /* Send WHOIS command */
879 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
880 r->argc, r->arg, r->arg_lens,
881 r->arg_types, r->ident);
882 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
883 res_cmd->data, res_cmd->len, FALSE);
884 silc_buffer_free(res_cmd);
886 /* Reprocess this packet after received reply */
887 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
889 silc_server_query_resolve_reply,
891 query->queries_left++;
894 /* Cleanup this temporary context */
895 for (i = 0; i < query->querylist_count; i++) {
897 for (k = 0; k < query->querylist[i].argc; k++)
898 silc_free(query->querylist[i].arg[k]);
899 silc_free(query->querylist[i].arg);
900 silc_free(query->querylist[i].arg_lens);
901 silc_free(query->querylist[i].arg_types);
903 silc_free(query->querylist);
904 query->querylist = NULL;
905 query->querylist_count = 0;
909 SILC_LOG_DEBUG(("Resolving client information"));
911 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
912 /* The entry is being resolved by some other external query already.
913 Attach to that query instead of resolving again. */
914 ident = client_entry->resolve_cmd_ident;
915 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
916 silc_server_query_resolve_reply, query))
917 query->queries_left++;
919 /* This entry will be resolved */
920 ident = ++server->cmd_ident;
922 switch (query->querycmd) {
924 case SILC_COMMAND_WHOIS:
925 case SILC_COMMAND_IDENTIFY:
926 /* Take existing query context if exist for this connection */
927 for (i = 0; i < query->queries_count; i++)
928 if (query->querylist[i].sock == sock) {
929 r = &query->querylist[i];
934 /* Allocate new temp query list context */
935 query->querylist = silc_realloc(query->querylist,
936 sizeof(*query->querylist) *
937 (query->querylist_count + 1));
938 r = &query->querylist[query->querylist_count];
939 query->querylist_count++;
940 memset(r, 0, sizeof(*r));
943 if (SILC_IS_LOCAL(client_entry))
947 /* If Requested Attributes were present put them to this resolving */
948 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
950 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
951 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
952 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
954 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
956 r->arg[r->argc] = silc_memdup(tmp, len);
957 r->arg_lens[r->argc] = len;
958 r->arg_types[r->argc] = 3;
963 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
964 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
965 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
967 /* Add the client entry to be resolved */
968 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
969 r->arg[r->argc] = silc_memdup(idp->data, idp->len);
970 r->arg_lens[r->argc] = idp->len;
971 r->arg_types[r->argc] = r->argc + 4;
973 silc_buffer_free(idp);
977 case SILC_COMMAND_WHOWAS:
978 /* We must send WHOWAS command since it's the only the way of
979 resolving clients that are not present in the network anymore. */
980 silc_server_send_command(server, sock, query->querycmd, ident, 1,
981 1, query->nickname, strlen(query->nickname));
982 if (silc_server_command_pending(server, query->querycmd, ident,
983 silc_server_query_resolve_reply, query))
984 query->queries_left++;
989 /* Mark the entry as being resolved */
990 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
991 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
992 client_entry->resolve_cmd_ident = ident;
993 client_entry->updated = time(NULL);
995 /* Save the queried ID, which we will reprocess after we get this and
996 all other queries back. */
997 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
998 (query->queries_count + 1));
999 if (query->queries) {
1000 i = query->queries_count;
1001 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1002 query->queries[i].id_type = SILC_ID_CLIENT;
1003 query->queries[i].ident = ident;
1004 query->queries_count++;
1008 /* Reply callback called after one resolving has been completed. If
1009 all resolvings has been received then we will continue with sending
1010 the command reply to the original sender of the query. */
1012 void silc_server_query_resolve_reply(void *context, void *reply)
1014 SilcServerQuery query = context;
1015 SilcServer server = query->cmd->server;
1016 SilcServerCommandReplyContext cmdr = reply;
1017 SilcUInt16 ident = cmdr->ident;
1018 SilcStatus error = SILC_STATUS_OK;
1019 SilcServerQueryID id = NULL;
1020 SilcClientEntry client_entry;
1023 /* One less query left */
1024 query->queries_left--;
1026 silc_command_get_status(cmdr->payload, NULL, &error);
1027 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1028 query->queries_left, error));
1030 /* If no error then skip to other stuff */
1031 if (error == SILC_STATUS_OK)
1034 /* Error occurred during resolving */
1036 /* Find the resolved client ID */
1037 for (i = 0; i < query->queries_count; i++) {
1038 if (query->queries[i].ident != ident)
1041 id = &query->queries[i];
1043 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1045 /* If timeout occurred for local entry when resolving attributes
1046 mark that this client doesn't support attributes in WHOIS. This
1047 assures we won't send the request again to the client. */
1048 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1049 client_entry = silc_idlist_find_client_by_id(server->local_list,
1050 id->id, TRUE, NULL);
1051 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1052 silc_id_render(id->id, SILC_ID_CLIENT)));
1053 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1054 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1055 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1060 /* Remove the RESOLVING status from the client entry */
1061 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1062 client_entry = silc_idlist_find_client_by_id(server->local_list,
1063 id->id, TRUE, NULL);
1065 client_entry = silc_idlist_find_client_by_id(server->global_list,
1066 id->id, TRUE, NULL);
1068 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1075 /* If there are queries left then wait for them */
1076 if (query->queries_left)
1079 SILC_LOG_DEBUG(("Reprocess the query"));
1081 /* We have received all queries. Now re-search all information required
1082 to complete this query. Reason we cannot save the values found in
1083 the first search is that SilcClientEntry, SilcServerEntry and
1084 SilcChannelEntry pointers may become invalid while we were waiting
1085 for these resolvings. */
1086 silc_server_query_process(server, query, FALSE);
1089 /* Send the reply to the original query. If arguments are NULL then this
1090 sends only the errors that has occurred during the processing of the
1091 query. This sends the errors always after sending all the found
1092 information. The query is over after this function returns and the
1093 `query' will become invalid. This is called only after all informations
1094 has been resolved. This means that if something is not found or is
1095 incomplete in this function we were unable to resolve the information
1096 or it does not exist at all. */
1098 void silc_server_query_send_reply(SilcServer server,
1099 SilcServerQuery query,
1100 SilcClientEntry *clients,
1101 SilcUInt32 clients_count,
1102 SilcServerEntry *servers,
1103 SilcUInt32 servers_count,
1104 SilcChannelEntry *channels,
1105 SilcUInt32 channels_count)
1107 SilcServerCommandContext cmd = query->cmd;
1108 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1113 int i, k, valid_count;
1114 char nh[256], uh[256];
1115 bool sent_reply = FALSE;
1117 SILC_LOG_DEBUG(("Sending reply to query"));
1119 status = SILC_STATUS_OK;
1122 if (clients_count) {
1123 SilcClientEntry entry;
1124 SilcSocketConnection hsock;
1126 /* Mark all invalid entries */
1127 for (i = 0, valid_count = 0; i < clients_count; i++) {
1129 switch (query->querycmd) {
1130 case SILC_COMMAND_WHOIS:
1131 if (!entry->nickname || !entry->username || !entry->userinfo ||
1132 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1133 /* When querying by ID, every "unfound" entry must cause error */
1135 silc_server_query_add_error_id(server, query,
1136 SILC_STATUS_ERR_TIMEDOUT,
1137 entry->id, SILC_ID_CLIENT);
1143 case SILC_COMMAND_IDENTIFY:
1144 if (!entry->nickname ||
1145 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1146 /* When querying by ID, every "unfound" entry must cause error */
1148 silc_server_query_add_error_id(server, query,
1149 SILC_STATUS_ERR_TIMEDOUT,
1150 entry->id, SILC_ID_CLIENT);
1156 case SILC_COMMAND_WHOWAS:
1157 if (!entry->nickname || !entry->username ||
1158 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1167 /* Start processing found clients */
1168 status = SILC_STATUS_OK;
1169 if (valid_count > 1)
1170 status = SILC_STATUS_LIST_START;
1172 /* Now do the sending of valid entries */
1174 for (i = 0; i < clients_count && valid_count; i++) {
1180 status = SILC_STATUS_LIST_ITEM;
1181 if (valid_count > 1 && k == valid_count - 1
1182 && !servers_count && !channels_count && !query->errors_count)
1183 status = SILC_STATUS_LIST_END;
1184 if (query->reply_count && k - 1 == query->reply_count)
1185 status = SILC_STATUS_LIST_END;
1187 SILC_LOG_DEBUG(("%s: client %s",
1188 (status == SILC_STATUS_OK ? " OK" :
1189 status == SILC_STATUS_LIST_START ? "START" :
1190 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1191 status == SILC_STATUS_LIST_END ? " END" :
1192 " : "), entry->nickname));
1194 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1195 memset(uh, 0, sizeof(uh));
1196 memset(nh, 0, sizeof(nh));
1198 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1199 if (!strchr(entry->nickname, '@')) {
1200 silc_strncat(nh, sizeof(nh), "@", 1);
1201 if (entry->servername) {
1202 silc_strncat(nh, sizeof(nh), entry->servername,
1203 strlen(entry->servername));
1205 len = entry->router ? strlen(entry->router->server_name) :
1206 strlen(server->server_name);
1207 silc_strncat(nh, sizeof(nh), entry->router ?
1208 entry->router->server_name :
1209 server->server_name, len);
1213 switch (query->querycmd) {
1215 case SILC_COMMAND_WHOIS:
1217 unsigned char idle[4], mode[4];
1218 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1219 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1221 memset(fempty, 0, sizeof(fempty));
1222 memset(idle, 0, sizeof(idle));
1223 silc_strncat(uh, sizeof(uh), entry->username,
1224 strlen(entry->username));
1225 if (!strchr(entry->username, '@') && entry->connection) {
1226 hsock = entry->connection;
1227 silc_strncat(uh, sizeof(uh), "@", 1);
1228 len = strlen(hsock->hostname);
1229 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1232 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1234 silc_server_get_client_channel_list(server, entry, FALSE,
1235 FALSE, &umode_list);
1238 silc_server_get_client_channel_list(server, entry, TRUE,
1241 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1242 fingerprint = entry->data.fingerprint;
1246 SILC_PUT32_MSB(entry->mode, mode);
1247 if (entry->connection)
1248 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1250 /* If Requested Attribute were present, and we do not have the
1251 attributes we will reply to them on behalf of the client. */
1254 if (!entry->attrs) {
1255 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1256 entry->attrs = silc_memdup(tmpattrs->data, tmpattrs->len);
1257 entry->attrs_len = tmpattrs->len;
1258 silc_buffer_free(tmpattrs);
1260 attrs = entry->attrs;
1261 len = entry->attrs_len;
1264 /* Send command reply */
1265 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1266 status, 0, ident, 10,
1267 2, idp->data, idp->len,
1271 strlen(entry->userinfo),
1272 6, channels ? channels->data : NULL,
1273 channels ? channels->len : 0,
1277 fingerprint ? 20 : 0,
1278 10, umode_list ? umode_list->data :
1279 NULL, umode_list ? umode_list->len :
1284 /* For now we always delete Requested Attributes, unless the client
1285 is detached, in which case we don't want to reconstruct the
1286 same data everytime */
1287 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1288 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1289 silc_free(entry->attrs);
1290 entry->attrs = NULL;
1294 silc_buffer_free(channels);
1296 silc_buffer_free(umode_list);
1302 case SILC_COMMAND_IDENTIFY:
1303 if (!entry->username) {
1304 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1305 status, 0, ident, 2,
1306 2, idp->data, idp->len,
1310 silc_strncat(uh, sizeof(uh), entry->username,
1311 strlen(entry->username));
1312 if (!strchr(entry->username, '@') && entry->connection) {
1313 hsock = entry->connection;
1314 silc_strncat(uh, sizeof(uh), "@", 1);
1315 len = strlen(hsock->hostname);
1316 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1319 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1320 status, 0, ident, 3,
1321 2, idp->data, idp->len,
1328 case SILC_COMMAND_WHOWAS:
1329 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1330 if (!strchr(entry->username, '@'))
1331 silc_strncat(uh, sizeof(uh), "@*private*", 10);
1333 /* Send command reply */
1334 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1335 status, 0, ident, 4,
1336 2, idp->data, idp->len,
1341 strlen(entry->userinfo) : 0);
1346 silc_buffer_free(idp);
1348 if (status == SILC_STATUS_LIST_END)
1354 /* Not one valid entry was found, send error. If nickname was used
1355 in query send error based on that, otherwise the query->errors
1356 already includes proper errors. */
1357 if (query->nickname)
1358 silc_server_query_add_error(server, query, TRUE, 1,
1359 SILC_STATUS_ERR_NO_SUCH_NICK);
1364 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1365 SilcServerEntry entry;
1367 if (status == SILC_STATUS_OK && servers_count > 1)
1368 status = SILC_STATUS_LIST_START;
1371 for (i = 0; i < servers_count; i++) {
1375 status = SILC_STATUS_LIST_ITEM;
1376 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1377 !query->errors_count)
1378 status = SILC_STATUS_LIST_END;
1379 if (query->reply_count && k - 1 == query->reply_count)
1380 status = SILC_STATUS_LIST_END;
1382 SILC_LOG_DEBUG(("%s: server %s",
1383 (status == SILC_STATUS_OK ? " OK" :
1384 status == SILC_STATUS_LIST_START ? "START" :
1385 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1386 status == SILC_STATUS_LIST_END ? " END" :
1388 entry->server_name ? entry->server_name : ""));
1390 /* Send command reply */
1391 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1392 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1393 status, 0, ident, 2,
1394 2, idp->data, idp->len,
1395 3, entry->server_name,
1396 entry->server_name ?
1397 strlen(entry->server_name) : 0);
1398 silc_buffer_free(idp);
1401 if (status == SILC_STATUS_LIST_END)
1408 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1409 SilcChannelEntry entry;
1411 if (status == SILC_STATUS_OK && channels_count > 1)
1412 status = SILC_STATUS_LIST_START;
1415 for (i = 0; i < channels_count; i++) {
1416 entry = channels[i];
1419 status = SILC_STATUS_LIST_ITEM;
1420 if (channels_count > 1 && k == channels_count - 1 &&
1421 !query->errors_count)
1422 status = SILC_STATUS_LIST_END;
1423 if (query->reply_count && k - 1 == query->reply_count)
1424 status = SILC_STATUS_LIST_END;
1426 SILC_LOG_DEBUG(("%s: channel %s",
1427 (status == SILC_STATUS_OK ? " OK" :
1428 status == SILC_STATUS_LIST_START ? "START" :
1429 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1430 status == SILC_STATUS_LIST_END ? " END" :
1432 entry->channel_name ? entry->channel_name : ""));
1434 /* Send command reply */
1435 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1436 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1437 status, 0, ident, 2,
1438 2, idp->data, idp->len,
1439 3, entry->channel_name,
1440 entry->channel_name ?
1441 strlen(entry->channel_name) : 0);
1442 silc_buffer_free(idp);
1445 if (status == SILC_STATUS_LIST_END)
1452 if (query->errors_count) {
1455 if (status == SILC_STATUS_OK && query->errors_count > 1)
1456 status = SILC_STATUS_LIST_START;
1459 for (i = 0; i < query->errors_count; i++) {
1462 /* Take error argument */
1463 if (query->errors[i].from_cmd) {
1465 tmp = silc_argument_get_arg_type(cmd->args,
1466 query->errors[i].index, &len);
1467 if (query->errors[i].index == 1)
1468 type = 3; /* Nickname */
1471 } else if (!query->errors[i].id) {
1473 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1474 query->ids[query->errors[k].index].id_type);
1479 idp = silc_id_payload_encode(query->errors[i].id,
1480 query->errors[k].id_type);
1487 status = SILC_STATUS_LIST_ITEM;
1488 if (query->errors_count > 1 && k == query->errors_count - 1)
1489 status = SILC_STATUS_LIST_END;
1490 if (query->reply_count && k - 1 == query->reply_count)
1491 status = SILC_STATUS_LIST_END;
1493 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1494 (status == SILC_STATUS_OK ? " OK" :
1495 status == SILC_STATUS_LIST_START ? "START" :
1496 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1497 status == SILC_STATUS_LIST_END ? " END" :
1499 silc_get_status_message(query->errors[i].error),
1500 query->errors[i].error));
1503 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1504 (status == SILC_STATUS_OK ?
1505 query->errors[i].error : status),
1506 (status == SILC_STATUS_OK ?
1507 0 : query->errors[i].error), ident, 1,
1509 silc_buffer_free(idp);
1512 if (status == SILC_STATUS_LIST_END)
1519 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1522 silc_server_query_free(query);
1525 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1526 of the client since we were unable to resolve them from the client.
1527 Either client does not support Requested Attributes or isn't replying
1528 to them like it should. */
1530 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1531 SilcServerQuery query,
1532 SilcClientEntry client_entry)
1534 SilcBuffer buffer = NULL;
1535 SilcAttribute attribute;
1536 SilcAttributePayload attr;
1537 SilcAttributeObjPk pk;
1538 SilcAttributeObjService service;
1540 unsigned char sign[2048];
1541 SilcUInt32 sign_len;
1543 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1545 /* Go through all requested attributes */
1546 silc_dlist_start(query->attrs);
1547 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1548 attribute = silc_attribute_get_attribute(attr);
1549 switch (attribute) {
1551 case SILC_ATTRIBUTE_SERVICE:
1552 /* Put SERVICE. Put only SILC service. */
1553 memset(&service, 0, sizeof(service));
1554 service.port = (server->config->server_info->primary ?
1555 server->config->server_info->primary->port : SILC_PORT);
1556 silc_strncat(service.address, sizeof(service.address),
1557 server->server_name, strlen(server->server_name));
1558 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1559 buffer = silc_attribute_payload_encode(buffer, attribute,
1560 SILC_ATTRIBUTE_FLAG_VALID,
1561 &service, sizeof(service));
1566 case SILC_ATTRIBUTE_STATUS_MOOD:
1567 /* Put STATUS_MOOD */
1568 buffer = silc_attribute_payload_encode(buffer, attribute,
1569 SILC_ATTRIBUTE_FLAG_VALID,
1571 SILC_ATTRIBUTE_MOOD_NORMAL,
1572 sizeof(SilcUInt32));
1577 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1578 /* Put STATUS_FREETEXT. We just tell in the message that we are
1579 replying on behalf of the client. */
1581 "This information was provided by the server on behalf of the user";
1582 buffer = silc_attribute_payload_encode(buffer, attribute,
1583 SILC_ATTRIBUTE_FLAG_VALID,
1589 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1590 /* Put PREFERRED_CONTACT */
1591 buffer = silc_attribute_payload_encode(buffer, attribute,
1592 SILC_ATTRIBUTE_FLAG_VALID,
1594 SILC_ATTRIBUTE_CONTACT_CHAT,
1595 sizeof(SilcUInt32));
1600 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1601 /* Put USER_PUBLIC_KEY */
1602 if (client_entry->data.public_key) {
1603 pk.type = "silc-rsa";
1604 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1606 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1607 SILC_ATTRIBUTE_FLAG_VALID :
1608 SILC_ATTRIBUTE_FLAG_INVALID,
1616 /* No public key available */
1617 buffer = silc_attribute_payload_encode(buffer, attribute,
1618 SILC_ATTRIBUTE_FLAG_INVALID,
1625 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1626 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1627 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1630 /* For other attributes we cannot reply so mark it invalid */
1631 buffer = silc_attribute_payload_encode(buffer, attribute,
1632 SILC_ATTRIBUTE_FLAG_INVALID,
1640 /* Always put our public key. This assures that we send at least
1641 something valid back always. */
1642 pk.type = "silc-rsa";
1643 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1644 buffer = silc_attribute_payload_encode(buffer,
1645 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1646 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1647 SILC_ATTRIBUTE_FLAG_INVALID,
1653 /* Finally compute the digital signature of all the data we provided
1654 as an indication that we provided rightfull information, and this
1655 also authenticates our public key. */
1656 if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
1657 silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1658 buffer->data, buffer->len,
1662 pk.data_len = sign_len;
1664 silc_attribute_payload_encode(buffer,
1665 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1666 SILC_ATTRIBUTE_FLAG_VALID,
1675 /* Find client by the Client ID indicated by the `client_id', and if not
1676 found then query it by using WHOIS command. The client information
1677 is also resolved if the cached information is incomplete or if the
1678 `always_resolve' is set to TRUE. The indication whether requested
1679 client was being resolved is saved into `resolved'. If the client
1680 is not being resolved its entry is returned by this function. NULL
1681 is returned if client is resolved. */
1683 SilcClientEntry silc_server_query_client(SilcServer server,
1684 const SilcClientID *client_id,
1685 bool always_resolve,
1688 SilcClientEntry client;
1690 SILC_LOG_DEBUG(("Resolving client by client ID"));
1695 client = silc_idlist_find_client_by_id(server->local_list,
1696 (SilcClientID *)client_id,
1699 client = silc_idlist_find_client_by_id(server->global_list,
1700 (SilcClientID *)client_id,
1702 if (!client && server->server_type == SILC_ROUTER)
1706 if (!client && server->standalone)
1709 if (!client || !client->nickname || !client->username ||
1711 SilcBuffer buffer, idp;
1714 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1715 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1716 client->resolve_cmd_ident = ++server->cmd_ident;
1719 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1720 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1721 server->cmd_ident, 1,
1722 4, idp->data, idp->len);
1723 silc_server_packet_send(server, client ? client->router->connection :
1724 SILC_PRIMARY_ROUTE(server),
1725 SILC_PACKET_COMMAND, 0,
1726 buffer->data, buffer->len, FALSE);
1727 silc_buffer_free(idp);
1728 silc_buffer_free(buffer);