Rewrote WHOIS, WHOWAS and IDENTIFY commands.
[silc.git] / apps / silcd / command.c
index c82175f1af3ed487ba8622e86958c0cb320ddacc..f7fd214be0cae1ce37cbb4d78632e0f50fd5e0ca 100644 (file)
@@ -349,7 +349,8 @@ SILC_TASK_CALLBACK(silc_server_command_pending_timeout)
 
   /* Create bogus command reply with an error inside */
   tmpreply =
-    silc_command_reply_payload_encode_va(reply->reply_cmd,
+    silc_command_reply_payload_encode_va(reply->reply_cmd ? reply->reply_cmd :
+                                        SILC_COMMAND_RESERVED,
                                         SILC_STATUS_ERR_TIMEDOUT, 0,
                                         reply->ident, 0);
   cmdr->payload = silc_command_payload_parse(tmpreply->data, tmpreply->len);
@@ -549,1641 +550,33 @@ silc_server_command_pending_error_check(SilcServerCommandContext cmd,
   return FALSE;
 }
 
-/******************************************************************************
-
-                              WHOIS Functions
-
-******************************************************************************/
-
-typedef struct {
-  void *id;
-  SilcIdType id_type;
-  SilcUInt32 index;
-  SilcStatus error;
-} *ResolveError;
-
-#define ADD_ERROR(errptr, errptr_count, _id, _id_type, _index, _status)        \
-do {                                                                   \
-  errptr = silc_realloc(errptr, sizeof(*errptr) * (errptr_count + 1)); \
-  if (!errptr)                                                         \
-    return FALSE;                                                      \
-  errptr[errptr_count].id = _id;                                       \
-  errptr[errptr_count].id_type = _id_type;                             \
-  errptr[errptr_count].index = _index;                                 \
-  errptr[errptr_count].error = _status;                                        \
-  errptr_count++;                                                      \
-} while(0)
-
-static int
-silc_server_command_whois_parse(SilcServerCommandContext cmd,
-                               SilcClientID ***client_id,
-                               SilcUInt32 *client_id_count,
-                               char **nickname,
-                               char **server_name,
-                               int *count,
-                               ResolveError *error_client,
-                               SilcUInt32 *error_client_count,
-                               SilcDList *attrs)
-{
-  unsigned char *tmp;
-  SilcUInt32 len;
-  SilcUInt32 argc = silc_argument_get_arg_num(cmd->args);
-  void *id;
-  int i, k;
-
-  /* If client ID is in the command it must be used instead of nickname */
-  tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
-  if (!tmp) {
-    /* No ID, get the nickname@server string and parse it. */
-    tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
-    if (tmp) {
-      silc_parse_userfqdn(tmp, nickname, server_name);
-    } else {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
-                                           SILC_STATUS_ERR_BAD_NICKNAME, 0);
-      return FALSE;
-    }
-  } else {
-    /* Command includes ID, we must use that.  Take all ID's from the 
-       command packet */
-    for (k = 0, i = 0; i < argc; i++) {
-      tmp = silc_argument_get_arg_type(cmd->args, i + 4, &len);
-      if (!tmp)
-       continue;
-      id = silc_id_payload_parse_id(tmp, len, NULL);
-      if (id) {
-       *client_id = silc_realloc(*client_id, sizeof(**client_id) *
-                                 (*client_id_count + 1));
-       (*client_id)[k] = id;
-       (*client_id_count)++;
-       k++;
-      } else {
-       ADD_ERROR((*error_client), (*error_client_count), NULL, 0, i + 4,
-                 SILC_STATUS_ERR_BAD_CLIENT_ID);
-      }
-    }
-  }
-
-  /* Get the max count of reply messages allowed */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
-  if (tmp)
-    SILC_GET32_MSB(*count, tmp);
-  else
-    *count = 0;
-
-  /* Get requested attributes if set */
-  tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
-  if (tmp && attrs)
-    *attrs = silc_attribute_payload_parse_list(tmp, len);
-
-  return TRUE;
-}
-
-/* Resolve context used by both WHOIS and IDENTIFY commands */
-typedef struct {
-  SilcSocketConnection sock;
-  SilcUInt16 ident;
-  unsigned char **res_argv;
-  SilcUInt32 *res_argv_lens;
-  SilcUInt32 *res_argv_types;
-  SilcUInt32 res_argc;
-  SilcUInt32 res_timeout;
-} *SilcServerResolveContext;
-
-static bool
-silc_server_command_whois_check(SilcServerCommandContext cmd,
-                               SilcClientEntry *clients,
-                               SilcUInt32 clients_count,
-                               SilcDList attrs)
-{
-  SilcServer server = cmd->server;
-  SilcClientEntry entry;
-  SilcServerResolveContext resolve = NULL, r = NULL;
-  SilcUInt32 resolve_count = 0;
-  int i, k;
-  bool no_res = TRUE;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  for (i = 0; i < clients_count; i++) {
-    entry = clients[i];
-    if (!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 or not.  Usually attributes
-       are not present so the this test is performed all the time. */
-    if (!attrs) {
-      if ((entry->nickname && entry->username && entry->userinfo) ||
-         !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
-       if (!entry->router)
-         continue;
-
-       /* If we are normal server, and we've not resolved this client from
-          router and it is global client, we'll check whether it is on some
-          channel.  If not then we cannot be sure about its validity, and
-          we'll resolve it from router. */
-       if (cmd->server->server_type != SILC_SERVER || cmd->pending ||
-           entry->connection || silc_hash_table_count(entry->channels))
-         continue;
-      }
-    }
-
-    /* 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 (attrs && SILC_IS_LOCAL(entry) && entry->mode & SILC_UMODE_DETACHED)
-      continue;
-
-    /* We need to resolve this entry since it is not complete */
-
-    if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
-      /* The entry is being resolved (and we are not the resolver) so attach
-        to the command reply and we're done with this one. */
-      silc_server_command_pending(server, SILC_COMMAND_NONE,
-                                 entry->resolve_cmd_ident,
-                                 silc_server_command_whois,
-                                 silc_server_command_dup(cmd));
-      no_res = FALSE;
-    } else {
-      SilcBuffer idp;
-      SilcSocketConnection sock;
-
-      if (entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
-       /* We've resolved this and it still is not ready.  We'll return
-          and are that this will be handled again after it is resolved. */
-       for (i = 0; i < resolve_count; i++) {
-         for (k = 0; k < r->res_argc; k++)
-           silc_free(r->res_argv[k]);
-         silc_free(r->res_argv);
-         silc_free(r->res_argv_lens);
-         silc_free(r->res_argv_types);
-       }
-       silc_free(resolve);
-       return FALSE;
-      }
-
-      /* We'll resolve this client now */
-
-      sock = (SILC_IS_LOCAL(entry) ? entry->connection :
-             entry->router->connection);
-      if (!sock)
-       continue;
-
-      r = NULL;
-      for (k = 0; k < resolve_count; k++) {
-       if (resolve[k].sock == sock) {
-         r = &resolve[k];
-         break;
-       }
-      }
-
-      if (!r) {
-       resolve = silc_realloc(resolve, sizeof(*resolve) * 
-                              (resolve_count + 1));
-       r = &resolve[resolve_count];
-       memset(r, 0, sizeof(*r));
-       r->sock = sock;
-       r->ident = ++server->cmd_ident;
-       if (SILC_IS_LOCAL(entry))
-         r->res_timeout = 2;
-       else
-         r->res_timeout = 0;
-       resolve_count++;
-      }
-
-      r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
-                                (r->res_argc + 1));
-      r->res_argv_lens = silc_realloc(r->res_argv_lens, 
-                                     sizeof(*r->res_argv_lens) *
-                                     (r->res_argc + 1));
-      r->res_argv_types = silc_realloc(r->res_argv_types, 
-                                      sizeof(*r->res_argv_types) *
-                                      (r->res_argc + 1));
-      idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-      r->res_argv[r->res_argc] = silc_calloc(idp->len, 
-                                            sizeof(**r->res_argv));
-      memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
-      r->res_argv_lens[r->res_argc] = idp->len;
-      r->res_argv_types[r->res_argc] = r->res_argc + 4;
-      r->res_argc++;
-      silc_buffer_free(idp);
-
-      entry->resolve_cmd_ident = r->ident;
-      entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
-      entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
-    }
-  }
-
-  /* Do the resolving */
-  for (i = 0; i < resolve_count; i++) {
-    SilcBuffer res_cmd;
-    unsigned char *attrs_buf;
-    SilcUInt32 attrs_buf_len;
-
-    r = &resolve[i];
-
-    /* If attributes were present put them to this resolving as well */
-    if (attrs) {
-      attrs_buf = silc_argument_get_arg_type(cmd->args, 3, &attrs_buf_len);
-      if (attrs_buf) {
-       r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
-                                  (r->res_argc + 1));
-       r->res_argv_lens = silc_realloc(r->res_argv_lens, 
-                                       sizeof(*r->res_argv_lens) *
-                                       (r->res_argc + 1));
-       r->res_argv_types = silc_realloc(r->res_argv_types, 
-                                        sizeof(*r->res_argv_types) *
-                                        (r->res_argc + 1));
-       r->res_argv[r->res_argc] = silc_memdup(attrs_buf, attrs_buf_len);
-       r->res_argv_lens[r->res_argc] = attrs_buf_len;
-       r->res_argv_types[r->res_argc] = 3;
-       r->res_argc++;
-      }
-    }
-
-    /* Send WHOIS command */
-    res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
-                                         r->res_argc, r->res_argv, 
-                                         r->res_argv_lens,
-                                         r->res_argv_types, 
-                                         r->ident);
-    silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND,
-                           cmd->packet->flags, res_cmd->data,
-                           res_cmd->len, FALSE);
-
-    /* Reprocess this packet after received reply */
-    silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS, r->ident,
-                                     silc_server_command_whois,
-                                     silc_server_command_dup(cmd),
-                                     r->res_timeout);
-    cmd->pending = TRUE;
-
-    silc_buffer_free(res_cmd);
-    for (k = 0; k < r->res_argc; k++)
-      silc_free(r->res_argv[k]);
-    silc_free(r->res_argv);
-    silc_free(r->res_argv_lens);
-    silc_free(r->res_argv_types);
-    no_res = FALSE;
-  }
-  silc_free(resolve);
-
-  return no_res;
-}
-
-static void
-silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
-                                    SilcClientEntry *clients,
-                                    SilcUInt32 clients_count, 
-                                    ResolveError errors,
-                                    SilcUInt32 errors_count,
-                                    int count, const char *nickname,
-                                    SilcClientID **client_ids)
-{
-  SilcServer server = cmd->server;
-  char *tmp;
-  int i, k, valid_count = clients_count;
-  SilcUInt32 len;
-  SilcBuffer packet, idp, channels, umode_list = NULL;
-  SilcClientEntry entry;
-  SilcStatus status;
-  SilcUInt16 ident = silc_command_get_ident(cmd->payload);
-  char nh[256], uh[256];
-  unsigned char idle[4], mode[4];
-  unsigned char *fingerprint, fempty[20];
-  SilcSocketConnection hsock;
-
-  if (nickname) {
-    /* Process only valid clients and ignore those that are not registered. 
-       This is checked with nickname only because when resolved client IDs
-       we check that they are registered earlier. */
-    valid_count = 0;
-    for (i = 0; i < clients_count; i++)
-      if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
-       valid_count++;
-      else
-       clients[i] = NULL;
-
-    if (!valid_count) {
-      silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
-                                          SILC_STATUS_ERR_NO_SUCH_NICK, 0,
-                                          3, nickname, strlen(nickname));
-      return;
-    }
-  }
-
-  memset(fempty, 0, sizeof(fempty));
-
-  /* Start processing found clients. */
-  status = SILC_STATUS_OK;
-  if (valid_count > 1)
-    status = SILC_STATUS_LIST_START;
-
-  for (i = 0, k = 0; i < clients_count; i++) {
-    entry = clients[i];
-    if (!entry)
-      continue;
-
-    if (k >= 1)
-      status = SILC_STATUS_LIST_ITEM;
-    if (valid_count > 1 && k == valid_count - 1 && !errors_count)
-      status = SILC_STATUS_LIST_END;
-    if (count && k - 1 == count)
-      status = SILC_STATUS_LIST_END;
-
-    /* Send WHOIS reply */
-    idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-    tmp = silc_argument_get_first_arg(cmd->args, NULL);
-    
-    memset(uh, 0, sizeof(uh));
-    memset(nh, 0, sizeof(nh));
-    memset(idle, 0, sizeof(idle));
-    
-    strncat(nh, entry->nickname, strlen(entry->nickname));
-    if (!strchr(entry->nickname, '@')) {
-      strncat(nh, "@", 1);
-      if (entry->servername) {
-       strncat(nh, entry->servername, strlen(entry->servername));
-      } else {
-       len = entry->router ? strlen(entry->router->server_name) :
-         strlen(server->server_name);
-       strncat(nh, entry->router ? entry->router->server_name :
-               server->server_name, len);
-      }
-    }
-      
-    strncat(uh, entry->username, strlen(entry->username));
-    if (!strchr(entry->username, '@') && entry->connection) {
-      strncat(uh, "@", 1);
-      hsock = (SilcSocketConnection)entry->connection;
-      len = strlen(hsock->hostname);
-      strncat(uh, hsock->hostname, len);
-    }
-
-    if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
-      channels = silc_server_get_client_channel_list(server, entry, FALSE, 
-                                                    FALSE, &umode_list);
-    else
-      channels = silc_server_get_client_channel_list(server, entry, TRUE, 
-                                                    TRUE, &umode_list);
-
-    if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
-      fingerprint = entry->data.fingerprint;
-    else
-      fingerprint = NULL;
-      
-    SILC_PUT32_MSB(entry->mode, mode);
-    if (entry->connection)
-      SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
-
-    packet = 
-      silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
-                                          status, 0, ident, 9, 
-                                          2, idp->data, idp->len,
-                                          3, nh, strlen(nh),
-                                          4, uh, strlen(uh),
-                                          5, entry->userinfo, 
-                                          strlen(entry->userinfo),
-                                          6, channels ? channels->data : NULL,
-                                          channels ? channels->len : 0,
-                                          7, mode, 4,
-                                          8, idle, 4,
-                                          9, fingerprint,
-                                          fingerprint ? 20 : 0,
-                                          10, umode_list ? umode_list->data :
-                                          NULL, umode_list ? umode_list->len :
-                                          0);
-
-    silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
-                           0, packet->data, packet->len, FALSE);
-    
-    silc_buffer_free(packet);
-    silc_buffer_free(idp);
-    if (channels)
-      silc_buffer_free(channels);
-    if (umode_list) {
-      silc_buffer_free(umode_list);
-      umode_list = NULL;
-    }
-
-    if (status == SILC_STATUS_LIST_END)
-      break;
-    k++;
-  }
-
-  /* Send error replies */
-  if (status == SILC_STATUS_OK && errors_count > 1)
-    status = SILC_STATUS_LIST_START;
-
-  idp = NULL;
-  for (i = 0, k = 0; i < errors_count; i++) {
-    if (errors[i].id) {
-      idp = silc_id_payload_encode(errors[i].id, SILC_ID_CLIENT);
-      tmp = idp->data;
-      len = idp->len;
-    } else {
-      tmp = silc_argument_get_arg_type(cmd->args, errors[i].index, &len);
-    }
-      
-    if (k >= 1)
-      status = SILC_STATUS_LIST_ITEM;
-    if (errors_count > 1 && k == errors_count - 1)
-      status = SILC_STATUS_LIST_END;
-    if (count && k - 1 == count)
-      status = SILC_STATUS_LIST_END;
-      
-    /* Send error */
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
-                                        (status == SILC_STATUS_OK ?
-                                         errors[i].error : status),
-                                        (status == SILC_STATUS_OK ?
-                                         0 : errors[i].error),
-                                        2, tmp, len);
-    silc_buffer_free(idp);
-    idp = NULL;
-      
-    if (status == SILC_STATUS_LIST_END)
-      break;
-    k++;
-  }
-}
-
-static void 
-silc_server_command_whois_send_router(SilcServerCommandContext cmd)
-{
-  SilcServer server = cmd->server;
-  SilcBuffer tmpbuf;
-  SilcUInt16 old_ident;
-
-  old_ident = silc_command_get_ident(cmd->payload);
-  silc_command_set_ident(cmd->payload, ++server->cmd_ident);
-  tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
-  /* Send WHOIS command to our router */
-  silc_server_packet_send(server, (SilcSocketConnection)
-                         SILC_PRIMARY_ROUTE(server),
-                         SILC_PACKET_COMMAND, cmd->packet->flags,
-                         tmpbuf->data, tmpbuf->len, TRUE);
-
-  /* Reprocess this packet after received reply from router */
-  silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
-                             silc_command_get_ident(cmd->payload),
-                             silc_server_command_whois,
-                             silc_server_command_dup(cmd));
-  cmd->pending = TRUE;
-  silc_command_set_ident(cmd->payload, old_ident);
-  silc_buffer_free(tmpbuf);
-}
-
-static int
-silc_server_command_whois_process(SilcServerCommandContext cmd)
-{
-  SilcServer server = cmd->server;
-  char *nick = NULL, *server_name = NULL;
-  int count = 0;
-  SilcClientEntry *clients = NULL, entry;
-  SilcClientID **client_id = NULL;
-  SilcUInt32 client_id_count = 0, clients_count = 0, error_client_count = 0;
-  ResolveError error_client = NULL;
-  SilcDList attrs = NULL;
-  int i, ret = 0;
-  bool check_global = FALSE;
-
-  /* Parse the whois request */
-  if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
-                                      &nick, &server_name, &count,
-                                      &error_client, &error_client_count,
-                                      &attrs))
-    return 0;
-
-  /* Send the WHOIS request to the router only if it included nickname.
-     Since nicknames can be expanded into many clients we need to send it
-     to router.  If the WHOIS included only client ID's we will check them
-     first locally since we just might have them. */
-  if (nick && !client_id_count && cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
-      server->server_type == SILC_SERVER && !cmd->pending &&
-      !server->standalone) {
-    silc_server_command_whois_send_router(cmd);
-    ret = -1;
-    goto out;
-  }
-
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
-    check_global = TRUE;
-  else if (server->server_type != SILC_SERVER)
-    check_global = TRUE;
-
-  /* Get all clients matching that ID or nickname from local list */
-  if (client_id_count) {
-    /* Check all Client ID's received in the command packet */
-    for (i = 0; i < client_id_count; i++) {
-      entry = silc_idlist_find_client_by_id(server->local_list,
-                                           client_id[i], TRUE, NULL);
-      if (!entry && check_global)
-       entry = silc_idlist_find_client_by_id(server->global_list,
-                                             client_id[i], TRUE, NULL);
-      if (entry) {
-       clients = silc_realloc(clients, sizeof(*clients) *
-                              (clients_count + 1));
-       clients[clients_count++] = entry;
-      } else {
-       /* If we are normal server and did not send the request first to router
-          do it now, since we do not have the Client ID information. */
-       if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
-           server->server_type == SILC_SERVER && !cmd->pending &&
-           !server->standalone) {
-         silc_server_command_whois_send_router(cmd);
-         ret = -1;
-         goto out;
-       }
-
-       ADD_ERROR(error_client, error_client_count, client_id[i],
-                 SILC_ID_CLIENT, 0, SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
-      }
-    }
-  } else if (nick) {
-    /* Find by nickname */
-    if (!silc_idlist_get_clients_by_hash(server->local_list,
-                                        nick, server->md5hash,
-                                        &clients, &clients_count))
-      silc_idlist_get_clients_by_nickname(server->local_list,
-                                         nick, server_name,
-                                         &clients, &clients_count);
-    if (check_global) {
-      if (!silc_idlist_get_clients_by_hash(server->global_list,
-                                          nick, server->md5hash,
-                                          &clients, &clients_count))
-       silc_idlist_get_clients_by_nickname(server->global_list,
-                                           nick, server_name,
-                                           &clients, &clients_count);
-    }
-  }
-  
-  if (!clients && (client_id_count || nick)) {
-    /* If we are normal server and did not send the request first to router
-       do it now, since we do not have the information. */
-    if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
-       server->server_type == SILC_SERVER && !cmd->pending &&
-       !server->standalone) {
-      silc_server_command_whois_send_router(cmd);
-      ret = -1;
-      goto out;
-    }
-
-    /* Such client(s) really does not exist in the SILC network. */
-    if (!client_id_count)
-      silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
-                                          SILC_STATUS_ERR_NO_SUCH_NICK, 0,
-                                          3, nick, strlen(nick));
-    else
-      silc_server_command_whois_send_reply(cmd, NULL, 0,
-                                          error_client, error_client_count,
-                                          0, NULL, NULL);
-    goto out;
-  }
-
-  /* Router always finds the client entry if it exists in the SILC network.
-     However, it might be incomplete entry and does not include all the
-     mandatory fields that WHOIS command reply requires. Check for these and
-     make query from the server who owns the client if some fields are 
-     missing. */
-  if (!silc_server_command_whois_check(cmd, clients, clients_count, attrs)) {
-    ret = -1;
-    goto out;
-  }
-
-  /* Send the command reply */
-  silc_server_command_whois_send_reply(cmd, clients, clients_count,
-                                      error_client, error_client_count,
-                                      count, nick, client_id);
-
- out:
-  if (client_id_count) {
-    for (i = 0; i < client_id_count; i++)
-      silc_free(client_id[i]);
-    silc_free(client_id);
-  }
-  silc_free(clients);
-  silc_free(error_client);
-  silc_free(nick);
-  silc_free(server_name);
-  if (attrs)
-    silc_attribute_payload_list_free(attrs);
-
-  return ret;
-}
-
-/* Server side of command WHOIS. Processes user's query and sends found 
-   results as command replies back to the client. */
+/* Server side of command WHOIS. */
 
 SILC_SERVER_CMD_FUNC(whois)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 256);
-
-  silc_server_command_whois_process(cmd);
+  silc_server_query_command(cmd->server, SILC_COMMAND_WHOIS, cmd);
   silc_server_command_free(cmd);
 }
 
-/******************************************************************************
-
-                              WHOWAS Functions
-
-******************************************************************************/
-
-static int
-silc_server_command_whowas_parse(SilcServerCommandContext cmd,
-                                char **nickname,
-                                char **server_name,
-                                int *count)
-{
-  unsigned char *tmp;
-  SilcUInt32 len;
-
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
-  if (!tmp) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOWAS,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 
-                                         0);
-    return FALSE;
-  }
-
-  /* Get the nickname@server string and parse it. */
-  silc_parse_userfqdn(tmp, nickname, server_name);
-
-  /* Get the max count of reply messages allowed */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
-  if (tmp)
-    SILC_GET32_MSB(*count, tmp);
-  else
-    *count = 0;
-
-  return TRUE;
-}
-
-static char
-silc_server_command_whowas_check(SilcServerCommandContext cmd,
-                                SilcClientEntry *clients,
-                                SilcUInt32 clients_count)
-{
-  SilcServer server = cmd->server;
-  int i;
-  SilcClientEntry entry;
-
-  for (i = 0; i < clients_count; i++) {
-    entry = clients[i];
-
-    if (!entry->nickname || !entry->username) {
-      SilcBuffer tmpbuf;
-      SilcUInt16 old_ident;
-
-      if (!entry->router)
-       continue;
-      
-      old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
-      tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
-      /* Send WHOWAS command */
-      silc_server_packet_send(server, entry->router->connection,
-                             SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
-
-      /* Reprocess this packet after received reply */
-      silc_server_command_pending(server, SILC_COMMAND_WHOWAS, 
-                                 silc_command_get_ident(cmd->payload),
-                                 silc_server_command_whowas, 
-                                 silc_server_command_dup(cmd));
-      cmd->pending = TRUE;
-      silc_command_set_ident(cmd->payload, old_ident);
-
-      silc_buffer_free(tmpbuf);
-      return FALSE;
-    }
-  }
-
-  return TRUE;
-}
-
-static void
-silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
-                                     SilcClientEntry *clients,
-                                     SilcUInt32 clients_count)
-{
-  SilcServer server = cmd->server;
-  char *tmp;
-  int i, k, count = 0, len;
-  SilcBuffer packet, idp;
-  SilcClientEntry entry = NULL;
-  SilcStatus status;
-  SilcUInt16 ident = silc_command_get_ident(cmd->payload);
-  char nh[256], uh[256];
-  int valid_count;
-
-  status = SILC_STATUS_OK;
-
-  /* Process only entries that are not registered anymore. */
-  valid_count = 0;
-  for (i = 0; i < clients_count; i++) {
-    if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
-      clients[i] = NULL;
-    else
-      valid_count++;
-  }
-
-  if (!valid_count) {
-    /* No valid entries found at all, just send error */
-    tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
-                                        SILC_STATUS_ERR_NO_SUCH_NICK, 0,
-                                        3, tmp, tmp ? strlen(tmp) : 0);
-    return;
-  }
-
-  if (valid_count > 1)
-    status = SILC_STATUS_LIST_START;
-
-  for (i = 0, k = 0; i < clients_count; i++) {
-    entry = clients[i];
-    if (!entry)
-      continue;
-
-    if (k >= 1)
-      status = SILC_STATUS_LIST_ITEM;
-    if (valid_count > 1 && k == valid_count - 1)
-      status = SILC_STATUS_LIST_END;
-    if (count && k - 1 == count)
-      status = SILC_STATUS_LIST_END;
-
-    /* Send WHOWAS reply */
-    idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-    tmp = silc_argument_get_first_arg(cmd->args, NULL);
-    memset(uh, 0, sizeof(uh));
-    memset(nh, 0, sizeof(nh));
-
-    strncat(nh, entry->nickname, strlen(entry->nickname));
-    if (!strchr(entry->nickname, '@')) {
-      strncat(nh, "@", 1);
-      if (entry->servername) {
-       strncat(nh, entry->servername, strlen(entry->servername));
-      } else {
-       len = entry->router ? strlen(entry->router->server_name) :
-         strlen(server->server_name);
-       strncat(nh, entry->router ? entry->router->server_name :
-               server->server_name, len);
-      }
-    }
-      
-    strncat(uh, entry->username, strlen(entry->username));
-    if (!strchr(entry->username, '@')) {
-      strncat(uh, "@", 1);
-      strcat(uh, "*private*");
-    }
-      
-    packet = 
-      silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
-                                          status, 0, ident, 4, 
-                                          2, idp->data, idp->len,
-                                          3, nh, strlen(nh),
-                                          4, uh, strlen(uh),
-                                          5, entry->userinfo, 
-                                          entry->userinfo ? 
-                                          strlen(entry->userinfo) : 0);
-    silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
-                           0, packet->data, packet->len, FALSE);
-    
-    silc_buffer_free(packet);
-    silc_buffer_free(idp);
-
-    if (status == SILC_STATUS_LIST_END)
-      break;
-    k++;
-  }
-}
-
-static int
-silc_server_command_whowas_process(SilcServerCommandContext cmd)
-{
-  SilcServer server = cmd->server;
-  char *nick = NULL, *server_name = NULL;
-  int count = 0;
-  SilcClientEntry *clients = NULL;
-  SilcUInt32 clients_count = 0;
-  int ret = 0;
-  bool check_global = FALSE;
-
-  /* Protocol dictates that we must always send the received WHOWAS request
-     to our router if we are normal server, so let's do it now unless we
-     are standalone. We will not send any replies to the client until we
-     have received reply from the router. */
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
-      server->server_type == SILC_SERVER && !cmd->pending && 
-      !server->standalone) {
-    SilcBuffer tmpbuf;
-    SilcUInt16 old_ident;
-
-    old_ident = silc_command_get_ident(cmd->payload);
-    silc_command_set_ident(cmd->payload, ++server->cmd_ident);
-    tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
-    /* Send WHOWAS command to our router */
-    silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
-                           SILC_PACKET_COMMAND, cmd->packet->flags,
-                           tmpbuf->data, tmpbuf->len, TRUE);
-
-    /* Reprocess this packet after received reply from router */
-    silc_server_command_pending(server, SILC_COMMAND_WHOWAS, 
-                               silc_command_get_ident(cmd->payload),
-                               silc_server_command_whowas,
-                               silc_server_command_dup(cmd));
-    cmd->pending = TRUE;
-    silc_command_set_ident(cmd->payload, old_ident);
-
-    silc_buffer_free(tmpbuf);
-    ret = -1;
-    goto out;
-  }
-
-  /* We are ready to process the command request. Let's search for the
-     requested client and send reply to the requesting client. */
-
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
-    check_global = TRUE;
-  else if (server->server_type != SILC_SERVER)
-    check_global = TRUE;
-
-  /* Parse the whowas request */
-  if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
-    return 0;
-
-  /* Get all clients matching that nickname from local list */
-  if (!silc_idlist_get_clients_by_nickname(server->local_list, 
-                                          nick, server_name,
-                                          &clients, &clients_count))
-    silc_idlist_get_clients_by_hash(server->local_list, 
-                                   nick, server->md5hash,
-                                   &clients, &clients_count);
-  
-  /* Check global list as well */
-  if (check_global) {
-    if (!silc_idlist_get_clients_by_nickname(server->global_list, 
-                                            nick, server_name,
-                                            &clients, &clients_count))
-      silc_idlist_get_clients_by_hash(server->global_list, 
-                                     nick, server->md5hash,
-                                     &clients, &clients_count);
-  }
-  
-  if (!clients) {
-    /* Such a client really does not exist in the SILC network. */
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
-                                        SILC_STATUS_ERR_NO_SUCH_NICK, 0,
-                                        3, nick, strlen(nick));
-    goto out;
-  }
-
-  if (!silc_server_command_whowas_check(cmd, clients, clients_count)) {
-    ret = -1;
-    goto out;
-  }
-
-  /* Send the command reply to the client */
-  silc_server_command_whowas_send_reply(cmd, clients, clients_count);
-
- out:
-  silc_free(clients);
-  silc_free(nick);
-  silc_free(server_name);
-  return ret;
-}
-
 /* Server side of command WHOWAS. */
 
 SILC_SERVER_CMD_FUNC(whowas)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  int ret = 0;
-
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOWAS, cmd, 1, 2);
-
-  ret = silc_server_command_whowas_process(cmd);
+  silc_server_query_command(cmd->server, SILC_COMMAND_WHOWAS, cmd);
   silc_server_command_free(cmd);
 }
 
-/******************************************************************************
-
-                              IDENTIFY Functions
-
-******************************************************************************/
-
-static void 
-silc_server_command_identify_send_router(SilcServerCommandContext cmd)
-{
-  SilcServer server = cmd->server;
-  SilcBuffer tmpbuf;
-  SilcUInt16 old_ident;
-
-  old_ident = silc_command_get_ident(cmd->payload);
-  silc_command_set_ident(cmd->payload, ++server->cmd_ident);
-  tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
-  /* Send IDENTIFY command to our router */
-  silc_server_packet_send(server, (SilcSocketConnection)
-                         SILC_PRIMARY_ROUTE(server),
-                         SILC_PACKET_COMMAND, cmd->packet->flags,
-                         tmpbuf->data, tmpbuf->len, TRUE);
-
-  /* Reprocess this packet after received reply from router */
-  silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, 
-                             silc_command_get_ident(cmd->payload),
-                             silc_server_command_identify,
-                             silc_server_command_dup(cmd));
-  cmd->pending = TRUE;
-  silc_command_set_ident(cmd->payload, old_ident);
-  silc_buffer_free(tmpbuf);
-}
-
-static int
-silc_server_command_identify_parse(SilcServerCommandContext cmd,
-                                  SilcClientEntry **clients,
-                                  SilcUInt32 *clients_count,
-                                  SilcServerEntry **servers,
-                                  SilcUInt32 *servers_count,
-                                  SilcChannelEntry **channels,
-                                  SilcUInt32 *channels_count,
-                                  SilcUInt32 *count,
-                                  ResolveError *error_id,
-                                  SilcUInt32 *error_id_count)
-{
-  SilcServer server = cmd->server;
-  unsigned char *tmp;
-  SilcUInt32 len;
-  SilcUInt32 argc = silc_argument_get_arg_num(cmd->args);
-  SilcIDPayload idp;
-  bool check_global = FALSE;
-  void *entry;
-  int i;
-
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
-    check_global = TRUE;
-  else if (server->server_type != SILC_SERVER)
-    check_global = TRUE;
-
-  /* If ID Payload is in the command it must be used instead of names */
-  tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
-  if (!tmp) {
-    /* No ID, get the names. */
-
-    /* If we are normal server and have not resolved information from
-       router yet, do so now. */
-    if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
-       server->server_type == SILC_SERVER && !cmd->pending && 
-       !server->standalone) {
-      silc_server_command_identify_send_router(cmd);
-      return -1;
-    }
-
-    /* Try to get nickname@server. */
-    tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
-    if (tmp) {
-      char *nick = NULL;
-      char *nick_server = NULL;
-
-      silc_parse_userfqdn(tmp, &nick, &nick_server);
-
-      if (!silc_idlist_get_clients_by_hash(server->local_list, 
-                                          nick, server->md5hash,
-                                          clients, clients_count))
-       silc_idlist_get_clients_by_nickname(server->local_list, 
-                                           nick, nick_server,
-                                           clients, clients_count);
-      if (check_global) {
-       if (!silc_idlist_get_clients_by_hash(server->global_list, 
-                                            nick, server->md5hash,
-                                            clients, clients_count))
-         silc_idlist_get_clients_by_nickname(server->global_list, 
-                                             nick, nick_server,
-                                             clients, clients_count);
-      }
-
-      silc_free(nick);
-      silc_free(nick_server);
-
-      if (!(*clients)) {
-       /* the nickname does not exist, send error reply */
-       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                            SILC_STATUS_ERR_NO_SUCH_NICK, 0,
-                                            3, tmp, strlen(tmp));
-       return 0;
-      }
-    }
-
-    /* Try to get server name */
-    tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
-    if (tmp) {
-      entry = silc_idlist_find_server_by_name(server->local_list,
-                                             tmp, TRUE, NULL);
-      if (!entry && check_global)
-       entry = silc_idlist_find_server_by_name(server->global_list,
-                                               tmp, TRUE, NULL);
-      if (entry) {
-       *servers = silc_realloc(*servers, sizeof(**servers) * 
-                               (*servers_count + 1));
-       (*servers)[(*servers_count)++] = entry;
-      }
-
-      if (!(*servers)) {
-       /* the server does not exist, send error reply */
-       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                            SILC_STATUS_ERR_NO_SUCH_SERVER,
-                                            0, 3, tmp, strlen(tmp));
-       return 0;
-      }
-    }
-
-    /* Try to get channel name */
-    tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
-    if (tmp) {
-      entry = silc_idlist_find_channel_by_name(server->local_list,
-                                              tmp, NULL);
-      if (!entry && check_global)
-       entry = silc_idlist_find_channel_by_name(server->global_list,
-                                                tmp, NULL);
-      if (entry) {
-       *channels = silc_realloc(*channels, sizeof(**channels) * 
-                                (*channels_count + 1));
-       (*channels)[(*channels_count)++] = entry;
-      }
-
-      if (!(*channels)) {
-       /* The channel does not exist, send error reply */
-       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                            SILC_STATUS_ERR_NO_SUCH_CHANNEL,
-                                            0, 3, tmp, strlen(tmp));
-       return 0;
-      }
-    }
-
-    if (!(*clients) && !(*servers) && !(*channels)) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
-                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
-                                           0);
-      return 0;
-    }
-  } else {
-    /* Command includes ID, we must use that.  Also check whether the command
-       has more than one ID set - take them all. */
-
-    /* Take all ID's from the command packet */
-    for (i = 0; i < argc; i++) {
-      void *id;
-
-      tmp = silc_argument_get_arg_type(cmd->args, i + 5, &len);
-      if (!tmp)
-       continue;
-      
-      idp = silc_id_payload_parse(tmp, len);
-      if (!idp)
-       ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
-                 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-
-      id = silc_id_payload_get_id(idp);
-      switch (silc_id_payload_get_type(idp)) {
-       
-      case SILC_ID_CLIENT:
-       entry = silc_idlist_find_client_by_id(server->local_list, 
-                                             id, TRUE, NULL);
-       if (!entry && check_global)
-         entry = silc_idlist_find_client_by_id(server->global_list, 
-                                               id, TRUE, NULL);
-       if (entry) {
-         *clients = silc_realloc(*clients, sizeof(**clients) * 
-                                 (*clients_count + 1));
-         (*clients)[(*clients_count)++] = (SilcClientEntry)entry;
-       } else {
-         /* If we are normal server and have not resolved information from
-            router yet, do so now. */
-         if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
-             server->server_type == SILC_SERVER && !cmd->pending && 
-             !server->standalone) {
-           silc_server_command_identify_send_router(cmd);
-           silc_free(*clients);
-           silc_free(*servers);
-           silc_free(*channels);
-           silc_free(*error_id);
-           return -1;
-         }
-
-         ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
-                   SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
-       }
-
-       break;
-       
-      case SILC_ID_SERVER:
-       entry = silc_idlist_find_server_by_id(server->local_list, 
-                                             id, TRUE, NULL);
-       if (!entry && check_global)
-         entry = silc_idlist_find_server_by_id(server->global_list, 
-                                               id, TRUE, NULL);
-       if (entry) {
-         *servers = silc_realloc(*servers, sizeof(**servers) * 
-                                 (*servers_count + 1));
-         (*servers)[(*servers_count)++] = (SilcServerEntry)entry;
-       } else {
-         /* If we are normal server and have not resolved information from
-            router yet, do so now. */
-         if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
-             server->server_type == SILC_SERVER && !cmd->pending && 
-             !server->standalone) {
-           silc_server_command_identify_send_router(cmd);
-           silc_free(*clients);
-           silc_free(*servers);
-           silc_free(*channels);
-           silc_free(*error_id);
-           return -1;
-         }
-
-         ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
-                   SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
-       }
-       break;
-       
-      case SILC_ID_CHANNEL:
-       entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
-       if (!entry && check_global)
-         entry = silc_idlist_find_channel_by_id(server->global_list, id,
-                                                NULL);
-       if (entry) {
-         *channels = silc_realloc(*channels, sizeof(**channels) * 
-                                  (*channels_count + 1));
-         (*channels)[(*channels_count)++] = (SilcChannelEntry)entry;
-       } else {
-         /* If we are normal server and have not resolved information from
-            router yet, do so now. */
-         if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
-             server->server_type == SILC_SERVER && !cmd->pending && 
-             !server->standalone) {
-           silc_server_command_identify_send_router(cmd);
-           silc_free(*clients);
-           silc_free(*servers);
-           silc_free(*channels);
-           silc_free(*error_id);
-           return -1;
-         }
-
-         ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
-                   SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
-       }
-       break;
-      }
-
-      silc_id_payload_free(idp);
-      silc_free(id);
-    }
-  }
-
-  /* Get the max count of reply messages allowed */
-  tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
-  if (tmp)
-    SILC_GET32_MSB(*count, tmp);
-  else
-    *count = 0;
-
-  return 1;
-}
-
-/* Checks that all mandatory fields in client entry are present. If not
-   then send WHOIS request to the server who owns the client. We use
-   WHOIS because we want to get as much information as possible at once. */
-
-static bool
-silc_server_command_identify_check_client(SilcServerCommandContext cmd,
-                                         SilcClientEntry *clients,
-                                         SilcUInt32 clients_count)
-{
-  SilcServer server = cmd->server;
-  SilcClientEntry entry;
-  SilcServerResolveContext resolve = NULL, r = NULL;
-  SilcUInt32 resolve_count = 0;
-  int i, k;
-  bool no_res = TRUE;
-
-  for (i = 0; i < clients_count; i++) {
-    entry = clients[i];
-    if (!entry)
-      continue;
-
-    if (entry->nickname || 
-       !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
-      if (!entry->router)
-       continue;
-
-      /* If we are normal server, and we've not resolved this client from
-        router and it is global client, we'll check whether it is on some
-        channel.  If not then we cannot be sure about its validity, and
-        we'll resolve it from router. */
-      if (cmd->server->server_type != SILC_SERVER || cmd->pending ||
-         entry->connection || silc_hash_table_count(entry->channels))
-       continue;
-    }
-
-    /* We need to resolve this entry since it is not complete */
-
-    if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
-      /* The entry is being resolved (and we are not the resolver) so attach
-        to the command reply and we're done with this one. */
-      silc_server_command_pending(server, SILC_COMMAND_NONE, 
-                                 entry->resolve_cmd_ident,
-                                 silc_server_command_identify,
-                                 silc_server_command_dup(cmd));
-      no_res = FALSE;
-    } else {
-      if (entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
-       /* We've resolved this and it still is not ready.  We'll return
-          and are that this will be handled again after it is resolved. */
-       for (i = 0; i < resolve_count; i++) {
-         for (k = 0; k < r->res_argc; k++)
-           silc_free(r->res_argv[k]);
-         silc_free(r->res_argv);
-         silc_free(r->res_argv_lens);
-         silc_free(r->res_argv_types);
-       }
-       silc_free(resolve);
-       return FALSE;
-      } else {
-       /* We'll resolve this client */
-       SilcBuffer idp;
-
-       r = NULL;
-       for (k = 0; k < resolve_count; k++) {
-         if (resolve[k].sock == entry->router->connection) {
-           r = &resolve[k];
-           break;
-         }
-       }
-
-       if (!r) {
-         resolve = silc_realloc(resolve, sizeof(*resolve) * 
-                                (resolve_count + 1));
-         r = &resolve[resolve_count];
-         memset(r, 0, sizeof(*r));
-         r->sock = entry->router->connection;
-         r->ident = ++server->cmd_ident;
-         resolve_count++;
-       }
-
-       r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
-                                  (r->res_argc + 1));
-       r->res_argv_lens = silc_realloc(r->res_argv_lens, 
-                                       sizeof(*r->res_argv_lens) *
-                                       (r->res_argc + 1));
-       r->res_argv_types = silc_realloc(r->res_argv_types, 
-                                        sizeof(*r->res_argv_types) *
-                                        (r->res_argc + 1));
-       idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-       r->res_argv[r->res_argc] = silc_calloc(idp->len, 
-                                              sizeof(**r->res_argv));
-       memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
-       r->res_argv_lens[r->res_argc] = idp->len;
-       r->res_argv_types[r->res_argc] = r->res_argc + 4;
-       r->res_argc++;
-       silc_buffer_free(idp);
-
-       entry->resolve_cmd_ident = r->ident;
-       entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
-       entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
-      }
-    }
-  }
-
-  /* Do the resolving */
-  for (i = 0; i < resolve_count; i++) {
-    SilcBuffer res_cmd;
-
-    r = &resolve[i];
-
-    /* Send WHOIS request. We send WHOIS since we're doing the requesting
-       now anyway so make it a good one. */
-    res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
-                                         r->res_argc, r->res_argv, 
-                                         r->res_argv_lens,
-                                         r->res_argv_types, 
-                                         r->ident);
-    silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND,
-                           cmd->packet->flags, res_cmd->data,
-                           res_cmd->len, FALSE);
-
-    /* Reprocess this packet after received reply */
-    silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
-                               r->ident,
-                               silc_server_command_identify,
-                               silc_server_command_dup(cmd));
-    cmd->pending = TRUE;
-
-    silc_buffer_free(res_cmd);
-    for (k = 0; k < r->res_argc; k++)
-      silc_free(r->res_argv[k]);
-    silc_free(r->res_argv);
-    silc_free(r->res_argv_lens);
-    silc_free(r->res_argv_types);
-    no_res = FALSE;
-  }
-  silc_free(resolve);
-
-  return no_res;
-}
-
-static void
-silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
-                                       SilcClientEntry *clients,
-                                       SilcUInt32 clients_count,
-                                       SilcServerEntry *servers,
-                                       SilcUInt32 servers_count,
-                                       SilcChannelEntry *channels,
-                                       SilcUInt32 channels_count,
-                                       ResolveError errors,
-                                       SilcUInt32 errors_count,
-                                       int count)
-{
-  SilcServer server = cmd->server;
-  int i, k, valid_count;
-  SilcUInt32 len;
-  SilcBuffer packet, idp;
-  SilcStatus status;
-  SilcUInt16 ident = silc_command_get_ident(cmd->payload);
-  char nh[256], uh[256];
-  SilcSocketConnection hsock;
-  unsigned char *tmp;
-
-  status = SILC_STATUS_OK;
-
-  if (clients) {
-    SilcClientEntry entry;
-    valid_count = clients_count;
-
-    if (silc_argument_get_arg_type(cmd->args, 1, NULL)) {
-      /* Process only valid clients and ignore those that are not registered. 
-        This is checked with nickname only because when resolved client IDs
-        we check that they are registered earlier. */
-      valid_count = 0;
-      for (i = 0; i < clients_count; i++) {
-       if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
-         valid_count++;
-       else
-         clients[i] = NULL;
-      }
-
-      if (!valid_count) {
-       /* No valid entries found at all, just send error */
-       tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
-       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                            SILC_STATUS_ERR_NO_SUCH_NICK, 0,
-                                            3, tmp, tmp ? strlen(tmp) : 0);
-       return;
-      }
-    }
-
-    /* Process all valid client entries and send command replies */
-
-    if (valid_count > 1)
-      status = SILC_STATUS_LIST_START;
-
-    for (i = 0, k = 0; i < clients_count; i++) {
-      entry = clients[i];
-      if (!entry)
-       continue;
-
-      if (k >= 1)
-       status = SILC_STATUS_LIST_ITEM;
-      if (valid_count > 1 && k == valid_count - 1 
-         && !servers_count && !channels_count && !errors_count)
-       status = SILC_STATUS_LIST_END;
-      if (count && k - 1 == count)
-       status = SILC_STATUS_LIST_END;
-
-      /* Send IDENTIFY reply */
-
-      idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-      memset(uh, 0, sizeof(uh));
-      memset(nh, 0, sizeof(nh));
-      strncat(nh, entry->nickname, strlen(entry->nickname));
-      if (!strchr(entry->nickname, '@')) {
-       strncat(nh, "@", 1);
-       if (entry->servername) {
-         strncat(nh, entry->servername, strlen(entry->servername));
-       } else {
-         len = entry->router ? strlen(entry->router->server_name) :
-           strlen(server->server_name);
-         strncat(nh, entry->router ? entry->router->server_name :
-                 server->server_name, len);
-       }
-      }
-
-      if (!entry->username) {
-       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                                     status, 0, ident, 2,
-                                                     2, idp->data, idp->len, 
-                                                     3, nh, strlen(nh));
-      } else {
-       strncat(uh, entry->username, strlen(entry->username));
-       if (!strchr(entry->username, '@') && entry->connection) {
-         strncat(uh, "@", 1);
-         hsock = (SilcSocketConnection)entry->connection;
-         len = strlen(hsock->hostname);
-         strncat(uh, hsock->hostname, len);
-       }
-       
-       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                                     status, 0, ident, 3,
-                                                     2, idp->data, idp->len, 
-                                                     3, nh, strlen(nh),
-                                                     4, uh, strlen(uh));
-      }
-      
-      silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
-                             0, packet->data, packet->len, FALSE);
-      
-      silc_buffer_free(packet);
-      silc_buffer_free(idp);
-      
-      if (status == SILC_STATUS_LIST_END)
-       break;
-      k++;
-    }
-  }
-
-  if (servers) {
-    SilcServerEntry entry;
-
-    if (status == SILC_STATUS_OK && servers_count > 1)
-      status = SILC_STATUS_LIST_START;
-
-    for (i = 0, k = 0; i < servers_count; i++) {
-      entry = servers[i];
-      
-      if (k >= 1)
-       status = SILC_STATUS_LIST_ITEM;
-      if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
-         !errors_count)
-       status = SILC_STATUS_LIST_END;
-      if (count && k - 1 == count)
-       status = SILC_STATUS_LIST_END;
-      
-      /* Send IDENTIFY reply */
-      idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                            status, 0, ident, 2,
-                                            2, idp->data, idp->len, 
-                                            3, entry->server_name, 
-                                            entry->server_name ? 
-                                            strlen(entry->server_name) : 0);
-      silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
-                             0, packet->data, packet->len, FALSE);
-      
-      silc_buffer_free(packet);
-      silc_buffer_free(idp);
-      
-      if (status == SILC_STATUS_LIST_END)
-       break;
-      k++;
-    }
-  }
-
-  if (channels) {
-    SilcChannelEntry entry;
-
-    if (status == SILC_STATUS_OK && channels_count > 1)
-      status = SILC_STATUS_LIST_START;
-
-    for (i = 0, k = 0; i < channels_count; i++) {
-      entry = channels[i];
-      
-      if (k >= 1)
-       status = SILC_STATUS_LIST_ITEM;
-      if (channels_count > 1 && k == channels_count - 1 && !errors_count)
-       status = SILC_STATUS_LIST_END;
-      if (count && k - 1 == count)
-       status = SILC_STATUS_LIST_END;
-      
-      /* Send IDENTIFY reply */
-      idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                            status, 0, ident, 2,
-                                            2, idp->data, idp->len, 
-                                            3, entry->channel_name, 
-                                            entry->channel_name ? 
-                                            strlen(entry->channel_name): 0);
-      silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
-                             0, packet->data, packet->len, FALSE);
-      
-      silc_buffer_free(packet);
-      silc_buffer_free(idp);
-      
-      if (status == SILC_STATUS_LIST_END)
-       break;
-      k++;
-    }
-  }
-
-  /* Send error replies */
-  if (errors) {
-    if (status == SILC_STATUS_OK && errors_count > 1)
-      status = SILC_STATUS_LIST_START;
-
-    idp = NULL;
-    for (i = 0, k = 0; i < errors_count; i++) {
-      if (errors[i].id) {
-       idp = silc_id_payload_encode(errors[i].id, SILC_ID_CLIENT);
-       tmp = idp->data;
-       len = idp->len;
-      } else {
-       tmp = silc_argument_get_arg_type(cmd->args, errors[i].index, &len);
-      }
-      
-      if (k >= 1)
-       status = SILC_STATUS_LIST_ITEM;
-      if (errors_count > 1 && k == errors_count - 1)
-       status = SILC_STATUS_LIST_END;
-      if (count && k - 1 == count)
-       status = SILC_STATUS_LIST_END;
-      
-      /* Send error */
-      silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                          (status == SILC_STATUS_OK ?
-                                           errors[i].error : status),
-                                          (status == SILC_STATUS_OK ?
-                                           0 : errors[i].error),
-                                          2, tmp, len);
-      silc_buffer_free(idp);
-      idp = NULL;
-      
-      if (status == SILC_STATUS_LIST_END)
-       break;
-      k++;
-    }
-  }
-}
-
-static int
-silc_server_command_identify_process(SilcServerCommandContext cmd)
-{
-  SilcUInt32 count = 0;
-  int ret = 0;
-  SilcClientEntry *clients = NULL;
-  SilcServerEntry *servers = NULL;
-  SilcChannelEntry *channels = NULL;
-  SilcUInt32 clients_count = 0, servers_count = 0, channels_count = 0;
-  SilcUInt32 errors_count = 0;
-  ResolveError errors = NULL;
-
-  /* Parse the IDENTIFY request */
-  ret = silc_server_command_identify_parse(cmd,
-                                          &clients, &clients_count,
-                                          &servers, &servers_count,
-                                          &channels, &channels_count,
-                                          &count, &errors, &errors_count);
-  if (ret < 1)
-    return ret;
-  ret = 0;
-
-  /* Check that all mandatory fields are present and request those data
-     from the server who owns the client if necessary. */
-  if (!silc_server_command_identify_check_client(cmd, clients, 
-                                                clients_count)) {
-    ret = -1;
-    goto out;
-  }
-
-  /* Send the command reply to the client */
-  silc_server_command_identify_send_reply(cmd, 
-                                         clients, clients_count,
-                                         servers, servers_count,
-                                         channels, channels_count, 
-                                         errors, errors_count,
-                                         count);
-
- out:
-  silc_free(clients);
-  silc_free(servers);
-  silc_free(channels);
-  silc_free(errors);
-  return ret;
-}
+/* Server side of command IDENTIFY. */
 
 SILC_SERVER_CMD_FUNC(identify)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  int ret = 0;
-
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 256);
-
-  ret = silc_server_command_identify_process(cmd);
+  silc_server_query_command(cmd->server, SILC_COMMAND_IDENTIFY, cmd);
   silc_server_command_free(cmd);
 }
 
@@ -5177,6 +3570,7 @@ SILC_SERVER_CMD_FUNC(detach)
   /* Send the user mode notify to notify that client is detached */
   client->mode |= SILC_UMODE_DETACHED;
   client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
+  client->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
   client->last_command = 0;
   client->fast_command = 0;
   silc_server_send_notify_umode(server, SILC_PRIMARY_ROUTE(server),