Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2005 Pekka Riikonen
+ Copyright (C) 1997 - 2006 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
/************************** Types and definitions ***************************/
-#define SILC_SERVER_COMMAND_CHECK(min, max) \
-do { \
- SilcUInt32 _argc; \
- \
- SILC_LOG_DEBUG(("Start")); \
- \
- _argc = silc_argument_get_arg_num(args); \
- if (_argc < min) { \
- SILC_LOG_DEBUG(("Not enough parameters in command")); \
- silc_server_command_send_status_reply(cmd, \
- silc_command_get(cmd->payload), \
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, \
- 0); \
- silc_server_command_free(cmd); \
- return SILC_FSM_FINISH; \
- } \
- if (_argc > max) { \
- SILC_LOG_DEBUG(("Too many parameters in command")); \
- silc_server_command_send_status_reply(cmd, \
- silc_command_get(cmd->payload), \
- SILC_STATUS_ERR_TOO_MANY_PARAMS, \
- 0); \
- silc_server_command_free(cmd); \
- return SILC_FSM_FINISH; \
- } \
+#define SILC_SERVER_COMMAND_CHECK(min, max) \
+do { \
+ SilcUInt32 _argc; \
+ \
+ SILC_LOG_DEBUG(("Start")); \
+ \
+ _argc = silc_argument_get_arg_num(args); \
+ if (_argc < min) { \
+ SILC_LOG_DEBUG(("Not enough parameters in command")); \
+ silc_server_command_status_reply(cmd, \
+ silc_command_get(cmd->payload), \
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, \
+ 0); \
+ silc_server_command_free(cmd); \
+ return SILC_FSM_FINISH; \
+ } \
+ if (_argc > max) { \
+ SILC_LOG_DEBUG(("Too many parameters in command")); \
+ silc_server_command_status_reply(cmd, \
+ silc_command_get(cmd->payload), \
+ SILC_STATUS_ERR_TOO_MANY_PARAMS, \
+ 0); \
+ silc_server_command_free(cmd); \
+ return SILC_FSM_FINISH; \
+ } \
} while(0)
/* Sends simple status message as command reply packet */
static void
-silc_server_command_send_status_reply(SilcServerCommand cmd,
+silc_server_command_status_reply(SilcServerCommand cmd,
SilcCommand command,
SilcStatus status,
SilcStatus error)
type must be sent as argument. */
static void
-silc_server_command_send_status_data(SilcServerCommand cmd,
+silc_server_command_status_data(SilcServerCommand cmd,
SilcCommand command,
SilcStatus status,
SilcStatus error,
}
static void
-silc_server_command_send_status_data2(SilcServerCommand cmd,
+silc_server_command_status_data2(SilcServerCommand cmd,
SilcCommand command,
SilcStatus status,
SilcStatus error,
else
client->fast_command -= 2;
}
+
+ client->last_command = time(NULL) + timeout;
}
silc_fsm_set_state_context(fsm, cmd);
return timeout ? SILC_FSM_WAIT : SILC_FSM_CONTINUE;
}
+/********************************* WHOIS ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_whois)
+{
+ SilcServerCommand cmd = state_context;
+ SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+ SILC_SERVER_COMMAND_CHECK(1, 256);
+
+ /** WHOIS query */
+ silc_fsm_next(fsm, silc_server_st_query_whois);
+
+ return SILC_FSM_CONTINUE;
+}
+
+
+/********************************* WHOWAS ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_whowas)
+{
+ SilcServerCommand cmd = state_context;
+ SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+ SILC_SERVER_COMMAND_CHECK(1, 2);
+
+ /** WHOWAS query */
+ silc_fsm_next(fsm, silc_server_st_query_whowas);
+
+ return SILC_FSM_CONTINUE;
+}
+
+
+/******************************** IDENTIFY **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_identify)
+{
+ SilcServerCommand cmd = state_context;
+ SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+ SILC_SERVER_COMMAND_CHECK(1, 256);
+
+ /** IDENTIFY query */
+ silc_fsm_next(fsm, silc_server_st_query_identify);
+
+ return SILC_FSM_CONTINUE;
+}
+
/********************************** NICK ************************************/
SilcServerThread thread = fsm_context;
SilcServerCommand cmd = state_context;
SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+ SilcClientEntry client = silc_packet_get_context(cmd->packet->stream);
+ SilcBuffer nidp, oidp = NULL;
+ SilcClientID new_id;
+ SilcUInt32 nick_len;
+ unsigned char *nick, *nickc;
+ SilcUInt16 ident = silc_command_get_ident(cmd->payload);
+ SILC_SERVER_COMMAND_CHECK(1, 1);
+
+ /* This command can come only from client */
+ if (!SILC_IS_CLIENT(client)) {
+ silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
+ SILC_STATUS_ERR_OPERATION_ALLOWED, 0);
+ goto out;
+ }
+
+ /* Get nickname */
+ nick = silc_argument_get_arg_type(args, 1, &nick_len);
+ if (!nick) {
+ silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+ goto out;
+ }
+
+ /* Truncate over long nicks */
+ if (nick_len > 128) {
+ nick_len = 128;
+ nick[nick_len - 1] = '\0';
+ }
+
+ /* Check for same nickname */
+ if (strlen(client->nickname) == nick_len &&
+ !memcmp(client->nickname, nick, nick_len)) {
+ nidp = silc_id_payload_encode(&client->id, SILC_ID_CLIENT);
+ goto send_reply;
+ }
+
+ /* Check for valid nickname string. */
+ nickc = silc_identifier_check(nick, nick_len, SILC_STRING_UTF8, 128, NULL);
+ if (!nickc) {
+ silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
+ SILC_STATUS_ERR_BAD_NICKNAME, 0);
+ goto out;
+ }
+
+ /* Create new Client ID */
+ if (!silc_server_create_client_id(thread->server, nickc, &new_id)) {
+ silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
+ SILC_STATUS_ERR_OPERATION_ALLOWED, 0);
+ goto out;
+ }
+ silc_free(nickc);
+
+ oidp = silc_id_payload_encode(&client->id, SILC_ID_CLIENT);
+
+ /* Replace the old nickname and ID with new ones. This checks for
+ validity of the nickname too. */
+ if (!silc_server_replace_client_id(thread->server, &client->id, &new_id,
+ nick)) {
+ silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
+ SILC_STATUS_ERR_BAD_NICKNAME, 0);
+ goto out;
+ }
+
+ nidp = silc_id_payload_encode(&client->id, SILC_ID_CLIENT);
+
+#if 0
+ /* Send notify about nickname and ID change to network. */
+ silc_server_send_notify_nick_change(server, SILC_PRIMARY_ROUTE(server),
+ SILC_BROADCAST(server), client->id,
+ &new_id, nick);
+
+ /* Send NICK_CHANGE notify to the client's channels */
+ silc_server_send_notify_on_channels(server, NULL, client,
+ SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
+ oidp->data, silc_buffer_len(oidp),
+ nidp->data, silc_buffer_len(nidp),
+ client->nickname,
+ strlen(client->nickname));
+#endif
+
+ send_reply:
+ /* Send the new Client ID as reply command back to client */
+ silc_server_send_command_reply(thread->server, cmd->packet->stream,
+ SILC_COMMAND_NICK,
+ SILC_STATUS_OK, 0, ident, 2,
+ 2, nidp->data, silc_buffer_len(nidp),
+ 3, nick, nick_len);
+ silc_buffer_free(nidp);
+ silc_buffer_free(oidp);
+
+ out:
+ silc_server_command_free(cmd);
return SILC_FSM_FINISH;
}
/********************************** INFO ************************************/
-/* Server side of command INFO. This sends information about us to
- the client. If client requested specific server we will send the
- command to that server. */
-
SILC_FSM_STATE(silc_server_st_command_info)
{
return SILC_FSM_FINISH;
/********************************** PING ************************************/
-/* Server side of command PING. */
-
SILC_FSM_STATE(silc_server_st_command_ping)
{
SilcServerThread thread = fsm_context;
SilcArgumentPayload args = silc_command_get_args(cmd->payload);
SilcUInt32 tmp_len;
unsigned char *tmp;
- SilcServerID server_id;
+ SilcID id;
SILC_SERVER_COMMAND_CHECK(1, 1);
/* Get Server ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
if (!tmp) {
- silc_server_command_send_status_reply(cmd, silc_command_get(cmd->payload),
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
- 0);
+ silc_server_command_status_reply(cmd, silc_command_get(cmd->payload),
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
goto out;
}
- if (!silc_id_payload_parse_id(tmp, tmp_len, NULL, &server_id,
- sizeof(server_id))) {
- silc_server_command_send_status_data(cmd, silc_command_get(cmd->payload),
- SILC_STATUS_ERR_BAD_SERVER_ID, 0,
- 2, tmp, tmp_len);
+ if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
+ silc_server_command_status_data(cmd, silc_command_get(cmd->payload),
+ SILC_STATUS_ERR_BAD_SERVER_ID, 0,
+ 2, tmp, tmp_len);
goto out;
}
- if (SILC_ID_SERVER_COMPARE(&server_id, &thread->server->id)) {
- /* Send our reply */
- silc_server_command_send_status_reply(cmd, silc_command_get(cmd->payload),
- SILC_STATUS_OK, 0);
- } else {
- silc_server_command_send_status_data(cmd, silc_command_get(cmd->payload),
- SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
- 2, tmp, tmp_len);
+ /* Must be our ID */
+ if (!SILC_ID_SERVER_COMPARE(&id.u.server_id, &thread->server->id)) {
+ silc_server_command_status_data(cmd, silc_command_get(cmd->payload),
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
+ 2, tmp, tmp_len);
+ goto out;
}
+ /* Send our reply */
+ silc_server_command_status_reply(cmd, silc_command_get(cmd->payload),
+ SILC_STATUS_OK, 0);
+
out:
silc_server_command_free(cmd);
return SILC_FSM_FINISH;
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2005 Pekka Riikonen
+ Copyright (C) 2002 - 2006 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "silcserver.h"
#include "server_internal.h"
-SILC_FSM_STATE(silc_server_st_command_whois)
+/************************** Types and definitions ***************************/
+
+/* Resolving entry */
+typedef struct SilcServerQueryResolveStruct {
+ struct SilcServerQueryResolveStruct *next;
+ SilcFSMThreadStruct thread; /* FSM thread for waiting reply */
+ SilcServerPending pending; /* Pending command context */
+ SilcPacketStream stream; /* Resolving connection */
+ SilcID *ids; /* Resolved IDs */
+ unsigned int ids_count : 30; /* Number of resolved IDs */
+ unsigned int attached : 1; /* Set if attached to a resolving */
+ unsigned int local : 1; /* Set if client is local to us */
+} *SilcServerQueryResolve;
+
+/* Represents one error occurred during query */
+typedef struct {
+ SilcID id; /* ID */
+ unsigned int index : 15; /* Index to IDs */
+ unsigned int type : 2; /* 0 = take from query->ids, 1 = take
+ from args, 2 = no args in error. */
+ unsigned int error : 7; /* The actual error (SilcStatus) */
+} *SilcServerQueryError;
+
+/* Query session context */
+typedef struct {
+ /* Queried data */
+ char *nickname; /* Queried nickname, normalized */
+ char *nick_server; /* Queried nickname's server */
+ char *server_name; /* Queried server name, normalized */
+ char *channel_name; /* Queried channel name, normalized */
+ SilcID *ids; /* Queried IDs */
+ SilcUInt32 ids_count; /* number of queried IDs */
+ SilcUInt32 reply_count; /* Requested reply count */
+ SilcDList attrs; /* Requested Attributes in WHOIS */
+ SilcFSMSemaStruct wait_resolve; /* Resolving signaller */
+
+ /* Query session data */
+ SilcServerComman cmd; /* Command context for query */
+ SilcList clients; /* Found clients */
+ SilcList servers; /* Found servers */
+ SilcList channels; /* Found channels */
+ SilcList resolve; /* Clients to resolve */
+ SilcList resolvings; /* Ongoing resolvings */
+ SilcServerQueryError errors; /* Query errors */
+ SilcServerPending redirect; /* Pending redirect */
+ SilcUInt16 errors_count; /* number of errors */
+ SilcUInt8 resolve_retry; /* Resolving retry count */
+ SilcCommand querycmd; /* Query command */
+} *SilcServerQuery;
+
+
+/************************ Static utility functions **************************/
+
+
+/********************************* WHOIS ************************************/
+
+SILC_FSM_STATE(silc_server_st_query_whois)
{
+ SilcServerThread thread = fsm_context;
+ SilcServer server = thread->server;
+ SilcServerCommand cmd = state_context;
+ SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+ SilcServerQuery query;
- return SILC_FSM_FINISH;
+ SILC_LOG_DEBUG(("WHOIS query"));
+
+ query = silc_calloc(1, sizeof(*query));
+ if (!query) {
+ silc_server_command_free(cmd);
+ return SILC_FSM_FINISH;
+ }
+
+ query->querycmd = SILC_COMMAND_WHOIS;
+ query->cmd = cmd;
+
+ silc_fsm_set_state_context(fsm, query);
+
+ /* If we are normal server and query contains a nickname OR query
+ doesn't contain nickname or ids BUT does contain user attributes,
+ send it to the router */
+ if (server->server_type != SILC_ROUTER && !server->standalone &&
+ cmd->packet->stream != SILC_PRIMARY_ROUTE(server) &&
+ (silc_argument_get_arg_type(args, 1, NULL) ||
+ (!silc_argument_get_arg_type(args, 1, NULL) &&
+ !silc_argument_get_arg_type(args, 4, NULL) &&
+ silc_argument_get_arg_type(args, 3, NULL)))) {
+ /** Send query to router */
+ silc_fsm_next(fsm, silc_server_st_query_send_router);
+ return SILC_FSM_CONTINUE;
+ }
+
+ /** Parse WHOIS query */
+ silc_fsm_next(fsm, silc_server_st_query_parse);
+ return SILC_FSM_CONTINUE;
}
-SILC_FSM_STATE(silc_server_st_command_whowas)
+
+/********************************* WHOWAS ***********************************/
+
+SILC_FSM_STATE(silc_server_st_query_whowas)
{
+ SilcServerThread thread = fsm_context;
+ SilcServerCommand cmd = state_context;
- return SILC_FSM_FINISH;
+ SILC_LOG_DEBUG(("WHOWAS query"));
+
+ query = silc_calloc(1, sizeof(*query));
+ if (!query) {
+ silc_server_command_free(cmd);
+ return SILC_FSM_FINISH;
+ }
+
+ query->querycmd = SILC_COMMAND_WHOWAS;
+ query->cmd = cmd;
+
+ silc_fsm_set_state_context(fsm, query);
+
+ /* WHOWAS query is always sent to router if we are normal server */
+ if (server->server_type == SILC_SERVER && !server->standalone &&
+ cmd->packet->stream != SILC_PRIMARY_ROUTE(server)) {
+ /** Send query to router */
+ silc_fsm_next(fsm, silc_server_st_query_send_router);
+ return SILC_FSM_CONTINUE;
+ }
+
+ /** Parse WHOWAS query */
+ silc_fsm_next(fsm, silc_server_st_query_parse);
+ return SILC_FSM_CONTINUE;
+}
+
+
+/******************************** IDENTIFY **********************************/
+
+SILC_FSM_STATE(silc_server_st_query_identify)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServerCommand cmd = state_context;
+ SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+ SILC_LOG_DEBUG(("IDENTIFY query"));
+
+ query = silc_calloc(1, sizeof(*query));
+ if (!query) {
+ silc_server_command_free(cmd);
+ return SILC_FSM_FINISH;
+ }
+
+ query->querycmd = SILC_COMMAND_IDENTIFY;
+ query->cmd = cmd;
+
+ silc_fsm_set_state_context(fsm, query);
+
+ /* If we are normal server and query does not contain IDs, send it directly
+ to router (it contains nickname, server name or channel name). */
+ if (server->server_type == SILC_SERVER && !server->standalone &&
+ cmd->packet->stream != SILC_PRIMARY_ROUTE(server) &&
+ !silc_argument_get_arg_type(args, 5, NULL)) {
+ /** Send query to router */
+ silc_fsm_next(fsm, silc_server_st_query_send_router);
+ return SILC_FSM_CONTINUE;
+ }
+
+ /** Parse IDENTIFY query */
+ silc_fsm_next(fsm, silc_server_st_query_parse);
+ return SILC_FSM_CONTINUE;
+}
+
+
+/**************************** Query redirecting *****************************/
+
+/* Send the query to router for further processing */
+
+SILC_FSM_STATE(silc_server_st_query_send_router)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServer server = thread->server;
+ SilcServerQuery query = state_context;
+ SilcBuffer tmpbuf;
+ SilcUInt16 cmd_ident, old_ident;
+
+ SILC_LOG_DEBUG(("Redirecting query to router"));
+
+ /* Send the command to our router */
+ cmd_ident = silc_server_cmd_ident(server);
+ old_ident = silc_command_get_ident(query->cmd->payload);
+ silc_command_set_ident(query->cmd->payload, cmd_ident);
+
+ tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
+ if (!tmpbuf || !silc_packet_send(SILC_PRIMARY_ROUTE(server),
+ SILC_PACKET_COMMAND, 0,
+ tmpbuf->data, silc_buffer_len(tmpbuf))) {
+ /** Error sending packet */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ silc_command_set_ident(query->cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+
+ /* Statistics */
+ server->stat.commands_sent++;
+
+ /* Continue parsing the query after receiving reply from router */
+ query->redirect = silc_server_command_pending(thread, query->redirect_ident);
+ if (!query->redirect) {
+ /** No memory */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ /** Wait router reply */
+ query->resolved = TRUE;
+ silc_fsm_next(fsm, silc_server_st_query_router_reply)
+ return SILC_FSM_CONTINUE;
+}
+
+/* Wait for router reply and process the reply when it arrives. */
+
+SILC_FSM_STATE(silc_server_st_query_router_reply)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServer server = thread->server;
+ SilcServerQuery query = state_context;
+ SilcServerPending pending = query->redirect;
+ SilcBool timedout;
+
+ /* Wait here for the reply */
+ SILC_FSM_SEMA_TIMEDWAIT(&pending->wait_reply, 10, 0, &timedout);
+
+ if (timedout) {
+ /** Timeout waiting reply */
+ silc_server_command_pending_free(thread, pending);
+ silc_server_query_send_error(server, query, SILC_STATUS_ERR_TIMEDOUT, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ /* Check if the query failed */
+ if (!silc_command_get_status(pending->reply->payload, NULL, NULL)) {
+ SilcBuffer buffer;
+
+ SILC_LOG_DEBUG(("Sending error to original query"));
+
+ /* Send the same command reply payload which contains the error */
+ silc_command_set_command(pending->reply->payload, query->querycmd);
+ silc_command_set_ident(pending->reply->payload,
+ silc_command_get_ident(query->cmd->payload));
+ buffer = silc_command_payload_encode_payload(pending->reply->payload);
+ if (buffer)
+ silc_packet_send(query->cmd->packet->stream,
+ SILC_PACKET_COMMAND_REPLY, 0,
+ buffer->data, silc_buffer_len(buffer));
+ silc_buffer_free(buffer);
+
+ /* Statistics */
+ server->stat.commands_sent++;
+
+ /** Query error received */
+ silc_server_command_pending_free(thread, pending);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ silc_server_command_pending_free(thread, pending);
+
+ /** Parse query command */
+ silc_fsm_next(fsm, silc_server_st_query_parse);
+ return SILC_FSM_CONTINUE;
+}
+
+/***************************** Query processing *****************************/
+
+/* Parse the command query */
+
+SILC_FSM_STATE(silc_server_st_query_parse)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServerQuery query = state_context;
+ SilcServerCommand cmd = query->cmd;
+ SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+ SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(args);
+ unsigned char *tmp;
+ SilcID id;
+ int i;
+
+ SILC_LOG_DEBUG(("Parsing %s query",
+ silc_get_command_name(query->querycmd)));
+
+ switch (query->querycmd) {
+
+ case SILC_COMMAND_WHOIS:
+ /* Get requested attributes if set */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN)
+ query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
+
+ /* Get Client IDs if present. Take IDs always instead of nickname. */
+ tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+ if (!tmp) {
+ /* No IDs present */
+
+ /* Get nickname */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp && !query->attrs) {
+ /* No nickname, no ids and no attributes - send error */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+
+ /** Not enough arguments */
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ /* Get the nickname@server string and parse it */
+ if (tmp && ((tmp_len > 128) ||
+ !silc_parse_userfqdn(tmp, &query->nickname,
+ &query->nick_server))) {
+ /** Bad nickname */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_BAD_NICKNAME, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ /* Check nickname */
+ if (tmp) {
+ tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
+ SILC_STRING_UTF8, 128, &tmp_len);
+ if (!tmp) {
+ /** Bad nickname */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_BAD_NICKNAME, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+ /* XXX why free nickname */
+ silc_free(query->nickname);
+ query->nickname = tmp;
+ }
+
+ } else {
+ /* Parse the IDs included in the query */
+ query->ids = silc_calloc(argc - 3, sizeof(*query->ids));
+ if (!query->ids) {
+ /** No memory */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ for (i = 0; i < argc - 3; i++) {
+ tmp = silc_argument_get_arg_type(args, i + 4, &tmp_len);
+ if (!tmp)
+ continue;
+
+ if (!silc_id_payload_parse_id(tmp, tmp_len, &id) ||
+ id.type != SILC_ID_CLIENT) {
+ silc_server_query_add_error(server, query, 1, i + 4,
+ SILC_STATUS_ERR_BAD_CLIENT_ID);
+ continue;
+ }
+
+ /* Normal server must check whether this ID exist, and if not then
+ send the query to router, unless done so already */
+ if (server->server_type == SILC_SERVER && !query->resolved &&
+ !silc_server_find_client_by_id(server, &client_id, TRUE, NULL)) {
+ /** Send query to router */
+ silc_free(query->ids);
+ query->ids = NULL;
+ query->ids_count = 0;
+ silc_fsm_next(fsm, silc_server_st_query_send_router);
+ return SILC_FSM_CONTINUE;
+ }
+
+ query->ids[query->ids_count] = id;
+ query->ids_count++;
+ }
+ }
+
+ /* Get the max count of reply messages allowed */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp && tmp_len == sizeof(SilcUInt32))
+ SILC_GET32_MSB(query->reply_count, tmp);
+ break
+
+ case SILC_COMMAND_WHOWAS:
+ /* Get nickname */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp) {
+ /** Not enough arguments */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ /* Get the nickname@server string and parse it */
+ if (tmp_len > 128 ||
+ !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
+ /** Bad nickname */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_BAD_NICKNAME, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ /* Check nickname */
+ tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
+ SILC_STRING_UTF8, 128, &tmp_len);
+ if (!tmp) {
+ /** Bad nickname */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_BAD_NICKNAME, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+ /* XXX why free nickname */
+ silc_free(query->nickname);
+ query->nickname = tmp;
+
+ /* Get the max count of reply messages allowed */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp && tmp_len == sizeof(SilcUInt32))
+ SILC_GET32_MSB(query->reply_count, tmp);
+ break;
+
+ case SILC_COMMAND_IDENTIFY:
+ /* Get IDs if present. Take IDs always instead of names. */
+ tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
+ if (!tmp) {
+ /* No IDs present */
+
+ /* Try get nickname */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (tmp) {
+ /* Get the nickname@server string and parse it */
+ if (tmp_len > 128 ||
+ !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
+ silc_server_query_add_error(server, query, 1, 1,
+ SILC_STATUS_ERR_BAD_NICKNAME);
+
+ /* Check nickname */
+ tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
+ SILC_STRING_UTF8, 128, &tmp_len);
+ if (!tmp) {
+ /** Bad nickname */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_BAD_NICKNAME, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+ /* XXX why free nickname */
+ silc_free(query->nickname);
+ query->nickname = tmp;
+ }
+
+ /* Try get server name */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp) {
+ /* Check server name */
+ tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
+ 256, &tmp_len);
+ if (!tmp) {
+ /** Bad server name */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_BAD_SERVER, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+ query->server_name = tmp;
+ }
+
+ /* Get channel name */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (tmp && tmp_len <= 256) {
+ /* Check channel name */
+ tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
+ 256, &tmp_len);
+ if (!tmp) {
+ /** Bad channel name */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_BAD_CHANNEL, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+ query->channel_name = tmp;
+ }
+
+ if (!query->nickname && !query->server_name && !query->channel_name) {
+ /** Nothing was queried */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ } else {
+ /* Parse the IDs included in the query */
+ query->ids = silc_calloc(argc - 4, sizeof(*query->ids));
+
+ for (i = 0; i < argc - 4; i++) {
+ tmp = silc_argument_get_arg_type(args, i + 5, &tmp_len);
+ if (!tmp)
+ continue;
+
+ if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
+ silc_server_query_add_error(server, query, 1, i + 5,
+ SILC_STATUS_ERR_BAD_CLIENT_ID);
+ continue;
+ }
+
+ /* Normal server must check whether this ID exist, and if not then
+ send the query to router, unless done so already */
+ if (server->server_type == SILC_SERVER && !query->resolved) {
+ if (id.type == SILC_ID_CLIENT) {
+ if (!silc_server_find_client_by_id(server, id, TRUE, NULL)) {
+ /** Send query to router */
+ silc_free(query->ids);
+ query->ids = NULL;
+ query->ids_count = 0;
+ silc_fsm_next(fsm, silc_server_st_query_send_router);
+ return SILC_FSM_CONTINUE;
+ }
+ } else {
+ /* For now all other ID's except Client ID's are explicitly
+ sent to router for resolving. */
+
+ /** Send query to router */
+ silc_free(query->ids);
+ query->ids = NULL;
+ query->ids_count = 0;
+ silc_fsm_next(fsm, silc_server_st_query_send_router);
+ return SILC_FSM_CONTINUE;
+ }
+ }
+
+ query->ids[query->ids_count] = id;
+ query->ids_count++;
+ }
+ }
+
+ /* Get the max count of reply messages allowed */
+ tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+ if (tmp && tmp_len == sizeof(SilcUInt32))
+ SILC_GET32_MSB(query->reply_count, tmp);
+ break;
+ }
+
+ /** Find entries for query */
+ silc_fsm_next(fsm, silc_server_st_query_find);
+ return SILC_FSM_CONTINUE;
+}
+
+/* Find the entries according to the query */
+
+SILC_FSM_STATE(silc_server_st_query_find)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServer server = thread->server;
+ SilcServerQuery query = state_context;
+ SilcServerCommand cmd = query->cmd;
+ SilcIDCacheEntry id_entry;
+ SilcID *id;
+ void *entry;
+ int i;
+
+ SILC_LOG_DEBUG(("Finding entries with %s query",
+ silc_get_command_name(query->querycmd)));
+
+ if (query->nickname) {
+ /* Find by nickname */
+ if (!silc_server_find_clients(server, query->nickname, &query->clients))
+ silc_server_query_add_error(server, query, 1, 1,
+ SILC_STATUS_ERR_NO_SUCH_NICK);
+ }
+
+ if (query->server_name) {
+ /* Find server by name */
+ if (!silc_server_find_server_by_name(server, query->server_name, TRUE,
+ &id_entry))
+ silc_server_query_add_error(server, query, 1, 2,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ else
+ silc_list_add(query->servers, id_entry);
+ }
+
+ if (query->channel_name) {
+ /* Find channel by name */
+ if (!silc_server_find_channel_by_name(server, query->channel_name,
+ &id_entry))
+ silc_server_query_add_error(server, query, 1, 3,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ else
+ silc_list_add(query->channels, id_entry);
+ }
+
+ if (query->ids_count) {
+ /* Find entries by the queried IDs */
+ for (i = 0; i < query->ids_count; i++) {
+ id = &query->ids[i];
+
+ switch (id->type) {
+
+ case SILC_ID_CLIENT:
+ /* Get client entry */
+ if (!silc_server_find_client_by_id(server, &id->u.client_id, TRUE,
+ &id_entry)) {
+ silc_server_query_add_error(server, query, 0, i,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+ continue;
+ }
+
+ silc_list_add(query->clients, id_entry);
+ break;
+
+ case SILC_ID_SERVER:
+ /* Get server entry */
+ if (!silc_server_find_server_by_id(server, &id->u.server_id, TRUE,
+ &id_entry)) {
+ silc_server_query_add_error(server, query, 0, i,
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
+ continue;
+ }
+
+ silc_list_add(query->servers, id_entry);
+ break;
+
+ case SILC_ID_CHANNEL:
+ /* Get channel entry */
+ if (!silc_server_find_channel_by_id(server, &id->u.channel_id,
+ &id_entry)) {
+ silc_server_query_add_error(server, query, 0, i,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
+ continue;
+ }
+
+ silc_list_add(query->channels, id_entry);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ /* Check the attributes to narrow down the search by using them. */
+ if (query->attrs) {
+ /** Check user attributes */
+ silc_fsm_next(fsm, silc_server_st_query_check_attrs);
+ return SILC_FSM_CONTINUE;
+ }
+
+ /** Process found entries */
+ silc_fsm_next(fsm, silc_server_st_query_process);
+ return SILC_FSM_CONTINUE;
+}
+
+/* Check user attributes to narrow down clients in WHOIS query */
+
+SILC_FSM_STATE(silc_server_st_query_check_attrs)
+{
+
+ /** Proecss found entries */
+ silc_fsm_next(fsm, silc_server_st_query_process);
+ return SILC_FSM_CONTINUE;
+}
+
+/* Process found entries */
+
+SILC_FSM_STATE(silc_server_st_query_process)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServer server = thread->server;
+ SilcServerQuery query = state_context;
+ SilcServerCommand cmd = query->cmd;
+ SilcServerQueryResolve res;
+ SilcIDCacheEntry id_entry;
+ SilcClientEntry client_entry;
+ SilcServerEntry server_entry;
+ SilcChannelEntry channel_entry;
+ SilcID *id;
+ void *entry;
+ int i;
+
+ SILC_LOG_DEBUG(("Process %s query",
+ silc_get_command_name(query->querycmd)));
+
+ SILC_LOG_DEBUG(("Querying %d clients", silc_list_count(query->clients)));
+ SILC_LOG_DEBUG(("Querying %d servers", silc_list_count(query->servers)));
+ SILC_LOG_DEBUG(("Querying %d channels", silc_list_count(query->channels)));
+
+ /* If nothing was found, then just send the errors */
+ if (!silc_list_count(query->clients) &&
+ !silc_list_count(query->channels) &&
+ !silc_list_count(query->servers)) {
+ /** Nothing found, send errors */
+ silc_fsm_next(fsm, silc_server_st_query_reply);
+ return SILC_FSM_CONTINUE;
+ }
+
+#if 0
+ /* If caller does not want us to resolve anything (has resolved already)
+ then just continue with sending the reply */
+ if (!resolve) {
+ silc_server_query_send_reply(server, query, clients, clients_count,
+ servers, servers_count, channels,
+ channels_count);
+ silc_free(clients);
+ silc_free(servers);
+ silc_free(channels);
+ return;
+ }
+#endif
+
+ /* Now process all found information and if necessary do some more
+ resolving. */
+ switch (query->querycmd) {
+
+ case SILC_COMMAND_WHOIS:
+ silc_list_start(query->clients);
+ while ((id_entry = silc_list_get(query->clients)) != SILC_LIST_END) {
+ client_entry = id_entry->context;
+
+ /* Ignore unregistered clients */
+ if (!SILC_IS_REGISTERED(client_entry)) {
+ silc_list_del(query->clients, id_entry);
+ continue;
+ }
+
+ /* If Requested Attributes is set then we always resolve the client
+ information, if not then check whether the entry is complete or not
+ and decide whether we need to resolve the missing information. */
+ if (!query->attrs) {
+
+ /* Even if nickname and stuff are present, we may need to resolve
+ the entry on normal server. */
+ if (client_entry->nickname && client_entry->username &&
+ client_entry->userinfo) {
+
+ /* If we are router, client is local to us, or client is on channel
+ we do not need to resolve the client information. */
+ if (server->server_type != SILC_SERVER ||
+ SILC_IS_LOCAL(client_entry)||
+ silc_hash_table_count(client_entry->channels) ||
+ query->resolved)
+ continue;
+ }
+ }
+
+ /* Remove the NOATTR status periodically */
+ if (client_entry->data.noattr &&
+ client_entry->updated + 600 < time(NULL))
+ client_entry->data.noattr = FALSE;
+
+ /* When requested attributes is present and local client is detached
+ we cannot send the command to the client, we'll reply on behalf of
+ the client instead. */
+ if (query->attrs && SILC_IS_LOCAL(client_entry) &&
+ (client_entry->mode & SILC_UMODE_DETACHED ||
+ client_entry->data.noattr))
+ continue;
+
+#if 0
+ /* If attributes are present in query, and in the entry and we have
+ done resolvings already we don't need to resolve anymore */
+ if (query->resolved && query->attrs && client_entry->attrs)
+ continue;
+#endif
+
+ /* Mark this entry to be resolved */
+ silc_list_add(query->resolve, id_entry);
+ }
+ break;
+
+ case SILC_COMMAND_WHOWAS:
+ silc_list_start(query->clients);
+ while ((id_entry = silc_list_get(query->clients)) != SILC_LIST_END) {
+ client_entry = id_entry->context;
+
+ /* Take only unregistered clients */
+ if (SILC_IS_REGISTERED(client_entry)) {
+ silc_list_del(query->clients, id_entry);
+ continue;
+ }
+
+ /* If both nickname and username are present no resolving is needed */
+ if (client_entry->nickname && client_entry->username)
+ continue;
+
+ /* Mark this entry to be resolved */
+ silc_list_add(query->resolve, id_entry);
+ }
+ break;
+
+ case SILC_COMMAND_IDENTIFY:
+ silc_list_start(query->clients);
+ while ((id_entry = silc_list_get(query->clients)) != SILC_LIST_END) {
+ client_entry = id_entry->context;
+
+ /* Ignore unregistered clients */
+ if (!SILC_IS_REGISTERED(client_entry))
+ continue;
+
+ /* Even if nickname is present, we may need to resolve the entry
+ on normal server. */
+ if (client_entry->nickname) {
+
+ /* If we are router, client is local to us, or client is on channel
+ we do not need to resolve the client information. */
+ if (server->server_type != SILC_SERVER ||
+ SILC_IS_LOCAL(client_entry)||
+ silc_hash_table_count(client_entry->channels) ||
+ query->resolved)
+ continue;
+ }
+
+ /* Mark this entry to be resolved */
+ silc_list_add(query->resolve, id_entry);
+ }
+ break;
+ }
+
+ /* If we need to resolve entries, do it now */
+ if (silc_list_count(query->resolve)) {
+ /** Resolve entries */
+ silc_fsm_next(fsm, silc_server_st_query_resolve);
+ return SILC_FSM_CONTINUE;
+ }
+
+ /** Send reply to query */
+ silc_fsm_next(fsm, silc_server_st_query_reply);
+ return SILC_FSM_CONTINUE;
}
-SILC_FSM_STATE(silc_server_st_command_identify)
+/* Resolve incomplete client entries. Other types of entries need not
+ resolving. */
+
+SILC_FSM_STATE(silc_server_st_query_resolve)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServer server = thread->server;
+ SilcServerQuery query = state_context;
+ SilcArgumentPayload cmd_args = silc_command_get_args(query->cmd->payload);
+ SilcServerQueryResolve res;
+ SilcIDCacheEntry id_entry;
+ unsigned char args[256][28];
+ SilcUInt32 arg_lens[256], arg_types[256], argc = 0;
+ SilcBuffer res_cmd;
+ int i;
+
+ SILC_LOG_DEBUG(("Resolve incomplete entries"));
+
+ silc_list_start(query->resolve);
+ while ((id_entry = silc_list_get(query->resolve)) != SILC_LIST_END) {
+ client_entry = id_entry->context;
+
+ /* If entry is being resolved, attach to that resolving */
+ if (client_entry->data.resolving) {
+ res = silc_calloc(1, sizeof(*res));
+ if (!res)
+ continue;
+
+ silc_fsm_thread_init(&res->thread, fsm, res, NULL, NULL, FALSE);
+ res->stream = client_entry->stream;
+
+ res->pending =
+ silc_server_command_pending(thread, client_entry->resolve_cmd_ident);
+ if (!res->pending) {
+ SILC_LOG_ERROR(("BUG: No pending command for resolving client entry"));
+ continue;
+ }
+
+ res->attached = TRUE;
+ silc_list_add(query->resolvings, res);
+ continue;
+ }
+
+ /* Check if we have resolving destination already set */
+ silc_list_start(query->resolvings);
+ while ((res = silc_list_get(query->resolvings)) != SILC_LIST_END)
+ if (res->stream == client_entry->stream && !res->attached)
+ break;
+
+ if (!res) {
+ /* Create new resolving context */
+ res = silc_calloc(1, sizeof(*res));
+ if (!res)
+ continue;
+
+ silc_fsm_thread_init(&res->thread, fsm, res, NULL, NULL, FALSE);
+ res->stream = client_entry->stream;
+
+ res->pending =
+ silc_server_command_pending(thread, silc_server_cmd_ident(server));
+ if (!res->pending)
+ continue;
+
+ silc_list_add(query->resolvings, res);
+ }
+
+ /* Mark the entry as being resolved */
+ client_entry->data.resolving = TRUE;
+ client_entry->data.resolved = FALSE;
+ client_entry->resolve_cmd_ident = res->pending->cmd_ident;
+ client_entry->updated = time(NULL);
+
+ if (SILC_IS_LOCAL(client_entry))
+ res->local = TRUE;
+
+ switch (query->querycmd) {
+ case SILC_COMMAND_WHOIS:
+ case SILC_COMMAND_IDENTIFY:
+ res->ids = silc_realloc(res->ids, sizeof(*res->ids) *
+ (res->ids_count + 1));
+ if (!res->ids)
+ continue;
+
+ res->ids[res->ids_count++].u.client_id = client_entry->id;
+ break;
+
+ case SILC_COMMAND_WHOWAS:
+ break;
+ }
+ }
+
+ SILC_LOG_DEBUG(("Sending the resolvings"));
+
+ /* Send the resolvings */
+ silc_list_start(query->resolvings);
+ while ((res = silc_list_get(query->resolvings)) != SILC_LIST_END) {
+
+ if (!res->attached) {
+
+ switch (query->querycmd) {
+ case SILC_COMMAND_WHOIS:
+ case SILC_COMMAND_IDENTIFY:
+
+ /* If Requested Attributes were present put them to this resolving */
+ if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
+ arg_types[argc] = 3;
+ args[argc] = silc_argument_get_arg_type(cmd_args, 3,
+ &arg_lens[argc]);
+ argc++;
+ }
+
+ /* Encode IDs */
+ for (i = 0; i < res->ids_count; i++) {
+ arg_types[argc] = (query->querycmd == SILC_COMMAND_WHOIS ?
+ 4 + i : 5 + i);
+ silc_id_id2str(&res->ids[argc].u.client_id, SILC_ID_CLIENT,
+ args[argc], sizeof(args[argc]), &arg_lens[argc]);
+ argc++;
+ if (i + 1 > 255)
+ break;
+ }
+
+ /* Send the command */
+ res_cmd = silc_command_payload_encode(query->querycmd, argc,
+ args, arg_lens, arg_types,
+ res->pending->cmd_ident);
+ if (!res_cmd) {
+ /** No memory */
+ silc_server_query_send_error(server, query,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, 0);
+ silc_fsm_next(fsm, silc_server_st_query_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ silc_packet_send(res->stream, SILC_PACKET_COMMAND, 0,
+ res_cmd->data, silc_buffer_send(res_cmd));
+ silc_buffer_free(res_cmd);
+ silc_free(res->ids);
+ res->ids = NULL;
+
+ /* Statistics */
+ server->stat.commands_sent++;
+ break;
+
+ case SILC_COMMAND_WHOWAS:
+ /* Send WHOWAS command */
+ silc_server_send_command(server, res->stream, query->querycmd,
+ res->pending->cmd_ident, 1,
+ 1, query->nickname, strlen(query->nickname));
+ break;
+ }
+ }
+
+ /*** Resolve */
+ silc_fsm_set_state_context(&res->thread, query);
+ silc_fsm_start_sync(&res->thread, silc_server_st_query_wait_resolve);
+ }
+
+ /** Wait all resolvings */
+ silc_fsm_next(fsm, silc_server_st_query_resolved);
+ return SILC_FSM_CONTINUE;
+}
+
+/* Wait for resolving command reply */
+
+SILC_FSM_STATE(silc_server_st_query_wait_resolve)
{
+ SilcServerQueryResolve res = fsm_context;
+ SilcServerQuery query = state_context;
+ SilcBool timedout;
+
+ /* Wait here for the reply */
+ SILC_FSM_SEMA_TIMEDWAIT(&res->pending->wait_reply,
+ res->local ? 3 : 10, 0, &timedout);
+
+
+
+ silc_list_del(query->resolvings, res);
+ silc_server_command_pending_free(res->pending);
+ silc_free(res);
+
+ /* Signal main thread that reply was received */
+ SILC_FSM_SEMA_POST(&query->wait_resolve);
+
return SILC_FSM_FINISH;
}
+
+/* Wait here that all resolvings has been received */
+
+SILC_FSM_STATE(silc_server_st_query_resolved)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServer server = thread->server;
+ SilcServerQuery query = state_context;
+ SilcServerCommand cmd = query->cmd;
+
+ /* Wait here until all resolvings has arrived */
+ SILC_FSM_SEMA_WAIT(&query->wait_resolve);
+ if (silc_list_count(query->resolvings) > 0)
+ return SILC_FSM_CONTINUE;
+
+}
+
+/* Send the reply to the query. */
+
+SILC_FSM_STATE(silc_server_st_query_reply)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServer server = thread->server;
+ SilcServerQuery query = state_context;
+ SilcServerCommand cmd = query->cmd;
+ SilcIDCacheEntry id_entry;
+
+}