New silcconfig library and server parser. Merged silc-newconfig-final.patch.
[silc.git] / apps / silcd / command.c
index 31fe32bd3b1ad4ca8e3962a70694f8db9a90cbb4..b4d5bcee37adf53669b7e5e77dde3ac515eb6dae 100644 (file)
@@ -35,7 +35,7 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
                                     SilcCommand command,
                                     SilcCommandStatus status,
                                     uint32 arg_type,
-                                    unsigned char *arg,
+                                    const unsigned char *arg,
                                     uint32 arg_len);
 static bool
 silc_server_command_pending_error_check(SilcServerCommandContext cmd,
@@ -131,7 +131,6 @@ static int silc_server_is_registered(SilcServer server,
 
   silc_server_command_send_status_reply(cmd, command,
                                        SILC_STATUS_ERR_NOT_REGISTERED);
-  silc_server_command_free(cmd);
   return FALSE;
 }
 
@@ -149,6 +148,11 @@ SILC_TASK_CALLBACK(silc_server_command_process_timeout)
   SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context;
   SilcClientEntry client = (SilcClientEntry)timeout->ctx->sock->user_data;
 
+  if (!client) {
+    silc_server_command_free(timeout->ctx);
+    silc_free(timeout);
+  }
+
   /* Update access time */
   client->last_command = time(NULL);
 
@@ -159,6 +163,8 @@ SILC_TASK_CALLBACK(silc_server_command_process_timeout)
                                     timeout->ctx, 
                                     timeout->cmd->cmd))
     timeout->cmd->cb(timeout->ctx, NULL);
+  else
+    silc_server_command_free(timeout->ctx);
 
   silc_free(timeout);
 }
@@ -181,7 +187,8 @@ void silc_server_command_process(SilcServer server,
   ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
   
   /* Parse the command payload in the packet */
-  ctx->payload = silc_command_payload_parse(packet->buffer);
+  ctx->payload = silc_command_payload_parse(packet->buffer->data,
+                                           packet->buffer->len);
   if (!ctx->payload) {
     SILC_LOG_ERROR(("Bad command payload, packet dropped"));
     silc_buffer_free(packet->buffer);
@@ -232,15 +239,12 @@ void silc_server_command_process(SilcServer server,
                         silc_server_command_process_timeout,
                         (void *)timeout, 
                         2 - (time(NULL) - client->last_command), 0,
-                        SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
     else
       silc_schedule_task_add(server->schedule, sock->sock, 
                         silc_server_command_process_timeout,
-                        (void *)timeout, 
-                        0, 1,
-                        SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+                        (void *)timeout, 0, 1,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
     return;
   }
 
@@ -250,6 +254,8 @@ void silc_server_command_process(SilcServer server,
     cmd->cb(ctx, NULL);
   else if (silc_server_is_registered(server, sock, ctx, cmd->cmd))
     cmd->cb(ctx, NULL);
+  else
+    silc_server_command_free(ctx);
 }
 
 /* Allocate Command Context */
@@ -296,24 +302,36 @@ silc_server_command_dup(SilcServerCommandContext ctx)
    with `context' when reply has been received.  It can be SILC_COMMAND_NONE
    to match any command with the `ident'.  If `ident' is non-zero
    the `callback' will be executed when received reply with command
-   identifier `ident'. */
+   identifier `ident'. If there already exists pending command for the
+   specified command, ident, callback and context this function has no
+   effect. */
 
-void silc_server_command_pending(SilcServer server,
+bool silc_server_command_pending(SilcServer server,
                                 SilcCommand reply_cmd,
                                 uint16 ident,
-                                SilcServerPendingDestructor destructor,
                                 SilcCommandCb callback,
                                 void *context)
 {
   SilcServerCommandPending *reply;
 
+  /* Check whether identical pending already exists for same command,
+     ident, callback and callback context. If it does then it would be
+     error to register it again. */
+  silc_dlist_start(server->pending_commands);
+  while ((reply = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
+    if (reply->reply_cmd == reply_cmd && reply->ident == ident &&
+       reply->callback == callback && reply->context == context)
+      return FALSE;
+  }
+
   reply = silc_calloc(1, sizeof(*reply));
   reply->reply_cmd = reply_cmd;
   reply->ident = ident;
   reply->context = context;
   reply->callback = callback;
-  reply->destructor = destructor;
   silc_dlist_add(server->pending_commands, reply);
+
+  return TRUE;
 }
 
 /* Deletes pending command by reply command type. */
@@ -354,7 +372,6 @@ silc_server_command_pending_check(SilcServer server,
       callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
       callbacks[i].context = r->context;
       callbacks[i].callback = r->callback;
-      callbacks[i].destructor = r->destructor;
       ctx->ident = ident;
       i++;
     }
@@ -364,14 +381,6 @@ silc_server_command_pending_check(SilcServer server,
   return callbacks;
 }
 
-/* Destructor function for pending callbacks. This is called when using
-   pending commands to free the context given for the pending command. */
-
-static void silc_server_command_destructor(void *context)
-{
-  silc_server_command_free((SilcServerCommandContext)context);
-}
-
 /* Sends simple status message as command reply packet */
 
 static void 
@@ -401,7 +410,7 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
                                     SilcCommand command,
                                     SilcCommandStatus status,
                                     uint32 arg_type,
-                                    unsigned char *arg,
+                                    const unsigned char *arg,
                                     uint32 arg_len)
 {
   SilcBuffer buffer;
@@ -438,8 +447,16 @@ silc_server_command_pending_error_check(SilcServerCommandContext cmd,
       status != SILC_STATUS_LIST_START &&
       status != SILC_STATUS_LIST_ITEM &&
       status != SILC_STATUS_LIST_END) {
-    /* Send the error message */
-    silc_server_command_send_status_reply(cmd, command, status);
+    SilcBuffer buffer;
+
+    /* Send the same command reply payload */
+    silc_command_set_ident(cmdr->payload, 
+                          silc_command_get_ident(cmd->payload));
+    buffer = silc_command_payload_encode_payload(cmdr->payload);
+    silc_server_packet_send(cmd->server, cmd->sock,
+                           SILC_PACKET_COMMAND_REPLY, 0, 
+                           buffer->data, buffer->len, FALSE);
+    silc_buffer_free(buffer);
     return TRUE;
   }
 
@@ -486,6 +503,8 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
     (*client_id)[0] = silc_id_payload_parse_id(tmp, len);
     if ((*client_id)[0] == NULL) {
       silc_free(*client_id);
+      silc_server_command_send_status_reply(cmd, command,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
       return FALSE;
     }
     *client_id_count = 1;
@@ -503,6 +522,9 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
            for (i = 0; i < *client_id_count; i++)
              silc_free((*client_id)[i]);
            silc_free(*client_id);
+           silc_server_command_send_status_reply(
+                                        cmd, command,
+                                        SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
            return FALSE;
          }
          (*client_id_count)++;
@@ -544,14 +566,27 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
   int i, k;
   bool no_res = TRUE;
 
+  SILC_LOG_DEBUG(("Start"));
+
   for (i = 0; i < clients_count; i++) {
     entry = clients[i];
-
-    if (!entry || (entry->nickname && entry->username && entry->userinfo) ||
-       !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
-       !entry->router)
+    if (!entry)
       continue;
 
+    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;
+    }
+
     /* We need to resolve this entry since it is not complete */
 
     if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
@@ -559,7 +594,6 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
         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_destructor,
                                  silc_server_command_whois,
                                  silc_server_command_dup(cmd));
       no_res = FALSE;
@@ -642,7 +676,6 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
     /* Reprocess this packet after received reply */
     silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
                                r->ident,
-                               silc_server_command_destructor,
                                silc_server_command_whois,
                                silc_server_command_dup(cmd));
     cmd->pending = TRUE;
@@ -664,84 +697,65 @@ static void
 silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
                                     SilcClientEntry *clients,
                                     uint32 clients_count,
-                                    int count)
+                                    int count,
+                                    const char *nickname,
+                                    SilcClientID **client_ids)
 {
   SilcServer server = cmd->server;
   char *tmp;
-  int i, k, len;
+  int i, k, len, valid_count;
   SilcBuffer packet, idp, channels;
   SilcClientEntry entry;
   SilcCommandStatus status;
   uint16 ident = silc_command_get_ident(cmd->payload);
   char nh[256], uh[256];
   unsigned char idle[4], mode[4];
+  unsigned char *fingerprint;
   SilcSocketConnection hsock;
 
-  len = 0;
-  for (i = 0; i < clients_count; i++)
+  /* Process only valid clients and ignore those that are not registered. */
+  valid_count = 0;
+  for (i = 0; i < clients_count; i++) {
     if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
-      len++;
+      valid_count++;
+    else
+      clients[i] = NULL;
+  }
 
-  if (len == 0 && clients_count) {
-    entry = clients[0];
-    if (entry->nickname) {
+  if (!valid_count) {
+    /* No valid clients found, send error reply */
+    if (nickname) {
       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
                                           SILC_STATUS_ERR_NO_SUCH_NICK,
-                                          3, entry->nickname, 
-                                          strlen(entry->nickname));
-    } else {
-      SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+                                          3, nickname, strlen(nickname));
+    } else if (client_ids && client_ids[0]) {
+      SilcBuffer idp = silc_id_payload_encode(client_ids[0], SILC_ID_CLIENT);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
                                           2, idp->data, idp->len);
       silc_buffer_free(idp);
     }
-
     return;
   }
 
-  status = SILC_STATUS_OK;
-  if (len > 1)
+  /* Start processing found clients. */
+  if (valid_count > 1)
     status = SILC_STATUS_LIST_START;
+  else
+    status = SILC_STATUS_OK;
 
   for (i = 0, k = 0; i < clients_count; i++) {
     entry = clients[i];
-
-    if (!(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
-      if (clients_count == 1) {
-       if (entry->nickname) {
-         silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
-                                              SILC_STATUS_ERR_NO_SUCH_NICK,
-                                              3, entry->nickname, 
-                                              strlen(entry->nickname));
-       } else {
-         SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-         silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
-                                    SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                              2, idp->data, idp->len);
-         silc_buffer_free(idp);
-       }
-      }
+    if (!entry)
       continue;
-    }
 
     if (k >= 1)
       status = SILC_STATUS_LIST_ITEM;
-
-    if (clients_count > 1 && k == clients_count - 1)
+    if (valid_count > 1 && k == valid_count - 1)
       status = SILC_STATUS_LIST_END;
-
     if (count && k - 1 == count)
       status = SILC_STATUS_LIST_END;
 
-    if (count && k - 1 > count)
-      break;
-
-    /* Sanity check, however these should never fail. However, as
-       this sanity check has been added here they have failed. */
-    if (!entry->nickname || !entry->username || !entry->userinfo)
-      continue;
-      
     /* Send WHOIS reply */
     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
     tmp = silc_argument_get_first_arg(cmd->args, NULL);
@@ -772,6 +786,11 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
     }
 
     channels = silc_server_get_client_channel_list(server, entry);
+
+    if (entry->data.fingerprint[0] != 0 && entry->data.fingerprint[1] != 0)
+      fingerprint = entry->data.fingerprint;
+    else
+      fingerprint = NULL;
       
     SILC_PUT32_MSB(entry->mode, mode);
 
@@ -779,29 +798,21 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
       SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
     }
 
-    if (channels)
-      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
-                                                   status, ident, 7, 
-                                                   2, idp->data, idp->len,
-                                                   3, nh, strlen(nh),
-                                                   4, uh, strlen(uh),
-                                                   5, entry->userinfo, 
-                                                   strlen(entry->userinfo),
-                                                   6, channels->data,
-                                                   channels->len,
-                                                   7, mode, 4,
-                                                   8, idle, 4);
-    else
-      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
-                                                   status, ident, 6, 
-                                                   2, idp->data, idp->len,
-                                                   3, nh, strlen(nh),
-                                                   4, uh, strlen(uh),
-                                                   5, entry->userinfo, 
-                                                   strlen(entry->userinfo),
-                                                   7, mode, 4,
-                                                   8, idle, 4);
-    
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
+                                          status, ident, 8, 
+                                          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);
+
     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                            0, packet->data, packet->len, FALSE);
     
@@ -814,6 +825,33 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
   }
 }
 
+static void 
+silc_server_command_whois_send_router(SilcServerCommandContext cmd)
+{
+  SilcServer server = cmd->server;
+  SilcBuffer tmpbuf;
+  uint16 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)
+                         server->router->connection,
+                         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)
 {
@@ -826,55 +864,29 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
   int i, ret = 0;
   bool check_global = FALSE;
 
-  /* Protocol dictates that we must always send the received WHOIS 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;
-    uint16 old_ident;
-
-    old_ident = silc_command_get_ident(cmd->payload);
-    silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
-    tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
-    /* Send WHOIS command to our router */
-    silc_server_packet_send(server, (SilcSocketConnection)
-                           server->router->connection,
-                           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_destructor,
-                               silc_server_command_whois,
-                               silc_server_command_dup(cmd));
-    cmd->pending = TRUE;
-
-    silc_command_set_ident(cmd->payload, old_ident);
+  /* Parse the whois request */
+  if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, 
+                                      &nick, &server_name, &count,
+                                      SILC_COMMAND_WHOIS))
+    return 0;
 
-    silc_buffer_free(tmpbuf);
+  /* 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;
   }
 
-  /* 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 whois request */
-  if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, 
-                                      &nick, &server_name, &count,
-                                      SILC_COMMAND_WHOIS))
-    return 0;
-
   /* 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 */
@@ -888,9 +900,20 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
        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;
+       }
       }
     }
   } else {
+    /* Find by nickname */
     if (!silc_idlist_get_clients_by_hash(server->local_list, 
                                         nick, server->md5hash,
                                         &clients, &clients_count))
@@ -908,6 +931,16 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
   }
   
   if (!clients) {
+    /* 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,
@@ -935,7 +968,7 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
 
   /* Send the command reply */
   silc_server_command_whois_send_reply(cmd, clients, clients_count,
-                                      count);
+                                      count, nick, client_id);
 
  out:
   if (client_id_count) {
@@ -961,9 +994,7 @@ SILC_SERVER_CMD_FUNC(whois)
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 3328);
 
   ret = silc_server_command_whois_process(cmd);
-
-  if (!ret)
-    silc_server_command_free(cmd);
+  silc_server_command_free(cmd);
 }
 
 /******************************************************************************
@@ -1021,7 +1052,7 @@ silc_server_command_whowas_check(SilcServerCommandContext cmd,
        continue;
       
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       /* Send WHOWAS command */
@@ -1032,11 +1063,9 @@ silc_server_command_whowas_check(SilcServerCommandContext cmd,
       /* Reprocess this packet after received reply */
       silc_server_command_pending(server, SILC_COMMAND_WHOWAS, 
                                  silc_command_get_ident(cmd->payload),
-                                 silc_server_command_destructor,
                                  silc_server_command_whowas, 
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
-      
       silc_command_set_ident(cmd->payload, old_ident);
 
       silc_buffer_free(tmpbuf);
@@ -1054,49 +1083,57 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
 {
   SilcServer server = cmd->server;
   char *tmp;
-  int i, count = 0, len;
+  int i, k, count = 0, len;
   SilcBuffer packet, idp;
   SilcClientEntry entry = NULL;
   SilcCommandStatus status;
   uint16 ident = silc_command_get_ident(cmd->payload);
-  char found = FALSE;
   char nh[256], uh[256];
+  int valid_count;
 
   status = SILC_STATUS_OK;
-  if (clients_count > 1)
-    status = SILC_STATUS_LIST_START;
 
+  /* Process only entries that are not registered anymore. */
+  valid_count = 0;
   for (i = 0; i < clients_count; i++) {
-    entry = clients[i];
+    if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
+      clients[i] = NULL;
+    else
+      valid_count++;
+  }
 
-    /* We will take only clients that are not valid anymore. They are the
-       ones that are not registered anymore but still have a ID. They
-       have disconnected us, and thus valid for WHOWAS. */
-    if (entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
-      continue;
-    if (entry->id == NULL)
-      continue;
+  if (!valid_count) {
+    /* No valid entries found at all, just send error */
+    unsigned char *tmp;
+    
+    tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+    if (tmp)
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
+                                          SILC_STATUS_ERR_NO_SUCH_NICK,
+                                          3, tmp, strlen(tmp));
+    return;
+  }
 
-    if (count && i - 1 == count)
-      break;
+  if (valid_count > 1)
+    status = SILC_STATUS_LIST_START;
 
-    found = TRUE;
+  for (i = 0, k = 0; i < clients_count; i++) {
+    entry = clients[i];
+    if (!entry)
+      continue;
 
-    if (clients_count > 2)
+    if (k >= 1)
       status = SILC_STATUS_LIST_ITEM;
-
-    if (clients_count > 1 && i == clients_count - 1)
+    if (valid_count > 1 && k == valid_count - 1)
+      status = SILC_STATUS_LIST_END;
+    if (count && k - 1 == count)
       status = SILC_STATUS_LIST_END;
+    if (count && k - 1 > count)
+      break;
 
-    /* Sanity check, however these should never fail. However, as
-       this sanity check has been added here they have failed. */
-    if (!entry->nickname || !entry->username)
-      continue;
-      
     /* 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));
 
@@ -1119,35 +1156,23 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
       strcat(uh, "*private*");
     }
       
-    if (entry->userinfo)
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
-                                            status, ident, 4, 
-                                            2, idp->data, idp->len,
-                                            3, nh, strlen(nh),
-                                            4, uh, strlen(uh),
-                                            5, entry->userinfo, 
-                                            strlen(entry->userinfo));
-    else
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
-                                            status, ident, 3, 
-                                            2, idp->data, idp->len,
-                                            3, nh, strlen(nh),
-                                            4, uh, strlen(uh));
-
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
+                                          status, 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 (found == FALSE && entry)
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
-                                        SILC_STATUS_ERR_NO_SUCH_NICK,
-                                        3, entry->nickname, 
-                                        strlen(entry->nickname));
+    k++;
+  }
 }
 
 static int
@@ -1172,7 +1197,7 @@ silc_server_command_whowas_process(SilcServerCommandContext cmd)
     uint16 old_ident;
 
     old_ident = silc_command_get_ident(cmd->payload);
-    silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+    silc_command_set_ident(cmd->payload, ++server->cmd_ident);
     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
     /* Send WHOWAS command to our router */
@@ -1184,11 +1209,9 @@ silc_server_command_whowas_process(SilcServerCommandContext cmd)
     /* 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_destructor,
                                silc_server_command_whowas,
                                silc_server_command_dup(cmd));
     cmd->pending = TRUE;
-
     silc_command_set_ident(cmd->payload, old_ident);
 
     silc_buffer_free(tmpbuf);
@@ -1246,7 +1269,6 @@ silc_server_command_whowas_process(SilcServerCommandContext cmd)
   silc_free(clients);
   silc_free(nick);
   silc_free(server_name);
-
   return ret;
 }
 
@@ -1260,9 +1282,7 @@ SILC_SERVER_CMD_FUNC(whowas)
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOWAS, cmd, 1, 2);
 
   ret = silc_server_command_whowas_process(cmd);
-
-  if (!ret)
-    silc_server_command_free(cmd);
+  silc_server_command_free(cmd);
 }
 
 /******************************************************************************
@@ -1271,7 +1291,34 @@ SILC_SERVER_CMD_FUNC(whowas)
 
 ******************************************************************************/
 
-static bool
+static void 
+silc_server_command_identify_send_router(SilcServerCommandContext cmd)
+{
+  SilcServer server = cmd->server;
+  SilcBuffer tmpbuf;
+  uint16 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)
+                         server->router->connection,
+                         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,
                                   uint32 *clients_count,
@@ -1301,6 +1348,15 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
   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) {
@@ -1328,10 +1384,11 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
       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,
                                             3, tmp, strlen(tmp));
-       return FALSE;
+       return 0;
       }
     }
 
@@ -1350,10 +1407,11 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
       }
 
       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,
                                             3, tmp, strlen(tmp));
-       return FALSE;
+       return 0;
       }
     }
 
@@ -1372,17 +1430,18 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
       }
 
       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,
                                             3, tmp, strlen(tmp));
-       return FALSE;
+       return 0;
       }
     }
 
     if (!(*clients) && !(*servers) && !(*channels)) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
                                            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-      return FALSE;
+      return 0;
     }
   } else {
     /* Command includes ID, we must use that.  Also check whether the command
@@ -1396,14 +1455,15 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
       if (!tmp)
        continue;
       
-      idp = silc_id_payload_parse_data(tmp, len);
+      idp = silc_id_payload_parse(tmp, len);
       if (!idp) {
        silc_free(*clients);
        silc_free(*servers);
        silc_free(*channels);
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
-                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-       return FALSE;
+       silc_server_command_send_status_reply(
+                                      cmd, SILC_COMMAND_IDENTIFY,
+                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       return 0;
       }
 
       id = silc_id_payload_get_id(idp);
@@ -1421,10 +1481,23 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
                                  (*clients_count + 1));
          (*clients)[(*clients_count)++] = (SilcClientEntry)entry;
        } else {
-         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+         /* 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);
+           return -1;
+         } else {
+           silc_server_command_send_status_data(
+                                       cmd, SILC_COMMAND_IDENTIFY,
                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                              2, tmp, len);
-         error = TRUE;
+                                       2, tmp, len);
+           error = TRUE;
+         }
        }
 
        break;
@@ -1440,10 +1513,23 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
                                  (*servers_count + 1));
          (*servers)[(*servers_count)++] = (SilcServerEntry)entry;
        } else {
-         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                       SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
-                                              2, tmp, len);
-         error = TRUE;
+         /* 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);
+           return -1;
+         } else {
+           silc_server_command_send_status_data(
+                                        cmd, SILC_COMMAND_IDENTIFY,
+                                        SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
+                                        2, tmp, len);
+           error = TRUE;
+         }
        }
        break;
        
@@ -1458,10 +1544,23 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
                                   (*channels_count + 1));
          (*channels)[(*channels_count)++] = (SilcChannelEntry)entry;
        } else {
-         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                       SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
-                                              2, tmp, len);
-         error = TRUE;
+         /* 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);
+           return -1;
+         } else {
+           silc_server_command_send_status_data(
+                                        cmd, SILC_COMMAND_IDENTIFY,
+                                        SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+                                        2, tmp, len);
+           error = TRUE;
+         }
        }
        break;
       }
@@ -1484,7 +1583,7 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
   else
     *count = 0;
 
-  return TRUE;
+  return 1;
 }
 
 /* Checks that all mandatory fields in client entry are present. If not
@@ -1505,12 +1604,23 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd,
 
   for (i = 0; i < clients_count; i++) {
     entry = clients[i];
-
-    if (!entry || entry->nickname || 
-       !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
-       !entry->router)
+    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) {
@@ -1518,7 +1628,6 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd,
         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_destructor,
                                  silc_server_command_identify,
                                  silc_server_command_dup(cmd));
       no_res = FALSE;
@@ -1601,7 +1710,6 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd,
     /* Reprocess this packet after received reply */
     silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
                                r->ident,
-                               silc_server_command_destructor,
                                silc_server_command_identify,
                                silc_server_command_dup(cmd));
     cmd->pending = TRUE;
@@ -1630,7 +1738,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
                                        int count)
 {
   SilcServer server = cmd->server;
-  int i, k, len;
+  int i, k, len, valid_count;
   SilcBuffer packet, idp;
   SilcCommandStatus status;
   uint16 ident = silc_command_get_ident(cmd->payload);
@@ -1642,62 +1750,58 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
   if (clients) {
     SilcClientEntry entry;
 
-    len = 0;
-    for (i = 0; i < clients_count; i++)
+    /* Process only valid entries. */
+    valid_count = 0;
+    for (i = 0; i < clients_count; i++) {
       if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
-       len++;
+       valid_count++;
+      else
+       clients[i] = NULL;
+    }
+
+    if (!valid_count) {
+      /* No valid entries found at all, just send error */
+      unsigned char *tmp;
 
-    if (len == 0 && clients_count) {
-      entry = clients[0];
-      if (entry->nickname) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+      if (tmp) {
        silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
                                             SILC_STATUS_ERR_NO_SUCH_NICK,
-                                            3, entry->nickname, 
-                                            strlen(entry->nickname));
+                                            3, tmp, strlen(tmp));
       } else {
-       SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+       tmp = silc_argument_get_arg_type(cmd->args, 5, (uint32 *)&len);
        silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
                                             SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                            2, idp->data, idp->len);
-       silc_buffer_free(idp);
+                                            2, tmp, len);
       }
-      
       return;
     }
 
-    if (len > 1)
+    /* 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->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
-       if (clients_count == 1) {
-         SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                              2, idp->data, idp->len);
-         silc_buffer_free(idp);
-       }
+      if (!entry)
        continue;
-      }
-      
+
       if (k >= 1)
        status = SILC_STATUS_LIST_ITEM;
-      if (clients_count > 1 && k == clients_count - 1 
+      if (valid_count > 1 && k == valid_count - 1 
          && !servers_count && !channels_count)
        status = SILC_STATUS_LIST_END;
       if (count && k - 1 == count)
        status = SILC_STATUS_LIST_END;
       if (count && k - 1 > count)
        break;
-      
+
       /* 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);
@@ -1710,7 +1814,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
                  server->server_name, len);
        }
       }
-      
+
       if (!entry->username) {
        packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
                                                      status, ident, 2,
@@ -1742,9 +1846,6 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
     }
   }
 
-  status = (status == SILC_STATUS_LIST_ITEM ? 
-           SILC_STATUS_LIST_ITEM : SILC_STATUS_OK);
-
   if (servers) {
     SilcServerEntry entry;
 
@@ -1765,19 +1866,13 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
       
       /* Send IDENTIFY reply */
       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
-      if (entry->server_name) {
-       packet = 
-         silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                              status, ident, 2,
-                                              2, idp->data, idp->len, 
-                                              3, entry->server_name, 
-                                              strlen(entry->server_name));
-      } else {
-       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                                     status, ident, 1,
-                                                     2, idp->data, idp->len);
-      }
-      
+      packet = 
+       silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+                                            status, 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);
       
@@ -1788,9 +1883,6 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
     }
   }
 
-  status = (status == SILC_STATUS_LIST_ITEM ? 
-           SILC_STATUS_LIST_ITEM : SILC_STATUS_OK);
-
   if (channels) {
     SilcChannelEntry entry;
 
@@ -1811,19 +1903,13 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
       
       /* Send IDENTIFY reply */
       idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
-      if (entry->channel_name) {
-       packet = 
-         silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                              status, ident, 2,
-                                              2, idp->data, idp->len, 
-                                              3, entry->channel_name, 
-                                              strlen(entry->channel_name));
-      } else {
-       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                                     status, ident, 1,
-                                                     2, idp->data, idp->len);
-      }
-      
+      packet = 
+       silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+                                            status, 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);
       
@@ -1838,7 +1924,6 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
 static int
 silc_server_command_identify_process(SilcServerCommandContext cmd)
 {
-  SilcServer server = cmd->server;
   uint32 count = 0;
   int ret = 0;
   SilcClientEntry *clients = NULL;
@@ -1846,51 +1931,15 @@ silc_server_command_identify_process(SilcServerCommandContext cmd)
   SilcChannelEntry *channels = NULL;
   uint32 clients_count = 0, servers_count = 0, channels_count = 0;
 
-  /* Protocol dictates that we must always send the received IDENTIFY 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;
-    uint16 old_ident;
-
-    old_ident = silc_command_get_ident(cmd->payload);
-    silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
-    tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
-    /* Send IDENTIFY command to our router */
-    silc_server_packet_send(server, (SilcSocketConnection)
-                           server->router->connection,
-                           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_destructor,
-                               silc_server_command_identify,
-                               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. */
-
   /* Parse the IDENTIFY request */
-  if (!silc_server_command_identify_parse(cmd,
-                                         &clients, &clients_count,
-                                         &servers, &servers_count,
-                                         &channels, &channels_count,
-                                         &count))
-    return 0;
+  ret = silc_server_command_identify_parse(cmd,
+                                          &clients, &clients_count,
+                                          &servers, &servers_count,
+                                          &channels, &channels_count,
+                                          &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. */
@@ -1911,7 +1960,6 @@ silc_server_command_identify_process(SilcServerCommandContext cmd)
   silc_free(clients);
   silc_free(servers);
   silc_free(channels);
-
   return ret;
 }
 
@@ -1923,31 +1971,7 @@ SILC_SERVER_CMD_FUNC(identify)
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
 
   ret = silc_server_command_identify_process(cmd);
-
-  if (!ret)
-    silc_server_command_free(cmd);
-}
-
-/* Checks string for bad characters and returns TRUE if they are found. */
-
-static int silc_server_command_bad_chars(char *nick)
-{
-  int i;
-
-  for (i = 0; i < strlen(nick); i++) {
-    if (!isascii(nick[i]))
-      return TRUE;
-    if (nick[i] <= 32) return TRUE;
-    if (nick[i] == ' ') return TRUE;
-    if (nick[i] == '\\') return TRUE;
-    if (nick[i] == '\"') return TRUE;
-    if (nick[i] == '*') return TRUE;
-    if (nick[i] == '?') return TRUE;
-    if (nick[i] == ',') return TRUE;
-    if (nick[i] == '@') return TRUE;
-  }
-
-  return FALSE;
+  silc_server_command_free(cmd);
 }
 
 /* Server side of command NICK. Sets nickname for user. Setting
@@ -1959,8 +1983,9 @@ SILC_SERVER_CMD_FUNC(nick)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   SilcServer server = cmd->server;
-  SilcBuffer packet, nidp, oidp;
+  SilcBuffer packet, nidp, oidp = NULL;
   SilcClientID *new_id;
+  uint32 nick_len;
   char *nick;
   uint16 ident = silc_command_get_ident(cmd->payload);
   int nickfail = 0;
@@ -1971,15 +1996,20 @@ SILC_SERVER_CMD_FUNC(nick)
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_NICK, cmd, 1, 1);
 
   /* Check nickname */
-  nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
-  if (silc_server_command_bad_chars(nick) == TRUE) {
+  nick = silc_argument_get_arg_type(cmd->args, 1, &nick_len);
+  if (nick_len > 128)
+    nick[128] = '\0';
+  if (silc_server_name_bad_chars(nick, nick_len) == TRUE) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
                                          SILC_STATUS_ERR_BAD_NICKNAME);
     goto out;
   }
 
-  if (strlen(nick) > 128)
-    nick[128] = '\0';
+  /* Check for same nickname */
+  if (!strcmp(client->nickname, nick)) {
+    nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+    goto send_reply;
+  }
 
   /* Create new Client ID */
   while (!silc_id_create_client_id(cmd->server, cmd->server->id, 
@@ -2015,7 +2045,7 @@ SILC_SERVER_CMD_FUNC(nick)
 
   /* Update client cache */
   silc_idcache_add(server->local_list->clients, client->nickname, 
-                  client->id, (void *)client, FALSE);
+                  client->id, (void *)client, 0, NULL);
 
   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
@@ -2025,6 +2055,7 @@ SILC_SERVER_CMD_FUNC(nick)
                                      oidp->data, oidp->len, 
                                      nidp->data, nidp->len);
 
+ send_reply:
   /* Send the new Client ID as reply command back to client */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
                                                SILC_STATUS_OK, ident, 1, 
@@ -2034,7 +2065,8 @@ SILC_SERVER_CMD_FUNC(nick)
 
   silc_buffer_free(packet);
   silc_buffer_free(nidp);
-  silc_buffer_free(oidp);
+  if (oidp)
+    silc_buffer_free(oidp);
   
  out:
   silc_server_command_free(cmd);
@@ -2049,7 +2081,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
                                    SilcChannelEntry *gch,
                                    uint32 gch_count)
 {
-  int i;
+  int i, k;
   SilcBuffer packet, idp;
   SilcChannelEntry entry;
   SilcCommandStatus status;
@@ -2057,31 +2089,34 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
   char *topic;
   unsigned char usercount[4];
   uint32 users;
+  int valid_lcount = 0, valid_rcount = 0;
 
-  for (i = 0; i < lch_count; i++)
+  for (i = 0; i < lch_count; i++) {
     if (lch[i]->mode & SILC_CHANNEL_MODE_SECRET)
       lch[i] = NULL;
-  for (i = 0; i < gch_count; i++)
+    else
+      valid_lcount++;
+  }
+  for (i = 0; i < gch_count; i++) {
     if (gch[i]->mode & SILC_CHANNEL_MODE_SECRET)
       gch[i] = NULL;
+    else
+      valid_rcount++;
+  }
 
   status = SILC_STATUS_OK;
   if ((lch_count + gch_count) > 1)
     status = SILC_STATUS_LIST_START;
 
   /* Local list */
-  for (i = 0; i < lch_count; i++) {
+  for (i = 0, k = 0; i < lch_count; i++) {
     entry = lch[i];
-
     if (!entry)
       continue;
 
-    if (i >= 1)
+    if (k >= 1)
       status = SILC_STATUS_LIST_ITEM;
-
-    if (i == lch_count - 1 && gch_count)
-      break;
-    if (lch_count > 1 && i == lch_count - 1)
+    if (valid_lcount > 1 && k == valid_lcount - 1 && !valid_rcount)
       status = SILC_STATUS_LIST_END;
 
     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
@@ -2096,43 +2131,31 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     }
 
     /* Send the reply */
-    if (topic)
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
-                                            status, ident, 4, 
-                                            2, idp->data, idp->len,
-                                            3, entry->channel_name, 
-                                            strlen(entry->channel_name),
-                                            4, topic, strlen(topic),
-                                            5, usercount, 4);
-    else
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
-                                            status, ident, 3, 
-                                            2, idp->data, idp->len,
-                                            3, entry->channel_name, 
-                                            strlen(entry->channel_name),
-                                            5, usercount, 4);
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
+                                          status, ident, 4,
+                                          2, idp->data, idp->len,
+                                          3, entry->channel_name, 
+                                          strlen(entry->channel_name),
+                                          4, topic, topic ? strlen(topic) : 0,
+                                          5, usercount, 4);
     silc_server_packet_send(cmd->server, cmd->sock, 
                            SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
                            packet->len, FALSE);
     silc_buffer_free(packet);
     silc_buffer_free(idp);
+    k++;
   }
 
-  status = i ? SILC_STATUS_LIST_ITEM : SILC_STATUS_OK;
-
   /* Global list */
-  for (i = 0; i < gch_count; i++) {
+  for (i = 0, k = 0; i < gch_count; i++) {
     entry = gch[i];
-
     if (!entry)
       continue;
 
-    if (i >= 1)
+    if (k >= 1)
       status = SILC_STATUS_LIST_ITEM;
-
-    if (gch_count > 1 && i == lch_count - 1)
+    if (valid_rcount > 1 && k == valid_rcount - 1)
       status = SILC_STATUS_LIST_END;
 
     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
@@ -2147,28 +2170,20 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     }
 
     /* Send the reply */
-    if (topic)
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
-                                            status, ident, 4, 
-                                            2, idp->data, idp->len,
-                                            3, entry->channel_name, 
-                                            strlen(entry->channel_name),
-                                            4, topic, strlen(topic),
-                                            5, usercount, 4);
-    else
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
-                                            status, ident, 3, 
-                                            2, idp->data, idp->len,
-                                            3, entry->channel_name, 
-                                            strlen(entry->channel_name),
-                                            5, usercount, 4);
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
+                                          status, ident, 4,
+                                          2, idp->data, idp->len,
+                                          3, entry->channel_name, 
+                                          strlen(entry->channel_name),
+                                          4, topic, topic ? strlen(topic) : 0,
+                                          5, usercount, 4);
     silc_server_packet_send(cmd->server, cmd->sock, 
                            SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
                            packet->len, FALSE);
     silc_buffer_free(packet);
     silc_buffer_free(idp);
+    k++;
   }
 }
 
@@ -2185,7 +2200,32 @@ SILC_SERVER_CMD_FUNC(list)
   SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
   uint32 lch_count = 0, gch_count = 0;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 1);
+
+  /* If we are normal server, send the command to router, since we
+     want to know all channels in the network. */
+  if (!cmd->pending && server->server_type == SILC_SERVER && 
+      !server->standalone) {
+    SilcBuffer tmpbuf;
+    uint16 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);
+    silc_server_packet_send(server, server->router->connection,
+                           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_LIST, 
+                               silc_command_get_ident(cmd->payload),
+                               silc_server_command_list, 
+                               silc_server_command_dup(cmd));
+    cmd->pending = TRUE;
+    silc_command_set_ident(cmd->payload, old_ident);
+    silc_buffer_free(tmpbuf);
+    goto out;
+  }
 
   /* Get Channel ID */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
@@ -2202,15 +2242,17 @@ SILC_SERVER_CMD_FUNC(list)
   lchannels = silc_idlist_get_channels(server->local_list, channel_id,
                                       &lch_count);
   
-  /* Get the channels from global list if we are router */
-  if (server->server_type != SILC_SERVER) 
-    gchannels = silc_idlist_get_channels(server->global_list, channel_id,
-                                        &gch_count);
+  /* Get the channels from global list */
+  gchannels = silc_idlist_get_channels(server->global_list, channel_id,
+                                      &gch_count);
 
   /* Send the reply */
   silc_server_command_list_send_reply(cmd, lchannels, lch_count, 
                                      gchannels, gch_count);
 
+  silc_free(lchannels);
+  silc_free(gchannels);
+
  out:
   silc_server_command_free(cmd);
 }
@@ -2301,13 +2343,14 @@ SILC_SERVER_CMD_FUNC(topic)
     if (!server->standalone)
       silc_server_send_notify_topic_set(server, server->router->connection,
                                        server->server_type == SILC_ROUTER ?
-                                       TRUE : FALSE, channel, client->id,
+                                       TRUE : FALSE, channel, 
+                                       client->id, SILC_ID_CLIENT,
                                        channel->topic);
 
     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
     /* Send notify about topic change to all clients on the channel */
-    silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
+    silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
                                       SILC_NOTIFY_TYPE_TOPIC_SET, 2,
                                       idp->data, idp->len,
                                       channel->topic, strlen(channel->topic));
@@ -2316,16 +2359,12 @@ SILC_SERVER_CMD_FUNC(topic)
 
   /* Send the topic to client as reply packet */
   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
-  if (channel->topic)
-    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
-                                                 SILC_STATUS_OK, ident, 2, 
-                                                 2, idp->data, idp->len,
-                                                 3, channel->topic, 
-                                                 strlen(channel->topic));
-  else
-    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
-                                                 SILC_STATUS_OK, ident, 1, 
-                                                 2, idp->data, idp->len);
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
+                                               SILC_STATUS_OK, ident, 2, 
+                                               2, idp->data, idp->len,
+                                               3, channel->topic, 
+                                               channel->topic ? 
+                                               strlen(channel->topic) : 0);
   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                          0, packet->data, packet->len, FALSE);
 
@@ -2408,6 +2447,7 @@ SILC_SERVER_CMD_FUNC(invite)
   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
   if (tmp) {
     char invite[512];
+    bool resolve;
 
     dest_id = silc_id_payload_parse_id(tmp, len);
     if (!dest_id) {
@@ -2417,11 +2457,12 @@ SILC_SERVER_CMD_FUNC(invite)
     }
 
     /* Get the client entry */
-    dest = silc_server_get_client_resolve(server, dest_id);
+    dest = silc_server_get_client_resolve(server, dest_id, &resolve);
     if (!dest) {
-      if (server->server_type != SILC_SERVER) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                    SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+      if (server->server_type != SILC_SERVER || !resolve) {
+       silc_server_command_send_status_reply(
+                                       cmd, SILC_COMMAND_INVITE,
+                                       SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
        goto out;
       }
       
@@ -2429,13 +2470,12 @@ SILC_SERVER_CMD_FUNC(invite)
         receiving the reply to the query. */
       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
                                  server->cmd_ident,
-                                 silc_server_command_destructor,
                                  silc_server_command_invite, 
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
       silc_free(channel_id);
       silc_free(dest_id);
-      return;
+      goto out;
     }
 
     /* Check whether the requested client is already on the channel. */
@@ -2635,6 +2675,7 @@ SILC_SERVER_CMD_FUNC(kill)
   SilcClientID *client_id;
   unsigned char *tmp, *comment;
   uint32 tmp_len, tmp_len2;
+  bool local;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2);
 
@@ -2672,9 +2713,11 @@ SILC_SERVER_CMD_FUNC(kill)
   /* Get the client entry */
   remote_client = silc_idlist_find_client_by_id(server->local_list, 
                                                client_id, TRUE, NULL);
+  local = TRUE;
   if (!remote_client) {
     remote_client = silc_idlist_find_client_by_id(server->global_list, 
                                                  client_id, TRUE, NULL);
+    local = FALSE;
     if (!remote_client) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
@@ -2728,9 +2771,17 @@ SILC_SERVER_CMD_FUNC(kill)
     silc_server_free_client_data(server, sock, remote_client, FALSE, NULL);
     silc_server_close_connection(server, sock);
   } else {
+    /* Update statistics */
+    if (remote_client->connection)
+      server->stat.my_clients--;
+    if (server->server_type == SILC_ROUTER)
+      server->stat.cell_clients--;
+    SILC_OPER_STATS_UPDATE(remote_client, server, SILC_UMODE_SERVER_OPERATOR);
+    SILC_OPER_STATS_UPDATE(remote_client, router, SILC_UMODE_ROUTER_OPERATOR);
+
     /* Remove remote client */
-    if (!silc_idlist_del_client(server->global_list, remote_client))
-      silc_idlist_del_client(server->local_list, remote_client);
+    silc_idlist_del_client(local ? server->local_list :
+                          server->global_list, remote_client);
   }
 
  out:
@@ -2798,10 +2849,10 @@ SILC_SERVER_CMD_FUNC(info)
     memset(info_string, 0, sizeof(info_string));
     snprintf(info_string, sizeof(info_string), 
             "location: %s server: %s admin: %s <%s>",
-            server->config->admin_info->location,
-            server->config->admin_info->server_type,
-            server->config->admin_info->admin_name,
-            server->config->admin_info->admin_email);
+            server->config->server_info->location,
+            server->config->server_info->server_type,
+            server->config->server_info->admin,
+            server->config->server_info->email);
 
     server_info = info_string;
     entry = server->id_entry;
@@ -2823,7 +2874,7 @@ SILC_SERVER_CMD_FUNC(info)
       uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       silc_server_packet_send(server, entry->connection,
@@ -2833,13 +2884,12 @@ SILC_SERVER_CMD_FUNC(info)
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_INFO, 
                                  silc_command_get_ident(cmd->payload),
-                                 silc_server_command_destructor,
                                  silc_server_command_info,
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
       silc_command_set_ident(cmd->payload, old_ident);
       silc_buffer_free(tmpbuf);
-      return;
+      goto out;
     }
 
     if (!entry && !cmd->pending && !server->standalone) {
@@ -2848,7 +2898,7 @@ SILC_SERVER_CMD_FUNC(info)
       uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       silc_server_packet_send(server, server->router->connection,
@@ -2858,13 +2908,12 @@ SILC_SERVER_CMD_FUNC(info)
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_INFO, 
                                  silc_command_get_ident(cmd->payload),
-                                 silc_server_command_destructor,
                                  silc_server_command_info,
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
       silc_command_set_ident(cmd->payload, old_ident);
       silc_buffer_free(tmpbuf);
-      return;
+      goto out;
     }
   }
 
@@ -2882,20 +2931,14 @@ SILC_SERVER_CMD_FUNC(info)
   server_name = entry->server_name;
 
   /* Send the reply */
-  if (server_info)
-    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
-                                                 SILC_STATUS_OK, ident, 3,
-                                                 2, idp->data, idp->len,
-                                                 3, server_name, 
-                                                 strlen(server_name),
-                                                 4, server_info, 
-                                                 strlen(server_info));
-  else
-    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
-                                                 SILC_STATUS_OK, ident, 2,
-                                                 2, idp->data, idp->len,
-                                                 3, server_name, 
-                                                 strlen(server_name));
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
+                                               SILC_STATUS_OK, ident, 3,
+                                               2, idp->data, idp->len,
+                                               3, server_name, 
+                                               strlen(server_name),
+                                               4, server_info, 
+                                               server_info ? 
+                                               strlen(server_info) : 0);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
     
@@ -2955,7 +2998,9 @@ static void silc_server_command_join_channel(SilcServer server,
                                             SilcClientID *client_id,
                                             bool created,
                                             bool create_key,
-                                            uint32 umode)
+                                            uint32 umode,
+                                            const unsigned char *auth,
+                                            uint32 auth_len)
 {
   SilcSocketConnection sock = cmd->sock;
   unsigned char *tmp;
@@ -2966,6 +3011,8 @@ static void silc_server_command_join_channel(SilcServer server,
   SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list;
   uint16 ident = silc_command_get_ident(cmd->payload);
   char check[512], check2[512];
+  bool founder = FALSE;
+  bool resolve;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -2976,102 +3023,137 @@ static void silc_server_command_join_channel(SilcServer server,
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
     client = (SilcClientEntry)sock->user_data;
   } else {
-    client = silc_server_get_client_resolve(server, client_id);
+    client = silc_server_get_client_resolve(server, client_id, &resolve);
     if (!client) {
       if (cmd->pending)
        goto out;
 
+      if (!resolve) {
+       silc_server_command_send_status_reply(
+                                        cmd, SILC_COMMAND_JOIN,
+                                        SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       goto out;
+      }
+
       /* The client info is being resolved. Reprocess this packet after
         receiving the reply to the query. */
       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
-                                 server->cmd_ident, NULL,
+                                 server->cmd_ident,
                                  silc_server_command_join, 
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
-      return;
+      goto out;
     }
 
     cmd->pending = FALSE;
   }
 
   /*
-   * Check channel modes
+   * Check founder auth payload if provided.  If client can gain founder
+   * privileges it can override various conditions on joining the channel,
+   * and can have directly the founder mode set on the channel.
    */
-
-  memset(check, 0, sizeof(check));
-  memset(check2, 0, sizeof(check2));
-  strncat(check, client->nickname, strlen(client->nickname));
-  strncat(check, "!", 1);
-  strncat(check, client->username, strlen(client->username));
-  if (!strchr(client->username, '@')) {
-    strncat(check, "@", 1);
-    strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
+  if (auth && auth_len && channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+    SilcIDListData idata = (SilcIDListData)client;
+
+    if (channel->founder_key && idata->public_key &&
+       silc_pkcs_public_key_compare(channel->founder_key, 
+                                    idata->public_key)) {
+      void *auth_data = (channel->founder_method == SILC_AUTH_PASSWORD ?
+                        (void *)channel->founder_passwd : 
+                        (void *)channel->founder_key);
+      uint32 auth_data_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
+                             channel->founder_passwd_len : 0);
+
+      /* Check whether the client is to become founder */
+      if (silc_auth_verify_data(auth, auth_len, channel->founder_method, 
+                               auth_data, auth_data_len,
+                               idata->hash, client->id, SILC_ID_CLIENT)) {
+       umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+       founder = TRUE;
+      }
+    }
   }
 
-  strncat(check2, client->nickname, strlen(client->nickname));
-  if (!strchr(client->nickname, '@')) {
-    strncat(check2, "@", 1);
-    strncat(check2, server->server_name, strlen(server->server_name));
-  }
-  strncat(check2, "!", 1);
-  strncat(check2, client->username, strlen(client->username));
-  if (!strchr(client->username, '@')) {
-    strncat(check2, "@", 1);
-    strncat(check2, cmd->sock->hostname, strlen(cmd->sock->hostname));
-  }
+  /*
+   * Check channel modes
+   */
 
-  /* Check invite list if channel is invite-only channel */
-  if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
-    if (!channel->invite_list ||
-       (!silc_string_match(channel->invite_list, check) &&
-        !silc_string_match(channel->invite_list, check2))) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                           SILC_STATUS_ERR_NOT_INVITED);
-      goto out;
+  if (!umode) {
+    memset(check, 0, sizeof(check));
+    memset(check2, 0, sizeof(check2));
+    strncat(check, client->nickname, strlen(client->nickname));
+    strncat(check, "!", 1);
+    strncat(check, client->username, strlen(client->username));
+    if (!strchr(client->username, '@')) {
+      strncat(check, "@", 1);
+      strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
     }
-  }
 
-  /* Check ban list if it exists. If the client's nickname, server,
-     username and/or hostname is in the ban list the access to the
-     channel is denied. */
-  if (channel->ban_list) {
-    if (!channel->ban_list ||
-        silc_string_match(channel->ban_list, check) ||
-       silc_string_match(channel->ban_list, check2)) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                             SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
-      goto out;
+    strncat(check2, client->nickname, strlen(client->nickname));
+    if (!strchr(client->nickname, '@')) {
+      strncat(check2, "@", 1);
+      strncat(check2, server->server_name, strlen(server->server_name));
+    }
+    strncat(check2, "!", 1);
+    strncat(check2, client->username, strlen(client->username));
+    if (!strchr(client->username, '@')) {
+      strncat(check2, "@", 1);
+      strncat(check2, cmd->sock->hostname, strlen(cmd->sock->hostname));
+    }
+    
+    /* Check invite list if channel is invite-only channel */
+    if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
+      if (!channel->invite_list ||
+         (!silc_string_match(channel->invite_list, check) &&
+          !silc_string_match(channel->invite_list, check2))) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                             SILC_STATUS_ERR_NOT_INVITED);
+       goto out;
+      }
     }
-  }
 
-  /* Get passphrase */
-  tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
-  if (tmp) {
-    passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
-    memcpy(passphrase, tmp, tmp_len);
+    /* Check ban list if it exists. If the client's nickname, server,
+       username and/or hostname is in the ban list the access to the
+       channel is denied. */
+    if (channel->ban_list) {
+      if (silc_string_match(channel->ban_list, check) ||
+         silc_string_match(channel->ban_list, check2)) {
+       silc_server_command_send_status_reply(
+                                     cmd, SILC_COMMAND_JOIN,
+                                     SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
+       goto out;
+      }
+    }
+    
+    /* Check user count limit if set. */
+    if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
+      if (silc_hash_table_count(channel->user_list) + 1 > 
+         channel->user_limit) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                             SILC_STATUS_ERR_CHANNEL_IS_FULL);
+       goto out;
+      }
+    }
   }
-  
+
   /* Check the channel passphrase if set. */
   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+    /* Get passphrase */
+    tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+    if (tmp) {
+      passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
+      memcpy(passphrase, tmp, tmp_len);
+    }
+  
     if (!passphrase || !channel->passphrase ||
-        memcmp(channel->passphrase, passphrase,
-               strlen(channel->passphrase))) {
+        memcmp(passphrase, channel->passphrase, strlen(channel->passphrase))) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                            SILC_STATUS_ERR_BAD_PASSWORD);
       goto out;
     }
   }
 
-  /* Check user count limit if set. */
-  if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
-    if (silc_hash_table_count(channel->user_list) + 1 > 
-       channel->user_limit) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                           SILC_STATUS_ERR_CHANNEL_IS_FULL);
-      goto out;
-    }
-  }
-
   /*
    * Client is allowed to join to the channel. Make it happen.
    */
@@ -3167,7 +3249,7 @@ static void silc_server_command_join_channel(SilcServer server,
      we'll ignore it (in packet_receive.c) so we must send it here. If
      we are router then this will send it to local clients and local
      servers. */
-  silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+  silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
                                     SILC_NOTIFY_TYPE_JOIN, 2,
                                     clidp->data, clidp->len,
                                     chidp->data, chidp->len);
@@ -3185,6 +3267,24 @@ static void silc_server_command_join_channel(SilcServer server,
                              keyp->data, keyp->len, FALSE, TRUE);
   }
 
+  /* If client became founder by providing correct founder auth data
+     notify the mode change to the channel. */
+  if (founder) {
+    SILC_PUT32_MSB(chl->mode, mode);
+    silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
+                                      SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+                                      clidp->data, clidp->len,
+                                      mode, 4, clidp->data, clidp->len);
+      
+    /* Set CUMODE notify type to network */
+    if (!server->standalone)
+      silc_server_send_notify_cumode(server, server->router->connection,
+                                    server->server_type == SILC_ROUTER ? 
+                                    TRUE : FALSE, channel,
+                                    chl->mode, client->id, SILC_ID_CLIENT,
+                                    client->id);
+  }
+
   silc_buffer_free(reply);
   silc_buffer_free(clidp);
   silc_buffer_free(chidp);
@@ -3203,14 +3303,15 @@ SILC_SERVER_CMD_FUNC(join)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  uint32 tmp_len;
+  unsigned char *auth;
+  uint32 tmp_len, auth_len;
   char *tmp, *channel_name = NULL, *cipher, *hmac;
   SilcChannelEntry channel;
   uint32 umode = 0;
   bool created = FALSE, create_key = TRUE;
   SilcClientID *client_id;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 1, 4);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 2, 6);
 
   /* Get channel name */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
@@ -3221,10 +3322,10 @@ SILC_SERVER_CMD_FUNC(join)
   }
   channel_name = tmp;
 
-  if (strlen(channel_name) > 256)
+  if (tmp_len > 256)
     channel_name[255] = '\0';
 
-  if (silc_server_command_bad_chars(channel_name) == TRUE) {
+  if (silc_server_name_bad_chars(channel_name, tmp_len) == TRUE) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                          SILC_STATUS_ERR_BAD_CHANNEL);
     goto out;
@@ -3244,25 +3345,18 @@ SILC_SERVER_CMD_FUNC(join)
     goto out;
   }
 
-  /* Get cipher and hmac name */
+  /* Get cipher, hmac name and auth payload */
   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
   hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
+  auth = silc_argument_get_arg_type(cmd->args, 6, &auth_len);
 
   /* See if the channel exists */
   channel = silc_idlist_find_channel_by_name(server->local_list, 
                                             channel_name, NULL);
 
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
-    /* If this is coming from client the Client ID in the command packet must
-       be same as the client's ID. */
-    if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
-      SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
-      if (!SILC_ID_CLIENT_COMPARE(entry->id, client_id)) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                       SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-       goto out;
-      }
-    }
+    SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
+    client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
 
     if (!channel || channel->disabled) {
       /* Channel not found */
@@ -3273,8 +3367,9 @@ SILC_SERVER_CMD_FUNC(join)
        channel = silc_server_create_new_channel(server, server->id, cipher, 
                                                 hmac, channel_name, TRUE);
        if (!channel) {
-         silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+         silc_server_command_send_status_reply(
+                                        cmd, SILC_COMMAND_JOIN,
+                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
          goto out;
        }
        
@@ -3299,7 +3394,7 @@ SILC_SERVER_CMD_FUNC(join)
            goto out;
          
          old_ident = silc_command_get_ident(cmd->payload);
-         silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+         silc_command_set_ident(cmd->payload, ++server->cmd_ident);
          tmpbuf = silc_command_payload_encode_payload(cmd->payload);
          
          /* Send JOIN command to our router */
@@ -3311,11 +3406,12 @@ SILC_SERVER_CMD_FUNC(join)
          /* Reprocess this packet after received reply from router */
          silc_server_command_pending(server, SILC_COMMAND_JOIN, 
                                      silc_command_get_ident(cmd->payload),
-                                     silc_server_command_destructor,
                                      silc_server_command_join,
                                      silc_server_command_dup(cmd));
          cmd->pending = TRUE;
-         return;
+          silc_command_set_ident(cmd->payload, old_ident);
+         silc_buffer_free(tmpbuf);
+         goto out;
        }
        
        /* We are router and the channel does not seem exist so we will check
@@ -3374,11 +3470,17 @@ SILC_SERVER_CMD_FUNC(join)
   if (cmd->pending && context2) {
     SilcServerCommandReplyContext reply = 
       (SilcServerCommandReplyContext)context2;
+
     if (silc_command_get(reply->payload) == SILC_COMMAND_JOIN) {
       tmp = silc_argument_get_arg_type(reply->args, 6, NULL);
       SILC_GET32_MSB(created, tmp);
-      create_key = FALSE;      /* Router returned the key already */
+      if (silc_argument_get_arg_type(reply->args, 7, NULL))
+       create_key = FALSE;     /* Router returned the key already */
     }
+
+    if (silc_command_get(reply->payload) == SILC_COMMAND_WHOIS &&
+       !silc_hash_table_count(channel->user_list))
+      created = TRUE;
   }
 
   /* If the channel does not have global users and is also empty the client
@@ -3388,7 +3490,8 @@ SILC_SERVER_CMD_FUNC(join)
 
   /* Join to the channel */
   silc_server_command_join_channel(server, cmd, channel, client_id,
-                                  created, create_key, umode);
+                                  created, create_key, umode,
+                                  auth, auth_len);
 
   silc_free(client_id);
 
@@ -3423,10 +3526,10 @@ SILC_SERVER_CMD_FUNC(motd)
 
     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
 
-    if (server->config && server->config->motd && 
-       server->config->motd->motd_file) {
+    if (server->config && server->config->server_info &&
+       server->config->server_info->motd_file) {
       /* Send motd */
-      motd = silc_file_readfile(server->config->motd->motd_file, &motd_len);
+      motd = silc_file_readfile(server->config->server_info->motd_file, &motd_len);
       if (!motd)
        goto out;
       
@@ -3435,7 +3538,6 @@ SILC_SERVER_CMD_FUNC(motd)
                                                    SILC_STATUS_OK, ident, 2,
                                                    2, idp, idp->len,
                                                    3, motd, motd_len);
-      goto out;
     } else {
       /* No motd */
       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
@@ -3465,7 +3567,7 @@ SILC_SERVER_CMD_FUNC(motd)
       uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       silc_server_packet_send(server, entry->connection,
@@ -3475,13 +3577,12 @@ SILC_SERVER_CMD_FUNC(motd)
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_MOTD, 
                                  silc_command_get_ident(cmd->payload),
-                                 silc_server_command_destructor,
                                  silc_server_command_motd,
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
       silc_command_set_ident(cmd->payload, old_ident);
       silc_buffer_free(tmpbuf);
-      return;
+      goto out;
     }
 
     if (!entry && !cmd->pending && !server->standalone) {
@@ -3490,7 +3591,7 @@ SILC_SERVER_CMD_FUNC(motd)
       uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       silc_server_packet_send(server, server->router->connection,
@@ -3500,13 +3601,12 @@ SILC_SERVER_CMD_FUNC(motd)
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_MOTD, 
                                  silc_command_get_ident(cmd->payload),
-                                 silc_server_command_destructor,
                                  silc_server_command_motd,
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
       silc_command_set_ident(cmd->payload, old_ident);
       silc_buffer_free(tmpbuf);
-      return;
+      goto out;
     }
 
     if (!entry) {
@@ -3516,18 +3616,12 @@ SILC_SERVER_CMD_FUNC(motd)
     }
 
     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
-
-    if (entry->motd)
-      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                   SILC_STATUS_OK, ident, 2,
-                                                   2, idp, idp->len,
-                                                   3, entry->motd,
-                                                   strlen(entry->motd));
-    else
-      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                   SILC_STATUS_OK, ident, 1,
-                                                   2, idp, idp->len);
-
+    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+                                                 SILC_STATUS_OK, ident, 2,
+                                                 2, idp, idp->len,
+                                                 3, entry->motd,
+                                                 entry->motd ? 
+                                                 strlen(entry->motd) : 0);
     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                            packet->data, packet->len, FALSE);
     silc_buffer_free(packet);
@@ -3578,9 +3672,14 @@ SILC_SERVER_CMD_FUNC(umode)
       goto out;
     }
   } else {
-    if (client->mode & SILC_UMODE_SERVER_OPERATOR)
-      /* Remove the server operator rights */
+    /* Remove the server operator rights */
+    if (client->mode & SILC_UMODE_SERVER_OPERATOR) {
       client->mode &= ~SILC_UMODE_SERVER_OPERATOR;
+      if (client->connection)
+       server->stat.my_server_ops--;
+      if (server->server_type == SILC_ROUTER)
+       server->stat.server_ops--;
+    }
   }
 
   if (mask & SILC_UMODE_ROUTER_OPERATOR) {
@@ -3591,9 +3690,14 @@ SILC_SERVER_CMD_FUNC(umode)
       goto out;
     }
   } else {
-    if (client->mode & SILC_UMODE_ROUTER_OPERATOR)
-      /* Remove the router operator rights */
+    /* Remove the router operator rights */
+    if (client->mode & SILC_UMODE_ROUTER_OPERATOR) {
       client->mode &= ~SILC_UMODE_ROUTER_OPERATOR;
+      if (client->connection)
+       server->stat.my_router_ops--;
+      if (server->server_type == SILC_ROUTER)
+       server->stat.router_ops--;
+    }
   }
 
   if (mask & SILC_UMODE_GONE) {
@@ -3703,7 +3807,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   SilcChannelClientEntry chl;
   SilcBuffer packet, cidp;
   unsigned char *tmp, *tmp_id, *tmp_mask;
-  char *cipher = NULL, *hmac = NULL;
+  char *cipher = NULL, *hmac = NULL, *passphrase = NULL;
   uint32 mode_mask, tmp_len, tmp_len2;
   uint16 ident = silc_command_get_ident(cmd->payload);
 
@@ -3776,22 +3880,22 @@ SILC_SERVER_CMD_FUNC(cmode)
       /* The mode is removed and we need to generate and distribute
         new channel key. Clients are not using private channel keys
         anymore after this. */
-
+      
       /* Re-generate channel key */
       if (!silc_server_create_channel_key(server, channel, 0))
        goto out;
-      
+       
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
       silc_server_send_channel_key(server, NULL, channel, 
                                   server->server_type == SILC_ROUTER ? 
                                   FALSE : !server->standalone);
-
+       
       cipher = channel->channel_key->cipher->name;
       hmac = (char *)silc_hmac_get_name(channel->hmac);
     }
   }
-  
+
   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
     /* User limit is set on channel */
     uint32 user_limit;
@@ -3827,7 +3931,7 @@ SILC_SERVER_CMD_FUNC(cmode)
       }
 
       /* Save the passphrase */
-      channel->passphrase = strdup(tmp);
+      passphrase = channel->passphrase = strdup(tmp);
     }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
@@ -4038,14 +4142,16 @@ SILC_SERVER_CMD_FUNC(cmode)
   /* Finally, set the mode */
   channel->mode = mode_mask;
 
-  /* Send CMODE_CHANGE notify */
+  /* Send CMODE_CHANGE notify. */
   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
-                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 4,
+                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 5,
                                     cidp->data, cidp->len, 
                                     tmp_mask, 4,
                                     cipher, cipher ? strlen(cipher) : 0,
-                                    hmac, hmac ? strlen(hmac) : 0);
+                                    hmac, hmac ? strlen(hmac) : 0,
+                                    passphrase, passphrase ? 
+                                    strlen(passphrase) : 0);
 
   /* Set CMODE notify type to network */
   if (!server->standalone)
@@ -4053,7 +4159,7 @@ SILC_SERVER_CMD_FUNC(cmode)
                                  server->server_type == SILC_ROUTER ? 
                                  TRUE : FALSE, channel,
                                  mode_mask, client->id, SILC_ID_CLIENT,
-                                 cipher, hmac);
+                                 cipher, hmac, passphrase);
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
@@ -4065,7 +4171,7 @@ SILC_SERVER_CMD_FUNC(cmode)
     
   silc_buffer_free(packet);
   silc_free(channel_id);
-  silc_free(cidp);
+  silc_buffer_free(cidp);
 
  out:
   silc_server_command_free(cmd);
@@ -4188,9 +4294,9 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* If the target client is founder, no one else can change their mode
      but themselves. */
-  if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
+  if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && client != target_client) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_NOT_YOU);
+                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
     goto out;
   }
 
@@ -4286,7 +4392,7 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* Send notify to channel, notify only if mode was actually changed. */
   if (notify) {
-    silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+    silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
                                       SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
                                       idp->data, idp->len,
                                       tmp_mask, 4, 
@@ -4333,8 +4439,8 @@ SILC_SERVER_CMD_FUNC(kick)
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcBuffer idp;
-  uint32 tmp_len;
-  unsigned char *tmp, *comment;
+  uint32 tmp_len, target_idp_len;
+  unsigned char *tmp, *comment, *target_idp;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 3);
 
@@ -4381,13 +4487,13 @@ SILC_SERVER_CMD_FUNC(kick)
   }
   
   /* Get target Client ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (!tmp) {
+  target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
+  if (!target_idp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
                                          SILC_STATUS_ERR_NO_CLIENT_ID);
     goto out;
   }
-  client_id = silc_id_payload_parse_id(tmp, tmp_len);
+  client_id = silc_id_payload_parse_id(target_idp, target_idp_len);
   if (!client_id) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
                                          SILC_STATUS_ERR_NO_CLIENT_ID);
@@ -4429,12 +4535,12 @@ SILC_SERVER_CMD_FUNC(kick)
                                        SILC_STATUS_OK);
 
   /* Send KICKED notify to local clients on the channel */
-  idp = silc_id_payload_encode(target_client->id, SILC_ID_CLIENT);
+  idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
-                                    SILC_NOTIFY_TYPE_KICKED, 
-                                    comment ? 2 : 1,
-                                    idp->data, idp->len,
-                                    comment, comment ? strlen(comment) : 0);
+                                    SILC_NOTIFY_TYPE_KICKED, 3,
+                                    target_idp, target_idp_len,
+                                    comment, comment ? strlen(comment) : 0,
+                                    idp->data, idp->len);
   silc_buffer_free(idp);
 
   /* Remove the client from the channel. If the channel does not exist
@@ -4449,7 +4555,7 @@ SILC_SERVER_CMD_FUNC(kick)
     silc_server_send_notify_kicked(server, server->router->connection,
                                   server->server_type == SILC_ROUTER ?
                                   TRUE : FALSE, channel,
-                                  target_client->id, comment);
+                                  target_client->id, client->id, comment);
 
   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
     /* Re-generate channel key */
@@ -4477,7 +4583,7 @@ SILC_SERVER_CMD_FUNC(oper)
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   unsigned char *username, *auth;
   uint32 tmp_len;
-  SilcServerConfigSectionAdminConnection *admin;
+  SilcServerConfigSectionAdmin *admin;
   SilcIDListData idata = (SilcIDListData)client;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
@@ -4526,6 +4632,12 @@ SILC_SERVER_CMD_FUNC(oper)
   /* Client is now server operator */
   client->mode |= SILC_UMODE_SERVER_OPERATOR;
 
+  /* Update statistics */
+  if (client->connection)
+    server->stat.my_server_ops++;
+  if (server->server_type == SILC_ROUTER)
+    server->stat.server_ops++;
+
   /* Send UMODE change to primary router */
   if (!server->standalone)
     silc_server_send_notify_umode(server, server->router->connection, TRUE,
@@ -4549,7 +4661,7 @@ SILC_SERVER_CMD_FUNC(silcoper)
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   unsigned char *username, *auth;
   uint32 tmp_len;
-  SilcServerConfigSectionAdminConnection *admin;
+  SilcServerConfigSectionAdmin *admin;
   SilcIDListData idata = (SilcIDListData)client;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
@@ -4604,6 +4716,12 @@ SILC_SERVER_CMD_FUNC(silcoper)
   /* Client is now router operator */
   client->mode |= SILC_UMODE_ROUTER_OPERATOR;
 
+  /* Update statistics */
+  if (client->connection)
+    server->stat.my_router_ops++;
+  if (server->server_type == SILC_ROUTER)
+    server->stat.router_ops++;
+
   /* Send UMODE change to primary router */
   if (!server->standalone)
     silc_server_send_notify_umode(server, server->router->connection, TRUE,
@@ -4726,7 +4844,11 @@ SILC_SERVER_CMD_FUNC(ban)
   }
 
   /* Get entry to the channel user list */
-  silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
+  if (!silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+                                         SILC_STATUS_ERR_NOT_ON_CHANNEL);
+    goto out;
+  }
 
   /* The client must be at least channel operator. */
   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
@@ -4781,19 +4903,13 @@ SILC_SERVER_CMD_FUNC(ban)
                                TRUE : FALSE, channel, add, del);
 
   /* Send the reply back to the client */
-  if (channel->ban_list)
-    packet = 
-      silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
-                                          SILC_STATUS_OK, ident, 2,
-                                          2, id, id_len,
-                                          3, channel->ban_list, 
-                                          strlen(channel->ban_list) - 1);
-  else
-    packet = 
-      silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
-                                          SILC_STATUS_OK, ident, 1,
-                                          2, id, id_len);
-
+  packet = 
+    silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
+                                        SILC_STATUS_OK, ident, 2,
+                                        2, id, id_len,
+                                        3, channel->ban_list, 
+                                        channel->ban_list ? 
+                                        strlen(channel->ban_list) -1 : 0);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
     
@@ -4869,7 +4985,7 @@ SILC_SERVER_CMD_FUNC(close)
     server->router = NULL;
     server->standalone = TRUE;
   }
-  silc_server_free_sock_user_data(server, sock);
+  silc_server_free_sock_user_data(server, sock, NULL);
   silc_server_close_connection(server, sock);
   
  out:
@@ -5045,7 +5161,7 @@ SILC_SERVER_CMD_FUNC(users)
        !cmd->pending) {
       SilcBuffer tmpbuf;
       
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
       
       /* Send USERS command */
@@ -5056,15 +5172,13 @@ SILC_SERVER_CMD_FUNC(users)
       /* Reprocess this packet after received reply */
       silc_server_command_pending(server, SILC_COMMAND_USERS, 
                                  silc_command_get_ident(cmd->payload),
-                                 silc_server_command_destructor,
                                  silc_server_command_users,
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
       silc_command_set_ident(cmd->payload, ident);
-      
       silc_buffer_free(tmpbuf);
       silc_free(id);
-      return;
+      goto out;
     }
 
     /* Check the global list as well. */
@@ -5147,6 +5261,7 @@ SILC_SERVER_CMD_FUNC(getkey)
   uint32 tmp_len, pklen;
   SilcBuffer pk = NULL;
   SilcIdType id_type;
+  SilcPublicKey public_key;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -5156,7 +5271,7 @@ SILC_SERVER_CMD_FUNC(getkey)
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  idp = silc_id_payload_parse_data(tmp, tmp_len);
+  idp = silc_id_payload_parse(tmp, tmp_len);
   if (!idp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
@@ -5188,7 +5303,7 @@ SILC_SERVER_CMD_FUNC(getkey)
        goto out;
       
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
       
       silc_server_packet_send(server, dest_sock,
@@ -5198,14 +5313,12 @@ SILC_SERVER_CMD_FUNC(getkey)
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_GETKEY, 
                                  silc_command_get_ident(cmd->payload),
-                                 silc_server_command_destructor,
                                  silc_server_command_getkey,
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
-      
       silc_command_set_ident(cmd->payload, old_ident);
       silc_buffer_free(tmpbuf);
-      return;
+      goto out;
     }
 
     if (!client) {
@@ -5217,11 +5330,12 @@ SILC_SERVER_CMD_FUNC(getkey)
     /* The client is locally connected, just get the public key and
        send it back. If they key does not exist then do not send it, 
        send just OK reply */
-    if (!client->data.public_key) {
+    public_key = client->data.public_key;
+    if (!public_key) {
       pkdata = NULL;
       pklen = 0;
     } else {
-      tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len);
+      tmp = silc_pkcs_public_key_encode(public_key, &tmp_len);
       pk = silc_buffer_alloc(4 + tmp_len);
       silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
       silc_buffer_format(pk,
@@ -5254,7 +5368,7 @@ SILC_SERVER_CMD_FUNC(getkey)
       uint16 old_ident;
       
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
       
       silc_server_packet_send(server, server->router->connection,
@@ -5264,14 +5378,12 @@ SILC_SERVER_CMD_FUNC(getkey)
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_GETKEY, 
                                  silc_command_get_ident(cmd->payload),
-                                 silc_server_command_destructor,
                                  silc_server_command_getkey,
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
-      
       silc_command_set_ident(cmd->payload, old_ident);
       silc_buffer_free(tmpbuf);
-      return;
+      goto out;
     }
 
     if (!server_entry) {
@@ -5281,12 +5393,14 @@ SILC_SERVER_CMD_FUNC(getkey)
     }
 
     /* If they key does not exist then do not send it, send just OK reply */
-    if (!server_entry->data.public_key) {
+    public_key = (!server_entry->data.public_key ? 
+                 (server_entry == server->id_entry ? server->public_key :
+                  NULL) : server_entry->data.public_key);
+    if (!public_key) {
       pkdata = NULL;
       pklen = 0;
     } else {
-      tmp = silc_pkcs_public_key_encode(server_entry->data.public_key, 
-                                       &tmp_len);
+      tmp = silc_pkcs_public_key_encode(public_key, &tmp_len);
       pk = silc_buffer_alloc(4 + tmp_len);
       silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
       silc_buffer_format(pk,