Created SILC Crypto Toolkit git repository.
[crypto.git] / lib / silcserver / server_st_query.c
diff --git a/lib/silcserver/server_st_query.c b/lib/silcserver/server_st_query.c
deleted file mode 100644 (file)
index 6ee135e..0000000
+++ /dev/null
@@ -1,1076 +0,0 @@
-/*
-
-  server_st_query.c
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  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
-  the Free Software Foundation; version 2 of the License.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-*/
-
-#include "silc.h"
-#include "silcserver.h"
-#include "server_internal.h"
-
-/************************** 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 */
-  SilcFSMEventStruct 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;
-
-  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;
-}
-
-
-/********************************* WHOWAS ***********************************/
-
-SILC_FSM_STATE(silc_server_st_query_whowas)
-{
-  SilcServerThread thread = fsm_context;
-  SilcServerCommand cmd = state_context;
-
-  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_EVENT_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;
-}
-
-/* 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_EVENT_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_EVENT_SIGNAL(&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_EVENT_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;
-
-}