Rewrote WHOIS, WHOWAS and IDENTIFY commands.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 22 Sep 2002 12:19:09 +0000 (12:19 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 22 Sep 2002 12:19:09 +0000 (12:19 +0000)
CHANGES
TODO
apps/silcd/command.c
apps/silcd/command_reply.c
apps/silcd/idlist.h
apps/silcd/packet_send.c
apps/silcd/server_query.c
lib/silccore/silcattrs.h
lib/silccore/silccommand.h
lib/silccore/silcpacket.h

diff --git a/CHANGES b/CHANGES
index 2f2451f347cbb3c570713a917782b573a4b99ade..a2aa219b2d62e7247092db56639299f4fdbae14e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,19 @@
+Sun Sep 22 14:54:05 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * Rewrote WHOIS, WHOWAS and IDENTIFY commands in the server.
+         Added server_query.[ch] which provides one interface for
+         querying information using all three commands.
+
+       * Changed all "typedef unsigned char" in core library to
+         "typedef SilcUInt8".
+
+Sat Sep 21 21:36:45 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added silc_strncat into lib/silcutil/silcstrutil.[ch].
+
+       * Renamed silc_server_get_client_resolve to
+         silc_server_query_resolve and moved to server_query.[ch].
+
 Wed Sep 18 18:28:04 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Resumed client packet handling from server put the resumed
diff --git a/TODO b/TODO
index a1e9ed62453bba1e6617b0685db11f5103c9317c..165c657f5a26e21d3d4e35bd7d307de4958dcf66 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,6 +1,12 @@
 TODO/bugs in Irssi SILC client
 ==============================
 
+ o Server password is not used at all.  It is not possible to automize
+   the password authentication currently.  The silc_get_auth_method
+   in irssi/src/silc/core/client_ops.c should find the connection's
+   password, only if not found then continue resolving the auth method.
+   Alternatively it can do it after resolving in the callback.
+
  o UTF-8 encode/decode WHOIS userinfos, topic, etc.
 
  o Testing
@@ -24,8 +30,6 @@ TODO/bugs In SILC Client Library
 TODO/bugs In SILC Server
 ========================
 
- o WHOIS may not send reply in certain situations.
-
  o Add support for the <Requested Attributes> in WHOIS.  Sending and
    reception, with clients and servers should be added.
 
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),
index bff81fa6644965d02569106e54f6924721fe894d..1044a2b7910533dccf28eb1cad49b94a8801c596 100644 (file)
@@ -376,6 +376,8 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
       return FALSE;
     }
 
+    client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
+    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; 
     client->servername = servername;
   } else {
@@ -386,10 +388,13 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
 
     silc_free(client->nickname);
     silc_free(client->username);
+    silc_free(client->servername);
     
     client->nickname = nick;
     client->username = strdup(username);
     client->servername = servername;
+    client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
+    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
 
     /* Remove the old cache entry and create a new one */
     silc_idcache_del_by_context(global ? server->global_list->clients :
@@ -436,8 +441,13 @@ SILC_SERVER_CMD_REPLY_FUNC(whowas)
   }
 
  out:
+  silc_server_command_process_error(cmd, error);
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
+  silc_server_command_reply_free(cmd);
+  return;
+
  err:
+  silc_server_command_process_error(cmd, error);
   silc_server_command_reply_free(cmd);
 }
 
index add6762069b37aed7c8296678c24fa0c817e7b06..1e99f2c16f4bb019ad4d230971f6a7186d4d92fb 100644 (file)
@@ -64,6 +64,8 @@ typedef SilcUInt8 SilcIDListStatus;
 #define SILC_IDLIST_STATUS_LOCAL        0x20  /* Entry locally connected */
 #define SILC_IDLIST_STATUS_RESUME_RES   0x40  /* Entry resolved while
                                                 resuming */
+#define SILC_IDLIST_STATUS_NOATTR       0x80  /* Entry does not support
+                                                attributes in WHOIS */
 
 /*
    Generic ID list data structure.
index 000f16df4f1b2018b49c941a08f2c5eb403e55c8..e69cc2f204479559734dd52754f62241c197e8ee 100644 (file)
@@ -1805,7 +1805,7 @@ void silc_server_send_command(SilcServer server,
 
   packet = silc_command_payload_encode_vap(command, ident, argc, ap);
   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND, 0,
-                         packet->data, packet->len, TRUE);
+                         packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
   va_end(ap);
 }
@@ -1856,7 +1856,7 @@ void silc_server_send_dest_command_reply(SilcServer server,
                                                 ident, argc, ap);
   silc_server_packet_send_dest(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
                               dst_id, dst_id_type, packet->data, 
-                              packet->len, TRUE);
+                              packet->len, FALSE);
   silc_buffer_free(packet);
   va_end(ap);
 }
index 711ecdefa3a416849fd7fab621666cb32b091e68..f3696c37a47a78a54f8b3d27a4b267eaf7c0db5d 100644 (file)
 */
 /* $Id$ */
 
+/* XXX TODO Requested Attributes to WHOIS
+   (NOTE: entry that is incomplete must be resolved first before resolving
+   the attributes) */
+
 #include "serverincludes.h"
 #include "server_internal.h"
 
+typedef struct {
+  SilcSocketConnection sock;       /* Connection of this query */
+  unsigned char **arg;             /* Query argument */
+  SilcUInt32 *arg_lens;                    /* Query argument lengths */
+  SilcUInt32 *arg_types;           /* Query argument types */
+  SilcUInt32 argc;                 /* Number of query arguments */
+  SilcUInt32 timeout;              /* Max timeout for query to complete */
+  SilcUInt16 ident;                /* Query command identifier */
+} *SilcServerQueryList;
+
 /* Represents an SILC ID */
 typedef struct {
   void *id;                        /* ID */
   SilcIdType id_type;              /* ID type */
+  SilcUInt16 ident;                /* Command identifier */
 } *SilcServerQueryID;
 
 /* Represents one error occurred during query */
 typedef struct {
-  SilcUInt32 index;                /* Index to IDs */
-  bool from_cmd;                   /* TRUE if `index' is from command args,
+  void *id;                        /* ID */
+  SilcUInt16 index;                /* Index to IDs */
+  SilcIdType id_type;              /* ID type */
+  unsigned int from_cmd : 1;               /* TRUE if `index' is from command args,
                                       otherwise from query->ids */
-  SilcStatus error;                /* The actual error */
+  unsigned int error : 7;          /* The actual error (SilcStatus) */
 } *SilcServerQueryError;
 
-/* Context for ongoing queries that server the original query (like to
-   resolve detailed information from some other server before replying
-   to the original sender). */
-typedef struct {
-  unsigned char **arg;             /* Query argument */
-  SilcUInt32 *arg_lens;                    /* Query argument lengths */
-  SilcUInt32 *arg_types;           /* Query argument types */
-  SilcUInt32 argc;                 /* Number of query arguments */
-  SilcUInt32 timeout;              /* Max timeout for query to complete */
-  SilcUInt16 ident;                /* Query command identifier */
-} *SilcServerQueryList;
-
 /* Query session context */
 typedef struct {
-  /* Query session data */
-  SilcCommand querycmd;                    /* Query command */
-  SilcServerCommandContext cmd;            /* Command context for query */
-  SilcServerQueryList queries;     /* Ongoing queries */
-  SilcUInt32 num_query;                    /* Number of ongoing queries left */
-
   /* Queried data */
   char *nickname;                  /* Queried nickname */
   char *nick_server;               /* Queried nickname's server */
@@ -65,14 +64,21 @@ typedef struct {
   SilcUInt32 reply_count;          /* Requested reply count */
   SilcDList attrs;                 /* Requested Attributes in WHOIS */
 
+  /* Query session data */
+  SilcServerCommandContext cmd;            /* Command context for query */
+  SilcServerQueryList querylist;    /* Temporary query list context */
+  SilcServerQueryID queries;       /* Ongoing queries */
   SilcServerQueryError errors;     /* Query errors */
-  SilcUInt32 errors_count;         /* number of errors */
+  SilcUInt16 querylist_count;      /* Number of query lists */
+  SilcUInt16 queries_count;        /* Number of ongoing queries */
+  SilcUInt16 queries_left;         /* Number of ongoing queries left */
+  SilcUInt16 errors_count;         /* number of errors */
+  unsigned int querycmd : 7;       /* Query command (SilcCommand) */
+  unsigned int resolved : 1;       /* TRUE if normal server has resolved
+                                      information from router */
 } *SilcServerQuery;
 
 void silc_server_query_free(SilcServerQuery query);
-bool silc_server_query_check_error(SilcServer server,
-                                  SilcServerQuery query,
-                                  SilcServerCommandReplyContext cmdr);
 void silc_server_query_send_error(SilcServer server,
                                  SilcServerQuery query,
                                  SilcStatus error, ...);
@@ -81,10 +87,15 @@ void silc_server_query_add_error(SilcServer server,
                                 bool from_cmd,
                                 SilcUInt32 index,
                                 SilcStatus error);
+void silc_server_query_add_error_id(SilcServer server,
+                                   SilcServerQuery query,
+                                   SilcStatus error,
+                                   void *id, SilcIdType id_type);
 void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
 void silc_server_query_send_router_reply(void *context, void *reply);
 void silc_server_query_parse(SilcServer server, SilcServerQuery query);
-void silc_server_query_process(SilcServer server, SilcServerQuery query);
+void silc_server_query_process(SilcServer server, SilcServerQuery query,
+                              bool resolve);
 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
                               SilcSocketConnection sock,
                               SilcClientEntry client_entry);
@@ -106,6 +117,10 @@ void silc_server_query_free(SilcServerQuery query)
 
   silc_server_command_free(query->cmd);
 
+  for (i = 0; i < query->queries_count; i++)
+    silc_free(query->queries[i].id);
+  silc_free(query->queries);
+
   silc_free(query->nickname);
   silc_free(query->nick_server);
   silc_free(query->server_name);
@@ -118,40 +133,14 @@ void silc_server_query_free(SilcServerQuery query)
   if (query->attrs)
     silc_attribute_payload_list_free(query->attrs);
 
+  for (i = 0; i < query->errors_count; i++)
+    silc_free(query->errors[i].id);
   silc_free(query->errors);
 
   memset(query, 'F', sizeof(*query));
   silc_free(query);
 }
 
-/* Check whether command reply contained error, and reply the error to
-   the original sender if it occurred. */
-
-bool silc_server_query_check_error(SilcServer server,
-                                  SilcServerQuery query,
-                                  SilcServerCommandReplyContext cmdr)
-{
-  if (!cmdr)
-    return FALSE;
-
-  if (!silc_command_get_status(cmdr->payload, NULL, NULL)) {
-    SilcBuffer buffer;
-
-    /* Send the same command reply payload which contains the error */
-    silc_command_set_command(cmdr->payload, query->querycmd);
-    silc_command_set_ident(cmdr->payload,
-                          silc_command_get_ident(query->cmd->payload));
-    buffer = silc_command_payload_encode_payload(cmdr->payload);
-    silc_server_packet_send(server, query->cmd->sock,
-                           SILC_PACKET_COMMAND_REPLY, 0, 
-                           buffer->data, buffer->len, FALSE);
-    silc_buffer_free(buffer);
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
 /* Send error reply indicated by the `error' to the original sender of
    the query. */
 
@@ -171,6 +160,8 @@ void silc_server_query_send_error(SilcServer server,
     data_len = va_arg(va, SilcUInt32);
   }
 
+  SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
+
   /* Send the command reply with error */
   silc_server_send_command_reply(server, query->cmd->sock,
                                 query->querycmd, error, 0, 
@@ -198,6 +189,28 @@ void silc_server_query_add_error(SilcServer server,
   query->errors[query->errors_count].index = index;
   query->errors[query->errors_count].from_cmd = from_cmd;
   query->errors[query->errors_count].error = error;
+  query->errors[query->errors_count].id = NULL;
+  query->errors[query->errors_count].id_type = 0;
+  query->errors_count++;
+}
+
+/* Same as silc_server_query_add_error but adds the ID data to be used
+   with error sending with this error type. */
+
+void silc_server_query_add_error_id(SilcServer server,
+                                   SilcServerQuery query,
+                                   SilcStatus error,
+                                   void *id, SilcIdType id_type)
+{
+  query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
+                              (query->errors_count + 1));
+  if (!query->errors)
+    return;
+  query->errors[query->errors_count].index = 0;
+  query->errors[query->errors_count].from_cmd = FALSE;
+  query->errors[query->errors_count].error = error;
+  query->errors[query->errors_count].id = silc_id_dup(id, id_type);
+  query->errors[query->errors_count].id_type = id_type;
   query->errors_count++;
 }
 
@@ -213,6 +226,8 @@ bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
 {
   SilcServerQuery query;
 
+  SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
+
   query = silc_calloc(1, sizeof(*query));
   query->querycmd = querycmd;
   query->cmd = silc_server_command_dup(cmd);
@@ -223,17 +238,19 @@ bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
     /* If we are normal server and query contains nickname, send it
        directly to router. */
     if (server->server_type == SILC_SERVER && !server->standalone &&
+       cmd->sock != SILC_PRIMARY_ROUTE(server) &&
        silc_argument_get_arg_type(cmd->args, 1, NULL)) {
       silc_server_query_send_router(server, query);
-      break;
+      return TRUE;
     }
     break;
 
   case SILC_COMMAND_WHOWAS:
     /* WHOWAS query is always sent to router if we are normal server */
-    if (server->server_type == SILC_SERVER && !server->standalone) {
+    if (server->server_type == SILC_SERVER && !server->standalone &&
+       cmd->sock != SILC_PRIMARY_ROUTE(server)) {
       silc_server_query_send_router(server, query);
-      break;
+      return TRUE;
     }
     break;
 
@@ -242,9 +259,10 @@ bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
        directly to router (it contains nickname, server name or channel
        name). */
     if (server->server_type == SILC_SERVER && !server->standalone &&
+       cmd->sock != SILC_PRIMARY_ROUTE(server) &&
        !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
       silc_server_query_send_router(server, query);
-      break;
+      return TRUE;
     }
     break;
 
@@ -269,6 +287,8 @@ void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
   SilcBuffer tmpbuf;
   SilcUInt16 old_ident;
 
+  SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
+
   /* Send WHOIS command to our router */
   old_ident = silc_command_get_ident(query->cmd->payload);
   silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
@@ -280,6 +300,8 @@ void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
   silc_command_set_ident(query->cmd->payload, old_ident);
   silc_buffer_free(tmpbuf);
 
+  query->resolved = TRUE;
+
   /* Continue parsing the query after received reply from router */
   silc_server_command_pending(server, query->querycmd, server->cmd_ident,
                              silc_server_query_send_router_reply, query);
@@ -292,9 +314,25 @@ void silc_server_query_send_router_reply(void *context, void *reply)
 {
   SilcServerQuery query = context;
   SilcServer server = query->cmd->server;
+  SilcServerCommandReplyContext cmdr = reply;
+
+  SILC_LOG_DEBUG(("Received reply from router to query"));
 
   /* Check if router sent error reply */
-  if (!silc_server_query_check_error(server, query, reply)) {
+  if (cmdr && !silc_command_get_status(cmdr->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(cmdr->payload, query->querycmd);
+    silc_command_set_ident(cmdr->payload,
+                          silc_command_get_ident(query->cmd->payload));
+    buffer = silc_command_payload_encode_payload(cmdr->payload);
+    silc_server_packet_send(server, query->cmd->sock,
+                           SILC_PACKET_COMMAND_REPLY, 0, 
+                           buffer->data, buffer->len, FALSE);
+    silc_buffer_free(buffer);
     silc_server_query_free(query);
     return;
   }
@@ -314,6 +352,9 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
   SilcIdType id_type;
   int i;
 
+  SILC_LOG_DEBUG(("Parsing %s query",
+                 silc_get_command_name(query->querycmd)));
+
   switch (query->querycmd) {
 
   case SILC_COMMAND_WHOIS:
@@ -354,6 +395,23 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
          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 (!silc_idlist_find_client_by_id(server->local_list,
+                                            id, TRUE, NULL)) {
+           if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
+               !silc_idlist_find_client_by_id(server->global_list,
+                                              id, TRUE, NULL)) {
+             silc_server_query_send_router(server, query);
+             for (i = 0; i < query->ids_count; i++)
+               silc_free(query->ids[i].id);
+             silc_free(query->ids);
+             return;
+           }
+         }
+       }
+
        query->ids[query->ids_count].id = id;
        query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
        query->ids_count++;
@@ -435,6 +493,23 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
          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 (!silc_idlist_find_client_by_id(server->local_list,
+                                            id, TRUE, NULL)) {
+           if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
+               !silc_idlist_find_client_by_id(server->global_list,
+                                              id, TRUE, NULL)) {
+             silc_server_query_send_router(server, query);
+             for (i = 0; i < query->ids_count; i++)
+               silc_free(query->ids[i].id);
+             silc_free(query->ids);
+             return;
+           }
+         }
+       }
+
        query->ids[query->ids_count].id = id;
        query->ids[query->ids_count].id_type = id_type;
        query->ids_count++;
@@ -449,15 +524,15 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
   }
 
   /* Start processing the query information */
-  silc_server_query_process(server, query);
+  silc_server_query_process(server, query, TRUE);
 }
 
 /* Processes the parsed query.  This does the actual finding of the
    queried information and prepares for sending reply to the original
-   sender of the query command.  It is guaranteed that this function
-   (which may be slow) is called only once for entire query. */
+   sender of the query command. */
 
-void silc_server_query_process(SilcServer server, SilcServerQuery query)
+void silc_server_query_process(SilcServer server, SilcServerQuery query,
+                              bool resolve)
 {
   SilcServerCommandContext cmd = query->cmd;
   bool check_global = FALSE;
@@ -468,6 +543,9 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query)
   SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
   int i;
 
+  SILC_LOG_DEBUG(("Processing %s query",
+                 silc_get_command_name(query->querycmd)));
+
   /* Check global lists if query is coming from client or we are not
      normal server (we know global information). */
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
@@ -607,29 +685,40 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query)
   /* If nothing was found, then just send the errors */
   if (!clients && !channels && !servers) {
     silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
-    silc_server_query_free(query);
+    return;
+  }
+
+  /* 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;
   }
 
   /* Now process all found information and if necessary do some more
-     querying. */
+     resolving. */
   switch (query->querycmd) {
 
   case SILC_COMMAND_WHOIS:
     for (i = 0; i < clients_count; i++) {
       client_entry = clients[i];
 
-      if (!client_entry)
+      /* Check if cannot query this anyway, so take next one */
+      if (!client_entry ||
+         !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
        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. */
       if (!query->attrs) {
-       if ((client_entry->nickname && client_entry->username &&
-            client_entry->userinfo) ||
-           !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
-
+       if (client_entry->nickname && client_entry->username &&
+           client_entry->userinfo) {
          /* Check if cannot query this anyway, so take next one */
          if (!client_entry->router)
            continue;
@@ -637,7 +726,8 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query)
          /* 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))
+             || silc_hash_table_count(client_entry->channels) ||
+             query->resolved)
            continue;
        }
       }
@@ -646,7 +736,8 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query)
         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->mode & SILC_UMODE_DETACHED ||
+          client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
        continue;
 
       /* Resolve the detailed client information. If client is local we
@@ -665,7 +756,8 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query)
       client_entry = clients[i];
 
       /* Check if cannot query this anyway, so take next one */
-      if (!client_entry || !client_entry->router)
+      if (!client_entry || !client_entry->router ||
+         client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
        continue;
 
       /* If both nickname and username are present no resolving is needed */
@@ -684,15 +776,16 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query)
       client_entry = clients[i];
 
       /* Check if cannot query this anyway, so take next one */
-      if (!client_entry || !client_entry->router)
+      if (!client_entry || !client_entry->router ||
+         !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
        continue;
 
-      if (client_entry->nickname ||
-         !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+      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))
+           || silc_hash_table_count(client_entry->channels) ||
+           query->resolved)
          continue;
       }
 
@@ -704,7 +797,7 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query)
     break;
   }
 
-  if (!query->num_query)
+  if (!query->queries_count)
     /* If we didn't have to do any resolving, continue with sending the
        command reply to the original sender. */
     silc_server_query_send_reply(server, query, clients, clients_count,
@@ -727,8 +820,13 @@ void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
                               SilcSocketConnection sock,
                               SilcClientEntry client_entry)
 {
-#if 0
+  SilcServerCommandContext cmd = query->cmd;
+  SilcServerQueryList r = NULL;
+  SilcBuffer idp;
+  unsigned char *tmp;
+  SilcUInt32 len;
   SilcUInt16 ident;
+  int i;
 
   if (!sock && client_entry)
     return;
@@ -736,23 +834,115 @@ void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
   /* If arguments are NULL we will now actually send the resolvings
      that earlier has been gathered by calling this function. */
   if (!sock && !client_entry) {
+    SilcBuffer res_cmd;
+
+    SILC_LOG_DEBUG(("Sending the resolvings"));
+
+    /* WHOWAS resolving has been done at the same time this function
+       was called to add the resolving for WHOWAS, so just return. */
+    if (query->querycmd == SILC_COMMAND_WHOWAS)
+      return;
+
+    for (i = 0; i < query->querylist_count; i++) {
+      r = &query->querylist[i];
+
+      /* Send WHOIS command */
+      res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
+                                           r->argc, r->arg, r->arg_lens,
+                                           r->arg_types, r->ident);
+      silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
+                             res_cmd->data, res_cmd->len, FALSE);
+      silc_buffer_free(res_cmd);
+
+      /* Reprocess this packet after received reply */
+      if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
+                                           r->ident,
+                                           silc_server_query_resolve_reply,
+                                           query, r->timeout))
+       query->queries_left++;
+    }
 
+    /* Cleanup this temporary context */
+    for (i = 0; i < query->querylist_count; i++) {
+      int k;
+      for (k = 0; k < query->querylist[i].argc; k++)
+       silc_free(query->querylist[i].arg[k]);
+      silc_free(query->querylist[i].arg);
+      silc_free(query->querylist[i].arg_lens);
+      silc_free(query->querylist[i].arg_types);
+    }
+    silc_free(query->querylist);
+    query->querylist = NULL;
+    query->querylist_count = 0;
     return;
   }
 
+  SILC_LOG_DEBUG(("Resolving client information"));
+
   if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
     /* The entry is being resolved by some other external query already.
        Attach to that query instead of resolving again. */
     ident = client_entry->resolve_cmd_ident;
-    silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
-                               silc_server_query_resolve_reply, query);
+    if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
+                                   silc_server_query_resolve_reply, query))
+      query->queries_left++;
   } else {
+    /* This entry will be resolved */
     ident = ++server->cmd_ident;
 
     switch (query->querycmd) {
 
     case SILC_COMMAND_WHOIS:
     case SILC_COMMAND_IDENTIFY:
+      /* Take existing query context if exist for this connection */
+      for (i = 0; i < query->queries_count; i++)
+       if (query->querylist[i].sock == sock) {
+         r = &query->querylist[i];
+         break;
+       }
+
+      if (!r) {
+       /* Allocate new temp query list context */
+       query->querylist = silc_realloc(query->querylist,
+                                       sizeof(*query->querylist) * 
+                                       (query->querylist_count + 1));
+       r = &query->querylist[query->querylist_count];
+       query->querylist_count++;
+       memset(r, 0, sizeof(*r));
+       r->sock = sock;
+       r->ident = ident;
+       if (SILC_IS_LOCAL(client_entry))
+         r->timeout = 3;
+      }
+
+      /* If attributes were present put them to this resolving */
+      if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
+       len = r->argc + 1;
+       r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
+       r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
+       r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
+
+       tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+       if (tmp)
+         r->arg[r->argc] = silc_memdup(tmp, len);
+       r->arg_lens[r->argc] = len;
+       r->arg_types[r->argc] = 3;
+       r->argc++;
+      }
+
+      len = r->argc + 1;
+      r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
+      r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
+      r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
+
+      /* Add the client entry to be resolved */
+      idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
+      r->arg[r->argc] = silc_memdup(idp->data, idp->len);
+      r->arg_lens[r->argc] = idp->len;
+      r->arg_types[r->argc] = r->argc + 4;
+      r->argc++;
+      silc_buffer_free(idp);
+
       break;
 
     case SILC_COMMAND_WHOWAS:
@@ -760,30 +950,29 @@ void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
         resolving clients that are not present in the network anymore. */
       silc_server_send_command(server, sock, query->querycmd, ident, 1,
                               1, query->nickname, strlen(query->nickname));
+      if (silc_server_command_pending(server, query->querycmd, ident,
+                                     silc_server_query_resolve_reply, query))
+       query->queries_left++;
       break;
     }
-
-    silc_server_command_pending(server, query->querycmd, ident,
-                               silc_server_query_resolve_reply, query);
   }
 
   /* Mark the entry as being resolved */
   client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
   client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
-  client_entry->resovle_cmd_ident = ident;
-
-  /* Save the query information, which we will reprocess after we
-     get this and all other queries back. */
-  query->ids = silc_realloc(query->ids, sizeof(*query->ids) *
-                           (query->ids_count + 1));
-  if (query->ids) {
-    query->ids[query->ids_count].id = silc_id_dup(id, id_type);
-    query->ids[query->ids_count].id_type = id_type;
-    query->ids[query->ids_count].ident = ident;
-    query->ids_count++;
+  client_entry->resolve_cmd_ident = ident;
+
+  /* Save the queried ID, which we will reprocess after we get this and
+     all other queries back. */
+  query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
+                               (query->queries_count + 1));
+  if (query->queries) {
+    i = query->queries_count;
+    query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
+    query->queries[i].id_type = SILC_ID_CLIENT;
+    query->queries[i].ident = ident;
+    query->queries_count++;
   }
-  query->num_query++;
-#endif
 }
 
 /* Reply callback called after one resolving has been completed.  If
@@ -793,10 +982,74 @@ void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
 void silc_server_query_resolve_reply(void *context, void *reply)
 {
   SilcServerQuery query = context;
+  SilcServer server = query->cmd->server;
+  SilcServerCommandReplyContext cmdr = reply;
+  SilcUInt16 ident = cmdr->ident;
+  SilcStatus error = SILC_STATUS_OK;
+  SilcServerQueryID id = NULL;
+  SilcClientEntry client_entry;
+  int i;
 
+  /* One less query left */
+  query->queries_left--;
+
+  silc_command_get_status(cmdr->payload, NULL, &error);
+  SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
+                 query->queries_left, error));
+
+  /* If no error then skip to other stuff */
+  if (error == SILC_STATUS_OK)
+    goto out;
+
+  /* Error occurred during resolving */
+
+  /* Find the resolved client ID */
+  for (i = 0; i < query->queries_count; i++) {
+    if (query->queries[i].ident != ident)
+      continue;
+
+    id = &query->queries[i];
+
+    if (error == SILC_STATUS_ERR_TIMEDOUT) {
+      /* If timeout occurred for local entry when resolving attributes
+        mark that this client doesn't support attributes in WHOIS. This
+        assures we won't send the request again to the client. */
+      if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
+       client_entry = silc_idlist_find_client_by_id(server->local_list,
+                                                    id->id, TRUE, NULL);
+       SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
+                       silc_id_render(id->id, SILC_ID_CLIENT)));
+       if (client_entry && SILC_IS_LOCAL(client_entry))
+         client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
+      }
+    }
+  }
+
+ out:
+
+  /* If there are queries left then wait for them */
+  if (query->queries_left)
+    return;
 
+  SILC_LOG_DEBUG(("Reprocess the query"));
+
+  /* We have received all queries.  Now re-search all information required
+     to complete this query.  Reason we cannot save the values found in
+     the first search is that SilcClientEntry, SilcServerEntry and
+     SilcChannelEntry pointers may become invalid while we were waiting
+     for these resolvings. */
+  silc_server_query_process(server, query, FALSE);
 }
 
+/* Send the reply to the original query.  If arguments are NULL then this
+   sends only the errors that has occurred during the processing of the
+   query.  This sends the errors always after sending all the found
+   information.  The query is over after this function returns and the
+   `query' will become invalid.  This is called only after all informations
+   has been resolved.  This means that if something is not found or is
+   incomplete in this function we were unable to resolve the information
+   or it does not exist at all. */
+
 void silc_server_query_send_reply(SilcServer server,
                                  SilcServerQuery query,
                                  SilcClientEntry *clients,
@@ -806,7 +1059,385 @@ void silc_server_query_send_reply(SilcServer server,
                                  SilcChannelEntry *channels,
                                  SilcUInt32 channels_count)
 {
+  SilcServerCommandContext cmd = query->cmd;
+  SilcUInt16 ident = silc_command_get_ident(cmd->payload);
+  SilcStatus status;
+  unsigned char *tmp;
+  SilcUInt32 len;
+  SilcBuffer idp;
+  int i, k, valid_count;
+  char nh[256], uh[256];
+
+  SILC_LOG_DEBUG(("Sending reply to query"));
+
+  status = SILC_STATUS_OK;
+
+  /* Send clients */
+  if (clients_count) {
+    SilcClientEntry entry;
+    SilcSocketConnection hsock;
+
+    /* Mark all invalid entries */
+    for (i = 0, valid_count = 0; i < clients_count; i++) {
+      entry = clients[i];
+      switch (query->querycmd) {
+      case SILC_COMMAND_WHOIS:
+       if (!entry->nickname || !entry->username || !entry->userinfo ||
+           !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+         /* When querying by ID, every "unfound" entry must cause error */
+         if (query->ids)
+           silc_server_query_add_error_id(server, query,
+                                          SILC_STATUS_ERR_TIMEDOUT,
+                                          entry->id, SILC_ID_CLIENT);
+         clients[i] = NULL;
+         continue;
+       }
+       break;
+
+      case SILC_COMMAND_IDENTIFY:
+       if (!entry->nickname ||
+           !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+         /* When querying by ID, every "unfound" entry must cause error */
+         if (query->ids)
+           silc_server_query_add_error_id(server, query,
+                                          SILC_STATUS_ERR_TIMEDOUT,
+                                          entry->id, SILC_ID_CLIENT);
+         clients[i] = NULL;
+         continue;
+       }
+       break;
+
+      case SILC_COMMAND_WHOWAS:
+       if (!entry->nickname || !entry->username ||
+           entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
+         clients[i] = NULL;
+         continue;
+       }
+       break;
+      }
+      valid_count++;
+    }
+
+    /* Start processing found clients */
+    status = SILC_STATUS_OK;
+    if (valid_count > 1)
+      status = SILC_STATUS_LIST_START;
+
+    /* Now do the sending of valid entries */
+    k = 0;
+    for (i = 0; i < clients_count && valid_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 && !query->errors_count)
+       status = SILC_STATUS_LIST_END;
+      if (query->reply_count && k - 1 == query->reply_count)
+       status = SILC_STATUS_LIST_END;
+
+      SILC_LOG_DEBUG(("%s: client %s",
+                     (status == SILC_STATUS_OK ?         "   OK" :
+                      status == SILC_STATUS_LIST_START ? "START" :
+                      status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
+                      status == SILC_STATUS_LIST_END  ?  "  END" :
+                      "      : "), entry->nickname));
+
+      idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+      memset(uh, 0, sizeof(uh));
+      memset(nh, 0, sizeof(nh));
+
+      silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
+      if (!strchr(entry->nickname, '@')) {
+       silc_strncat(nh, sizeof(nh), "@", 1);
+       if (entry->servername) {
+         silc_strncat(nh, sizeof(nh), entry->servername,
+                      strlen(entry->servername));
+       } else {
+         len = entry->router ? strlen(entry->router->server_name) :
+           strlen(server->server_name);
+         silc_strncat(nh, sizeof(nh), entry->router ?
+                      entry->router->server_name :
+                      server->server_name, len);
+       }
+      }
+      
+      switch (query->querycmd) {
+       
+      case SILC_COMMAND_WHOIS:
+       {
+         unsigned char idle[4], mode[4];
+         unsigned char *fingerprint, fempty[20];
+         SilcBuffer channels, umode_list = NULL;
+
+         memset(fempty, 0, sizeof(fempty));
+         silc_strncat(uh, sizeof(uh), entry->username,
+                      strlen(entry->username));
+         if (!strchr(entry->username, '@') && entry->connection) {
+           hsock = entry->connection;
+           silc_strncat(uh, sizeof(uh), "@", 1);
+           len = strlen(hsock->hostname);
+           silc_strncat(uh, sizeof(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);
+
+         /* Send command reply */
+         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
+                                        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);
+
+         if (channels)
+           silc_buffer_free(channels);
+         if (umode_list) {
+           silc_buffer_free(umode_list);
+           umode_list = NULL;
+         }
+       }
+       break;
+
+      case SILC_COMMAND_IDENTIFY:
+       if (!entry->username) {
+         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
+                                        status, 0, ident, 2,
+                                        2, idp->data, idp->len,
+                                        3, nh, strlen(nh));
+       } else {
+         silc_strncat(uh, sizeof(uh), entry->username,
+                      strlen(entry->username));
+         if (!strchr(entry->username, '@') && entry->connection) {
+           hsock = entry->connection;
+           silc_strncat(uh, sizeof(uh), "@", 1);
+           len = strlen(hsock->hostname);
+           silc_strncat(uh, sizeof(uh), hsock->hostname, len);
+         }
+
+         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
+                                        status, 0, ident, 3,
+                                        2, idp->data, idp->len,
+                                        3, nh, strlen(nh),
+                                        4, uh, strlen(uh));
+       }
+       break;
+
+      case SILC_COMMAND_WHOWAS:
+       silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
+       if (!strchr(entry->username, '@'))
+         silc_strncat(uh, sizeof(uh), "@*private*", 10);
+
+       /* Send command reply */
+       silc_server_send_command_reply(server, cmd->sock, query->querycmd,
+                                      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);
+       break;
+      }
+
+      silc_buffer_free(idp);
 
+      if (status == SILC_STATUS_LIST_END)
+       break;
+      k++;
+    }
+
+    if (k == 0) {
+      /* Not one valid entry was found, send error.  If nickname was used
+        in query send error based on that, otherwise the query->errors
+        already includes proper errors. */
+      if (query->nickname)
+       silc_server_query_add_error(server, query, TRUE, 1,
+                                   SILC_STATUS_ERR_NO_SUCH_NICK);
+    }
+  }
+
+  /* Send servers */
+  if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
+    SilcServerEntry entry;
+
+    if (status == SILC_STATUS_OK && servers_count > 1)
+      status = SILC_STATUS_LIST_START;
+
+    k = 0;
+    for (i = 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 &&
+         !query->errors_count)
+       status = SILC_STATUS_LIST_END;
+      if (query->reply_count && k - 1 == query->reply_count)
+       status = SILC_STATUS_LIST_END;
+      
+      SILC_LOG_DEBUG(("%s: server %s",
+                     (status == SILC_STATUS_OK ?         "   OK" :
+                      status == SILC_STATUS_LIST_START ? "START" :
+                      status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
+                      status == SILC_STATUS_LIST_END  ?  "  END" :
+                      "      : "),
+                     entry->server_name ? entry->server_name : ""));
+
+      /* Send command reply */
+      idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
+      silc_server_send_command_reply(server, cmd->sock, 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_buffer_free(idp);
+      
+      if (status == SILC_STATUS_LIST_END)
+       break;
+      k++;
+    }
+  }
+
+  /* Send channels */
+  if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
+    SilcChannelEntry entry;
+
+    if (status == SILC_STATUS_OK && channels_count > 1)
+      status = SILC_STATUS_LIST_START;
+
+    k = 0;
+    for (i = 0; i < channels_count; i++) {
+      entry = channels[i];
+      
+      if (k >= 1)
+       status = SILC_STATUS_LIST_ITEM;
+      if (channels_count > 1 && k == channels_count - 1 &&
+         !query->errors_count)
+       status = SILC_STATUS_LIST_END;
+      if (query->reply_count && k - 1 == query->reply_count)
+       status = SILC_STATUS_LIST_END;
+      
+      SILC_LOG_DEBUG(("%s: channel %s",
+                     (status == SILC_STATUS_OK ?         "   OK" :
+                      status == SILC_STATUS_LIST_START ? "START" :
+                      status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
+                      status == SILC_STATUS_LIST_END  ?  "  END" :
+                      "      : "),
+                     entry->channel_name ? entry->channel_name : ""));
+
+      /* Send command reply */
+      idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
+      silc_server_send_command_reply(server, cmd->sock, 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_buffer_free(idp);
+      
+      if (status == SILC_STATUS_LIST_END)
+       break;
+      k++;
+    }
+  }
+
+  /* Send errors */
+  if (query->errors_count) {
+    int type;
+
+    if (status == SILC_STATUS_OK && query->errors_count > 1)
+      status = SILC_STATUS_LIST_START;
+
+    k = 0;
+    for (i = 0; i < query->errors_count; i++) {
+      idp = NULL;
+
+      /* Take error argument */
+      if (query->errors[i].from_cmd) {
+       tmp = silc_argument_get_arg_type(cmd->args,
+                                        query->errors[i].index, &len);
+       if (query->errors[i].index == 1)
+         type = 3;                 /* Nickname */
+       else
+         type = 2;                 /* ID */
+      } else if (!query->errors[i].id) {
+       idp =
+         silc_id_payload_encode(query->ids[query->errors[i].index].id,
+                                query->ids[query->errors[k].index].id_type);
+       tmp = idp->data;
+       len = idp->len;
+       type = 2;
+      } else {
+       idp = silc_id_payload_encode(query->errors[i].id,
+                                    query->errors[k].id_type);
+       tmp = idp->data;
+       len = idp->len;
+       type = 2;
+      }
+
+      if (k >= 1)
+       status = SILC_STATUS_LIST_ITEM;
+      if (query->errors_count > 1 && k == query->errors_count - 1)
+       status = SILC_STATUS_LIST_END;
+      if (query->reply_count && k - 1 == query->reply_count)
+       status = SILC_STATUS_LIST_END;
+
+      SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
+                     (status == SILC_STATUS_OK ?         "   OK" :
+                      status == SILC_STATUS_LIST_START ? "START" :
+                      status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
+                      status == SILC_STATUS_LIST_END  ?  "  END" :
+                      "      : "), 
+                     silc_get_status_message(query->errors[i].error),
+                     query->errors[i].error));
+
+      /* Send error */
+      silc_server_send_command_reply(server, cmd->sock, query->querycmd,
+                                    (status == SILC_STATUS_OK ?
+                                     query->errors[i].error : status),
+                                    (status == SILC_STATUS_OK ?
+                                     0 : query->errors[i].error), ident, 1,
+                                    type, tmp, len);
+      silc_buffer_free(idp);
+
+      if (status == SILC_STATUS_LIST_END)
+       break;
+      k++;
+    }
+  }
+
+  /* Cleanup */
+  silc_server_query_free(query);
 }
 
 /* Find client by the Client ID indicated by the `client_id', and if not
@@ -824,6 +1455,8 @@ SilcClientEntry silc_server_query_client(SilcServer server,
 {
   SilcClientEntry client;
 
+  SILC_LOG_DEBUG(("Resolving client by client ID"));
+
   if (resolved)
     *resolved = FALSE;
 
index f03dc7f4d0a6484845a0d8ce5f14487f6cfec1a7..89e6c00a4fc18b7d44b1793e6c2b7cf0296d46e7 100644 (file)
@@ -50,7 +50,7 @@ typedef struct SilcAttributePayloadStruct *SilcAttributePayload;
  *
  * NAME
  * 
- *    typedef unsigned char SilcAttribute;
+ *    typedef SilcUInt8 SilcAttribute;
  *
  * DESCRIPTION
  *
@@ -61,7 +61,7 @@ typedef struct SilcAttributePayloadStruct *SilcAttributePayload;
  *
  * SOURCE
  */
-typedef unsigned char SilcAttribute;
+typedef SilcUInt8 SilcAttribute;
 
 /* All defined attributes.  See the specs for detailed information.  The
    comment is the structure or data type that must be used with the
@@ -88,7 +88,7 @@ typedef unsigned char SilcAttribute;
  *
  * NAME
  * 
- *    typedef unsigned char SilcAttributeFlags;
+ *    typedef SilcUInt8 SilcAttributeFlags;
  *
  * DESCRIPTION
  *
@@ -96,7 +96,7 @@ typedef unsigned char SilcAttribute;
  *
  * SOURCE
  */
-typedef unsigned char SilcAttributeFlags;
+typedef SilcUInt8 SilcAttributeFlags;
 
 /* All defined flags */
 #define SILC_ATTRIBUTE_FLAG_NONE          0x00    /* No flags */
index b864a4261c20ab6f20617e7eb37006a77f67d0ff..363bbe0122517421f0b303e170c3c6ced1fca4c2 100644 (file)
@@ -109,7 +109,7 @@ typedef enum {
  *
  * NAME
  * 
- *    typedef unsigned char SilcCommand;
+ *    typedef SilcUInt8 SilcCommand;
  *
  * DESCRIPTION
  *
@@ -119,7 +119,7 @@ typedef enum {
  *
  * SOURCE
  */
-typedef unsigned char SilcCommand;
+typedef SilcUInt8 SilcCommand;
 
 /* All SILC commands. These are commands that have client and server
    counterparts. */
index 561b8fe1d3c3e7ca8b225f71ee598af078e4eeca..3583e473927e5a952819b8422e0aa2ebad5bde23 100644 (file)
@@ -61,7 +61,7 @@
  *
  * NAME
  * 
- *    typedef unsigned char SilcPacketType;
+ *    typedef SilcUInt8 SilcPacketType;
  *
  * DESCRIPTION
  *
@@ -69,7 +69,7 @@
  *
  * SOURCE
  */
-typedef unsigned char SilcPacketType;
+typedef SilcUInt8 SilcPacketType;
 
 /* SILC Packet types. */
 #define SILC_PACKET_NONE                0       /* NULL, never sent */
@@ -110,20 +110,20 @@ typedef unsigned char SilcPacketType;
  *
  * NAME
  * 
- *    typedef unsigned char SilcPacketVersion;
+ *    typedef SilcUInt8 SilcPacketVersion;
  *
  * DESCRIPTION
  *
  *    SILC packet version type definition.
  *
  ***/
-typedef unsigned char SilcPacketVersion;
+typedef SilcUInt8 SilcPacketVersion;
 
 /****d* silccore/SilcPacketAPI/SilcPacketFlags
  *
  * NAME
  * 
- *    typedef unsigned char SilcPacketFlags;
+ *    typedef SilcUInt8 SilcPacketFlags;
  *
  * DESCRIPTION
  *
@@ -131,7 +131,7 @@ typedef unsigned char SilcPacketVersion;
  *
  * SOURCE
  */
-typedef unsigned char SilcPacketFlags;
+typedef SilcUInt8 SilcPacketFlags;
 
 /* All defined packet flags */
 #define SILC_PACKET_FLAG_NONE             0x00    /* No flags */