5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2006 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 "silcserver.h"
22 #include "server_internal.h"
24 /************************** Types and definitions ***************************/
27 typedef struct SilcServerQueryResolveStruct {
28 struct SilcServerQueryResolveStruct *next;
29 SilcFSMThreadStruct thread; /* FSM thread for waiting reply */
30 SilcServerPending pending; /* Pending command context */
31 SilcPacketStream stream; /* Resolving connection */
32 SilcID *ids; /* Resolved IDs */
33 unsigned int ids_count : 30; /* Number of resolved IDs */
34 unsigned int attached : 1; /* Set if attached to a resolving */
35 unsigned int local : 1; /* Set if client is local to us */
36 } *SilcServerQueryResolve;
38 /* Represents one error occurred during query */
41 unsigned int index : 15; /* Index to IDs */
42 unsigned int type : 2; /* 0 = take from query->ids, 1 = take
43 from args, 2 = no args in error. */
44 unsigned int error : 7; /* The actual error (SilcStatus) */
45 } *SilcServerQueryError;
47 /* Query session context */
50 char *nickname; /* Queried nickname, normalized */
51 char *nick_server; /* Queried nickname's server */
52 char *server_name; /* Queried server name, normalized */
53 char *channel_name; /* Queried channel name, normalized */
54 SilcID *ids; /* Queried IDs */
55 SilcUInt32 ids_count; /* number of queried IDs */
56 SilcUInt32 reply_count; /* Requested reply count */
57 SilcDList attrs; /* Requested Attributes in WHOIS */
58 SilcFSMEventStruct wait_resolve; /* Resolving signaller */
60 /* Query session data */
61 SilcServerComman cmd; /* Command context for query */
62 SilcList clients; /* Found clients */
63 SilcList servers; /* Found servers */
64 SilcList channels; /* Found channels */
65 SilcList resolve; /* Clients to resolve */
66 SilcList resolvings; /* Ongoing resolvings */
67 SilcServerQueryError errors; /* Query errors */
68 SilcServerPending redirect; /* Pending redirect */
69 SilcUInt16 errors_count; /* number of errors */
70 SilcUInt8 resolve_retry; /* Resolving retry count */
71 SilcCommand querycmd; /* Query command */
75 /************************ Static utility functions **************************/
78 /********************************* WHOIS ************************************/
80 SILC_FSM_STATE(silc_server_st_query_whois)
82 SilcServerThread thread = fsm_context;
83 SilcServer server = thread->server;
84 SilcServerCommand cmd = state_context;
85 SilcArgumentPayload args = silc_command_get_args(cmd->payload);
86 SilcServerQuery query;
88 SILC_LOG_DEBUG(("WHOIS query"));
90 query = silc_calloc(1, sizeof(*query));
92 silc_server_command_free(cmd);
96 query->querycmd = SILC_COMMAND_WHOIS;
99 silc_fsm_set_state_context(fsm, query);
101 /* If we are normal server and query contains a nickname OR query
102 doesn't contain nickname or ids BUT does contain user attributes,
103 send it to the router */
104 if (server->server_type != SILC_ROUTER && !server->standalone &&
105 cmd->packet->stream != SILC_PRIMARY_ROUTE(server) &&
106 (silc_argument_get_arg_type(args, 1, NULL) ||
107 (!silc_argument_get_arg_type(args, 1, NULL) &&
108 !silc_argument_get_arg_type(args, 4, NULL) &&
109 silc_argument_get_arg_type(args, 3, NULL)))) {
110 /** Send query to router */
111 silc_fsm_next(fsm, silc_server_st_query_send_router);
115 /** Parse WHOIS query */
116 silc_fsm_next(fsm, silc_server_st_query_parse);
121 /********************************* WHOWAS ***********************************/
123 SILC_FSM_STATE(silc_server_st_query_whowas)
125 SilcServerThread thread = fsm_context;
126 SilcServerCommand cmd = state_context;
128 SILC_LOG_DEBUG(("WHOWAS query"));
130 query = silc_calloc(1, sizeof(*query));
132 silc_server_command_free(cmd);
136 query->querycmd = SILC_COMMAND_WHOWAS;
139 silc_fsm_set_state_context(fsm, query);
141 /* WHOWAS query is always sent to router if we are normal server */
142 if (server->server_type == SILC_SERVER && !server->standalone &&
143 cmd->packet->stream != SILC_PRIMARY_ROUTE(server)) {
144 /** Send query to router */
145 silc_fsm_next(fsm, silc_server_st_query_send_router);
149 /** Parse WHOWAS query */
150 silc_fsm_next(fsm, silc_server_st_query_parse);
155 /******************************** IDENTIFY **********************************/
157 SILC_FSM_STATE(silc_server_st_query_identify)
159 SilcServerThread thread = fsm_context;
160 SilcServerCommand cmd = state_context;
161 SilcArgumentPayload args = silc_command_get_args(cmd->payload);
163 SILC_LOG_DEBUG(("IDENTIFY query"));
165 query = silc_calloc(1, sizeof(*query));
167 silc_server_command_free(cmd);
171 query->querycmd = SILC_COMMAND_IDENTIFY;
174 silc_fsm_set_state_context(fsm, query);
176 /* If we are normal server and query does not contain IDs, send it directly
177 to router (it contains nickname, server name or channel name). */
178 if (server->server_type == SILC_SERVER && !server->standalone &&
179 cmd->packet->stream != SILC_PRIMARY_ROUTE(server) &&
180 !silc_argument_get_arg_type(args, 5, NULL)) {
181 /** Send query to router */
182 silc_fsm_next(fsm, silc_server_st_query_send_router);
186 /** Parse IDENTIFY query */
187 silc_fsm_next(fsm, silc_server_st_query_parse);
192 /**************************** Query redirecting *****************************/
194 /* Send the query to router for further processing */
196 SILC_FSM_STATE(silc_server_st_query_send_router)
198 SilcServerThread thread = fsm_context;
199 SilcServer server = thread->server;
200 SilcServerQuery query = state_context;
202 SilcUInt16 cmd_ident, old_ident;
204 SILC_LOG_DEBUG(("Redirecting query to router"));
206 /* Send the command to our router */
207 cmd_ident = silc_server_cmd_ident(server);
208 old_ident = silc_command_get_ident(query->cmd->payload);
209 silc_command_set_ident(query->cmd->payload, cmd_ident);
211 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
212 if (!tmpbuf || !silc_packet_send(SILC_PRIMARY_ROUTE(server),
213 SILC_PACKET_COMMAND, 0,
214 tmpbuf->data, silc_buffer_len(tmpbuf))) {
215 /** Error sending packet */
216 silc_server_query_send_error(server, query,
217 SILC_STATUS_ERR_RESOURCE_LIMIT, 0);
218 silc_fsm_next(fsm, silc_server_st_query_error);
222 silc_command_set_ident(query->cmd->payload, old_ident);
223 silc_buffer_free(tmpbuf);
226 server->stat.commands_sent++;
228 /* Continue parsing the query after receiving reply from router */
229 query->redirect = silc_server_command_pending(thread, query->redirect_ident);
230 if (!query->redirect) {
232 silc_server_query_send_error(server, query,
233 SILC_STATUS_ERR_RESOURCE_LIMIT, 0);
234 silc_fsm_next(fsm, silc_server_st_query_error);
238 /** Wait router reply */
239 query->resolved = TRUE;
240 silc_fsm_next(fsm, silc_server_st_query_router_reply)
244 /* Wait for router reply and process the reply when it arrives. */
246 SILC_FSM_STATE(silc_server_st_query_router_reply)
248 SilcServerThread thread = fsm_context;
249 SilcServer server = thread->server;
250 SilcServerQuery query = state_context;
251 SilcServerPending pending = query->redirect;
254 /* Wait here for the reply */
255 SILC_FSM_EVENT_TIMEDWAIT(&pending->wait_reply, 10, 0, &timedout);
258 /** Timeout waiting reply */
259 silc_server_command_pending_free(thread, pending);
260 silc_server_query_send_error(server, query, SILC_STATUS_ERR_TIMEDOUT, 0);
261 silc_fsm_next(fsm, silc_server_st_query_error);
265 /* Check if the query failed */
266 if (!silc_command_get_status(pending->reply->payload, NULL, NULL)) {
269 SILC_LOG_DEBUG(("Sending error to original query"));
271 /* Send the same command reply payload which contains the error */
272 silc_command_set_command(pending->reply->payload, query->querycmd);
273 silc_command_set_ident(pending->reply->payload,
274 silc_command_get_ident(query->cmd->payload));
275 buffer = silc_command_payload_encode_payload(pending->reply->payload);
277 silc_packet_send(query->cmd->packet->stream,
278 SILC_PACKET_COMMAND_REPLY, 0,
279 buffer->data, silc_buffer_len(buffer));
280 silc_buffer_free(buffer);
283 server->stat.commands_sent++;
285 /** Query error received */
286 silc_server_command_pending_free(thread, pending);
287 silc_fsm_next(fsm, silc_server_st_query_error);
291 silc_server_command_pending_free(thread, pending);
293 /** Parse query command */
294 silc_fsm_next(fsm, silc_server_st_query_parse);
298 /***************************** Query processing *****************************/
300 /* Parse the command query */
302 SILC_FSM_STATE(silc_server_st_query_parse)
304 SilcServerThread thread = fsm_context;
305 SilcServerQuery query = state_context;
306 SilcServerCommand cmd = query->cmd;
307 SilcArgumentPayload args = silc_command_get_args(cmd->payload);
308 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(args);
313 SILC_LOG_DEBUG(("Parsing %s query",
314 silc_get_command_name(query->querycmd)));
316 switch (query->querycmd) {
318 case SILC_COMMAND_WHOIS:
319 /* Get requested attributes if set */
320 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
321 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN)
322 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
324 /* Get Client IDs if present. Take IDs always instead of nickname. */
325 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
330 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
331 if (!tmp && !query->attrs) {
332 /* No nickname, no ids and no attributes - send error */
333 silc_server_query_send_error(server, query,
334 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
336 /** Not enough arguments */
337 silc_fsm_next(fsm, silc_server_st_query_error);
341 /* Get the nickname@server string and parse it */
342 if (tmp && ((tmp_len > 128) ||
343 !silc_parse_userfqdn(tmp, &query->nickname,
344 &query->nick_server))) {
346 silc_server_query_send_error(server, query,
347 SILC_STATUS_ERR_BAD_NICKNAME, 0);
348 silc_fsm_next(fsm, silc_server_st_query_error);
354 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
355 SILC_STRING_UTF8, 128, &tmp_len);
358 silc_server_query_send_error(server, query,
359 SILC_STATUS_ERR_BAD_NICKNAME, 0);
360 silc_fsm_next(fsm, silc_server_st_query_error);
363 /* XXX why free nickname */
364 silc_free(query->nickname);
365 query->nickname = tmp;
369 /* Parse the IDs included in the query */
370 query->ids = silc_calloc(argc - 3, sizeof(*query->ids));
373 silc_server_query_send_error(server, query,
374 SILC_STATUS_ERR_RESOURCE_LIMIT, 0);
375 silc_fsm_next(fsm, silc_server_st_query_error);
379 for (i = 0; i < argc - 3; i++) {
380 tmp = silc_argument_get_arg_type(args, i + 4, &tmp_len);
384 if (!silc_id_payload_parse_id(tmp, tmp_len, &id) ||
385 id.type != SILC_ID_CLIENT) {
386 silc_server_query_add_error(server, query, 1, i + 4,
387 SILC_STATUS_ERR_BAD_CLIENT_ID);
391 /* Normal server must check whether this ID exist, and if not then
392 send the query to router, unless done so already */
393 if (server->server_type == SILC_SERVER && !query->resolved &&
394 !silc_server_find_client_by_id(server, &client_id, TRUE, NULL)) {
395 /** Send query to router */
396 silc_free(query->ids);
398 query->ids_count = 0;
399 silc_fsm_next(fsm, silc_server_st_query_send_router);
403 query->ids[query->ids_count] = id;
408 /* Get the max count of reply messages allowed */
409 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
410 if (tmp && tmp_len == sizeof(SilcUInt32))
411 SILC_GET32_MSB(query->reply_count, tmp);
414 case SILC_COMMAND_WHOWAS:
416 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
418 /** Not enough arguments */
419 silc_server_query_send_error(server, query,
420 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
421 silc_fsm_next(fsm, silc_server_st_query_error);
425 /* Get the nickname@server string and parse it */
427 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
429 silc_server_query_send_error(server, query,
430 SILC_STATUS_ERR_BAD_NICKNAME, 0);
431 silc_fsm_next(fsm, silc_server_st_query_error);
436 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
437 SILC_STRING_UTF8, 128, &tmp_len);
440 silc_server_query_send_error(server, query,
441 SILC_STATUS_ERR_BAD_NICKNAME, 0);
442 silc_fsm_next(fsm, silc_server_st_query_error);
445 /* XXX why free nickname */
446 silc_free(query->nickname);
447 query->nickname = tmp;
449 /* Get the max count of reply messages allowed */
450 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
451 if (tmp && tmp_len == sizeof(SilcUInt32))
452 SILC_GET32_MSB(query->reply_count, tmp);
455 case SILC_COMMAND_IDENTIFY:
456 /* Get IDs if present. Take IDs always instead of names. */
457 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
461 /* Try get nickname */
462 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
464 /* Get the nickname@server string and parse it */
466 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
467 silc_server_query_add_error(server, query, 1, 1,
468 SILC_STATUS_ERR_BAD_NICKNAME);
471 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
472 SILC_STRING_UTF8, 128, &tmp_len);
475 silc_server_query_send_error(server, query,
476 SILC_STATUS_ERR_BAD_NICKNAME, 0);
477 silc_fsm_next(fsm, silc_server_st_query_error);
480 /* XXX why free nickname */
481 silc_free(query->nickname);
482 query->nickname = tmp;
485 /* Try get server name */
486 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
488 /* Check server name */
489 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
492 /** Bad server name */
493 silc_server_query_send_error(server, query,
494 SILC_STATUS_ERR_BAD_SERVER, 0);
495 silc_fsm_next(fsm, silc_server_st_query_error);
498 query->server_name = tmp;
501 /* Get channel name */
502 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
503 if (tmp && tmp_len <= 256) {
504 /* Check channel name */
505 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
508 /** Bad channel name */
509 silc_server_query_send_error(server, query,
510 SILC_STATUS_ERR_BAD_CHANNEL, 0);
511 silc_fsm_next(fsm, silc_server_st_query_error);
514 query->channel_name = tmp;
517 if (!query->nickname && !query->server_name && !query->channel_name) {
518 /** Nothing was queried */
519 silc_server_query_send_error(server, query,
520 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
521 silc_fsm_next(fsm, silc_server_st_query_error);
526 /* Parse the IDs included in the query */
527 query->ids = silc_calloc(argc - 4, sizeof(*query->ids));
529 for (i = 0; i < argc - 4; i++) {
530 tmp = silc_argument_get_arg_type(args, i + 5, &tmp_len);
534 if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
535 silc_server_query_add_error(server, query, 1, i + 5,
536 SILC_STATUS_ERR_BAD_CLIENT_ID);
540 /* Normal server must check whether this ID exist, and if not then
541 send the query to router, unless done so already */
542 if (server->server_type == SILC_SERVER && !query->resolved) {
543 if (id.type == SILC_ID_CLIENT) {
544 if (!silc_server_find_client_by_id(server, id, TRUE, NULL)) {
545 /** Send query to router */
546 silc_free(query->ids);
548 query->ids_count = 0;
549 silc_fsm_next(fsm, silc_server_st_query_send_router);
553 /* For now all other ID's except Client ID's are explicitly
554 sent to router for resolving. */
556 /** Send query to router */
557 silc_free(query->ids);
559 query->ids_count = 0;
560 silc_fsm_next(fsm, silc_server_st_query_send_router);
565 query->ids[query->ids_count] = id;
570 /* Get the max count of reply messages allowed */
571 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
572 if (tmp && tmp_len == sizeof(SilcUInt32))
573 SILC_GET32_MSB(query->reply_count, tmp);
577 /** Find entries for query */
578 silc_fsm_next(fsm, silc_server_st_query_find);
582 /* Find the entries according to the query */
584 SILC_FSM_STATE(silc_server_st_query_find)
586 SilcServerThread thread = fsm_context;
587 SilcServer server = thread->server;
588 SilcServerQuery query = state_context;
589 SilcServerCommand cmd = query->cmd;
590 SilcIDCacheEntry id_entry;
595 SILC_LOG_DEBUG(("Finding entries with %s query",
596 silc_get_command_name(query->querycmd)));
598 if (query->nickname) {
599 /* Find by nickname */
600 if (!silc_server_find_clients(server, query->nickname, &query->clients))
601 silc_server_query_add_error(server, query, 1, 1,
602 SILC_STATUS_ERR_NO_SUCH_NICK);
605 if (query->server_name) {
606 /* Find server by name */
607 if (!silc_server_find_server_by_name(server, query->server_name, TRUE,
609 silc_server_query_add_error(server, query, 1, 2,
610 SILC_STATUS_ERR_NO_SUCH_SERVER);
612 silc_list_add(query->servers, id_entry);
615 if (query->channel_name) {
616 /* Find channel by name */
617 if (!silc_server_find_channel_by_name(server, query->channel_name,
619 silc_server_query_add_error(server, query, 1, 3,
620 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
622 silc_list_add(query->channels, id_entry);
625 if (query->ids_count) {
626 /* Find entries by the queried IDs */
627 for (i = 0; i < query->ids_count; i++) {
633 /* Get client entry */
634 if (!silc_server_find_client_by_id(server, &id->u.client_id, TRUE,
636 silc_server_query_add_error(server, query, 0, i,
637 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
641 silc_list_add(query->clients, id_entry);
645 /* Get server entry */
646 if (!silc_server_find_server_by_id(server, &id->u.server_id, TRUE,
648 silc_server_query_add_error(server, query, 0, i,
649 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
653 silc_list_add(query->servers, id_entry);
656 case SILC_ID_CHANNEL:
657 /* Get channel entry */
658 if (!silc_server_find_channel_by_id(server, &id->u.channel_id,
660 silc_server_query_add_error(server, query, 0, i,
661 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
665 silc_list_add(query->channels, id_entry);
674 /* Check the attributes to narrow down the search by using them. */
676 /** Check user attributes */
677 silc_fsm_next(fsm, silc_server_st_query_check_attrs);
681 /** Process found entries */
682 silc_fsm_next(fsm, silc_server_st_query_process);
686 /* Check user attributes to narrow down clients in WHOIS query */
688 SILC_FSM_STATE(silc_server_st_query_check_attrs)
691 /** Proecss found entries */
692 silc_fsm_next(fsm, silc_server_st_query_process);
696 /* Process found entries */
698 SILC_FSM_STATE(silc_server_st_query_process)
700 SilcServerThread thread = fsm_context;
701 SilcServer server = thread->server;
702 SilcServerQuery query = state_context;
703 SilcServerCommand cmd = query->cmd;
704 SilcServerQueryResolve res;
705 SilcIDCacheEntry id_entry;
706 SilcClientEntry client_entry;
707 SilcServerEntry server_entry;
708 SilcChannelEntry channel_entry;
713 SILC_LOG_DEBUG(("Process %s query",
714 silc_get_command_name(query->querycmd)));
716 SILC_LOG_DEBUG(("Querying %d clients", silc_list_count(query->clients)));
717 SILC_LOG_DEBUG(("Querying %d servers", silc_list_count(query->servers)));
718 SILC_LOG_DEBUG(("Querying %d channels", silc_list_count(query->channels)));
720 /* If nothing was found, then just send the errors */
721 if (!silc_list_count(query->clients) &&
722 !silc_list_count(query->channels) &&
723 !silc_list_count(query->servers)) {
724 /** Nothing found, send errors */
725 silc_fsm_next(fsm, silc_server_st_query_reply);
730 /* If caller does not want us to resolve anything (has resolved already)
731 then just continue with sending the reply */
733 silc_server_query_send_reply(server, query, clients, clients_count,
734 servers, servers_count, channels,
743 /* Now process all found information and if necessary do some more
745 switch (query->querycmd) {
747 case SILC_COMMAND_WHOIS:
748 silc_list_start(query->clients);
749 while ((id_entry = silc_list_get(query->clients)) != SILC_LIST_END) {
750 client_entry = id_entry->context;
752 /* Ignore unregistered clients */
753 if (!SILC_IS_REGISTERED(client_entry)) {
754 silc_list_del(query->clients, id_entry);
758 /* If Requested Attributes is set then we always resolve the client
759 information, if not then check whether the entry is complete or not
760 and decide whether we need to resolve the missing information. */
763 /* Even if nickname and stuff are present, we may need to resolve
764 the entry on normal server. */
765 if (client_entry->nickname && client_entry->username &&
766 client_entry->userinfo) {
768 /* If we are router, client is local to us, or client is on channel
769 we do not need to resolve the client information. */
770 if (server->server_type != SILC_SERVER ||
771 SILC_IS_LOCAL(client_entry)||
772 silc_hash_table_count(client_entry->channels) ||
778 /* Remove the NOATTR status periodically */
779 if (client_entry->data.noattr &&
780 client_entry->updated + 600 < time(NULL))
781 client_entry->data.noattr = FALSE;
783 /* When requested attributes is present and local client is detached
784 we cannot send the command to the client, we'll reply on behalf of
785 the client instead. */
786 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
787 (client_entry->mode & SILC_UMODE_DETACHED ||
788 client_entry->data.noattr))
792 /* If attributes are present in query, and in the entry and we have
793 done resolvings already we don't need to resolve anymore */
794 if (query->resolved && query->attrs && client_entry->attrs)
798 /* Mark this entry to be resolved */
799 silc_list_add(query->resolve, id_entry);
803 case SILC_COMMAND_WHOWAS:
804 silc_list_start(query->clients);
805 while ((id_entry = silc_list_get(query->clients)) != SILC_LIST_END) {
806 client_entry = id_entry->context;
808 /* Take only unregistered clients */
809 if (SILC_IS_REGISTERED(client_entry)) {
810 silc_list_del(query->clients, id_entry);
814 /* If both nickname and username are present no resolving is needed */
815 if (client_entry->nickname && client_entry->username)
818 /* Mark this entry to be resolved */
819 silc_list_add(query->resolve, id_entry);
823 case SILC_COMMAND_IDENTIFY:
824 silc_list_start(query->clients);
825 while ((id_entry = silc_list_get(query->clients)) != SILC_LIST_END) {
826 client_entry = id_entry->context;
828 /* Ignore unregistered clients */
829 if (!SILC_IS_REGISTERED(client_entry))
832 /* Even if nickname is present, we may need to resolve the entry
834 if (client_entry->nickname) {
836 /* If we are router, client is local to us, or client is on channel
837 we do not need to resolve the client information. */
838 if (server->server_type != SILC_SERVER ||
839 SILC_IS_LOCAL(client_entry)||
840 silc_hash_table_count(client_entry->channels) ||
845 /* Mark this entry to be resolved */
846 silc_list_add(query->resolve, id_entry);
851 /* If we need to resolve entries, do it now */
852 if (silc_list_count(query->resolve)) {
853 /** Resolve entries */
854 silc_fsm_next(fsm, silc_server_st_query_resolve);
858 /** Send reply to query */
859 silc_fsm_next(fsm, silc_server_st_query_reply);
863 /* Resolve incomplete client entries. Other types of entries need not
866 SILC_FSM_STATE(silc_server_st_query_resolve)
868 SilcServerThread thread = fsm_context;
869 SilcServer server = thread->server;
870 SilcServerQuery query = state_context;
871 SilcArgumentPayload cmd_args = silc_command_get_args(query->cmd->payload);
872 SilcServerQueryResolve res;
873 SilcIDCacheEntry id_entry;
874 unsigned char args[256][28];
875 SilcUInt32 arg_lens[256], arg_types[256], argc = 0;
879 SILC_LOG_DEBUG(("Resolve incomplete entries"));
881 silc_list_start(query->resolve);
882 while ((id_entry = silc_list_get(query->resolve)) != SILC_LIST_END) {
883 client_entry = id_entry->context;
885 /* If entry is being resolved, attach to that resolving */
886 if (client_entry->data.resolving) {
887 res = silc_calloc(1, sizeof(*res));
891 silc_fsm_thread_init(&res->thread, fsm, res, NULL, NULL, FALSE);
892 res->stream = client_entry->stream;
895 silc_server_command_pending(thread, client_entry->resolve_cmd_ident);
897 SILC_LOG_ERROR(("BUG: No pending command for resolving client entry"));
901 res->attached = TRUE;
902 silc_list_add(query->resolvings, res);
906 /* Check if we have resolving destination already set */
907 silc_list_start(query->resolvings);
908 while ((res = silc_list_get(query->resolvings)) != SILC_LIST_END)
909 if (res->stream == client_entry->stream && !res->attached)
913 /* Create new resolving context */
914 res = silc_calloc(1, sizeof(*res));
918 silc_fsm_thread_init(&res->thread, fsm, res, NULL, NULL, FALSE);
919 res->stream = client_entry->stream;
922 silc_server_command_pending(thread, silc_server_cmd_ident(server));
926 silc_list_add(query->resolvings, res);
929 /* Mark the entry as being resolved */
930 client_entry->data.resolving = TRUE;
931 client_entry->data.resolved = FALSE;
932 client_entry->resolve_cmd_ident = res->pending->cmd_ident;
933 client_entry->updated = time(NULL);
935 if (SILC_IS_LOCAL(client_entry))
938 switch (query->querycmd) {
939 case SILC_COMMAND_WHOIS:
940 case SILC_COMMAND_IDENTIFY:
941 res->ids = silc_realloc(res->ids, sizeof(*res->ids) *
942 (res->ids_count + 1));
946 res->ids[res->ids_count++].u.client_id = client_entry->id;
949 case SILC_COMMAND_WHOWAS:
954 SILC_LOG_DEBUG(("Sending the resolvings"));
956 /* Send the resolvings */
957 silc_list_start(query->resolvings);
958 while ((res = silc_list_get(query->resolvings)) != SILC_LIST_END) {
960 if (!res->attached) {
962 switch (query->querycmd) {
963 case SILC_COMMAND_WHOIS:
964 case SILC_COMMAND_IDENTIFY:
966 /* If Requested Attributes were present put them to this resolving */
967 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
969 args[argc] = silc_argument_get_arg_type(cmd_args, 3,
975 for (i = 0; i < res->ids_count; i++) {
976 arg_types[argc] = (query->querycmd == SILC_COMMAND_WHOIS ?
978 silc_id_id2str(&res->ids[argc].u.client_id, SILC_ID_CLIENT,
979 args[argc], sizeof(args[argc]), &arg_lens[argc]);
985 /* Send the command */
986 res_cmd = silc_command_payload_encode(query->querycmd, argc,
987 args, arg_lens, arg_types,
988 res->pending->cmd_ident);
991 silc_server_query_send_error(server, query,
992 SILC_STATUS_ERR_RESOURCE_LIMIT, 0);
993 silc_fsm_next(fsm, silc_server_st_query_error);
997 silc_packet_send(res->stream, SILC_PACKET_COMMAND, 0,
998 res_cmd->data, silc_buffer_send(res_cmd));
999 silc_buffer_free(res_cmd);
1000 silc_free(res->ids);
1004 server->stat.commands_sent++;
1007 case SILC_COMMAND_WHOWAS:
1008 /* Send WHOWAS command */
1009 silc_server_send_command(server, res->stream, query->querycmd,
1010 res->pending->cmd_ident, 1,
1011 1, query->nickname, strlen(query->nickname));
1017 silc_fsm_set_state_context(&res->thread, query);
1018 silc_fsm_start_sync(&res->thread, silc_server_st_query_wait_resolve);
1021 /** Wait all resolvings */
1022 silc_fsm_next(fsm, silc_server_st_query_resolved);
1026 /* Wait for resolving command reply */
1028 SILC_FSM_STATE(silc_server_st_query_wait_resolve)
1030 SilcServerQueryResolve res = fsm_context;
1031 SilcServerQuery query = state_context;
1034 /* Wait here for the reply */
1035 SILC_FSM_EVENT_TIMEDWAIT(&res->pending->wait_reply,
1036 res->local ? 3 : 10, 0, &timedout);
1040 silc_list_del(query->resolvings, res);
1041 silc_server_command_pending_free(res->pending);
1044 /* Signal main thread that reply was received */
1045 SILC_FSM_EVENT_SIGNAL(&query->wait_resolve);
1050 /* Wait here that all resolvings has been received */
1052 SILC_FSM_STATE(silc_server_st_query_resolved)
1054 SilcServerThread thread = fsm_context;
1055 SilcServer server = thread->server;
1056 SilcServerQuery query = state_context;
1057 SilcServerCommand cmd = query->cmd;
1059 /* Wait here until all resolvings has arrived */
1060 SILC_FSM_EVENT_WAIT(&query->wait_resolve);
1061 if (silc_list_count(query->resolvings) > 0)
1066 /* Send the reply to the query. */
1068 SILC_FSM_STATE(silc_server_st_query_reply)
1070 SilcServerThread thread = fsm_context;
1071 SilcServer server = thread->server;
1072 SilcServerQuery query = state_context;
1073 SilcServerCommand cmd = query->cmd;
1074 SilcIDCacheEntry id_entry;