Fix double free in silcd.
[silc.git] / apps / silcd / command.c
index 0d594b9d9891049af8823d33408054cd9316dc73..d8d105c535a76a72de9518fe9c1853fe17c48765 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2003 Pekka Riikonen
+  Copyright (C) 1997 - 2008 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
 #include "server_internal.h"
 
 static int silc_server_is_registered(SilcServer server,
-                                    SilcSocketConnection sock,
+                                    SilcPacketStream sock,
                                     SilcServerCommandContext cmd,
                                     SilcCommand command);
 static void
@@ -74,6 +74,7 @@ SilcServerCommand silc_command_list[] =
   SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG),
   SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(getkey, GETKEY, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(service, SERVICE, SILC_CF_LAG_STRICT | SILC_CF_REG),
 
   SILC_SERVER_CMD(connect, PRIV_CONNECT,
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
@@ -125,11 +126,11 @@ do {                                                                           \
    usually cannot send commands hence the check. */
 
 static int silc_server_is_registered(SilcServer server,
-                                    SilcSocketConnection sock,
+                                    SilcPacketStream sock,
                                     SilcServerCommandContext cmd,
                                     SilcCommand command)
 {
-  SilcIDListData idata = (SilcIDListData)sock->user_data;
+  SilcIDListData idata = silc_packet_get_context(sock);
 
   if (!idata)
     return FALSE;
@@ -154,7 +155,7 @@ typedef struct {
 SILC_TASK_CALLBACK(silc_server_command_process_timeout)
 {
   SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context;
-  SilcClientEntry client = (SilcClientEntry)timeout->ctx->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(timeout->ctx->sock);
 
   if (!client) {
     SILC_LOG_DEBUG(("Client entry is invalid"));
@@ -188,27 +189,32 @@ SILC_TASK_CALLBACK(silc_server_command_process_timeout)
 /* Processes received command packet. */
 
 void silc_server_command_process(SilcServer server,
-                                SilcSocketConnection sock,
-                                SilcPacketContext *packet)
+                                SilcPacketStream sock,
+                                SilcPacket packet)
 {
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcServerCommandContext ctx;
   SilcServerCommand *cmd;
   SilcCommand command;
 
+  if (!idata)
+    return;
+
   /* Allocate command context. This must be free'd by the
      command routine receiving it. */
   ctx = silc_server_command_alloc();
   ctx->server = server;
-  ctx->sock = silc_socket_dup(sock);
-  ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
+  ctx->sock = sock;
+  ctx->packet = packet; /* Save original packet */
+  silc_packet_stream_ref(sock);
 
   /* Parse the command payload in the packet */
-  ctx->payload = silc_command_payload_parse(packet->buffer->data,
-                                           packet->buffer->len);
+  ctx->payload = silc_command_payload_parse(packet->buffer.data,
+                                           silc_buffer_len(&packet->buffer));
   if (!ctx->payload) {
-    SILC_LOG_ERROR(("Bad command payload, packet dropped"));
-    silc_packet_context_free(packet);
-    silc_socket_free(ctx->sock);
+    SILC_LOG_ERROR(("Bad command payload"));
+    silc_packet_free(packet);
+    silc_packet_stream_unref(ctx->sock);
     silc_free(ctx);
     return;
   }
@@ -224,7 +230,9 @@ void silc_server_command_process(SilcServer server,
     SILC_LOG_DEBUG(("Unknown command %d", command));
     silc_server_command_send_status_reply(ctx, command,
                                          SILC_STATUS_ERR_UNKNOWN_COMMAND, 0);
-    silc_server_command_free(ctx);
+    silc_packet_free(packet);
+    silc_packet_stream_unref(ctx->sock);
+    silc_free(ctx);
     return;
   }
 
@@ -232,17 +240,11 @@ void silc_server_command_process(SilcServer server,
      executed with zero (0) timeout but if client is sending command more
      frequently than once in 2 seconds, then the timeout may be 0 to 2
      seconds. */
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
-    SilcClientEntry client = (SilcClientEntry)sock->user_data;
+  if (idata->conn_type == SILC_CONN_CLIENT) {
+    SilcClientEntry client = silc_packet_get_context(sock);
     SilcServerCommandTimeout timeout;
     int fast;
 
-    if (!client) {
-      SILC_LOG_DEBUG(("Client entry is invalid"));
-      silc_server_command_free(ctx);
-      return;
-    }
-
     timeout = silc_calloc(1, sizeof(*timeout));
     timeout->ctx = ctx;
     timeout->cmd = cmd;
@@ -260,16 +262,16 @@ void silc_server_command_process(SilcServer server,
 
     if (!fast && ((cmd->flags & SILC_CF_LAG_STRICT) ||
                  (client->fast_command > 5 && cmd->flags & SILC_CF_LAG)))
-      silc_schedule_task_add(server->schedule, sock->sock,
-                            silc_server_command_process_timeout, timeout,
-                            (client->fast_command < 3 ? 0 :
-                             2 - (time(NULL) - client->last_command)),
-                            (client->fast_command < 3 ? 200000 : 0),
-                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+      silc_schedule_task_add_timeout(
+                           server->schedule,
+                           silc_server_command_process_timeout, timeout,
+                           (client->fast_command < 3 ? 0 :
+                            2 - (time(NULL) - client->last_command)),
+                           (client->fast_command < 3 ? 200000 : 0));
     else
-      silc_schedule_task_add(server->schedule, sock->sock,
-                            silc_server_command_process_timeout, timeout,
-                            0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_command_process_timeout,
+                                    timeout, 0, 0);
     return;
   }
 
@@ -307,9 +309,9 @@ void silc_server_command_free(SilcServerCommandContext ctx)
     if (ctx->payload)
       silc_command_payload_free(ctx->payload);
     if (ctx->packet)
-      silc_packet_context_free(ctx->packet);
+      silc_packet_free(ctx->packet);
     if (ctx->sock)
-      silc_socket_free(ctx->sock); /* Decrease reference counter */
+      silc_packet_stream_unref(ctx->sock);
     silc_free(ctx);
   }
 }
@@ -355,7 +357,8 @@ SILC_TASK_CALLBACK(silc_server_command_pending_timeout)
                                         SILC_COMMAND_RESERVED,
                                         SILC_STATUS_ERR_TIMEDOUT, 0,
                                         reply->ident, 0);
-  cmdr->payload = silc_command_payload_parse(tmpreply->data, tmpreply->len);
+  cmdr->payload = silc_command_payload_parse(tmpreply->data,
+                                            silc_buffer_len(tmpreply));
   silc_buffer_free(tmpreply);
 
   /* Call all callbacks. Same as SILC_SERVER_PENDING_EXEC macro. */
@@ -376,7 +379,7 @@ SILC_TASK_CALLBACK(silc_server_command_pending_timeout)
    specified command, ident, callback and context this function has no
    effect. */
 
-bool silc_server_command_pending(SilcServer server,
+SilcBool silc_server_command_pending(SilcServer server,
                                 SilcCommand reply_cmd,
                                 SilcUInt16 ident,
                                 SilcCommandCb callback,
@@ -389,7 +392,7 @@ bool silc_server_command_pending(SilcServer server,
 /* Same as silc_server_command_pending with specific timeout for pending
    commands.  If the `timeout' is zero default timeout is used. */
 
-bool silc_server_command_pending_timed(SilcServer server,
+SilcBool silc_server_command_pending_timed(SilcServer server,
                                       SilcCommand reply_cmd,
                                       SilcUInt16 ident,
                                       SilcCommandCb callback,
@@ -414,10 +417,9 @@ bool silc_server_command_pending_timed(SilcServer server,
   reply->context = context;
   reply->callback = callback;
   reply->timeout =
-    silc_schedule_task_add(server->schedule, 0,
-                          silc_server_command_pending_timeout, reply,
-                          timeout ? timeout : 10, 0,
-                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_command_pending_timeout, reply,
+                                  timeout ? timeout : 12, 0);
   silc_dlist_add(server->pending_commands, reply);
 
   return TRUE;
@@ -483,6 +485,9 @@ silc_server_command_send_status_reply(SilcServerCommandContext cmd,
 {
   SilcBuffer buffer;
 
+  /* Statistics */
+  cmd->server->stat.commands_sent++;
+
   SILC_LOG_DEBUG(("Sending command status %d", status));
 
   buffer =
@@ -491,7 +496,7 @@ silc_server_command_send_status_reply(SilcServerCommandContext cmd,
                                         0);
   silc_server_packet_send(cmd->server, cmd->sock,
                          SILC_PACKET_COMMAND_REPLY, 0,
-                         buffer->data, buffer->len, FALSE);
+                         buffer->data, silc_buffer_len(buffer));
   silc_buffer_free(buffer);
 }
 
@@ -509,6 +514,9 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
 {
   SilcBuffer buffer;
 
+  /* Statistics */
+  cmd->server->stat.commands_sent++;
+
   SILC_LOG_DEBUG(("Sending command status %d", status));
 
   buffer =
@@ -517,7 +525,7 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
                                         1, arg_type, arg, arg_len);
   silc_server_packet_send(cmd->server, cmd->sock,
                          SILC_PACKET_COMMAND_REPLY, 0,
-                         buffer->data, buffer->len, FALSE);
+                         buffer->data, silc_buffer_len(buffer));
   silc_buffer_free(buffer);
 }
 
@@ -535,6 +543,9 @@ silc_server_command_send_status_data2(SilcServerCommandContext cmd,
 {
   SilcBuffer buffer;
 
+  /* Statistics */
+  cmd->server->stat.commands_sent++;
+
   SILC_LOG_DEBUG(("Sending command status %d", status));
 
   buffer =
@@ -544,7 +555,7 @@ silc_server_command_send_status_data2(SilcServerCommandContext cmd,
                                         arg_type2, arg2, arg_len2);
   silc_server_packet_send(cmd->server, cmd->sock,
                          SILC_PACKET_COMMAND_REPLY, 0,
-                         buffer->data, buffer->len, FALSE);
+                         buffer->data, silc_buffer_len(buffer));
   silc_buffer_free(buffer);
 }
 
@@ -564,6 +575,9 @@ silc_server_command_pending_error_check(SilcServerCommandContext cmd,
   if (!silc_command_get_status(cmdr->payload, NULL, NULL)) {
     SilcBuffer buffer;
 
+    /* Statistics */
+    cmd->server->stat.commands_sent++;
+
     /* Send the same command reply payload */
     silc_command_set_command(cmdr->payload, silc_command_get(cmd->payload));
     silc_command_set_ident(cmdr->payload,
@@ -571,7 +585,7 @@ silc_server_command_pending_error_check(SilcServerCommandContext cmd,
     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);
+                           buffer->data, silc_buffer_len(buffer));
     silc_buffer_free(buffer);
     return TRUE;
   }
@@ -585,7 +599,7 @@ SILC_SERVER_CMD_FUNC(whois)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 256);
-  silc_server_query_command(cmd->server, SILC_COMMAND_WHOIS, cmd);
+  silc_server_query_command(cmd->server, SILC_COMMAND_WHOIS, cmd, NULL);
   silc_server_command_free(cmd);
 }
 
@@ -595,7 +609,7 @@ SILC_SERVER_CMD_FUNC(whowas)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOWAS, cmd, 1, 2);
-  silc_server_query_command(cmd->server, SILC_COMMAND_WHOWAS, cmd);
+  silc_server_query_command(cmd->server, SILC_COMMAND_WHOWAS, cmd, NULL);
   silc_server_command_free(cmd);
 }
 
@@ -605,7 +619,7 @@ SILC_SERVER_CMD_FUNC(identify)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 256);
-  silc_server_query_command(cmd->server, SILC_COMMAND_IDENTIFY, cmd);
+  silc_server_query_command(cmd->server, SILC_COMMAND_IDENTIFY, cmd, NULL);
   silc_server_command_free(cmd);
 }
 
@@ -616,53 +630,59 @@ SILC_SERVER_CMD_FUNC(identify)
 SILC_SERVER_CMD_FUNC(nick)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   SilcServer server = cmd->server;
-  SilcBuffer packet, nidp, oidp = NULL;
+  SilcBuffer nidp, oidp = NULL;
   SilcClientID *new_id;
   SilcUInt32 nick_len;
-  char *nick;
+  unsigned char *nick, *nickc = NULL;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
-  int nickfail = 0;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_NICK, cmd, 1, 1);
 
-  /* Check nickname */
+  /* Get nickname */
   nick = silc_argument_get_arg_type(cmd->args, 1, &nick_len);
   if (!nick) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
                                          SILC_STATUS_ERR_BAD_NICKNAME, 0);
     goto out;
   }
-  if (nick_len > 128)
-    nick[128] = '\0';
-  if (silc_server_name_bad_chars(nick, nick_len) == TRUE) {
+
+  /* Truncate over long nicks */
+  if (nick_len > 128) {
+    nick_len = 128;
+    nick[nick_len - 1] = '\0';
+  }
+
+  /* Check for valid nickname string.  This is cached, original is saved
+     in the client context. */
+  nickc = silc_identifier_check(nick, nick_len, SILC_STRING_UTF8, 128, NULL);
+  if (!nickc) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
                                          SILC_STATUS_ERR_BAD_NICKNAME, 0);
     goto out;
   }
 
   /* Check for same nickname */
-  if (!strcmp(client->nickname, nick)) {
+  if (strlen(client->nickname) == nick_len &&
+      !memcmp(client->nickname, nick, nick_len)) {
     nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+    silc_free(nickc);
     goto send_reply;
   }
 
   /* Create new Client ID */
-  while (!silc_id_create_client_id(cmd->server, cmd->server->id,
-                                  cmd->server->rng,
-                                  cmd->server->md5hash, nick,
-                                  &new_id)) {
-    nickfail++;
-    if (nickfail > 9) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
-                                           SILC_STATUS_ERR_BAD_NICKNAME, 0);
-      goto out;
-    }
-    snprintf(&nick[strlen(nick) - 1], 1, "%d", nickfail);
+  if (!silc_id_create_client_id(cmd->server, cmd->server->id,
+                               cmd->server->rng,
+                               cmd->server->md5hash,
+                               nickc, strlen(nickc), &new_id)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
+                                         SILC_STATUS_ERR_BAD_NICKNAME, 0);
+    silc_free(nickc);
+    goto out;
   }
 
   /* Send notify about nickname change to our router. We send the new
@@ -679,26 +699,20 @@ SILC_SERVER_CMD_FUNC(nick)
 
   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
-  /* Remove old cache entry */
-  silc_idcache_del_by_context(server->local_list->clients, client);
-
-  silc_free(client->id);
-  client->id = new_id;
-
+  /* Update client entry */
+  silc_idcache_update_by_context(server->local_list->clients, client,
+                                new_id, nickc, TRUE);
+  silc_free(new_id);
   silc_free(client->nickname);
   client->nickname = strdup(nick);
 
-  /* Update client cache */
-  silc_idcache_add(server->local_list->clients, client->nickname,
-                  client->id, (void *)client, 0, NULL);
-
   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
   /* Send NICK_CHANGE notify to the client's channels */
   silc_server_send_notify_on_channels(server, NULL, client,
                                      SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
-                                     oidp->data, oidp->len,
-                                     nidp->data, nidp->len,
+                                     oidp->data, silc_buffer_len(oidp),
+                                     nidp->data, silc_buffer_len(nidp),
                                      client->nickname,
                                      strlen(client->nickname));
 
@@ -709,14 +723,11 @@ SILC_SERVER_CMD_FUNC(nick)
 
  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, 0, ident, 2,
-                                               2, nidp->data, nidp->len,
-                                               3, nick, strlen(nick));
-  silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
-                         0, packet->data, packet->len, FALSE);
-
-  silc_buffer_free(packet);
+  silc_server_send_command_reply(cmd->server, cmd->sock,
+                                SILC_COMMAND_NICK,
+                                SILC_STATUS_OK, 0, ident, 2,
+                                2, nidp->data, silc_buffer_len(nidp),
+                                3, nick, nick_len);
   silc_buffer_free(nidp);
   if (oidp)
     silc_buffer_free(oidp);
@@ -735,7 +746,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
                                    SilcUInt32 gch_count)
 {
   int i, k;
-  SilcBuffer packet, idp;
+  SilcBuffer idp;
   SilcChannelEntry entry;
   SilcStatus status;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
@@ -757,6 +768,12 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
       valid_rcount++;
   }
 
+  if (!lch_count && !gch_count) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
+                                         SILC_STATUS_OK, 0);
+    return;
+  }
+
   status = SILC_STATUS_OK;
   if ((lch_count + gch_count) > 1)
     status = SILC_STATUS_LIST_START;
@@ -784,18 +801,13 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     }
 
     /* Send the reply */
-    packet =
-      silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
-                                          status, 0, 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_server_send_command_reply(cmd->server, cmd->sock, SILC_COMMAND_LIST,
+                                  status, 0, ident, 4,
+                                  2, idp->data, silc_buffer_len(idp),
+                                  3, entry->channel_name,
+                                  strlen(entry->channel_name),
+                                  4, topic, topic ? strlen(topic) : 0,
+                                  5, usercount, 4);
     silc_buffer_free(idp);
     k++;
   }
@@ -823,18 +835,13 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     }
 
     /* Send the reply */
-    packet =
-      silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
-                                          status, 0, 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_server_send_command_reply(cmd->server, cmd->sock, SILC_COMMAND_LIST,
+                                  status, 0, ident, 4,
+                                  2, idp->data, silc_buffer_len(idp),
+                                  3, entry->channel_name,
+                                  strlen(entry->channel_name),
+                                  4, topic, topic ? strlen(topic) : 0,
+                                  5, usercount, 4);
     silc_buffer_free(idp);
     k++;
   }
@@ -847,9 +854,8 @@ SILC_SERVER_CMD_FUNC(list)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
+  SilcID id;
   SilcChannelID *channel_id = NULL;
-  unsigned char *tmp;
-  SilcUInt32 tmp_len;
   SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
   SilcUInt32 lch_count = 0, gch_count = 0;
 
@@ -862,12 +868,15 @@ SILC_SERVER_CMD_FUNC(list)
     SilcBuffer tmpbuf;
     SilcUInt16 old_ident;
 
+    /* Statistics */
+    cmd->server->stat.commands_sent++;
+
     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, SILC_PRIMARY_ROUTE(server),
                            SILC_PACKET_COMMAND, cmd->packet->flags,
-                           tmpbuf->data, tmpbuf->len, TRUE);
+                           tmpbuf->data, silc_buffer_len(tmpbuf));
 
     /* Reprocess this packet after received reply from router */
     silc_server_command_pending(server, SILC_COMMAND_LIST,
@@ -881,15 +890,8 @@ SILC_SERVER_CMD_FUNC(list)
   }
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (tmp) {
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!channel_id) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
-                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-      goto out;
-    }
-  }
+  if (silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL))
+    channel_id = SILC_ID_GET_ID(id);
 
   /* Get the channels from local list */
   lchannels = silc_idlist_get_channels(server->local_list, channel_id,
@@ -917,16 +919,16 @@ SILC_SERVER_CMD_FUNC(topic)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  SilcChannelID *channel_id;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
+  SilcID id;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
-  SilcBuffer packet, idp;
+  SilcBuffer idp;
   unsigned char *tmp;
   SilcUInt32 argc, tmp_len;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_TOPIC, cmd, 1, 2);
@@ -934,14 +936,7 @@ SILC_SERVER_CMD_FUNC(topic)
   argc = silc_argument_get_arg_num(cmd->args);
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
-                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-    goto out;
-  }
-  channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!channel_id) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
     goto out;
@@ -949,11 +944,12 @@ SILC_SERVER_CMD_FUNC(topic)
 
   /* Check whether the channel exists */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_TOPIC,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
                                           0, 2, tmp, tmp_len);
@@ -963,15 +959,19 @@ SILC_SERVER_CMD_FUNC(topic)
 
   if (argc > 1) {
     /* Get the topic */
-    tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+    tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
     if (!tmp) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
                                            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
                                            0);
       goto out;
     }
+    if (tmp_len > 256) {
+      tmp_len = 256;
+      tmp[tmp_len - 1] = '\0';
+    }
 
-    if (strlen(tmp) > 256) {
+    if (!silc_utf8_valid(tmp, tmp_len)) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
                                            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
                                            0);
@@ -1012,7 +1012,7 @@ SILC_SERVER_CMD_FUNC(topic)
       idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                         SILC_NOTIFY_TYPE_TOPIC_SET, 2,
-                                        idp->data, idp->len,
+                                        idp->data, silc_buffer_len(idp),
                                         channel->topic,
                                         strlen(channel->topic));
       silc_buffer_free(idp);
@@ -1020,19 +1020,14 @@ SILC_SERVER_CMD_FUNC(topic)
   }
 
   /* Send the topic to client as reply packet */
-  idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC,
-                                               SILC_STATUS_OK, 0, 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);
-
-  silc_buffer_free(packet);
+  idp = silc_id_payload_encode(SILC_ID_GET_ID(id), SILC_ID_CHANNEL);
+  silc_server_send_command_reply(cmd->server, cmd->sock, SILC_COMMAND_TOPIC,
+                                SILC_STATUS_OK, 0, ident, 2,
+                                2, idp->data, silc_buffer_len(idp),
+                                3, channel->topic,
+                                channel->topic ?
+                                strlen(channel->topic) : 0);
   silc_buffer_free(idp);
-  silc_free(channel_id);
 
  out:
   silc_server_command_free(cmd);
@@ -1045,32 +1040,25 @@ SILC_SERVER_CMD_FUNC(invite)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcSocketConnection sock = cmd->sock, dest_sock;
+  SilcPacketStream sock = cmd->sock, dest_sock;
   SilcChannelClientEntry chl;
   SilcClientEntry sender, dest;
-  SilcClientID *dest_id = NULL;
   SilcChannelEntry channel;
-  SilcChannelID *channel_id = NULL;
+  SilcID id, id2;
   SilcIDListData idata;
   SilcArgumentPayload args;
   SilcHashTableList htl;
-  SilcBuffer packet, list, tmp2;
+  SilcBuffer list, tmp2;
   SilcBufferStruct alist;
   unsigned char *tmp, *atype = NULL;
-  SilcUInt32 len, type, len2;
+  SilcUInt32 len, len2, ttype;
+  void *type;
   SilcUInt16 argc = 0, ident = silc_command_get_ident(cmd->payload);
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INVITE, cmd, 1, 4);
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
-  if (!tmp) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-    goto out;
-  }
-  channel_id = silc_id_payload_parse_id(tmp, len, NULL);
-  if (!channel_id) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
     goto out;
@@ -1078,11 +1066,12 @@ SILC_SERVER_CMD_FUNC(invite)
 
   /* Get the channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
                                           0, 2, tmp, len);
@@ -1091,8 +1080,9 @@ SILC_SERVER_CMD_FUNC(invite)
   }
 
   /* Check whether the sender of this command is on the channel. */
-  sender = (SilcClientEntry)sock->user_data;
+  sender = silc_packet_get_context(sock);
   if (!sender || !silc_server_client_on_channel(sender, channel, &chl)) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
                                         2, tmp, len);
@@ -1104,6 +1094,7 @@ SILC_SERVER_CMD_FUNC(invite)
   if (channel->mode & SILC_CHANNEL_MODE_INVITE &&
       !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV,
                                         0, 2, tmp, len);
@@ -1111,21 +1102,15 @@ SILC_SERVER_CMD_FUNC(invite)
   }
 
   /* Get destination client ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
-  if (tmp) {
-    bool resolve;
-
-    dest_id = silc_id_payload_parse_id(tmp, len, NULL);
-    if (!dest_id) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                           SILC_STATUS_ERR_NO_CLIENT_ID, 0);
-      goto out;
-    }
+  if (silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id2, NULL)) {
+    SilcBool resolve;
 
     /* Get the client entry */
-    dest = silc_server_query_client(server, dest_id, FALSE, &resolve);
+    dest = silc_server_query_client(server, SILC_ID_GET_ID(id2),
+                                   FALSE, &resolve);
     if (!dest) {
       if (server->server_type != SILC_SERVER || !resolve || cmd->pending) {
+       tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
        silc_server_command_send_status_data(
                                        cmd, SILC_COMMAND_INVITE,
                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0,
@@ -1145,6 +1130,7 @@ SILC_SERVER_CMD_FUNC(invite)
 
     /* Check whether the requested client is already on the channel. */
     if (silc_server_client_on_channel(dest, channel, NULL)) {
+      tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
       atype = silc_argument_get_arg_type(cmd->args, 1, &len2);
       silc_server_command_send_status_data2(cmd, SILC_COMMAND_INVITE,
                                            SILC_STATUS_ERR_USER_ON_CHANNEL,
@@ -1154,9 +1140,11 @@ SILC_SERVER_CMD_FUNC(invite)
     }
 
     /* Get route to the client */
-    dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id,
+    dest_sock = silc_server_get_client_route(server, NULL, 0,
+                                            SILC_ID_GET_ID(id2),
                                             &idata, NULL);
     if (!dest_sock) {
+      tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
                                           0, 2, tmp, len);
@@ -1173,9 +1161,10 @@ SILC_SERVER_CMD_FUNC(invite)
                              silc_server_inviteban_destruct, channel, TRUE);
 
     /* Check if the ID is in the list already */
+    tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
     silc_hash_table_list(channel->invite_list, &htl);
-    while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) {
-      if (type == 3 && !memcmp(tmp2->data, tmp, len)) {
+    while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2)) {
+      if (SILC_PTR_TO_32(type) == 3 && !memcmp(tmp2->data, tmp, len)) {
        tmp = NULL;
        break;
       }
@@ -1192,15 +1181,15 @@ SILC_SERVER_CMD_FUNC(invite)
     if (!(dest->mode & SILC_UMODE_BLOCK_INVITE)) {
       /* Send notify to the client that is invited to the channel */
       SilcBuffer idp, idp2;
-      idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+      idp = silc_id_payload_encode(SILC_ID_GET_ID(id), SILC_ID_CHANNEL);
       idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
-      silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id,
-                                  SILC_ID_CLIENT,
+      silc_server_send_notify_dest(server, dest_sock, FALSE,
+                                  SILC_ID_GET_ID(id2), SILC_ID_CLIENT,
                                   SILC_NOTIFY_TYPE_INVITE, 3,
-                                  idp->data, idp->len,
+                                  idp->data, silc_buffer_len(idp),
                                   channel->channel_name,
                                   strlen(channel->channel_name),
-                                  idp2->data, idp2->len);
+                                  idp2->data, silc_buffer_len(idp2));
       silc_buffer_free(idp);
       silc_buffer_free(idp2);
     }
@@ -1241,8 +1230,14 @@ SILC_SERVER_CMD_FUNC(invite)
       }
 
       /* Now add or delete the information. */
-      silc_server_inviteban_process(server, channel->invite_list,
-                                   (SilcUInt8)atype[0], args);
+      if (!silc_server_inviteban_process(server, channel->invite_list,
+                                        (SilcUInt8)atype[0], args)) {
+       silc_server_command_send_status_reply(
+                                   cmd, SILC_COMMAND_INVITE,
+                                   SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                   0);
+       goto out;
+      }
     }
     silc_argument_payload_free(args);
   }
@@ -1256,9 +1251,10 @@ SILC_SERVER_CMD_FUNC(invite)
                                          channel->invite_list)),
                       SILC_STR_END);
     silc_hash_table_list(channel->invite_list, &htl);
-    while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2))
-      list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
-                                             type);
+    while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
+      list = silc_argument_payload_encode_one(list, tmp2->data,
+                                             silc_buffer_len(tmp2),
+                                             SILC_PTR_TO_32(type));
     silc_hash_table_list_reset(&htl);
   }
 
@@ -1269,17 +1265,17 @@ SILC_SERVER_CMD_FUNC(invite)
     /* Send to local servers if we are router */
     if (server->server_type == SILC_ROUTER) {
       SilcBuffer idp, idp2;
-      idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+      idp = silc_id_payload_encode(SILC_ID_GET_ID(id), SILC_ID_CHANNEL);
       idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, FALSE,
                                          SILC_NOTIFY_TYPE_INVITE, 5,
-                                        idp->data, idp->len,
+                                        idp->data, silc_buffer_len(idp),
                                         channel->channel_name,
                                         strlen(channel->channel_name),
-                                        idp2->data, idp2->len,
+                                        idp2->data, silc_buffer_len(idp2),
                                         atype, 1,
                                         tmp ? alist.data : NULL,
-                                        tmp ? alist.len : 0);
+                                        tmp ? silc_buffer_len(&alist) : 0);
       silc_buffer_free(idp);
       silc_buffer_free(idp2);
     }
@@ -1293,34 +1289,29 @@ SILC_SERVER_CMD_FUNC(invite)
 
   /* Send invite list back only if the list was modified, or no arguments
      was given. */
-  type = 0;
+  ttype = 0;
   argc = silc_argument_get_arg_num(cmd->args);
   if (argc == 1)
-    type = 1;
+    ttype = 1;
   if (silc_argument_get_arg_type(cmd->args, 3, &len))
-    type = 1;
+    ttype = 1;
 
   /* Send command reply */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
-                                               SILC_STATUS_OK, 0, ident, 2,
-                                               2, tmp, len,
-                                               3, type && list ?
-                                               list->data : NULL,
-                                               type && list ? list->len : 0);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
-                         packet->data, packet->len, FALSE);
-  silc_buffer_free(packet);
+  silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_INVITE,
+                                SILC_STATUS_OK, 0, ident, 2,
+                                2, tmp, len,
+                                3, ttype && list ?
+                                list->data : NULL,
+                                ttype && list ? silc_buffer_len(list) : 0);
   silc_buffer_free(list);
 
  out:
-  silc_free(dest_id);
-  silc_free(channel_id);
   silc_server_command_free(cmd);
 }
 
 typedef struct {
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   char *signoff;
 } *QuitInternal;
 
@@ -1331,17 +1322,16 @@ SILC_TASK_CALLBACK(silc_server_command_quit_cb)
 {
   SilcServer server = app_context;
   QuitInternal q = (QuitInternal)context;
+  SilcClientEntry client = silc_packet_get_context(q->sock);
 
-  /* Free all client specific data, such as client entry and entires
-     on channels this client may be on. */
-  silc_server_free_client_data(server, q->sock, q->sock->user_data,
-                              TRUE, q->signoff);
-  q->sock->user_data = NULL;
-
-  /* Close the connection on our side */
-  silc_server_close_connection(server, q->sock);
+  if (client) {
+    /* Free all client specific data, such as client entry and entires
+       on channels this client may be on. */
+    silc_server_free_sock_user_data(server, q->sock, q->signoff);
+    silc_server_close_connection(server, q->sock);
+  }
 
-  silc_socket_free(q->sock);
+  silc_packet_stream_unref(q->sock);
   silc_free(q->signoff);
   silc_free(q);
 }
@@ -1352,14 +1342,15 @@ SILC_SERVER_CMD_FUNC(quit)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcSocketConnection sock = cmd->sock;
+  SilcPacketStream sock = cmd->sock;
+  SilcClientEntry client = silc_packet_get_context(sock);
   QuitInternal q;
   unsigned char *tmp = NULL;
   SilcUInt32 len = 0;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_QUIT, cmd, 0, 1);
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+  if (client->data.conn_type != SILC_CONN_CLIENT)
     goto out;
 
   /* Get message */
@@ -1368,13 +1359,14 @@ SILC_SERVER_CMD_FUNC(quit)
     tmp = NULL;
 
   q = silc_calloc(1, sizeof(*q));
-  q->sock = silc_socket_dup(sock);
+  q->sock = sock;
   q->signoff = tmp ? strdup(tmp) : NULL;
+  silc_packet_stream_ref(q->sock);
 
   /* We quit the connection with little timeout */
-  silc_schedule_task_add(server->schedule, sock->sock,
-                        silc_server_command_quit_cb, (void *)q,
-                        0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_command_quit_cb, (void *)q,
+                                0, 200000);
 
  out:
   silc_server_command_free(cmd);
@@ -1387,15 +1379,15 @@ SILC_SERVER_CMD_FUNC(kill)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   SilcClientEntry remote_client;
-  SilcClientID *client_id = NULL;
+  SilcID id;
   unsigned char *tmp, *comment, *auth;
   SilcUInt32 tmp_len, tmp_len2, auth_len;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 3);
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   /* Get authentication payload if present */
@@ -1420,28 +1412,22 @@ SILC_SERVER_CMD_FUNC(kill)
   }
 
   /* Get the client ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
-                                         0);
-    goto out;
-  }
-  client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!client_id) {
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
-                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                        0, 2, tmp, tmp_len);
+                                         SILC_STATUS_ERR_NO_CLIENT_ID, 0);
     goto out;
   }
 
   /* Get the client entry */
   remote_client = silc_idlist_find_client_by_id(server->local_list,
-                                               client_id, TRUE, NULL);
+                                               SILC_ID_GET_ID(id),
+                                               TRUE, NULL);
   if (!remote_client) {
     remote_client = silc_idlist_find_client_by_id(server->global_list,
-                                                 client_id, TRUE, NULL);
+                                                 SILC_ID_GET_ID(id),
+                                                 TRUE, NULL);
     if (!remote_client) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
                                           0, 2, tmp, tmp_len);
@@ -1453,13 +1439,13 @@ SILC_SERVER_CMD_FUNC(kill)
   comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
   if (comment && tmp_len2 > 128) {
     tmp_len2 = 128;
-    comment[127] = '\0';
+    comment[tmp_len2 - 1] = '\0';
   }
 
   /* If authentication data is provided then verify that killing is
      actually allowed */
   if (auth && auth_len) {
-    SilcSocketConnection sock;
+    SilcPacketStream sock;
 
     if (!SILC_IS_LOCAL(remote_client) || !remote_client->data.public_key) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
@@ -1479,23 +1465,31 @@ SILC_SERVER_CMD_FUNC(kill)
     }
 
     /* Send reply to the sender */
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
                                         SILC_STATUS_OK, 0,
                                         2, tmp, tmp_len);
 
     /* Do normal signoff for the destination client */
     sock = remote_client->connection;
+
+    if (sock)
+      silc_packet_stream_ref(sock);
+
     silc_server_remove_from_channels(server, NULL, remote_client,
                                     TRUE, (char *)"Killed", TRUE, TRUE);
-    silc_server_free_client_data(server, NULL, remote_client, TRUE,
-                                comment ? comment :
-                                (unsigned char *)"Killed");
-    if (sock)
+    silc_server_free_sock_user_data(server, sock, comment ? comment :
+                                   (unsigned char *)"Killed");
+    if (sock) {
+      silc_packet_set_context(sock, NULL);
       silc_server_close_connection(server, sock);
+      silc_packet_stream_unref(sock);
+    }
   } else {
     /* Router operator killing */
 
     /* Send reply to the sender */
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
                                         SILC_STATUS_OK, 0,
                                         2, tmp, tmp_len);
@@ -1511,7 +1505,6 @@ SILC_SERVER_CMD_FUNC(kill)
   }
 
  out:
-  silc_free(client_id);
   silc_server_command_free(cmd);
 }
 
@@ -1523,38 +1516,39 @@ SILC_SERVER_CMD_FUNC(info)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcBuffer packet, idp;
+  SilcBuffer idp;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
-  char *dest_server, *server_info = NULL, *server_name;
+  char *dest_server = NULL, *server_info = NULL, *server_name;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   SilcServerEntry entry = NULL;
-  SilcServerID *server_id = NULL;
+  SilcID id;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 0, 2);
 
   /* Get server name */
   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
-
-  /* Get Server ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (tmp) {
-    server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!server_id) {
+  if (dest_server) {
+    /* Check server name. */
+    dest_server = silc_identifier_check(dest_server, strlen(dest_server),
+                                       SILC_STRING_UTF8, 256, &tmp_len);
+    if (!dest_server) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
-                                           SILC_STATUS_ERR_NO_SERVER_ID, 0);
+                                           SILC_STATUS_ERR_BAD_SERVER, 0);
       goto out;
     }
   }
 
-  if (server_id) {
+  /* Get Server ID */
+  if (silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
     /* Check whether we have this server cached */
     entry = silc_idlist_find_server_by_id(server->local_list,
-                                         server_id, TRUE, NULL);
+                                         SILC_ID_GET_ID(id), TRUE, NULL);
     if (!entry) {
       entry = silc_idlist_find_server_by_id(server->global_list,
-                                           server_id, TRUE, NULL);
+                                           SILC_ID_GET_ID(id), TRUE, NULL);
       if (!entry && server->server_type != SILC_SERVER) {
+       tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
        silc_server_command_send_status_data(cmd, SILC_COMMAND_INFO,
                                             SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
                                             0, 2, tmp, tmp_len);
@@ -1563,14 +1557,9 @@ SILC_SERVER_CMD_FUNC(info)
     }
   }
 
-  /* Some buggy servers has sent request to router about themselves. */
-  if (server->server_type != SILC_SERVER && cmd->sock->user_data == entry)
-    goto out;
-
-  if ((!dest_server && !server_id && !entry) || (entry &&
-                                                entry == server->id_entry) ||
+  if ((!dest_server && !entry) || (entry && entry == server->id_entry) ||
       (dest_server && !cmd->pending &&
-       !strncasecmp(dest_server, server->server_name, strlen(dest_server)))) {
+       !memcmp(dest_server, server->server_name, strlen(dest_server)))) {
     /* Send our reply */
     char info_string[256];
 
@@ -1601,13 +1590,16 @@ SILC_SERVER_CMD_FUNC(info)
       SilcBuffer tmpbuf;
       SilcUInt16 old_ident;
 
+      /* Statistics */
+      cmd->server->stat.commands_sent++;
+
       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, entry->connection,
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_INFO,
@@ -1625,13 +1617,16 @@ SILC_SERVER_CMD_FUNC(info)
       SilcBuffer tmpbuf;
       SilcUInt16 old_ident;
 
+      /* Statistics */
+      cmd->server->stat.commands_sent++;
+
       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, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_INFO,
@@ -1645,14 +1640,16 @@ SILC_SERVER_CMD_FUNC(info)
     }
   }
 
-  silc_free(server_id);
-
   if (!entry) {
-    if (dest_server)
+    if (dest_server) {
+      silc_free(dest_server);
+      dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_INFO,
                                           SILC_STATUS_ERR_NO_SUCH_SERVER, 0,
                                           2, dest_server,
                                           strlen(dest_server));
+      dest_server = NULL;
+    }
     goto out;
   }
 
@@ -1662,21 +1659,18 @@ SILC_SERVER_CMD_FUNC(info)
   server_name = entry->server_name;
 
   /* Send the reply */
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
-                                               SILC_STATUS_OK, 0, 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);
-
-  silc_buffer_free(packet);
+  silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_INFO,
+                                SILC_STATUS_OK, 0, ident, 3,
+                                2, idp->data, silc_buffer_len(idp),
+                                3, server_name,
+                                strlen(server_name),
+                                4, server_info,
+                                server_info ?
+                                strlen(server_info) : 0);
   silc_buffer_free(idp);
 
  out:
+  silc_free(dest_server);
   silc_server_command_free(cmd);
 }
 
@@ -1688,27 +1682,24 @@ SILC_SERVER_CMD_FUNC(ping)
   SilcServer server = cmd->server;
   SilcUInt32 tmp_len;
   unsigned char *tmp;
-  SilcServerID *server_id = NULL;
+  SilcID id;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PING, cmd, 1, 1);
 
   /* Get Server ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
                                          0);
     goto out;
   }
-  server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!server_id)
-    goto out;
 
-  if (SILC_ID_SERVER_COMPARE(server_id, server->id)) {
+  if (SILC_ID_SERVER_COMPARE(SILC_ID_GET_ID(id), server->id)) {
     /* Send our reply */
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
                                          SILC_STATUS_OK, 0);
   } else {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_PING,
                                         SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
                                         2, tmp, tmp_len);
@@ -1716,7 +1707,6 @@ SILC_SERVER_CMD_FUNC(ping)
   }
 
  out:
-  silc_free(server_id);
   silc_server_command_free(cmd);
 }
 
@@ -1726,7 +1716,7 @@ SILC_SERVER_CMD_FUNC(stats)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcServerID *server_id;
+  SilcID id;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
   SilcBuffer packet, stats;
@@ -1736,40 +1726,44 @@ SILC_SERVER_CMD_FUNC(stats)
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_STATS, cmd, 1, 1);
 
   /* Get Server ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_STATS,
                                          SILC_STATUS_ERR_NO_SERVER_ID, 0);
     goto out;
   }
-  server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!server_id)
-    goto out;
+
+  SILC_LOG_DEBUG(("id %s", silc_id_render(SILC_ID_GET_ID(id),
+                                         id.type)));
 
   /* The ID must be ours */
-  if (!SILC_ID_SERVER_COMPARE(server->id, server_id)) {
+  if (!SILC_ID_SERVER_COMPARE(server->id, SILC_ID_GET_ID(id))) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_STATS,
                                         SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
                                         2, tmp, tmp_len);
-    silc_free(server_id);
     goto out;
   }
-  silc_free(server_id);
 
   /* If we are router then just send everything we got. If we are normal
      server then we'll send this to our router to get all the latest
      statistical information. */
   if (!cmd->pending && server->server_type != SILC_ROUTER &&
       !server->standalone) {
+    SilcBuffer idp;
+
+    /* Statistics */
+    cmd->server->stat.commands_sent++;
+
     /* Send request to our router */
-    SilcBuffer idp = silc_id_payload_encode(server->router->id,
-                                           SILC_ID_SERVER);
+    idp = silc_id_payload_encode(server->router->id,
+                                SILC_ID_SERVER);
     packet = silc_command_payload_encode_va(SILC_COMMAND_STATS,
                                            ++server->cmd_ident, 1,
-                                           1, idp->data, idp->len);
+                                           1, idp->data,
+                                           silc_buffer_len(idp));
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            SILC_PACKET_COMMAND, 0, packet->data,
-                           packet->len, FALSE);
+                           silc_buffer_len(packet));
 
     /* Reprocess this packet after received reply from router */
     silc_server_command_pending(server, SILC_COMMAND_STATS,
@@ -1804,13 +1798,11 @@ SILC_SERVER_CMD_FUNC(stats)
                     SILC_STR_UI_INT(server->stat.router_ops),
                     SILC_STR_END);
 
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_STATS,
-                                               SILC_STATUS_OK, 0, ident, 2,
-                                               2, tmp, tmp_len,
-                                               3, stats->data, stats->len);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
-                         0, packet->data, packet->len, FALSE);
-  silc_buffer_free(packet);
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_STATS,
+                                SILC_STATUS_OK, 0, ident, 2,
+                                2, tmp, tmp_len,
+                                3, stats->data, silc_buffer_len(stats));
   silc_buffer_free(stats);
 
  out:
@@ -1825,37 +1817,42 @@ static void silc_server_command_join_channel(SilcServer server,
                                             SilcServerCommandContext cmd,
                                             SilcChannelEntry channel,
                                             SilcClientID *client_id,
-                                            bool created,
-                                            bool create_key,
+                                            SilcBool created,
+                                            SilcBool create_key,
                                             SilcUInt32 umode,
                                             const unsigned char *auth,
                                             SilcUInt32 auth_len,
                                             const unsigned char *cauth,
                                             SilcUInt32 cauth_len)
 {
-  SilcSocketConnection sock = cmd->sock;
+  SilcPacketStream sock = cmd->sock;
+  SilcIDListData idata = silc_packet_get_context(sock);
   unsigned char *tmp;
   SilcUInt32 tmp_len, user_count;
-  unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4];
+  unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4], ulimit[4];
   SilcClientEntry client;
   SilcChannelClientEntry chl;
   SilcBuffer reply, chidp, clidp, keyp = NULL;
   SilcBuffer user_list, mode_list, invite_list, ban_list;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   char check[512], check2[512];
-  bool founder = FALSE;
-  bool resolve;
+  void *plen;
+  SilcBool founder = FALSE;
+  SilcBool resolve;
   SilcBuffer fkey = NULL, chpklist = NULL;
-  const char *cipher;
+  const char *cipher, *hostname, *ip;
 
   SILC_LOG_DEBUG(("Joining client to channel"));
 
   if (!channel)
     return;
 
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+                             NULL, &hostname, &ip, NULL);
+
   /* Get the client entry */
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
-    client = (SilcClientEntry)sock->user_data;
+  if (idata->conn_type == SILC_CONN_CLIENT) {
+    client = (SilcClientEntry)idata;
     if (!client)
       return;
   } else {
@@ -1863,9 +1860,11 @@ static void silc_server_command_join_channel(SilcServer server,
                                      &resolve);
     if (!client) {
       if (!resolve || cmd->pending) {
-       silc_server_command_send_status_reply(
+       tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+       silc_server_command_send_status_data(
                                         cmd, SILC_COMMAND_JOIN,
-                                        SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0,
+                                        2, tmp, tmp_len);
        goto out;
       }
 
@@ -1890,7 +1889,7 @@ static void silc_server_command_join_channel(SilcServer server,
       clidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
       silc_server_send_command(server, cmd->sock,
                               SILC_COMMAND_GETKEY, ++server->cmd_ident,
-                              1, 1, clidp->data, clidp->len);
+                              1, 1, clidp->data, silc_buffer_len(clidp));
       silc_buffer_free(clidp);
       silc_server_command_pending(server, SILC_COMMAND_GETKEY,
                                  server->cmd_ident,
@@ -1954,7 +1953,7 @@ static void silc_server_command_join_channel(SilcServer server,
     if (!strchr(client->username, '@')) {
       silc_strncat(check, sizeof(check), "@", 1);
       silc_strncat(check, sizeof(check),
-                  cmd->sock->hostname, strlen(cmd->sock->hostname));
+                  hostname, strlen(hostname));
     }
 
     silc_strncat(check2, sizeof(check2),
@@ -1962,7 +1961,10 @@ static void silc_server_command_join_channel(SilcServer server,
     if (!strchr(client->nickname, '@')) {
       silc_strncat(check2, sizeof(check2), "@", 1);
       silc_strncat(check2, sizeof(check2),
-                  server->server_name, strlen(server->server_name));
+                  SILC_IS_LOCAL(client) ? server->server_name :
+                  client->router->server_name,
+                  SILC_IS_LOCAL(client) ? strlen(server->server_name) :
+                  strlen(client->router->server_name));
     }
     silc_strncat(check2, sizeof(check2), "!", 1);
     silc_strncat(check2, sizeof(check2),
@@ -1970,7 +1972,7 @@ static void silc_server_command_join_channel(SilcServer server,
     if (!strchr(client->username, '@')) {
       silc_strncat(check2, sizeof(check2), "@", 1);
       silc_strncat(check2, sizeof(check2),
-                  cmd->sock->hostname, strlen(cmd->sock->hostname));
+                  hostname, strlen(hostname));
     }
 
     /* Check invite list if channel is invite-only channel */
@@ -1990,7 +1992,8 @@ static void silc_server_command_join_channel(SilcServer server,
        chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
        silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
                                             SILC_STATUS_ERR_NOT_INVITED, 0,
-                                            2, chidp->data, chidp->len);
+                                            2, chidp->data,
+                                            silc_buffer_len(chidp));
        silc_buffer_free(chidp);
        goto out;
       }
@@ -2014,7 +2017,8 @@ static void silc_server_command_join_channel(SilcServer server,
        silc_server_command_send_status_data(
                                      cmd, SILC_COMMAND_JOIN,
                                      SILC_STATUS_ERR_BANNED_FROM_CHANNEL, 0,
-                                     2, chidp->data, chidp->len);
+                                     2, chidp->data,
+                                     silc_buffer_len(chidp));
        silc_buffer_free(chidp);
        goto out;
       }
@@ -2027,7 +2031,8 @@ static void silc_server_command_join_channel(SilcServer server,
        chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
        silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
                                             SILC_STATUS_ERR_CHANNEL_IS_FULL,
-                                            0, 2, chidp->data, chidp->len);
+                                            0, 2, chidp->data,
+                                            silc_buffer_len(chidp));
        silc_buffer_free(chidp);
        goto out;
       }
@@ -2042,11 +2047,13 @@ static void silc_server_command_join_channel(SilcServer server,
       passphrase = silc_memdup(tmp, tmp_len);
 
     if (!passphrase || !channel->passphrase ||
+       strlen(channel->passphrase) != strlen(passphrase) ||
         memcmp(passphrase, channel->passphrase, strlen(channel->passphrase))) {
       chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
                                           SILC_STATUS_ERR_BAD_PASSWORD, 0,
-                                          2, chidp->data, chidp->len);
+                                          2, chidp->data,
+                                          silc_buffer_len(chidp));
       silc_buffer_free(chidp);
       goto out;
     }
@@ -2072,8 +2079,10 @@ static void silc_server_command_join_channel(SilcServer server,
     chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
     silc_server_command_send_status_data2(cmd, SILC_COMMAND_JOIN,
                                          SILC_STATUS_ERR_USER_ON_CHANNEL, 0,
-                                         2, clidp->data, clidp->len,
-                                         3, chidp->data, chidp->len);
+                                         2, clidp->data,
+                                         silc_buffer_len(clidp),
+                                         3, chidp->data,
+                                         silc_buffer_len(chidp));
     silc_buffer_free(clidp);
     silc_buffer_free(chidp);
     goto out;
@@ -2116,20 +2125,21 @@ static void silc_server_command_join_channel(SilcServer server,
   SILC_PUT32_MSB(channel->mode, mode);
   SILC_PUT32_MSB(created, tmp2);
   SILC_PUT32_MSB(user_count, tmp3);
+  if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
+    SILC_PUT32_MSB(channel->user_limit, ulimit);
 
   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
-    tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-    cipher = silc_cipher_get_name(channel->channel_key);
-    keyp = silc_channel_key_payload_encode(silc_id_get_len(channel->id,
-                                                          SILC_ID_CHANNEL),
-                                          tmp,
+    unsigned char cid[32];
+    SilcUInt32 cid_len;
+    silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid), &cid_len);
+    cipher = silc_cipher_get_name(channel->send_key);
+    keyp = silc_channel_key_payload_encode(cid_len, cid,
                                           strlen(cipher), cipher,
                                           channel->key_len / 8, channel->key);
-    silc_free(tmp);
   }
 
   if (channel->founder_key)
-    fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
+    fkey = silc_public_key_payload_encode(channel->founder_key);
 
   /* Encode invite list */
   invite_list = NULL;
@@ -2143,10 +2153,11 @@ static void silc_server_command_join_channel(SilcServer server,
                       SILC_STR_END);
 
     silc_hash_table_list(channel->invite_list, &htl);
-    while (silc_hash_table_get(&htl, (void **)&tmp_len, (void **)&reply))
+    while (silc_hash_table_get(&htl, (void *)&plen, (void *)&reply))
       invite_list = silc_argument_payload_encode_one(invite_list,
                                                     reply->data,
-                                                    reply->len, tmp_len);
+                                                    silc_buffer_len(reply),
+                                                    SILC_PTR_TO_32(plen));
     silc_hash_table_list_reset(&htl);
   }
 
@@ -2162,10 +2173,11 @@ static void silc_server_command_join_channel(SilcServer server,
                       SILC_STR_END);
 
     silc_hash_table_list(channel->ban_list, &htl);
-    while (silc_hash_table_get(&htl, (void **)&tmp_len, (void **)&reply))
+    while (silc_hash_table_get(&htl, (void *)&plen, (void *)&reply))
       ban_list = silc_argument_payload_encode_one(ban_list,
                                                  reply->data,
-                                                 reply->len, tmp_len);
+                                                 silc_buffer_len(reply),
+                                                 SILC_PTR_TO_32(plen));
     silc_hash_table_list_reset(&htl);
   }
 
@@ -2174,20 +2186,24 @@ static void silc_server_command_join_channel(SilcServer server,
 
   reply =
     silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
-                                        SILC_STATUS_OK, 0, ident, 15,
+                                        SILC_STATUS_OK, 0, ident, 16,
                                         2, channel->channel_name,
                                         strlen(channel->channel_name),
-                                        3, chidp->data, chidp->len,
-                                        4, clidp->data, clidp->len,
+                                        3, chidp->data,
+                                        silc_buffer_len(chidp),
+                                        4, clidp->data,
+                                        silc_buffer_len(clidp),
                                         5, mode, 4,
                                         6, tmp2, 4,
                                         7, keyp ? keyp->data : NULL,
-                                        keyp ? keyp->len : 0,
+                                        keyp ? silc_buffer_len(keyp) : 0,
                                         8, ban_list ? ban_list->data : NULL,
-                                        ban_list ? ban_list->len : 0,
+                                        ban_list ?
+                                        silc_buffer_len(ban_list): 0,
                                         9, invite_list ? invite_list->data :
                                         NULL,
-                                        invite_list ? invite_list->len : 0,
+                                        invite_list ?
+                                        silc_buffer_len(invite_list) : 0,
                                         10, channel->topic,
                                         channel->topic ?
                                         strlen(channel->topic) : 0,
@@ -2195,17 +2211,27 @@ static void silc_server_command_join_channel(SilcServer server,
                                         strlen(silc_hmac_get_name(channel->
                                                                   hmac)),
                                         12, tmp3, 4,
-                                        13, user_list->data, user_list->len,
+                                        13, user_list->data,
+                                        silc_buffer_len(user_list),
                                         14, mode_list->data,
-                                        mode_list->len,
+                                        silc_buffer_len(mode_list),
                                         15, fkey ? fkey->data : NULL,
-                                        fkey ? fkey->len : 0,
+                                        fkey ? silc_buffer_len(fkey) : 0,
                                         16, chpklist ? chpklist->data : NULL,
-                                        chpklist ? chpklist->len : 0);
+                                        chpklist ? silc_buffer_len(chpklist) : 0,
+                                        17, (channel->mode &
+                                             SILC_CHANNEL_MODE_ULIMIT ?
+                                             ulimit : NULL),
+                                        (channel->mode &
+                                         SILC_CHANNEL_MODE_ULIMIT ?
+                                         sizeof(ulimit) : 0));
 
   /* Send command reply */
   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
-                         reply->data, reply->len, FALSE);
+                         reply->data, silc_buffer_len(reply));
+
+  /* Statistics */
+  cmd->server->stat.commands_sent++;
 
   /* Send JOIN notify to locally connected clients on the channel. If
      we are normal server then router will send or have sent JOIN notify
@@ -2216,8 +2242,8 @@ static void silc_server_command_join_channel(SilcServer server,
   SILC_LOG_DEBUG(("Send JOIN notify to channel"));
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                     SILC_NOTIFY_TYPE_JOIN, 2,
-                                    clidp->data, clidp->len,
-                                    chidp->data, chidp->len);
+                                    clidp->data, silc_buffer_len(clidp),
+                                    chidp->data, silc_buffer_len(chidp));
 
   /* Update statistics */
   server->stat.my_chanclients++;
@@ -2234,7 +2260,7 @@ static void silc_server_command_join_channel(SilcServer server,
     if (keyp)
       /* Distribute the channel key to all backup routers. */
       silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
-                             keyp->data, keyp->len, FALSE, TRUE);
+                             keyp->data, silc_buffer_len(keyp), FALSE, TRUE);
 
     /* If client became founder by providing correct founder auth data
        notify the mode change to the channel. */
@@ -2243,10 +2269,12 @@ static void silc_server_command_join_channel(SilcServer server,
       SILC_LOG_DEBUG(("Send CUMODE_CHANGE notify to channel"));
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                         SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
-                                        clidp->data, clidp->len,
-                                        mode, 4, clidp->data, clidp->len,
+                                        clidp->data,
+                                        silc_buffer_len(clidp),
+                                        mode, 4, clidp->data,
+                                        silc_buffer_len(clidp),
                                         fkey ? fkey->data : NULL,
-                                        fkey ? fkey->len : 0);
+                                        fkey ? silc_buffer_len(fkey) : 0);
     }
   }
 
@@ -2277,17 +2305,51 @@ static void silc_server_command_join_channel(SilcServer server,
 /* Server side of command JOIN. Joins client into requested channel. If
    the channel does not exist it will be created. */
 
+void silc_server_command_join_connected(SilcServer server,
+                                       SilcServerEntry server_entry,
+                                       void *context)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+
+  if (!server_entry) {
+    SilcUInt32 tmp_len;
+    unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+    char serv[256 + 1];
+
+    SILC_LOG_DEBUG(("Connecting to router failed"));
+    silc_parse_userfqdn(tmp, NULL, 0, serv, sizeof(serv));
+
+    if (serv[0]) {
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
+                                          SILC_STATUS_ERR_NO_SUCH_SERVER, 0,
+                                          2, serv, strlen(serv));
+    } else {
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
+                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL, 0,
+                                          2, tmp, tmp_len);
+    }
+    silc_server_command_free(cmd);
+    return;
+  }
+
+  /* Reprocess command */
+  SILC_LOG_DEBUG(("Reprocess JOIN after connecting to router"));
+  silc_server_command_join(cmd, NULL);
+}
+
 SILC_SERVER_CMD_FUNC(join)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
+  SilcIDListData idata = silc_packet_get_context(cmd->sock);
   unsigned char *auth, *cauth;
   SilcUInt32 tmp_len, auth_len, cauth_len;
-  char *tmp, *channel_name = NULL, *cipher, *hmac;
+  char *tmp, *channel_name, *channel_namec = NULL, *cipher, *hmac;
+  char parsed[256 + 1], serv[256 + 1];
   SilcChannelEntry channel;
   SilcUInt32 umode = 0;
-  bool created = FALSE, create_key = TRUE;
-  SilcClientID *client_id;
+  SilcBool created = FALSE, create_key = TRUE;
+  SilcID id;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 2, 7);
 
@@ -2299,32 +2361,78 @@ SILC_SERVER_CMD_FUNC(join)
                                          0);
     goto out;
   }
-  channel_name = tmp;
 
-  if (tmp_len > 256)
-    channel_name[255] = '\0';
+  /* Truncate over long channel names */
+  if (tmp_len > 256) {
+    tmp_len = 256;
+    tmp[tmp_len - 1] = '\0';
+  }
+
+  /* Parse server name from the channel name */
+  silc_parse_userfqdn(tmp, parsed, sizeof(parsed), serv,
+                     sizeof(serv));
+  channel_name = parsed;
 
-  if (silc_server_name_bad_chchars(channel_name, tmp_len) == TRUE) {
+  if (server->config->dynamic_server) {
+    /* If server name is not specified but local channels is FALSE then the
+       channel will be global, based on our router name. */
+    if (!serv[0] && !server->config->local_channels) {
+      if (!server->standalone) {
+       silc_snprintf(serv, sizeof(serv), server->router->server_name);
+      } else {
+       SilcServerConfigRouter *router;
+       router = silc_server_config_get_primary_router(server);
+       if (router) {
+         /* Create connection to primary router */
+         SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
+                         router->host, router->port));
+         silc_server_create_connection(server, FALSE, TRUE,
+                                       router->host, router->port,
+                                       silc_server_command_join_connected,
+                                       cmd);
+         return;
+       }
+      }
+    }
+
+    /* If server name is ours, ignore it. */
+    if (serv[0] && silc_utf8_strcasecmp(serv, server->server_name))
+      memset(serv, 0, sizeof(serv));
+
+    /* Create connection */
+    if (serv[0] && server->standalone) {
+      SilcServerConfigRouter *router;
+      router = silc_server_config_get_primary_router(server);
+      if (router) {
+       /* Create connection to primary router */
+       SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
+                       router->host, router->port));
+       silc_server_create_connection(server, FALSE, TRUE,
+                                     router->host, router->port,
+                                     silc_server_command_join_connected, cmd);
+       return;
+      }
+    }
+  }
+
+  /* Check for valid channel name.  This is cached, the original is saved
+     in the channel context. */
+  channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
+                                         SILC_STRING_UTF8, 256, NULL);
+  if (!channel_namec) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                          SILC_STATUS_ERR_BAD_CHANNEL, 0);
     goto out;
   }
 
   /* Get Client ID of the client who is joining to the channel */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (!tmp) {
+  if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
-                                         0);
-    goto out;
-  }
-  client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!client_id) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                         SILC_STATUS_ERR_NO_CLIENT_ID,
                                          0);
     goto out;
   }
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
 
   /* Get cipher, hmac name and auth payload */
   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
@@ -2334,10 +2442,10 @@ SILC_SERVER_CMD_FUNC(join)
 
   /* See if the channel exists */
   channel = silc_idlist_find_channel_by_name(server->local_list,
-                                            channel_name, NULL);
+                                            channel_namec, NULL);
 
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
-    SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
+  if (idata->conn_type == SILC_CONN_CLIENT) {
+    SilcClientEntry entry = (SilcClientEntry)idata;
     if (!entry) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
@@ -2345,8 +2453,17 @@ SILC_SERVER_CMD_FUNC(join)
       goto out;
     }
 
-    silc_free(client_id);
-    client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
+#ifndef SILC_DIST_INPLACE
+    /* Limit how many channels client can join */
+    if (!cmd->pending && entry->channels &&
+       silc_hash_table_count(entry->channels) >=
+       server->config->param.chlimit) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                           SILC_STATUS_ERR_RESOURCE_LIMIT,
+                                           0);
+      goto out;
+    }
+#endif /* SILC_DIST_INPLACE */
 
     if (!channel ||
        (channel->disabled && server->server_type != SILC_ROUTER)) {
@@ -2359,11 +2476,22 @@ 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_data(
-                                 cmd, SILC_COMMAND_JOIN,
-                                 SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
-                                 0, 2, cipher, strlen(cipher));
-           silc_free(client_id);
+           if (cipher) {
+             silc_server_command_send_status_data(
+                               cmd, SILC_COMMAND_JOIN,
+                               SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
+                               0, 2, cipher, strlen(cipher));
+           } else if (hmac) {
+             silc_server_command_send_status_data(
+                               cmd, SILC_COMMAND_JOIN,
+                               SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
+                               0, 2, hmac, strlen(hmac));
+           } else {
+             silc_server_command_send_status_reply(
+                               cmd, SILC_COMMAND_JOIN,
+                               SILC_STATUS_ERR_RESOURCE_LIMIT,
+                               0);
+           }
            goto out;
          }
 
@@ -2384,20 +2512,20 @@ SILC_SERVER_CMD_FUNC(join)
          /* If this is pending command callback then we've resolved
             it and it didn't work, return since we've notified the
             client already in the command reply callback. */
-         if (cmd->pending) {
-           silc_free(client_id);
+         if (cmd->pending)
            goto out;
-         }
+
+         /* Statistics */
+         cmd->server->stat.commands_sent++;
 
          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 JOIN command to our router */
-         silc_server_packet_send(server, (SilcSocketConnection)
-                                 SILC_PRIMARY_ROUTE(server),
+         silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                                  SILC_PACKET_COMMAND, cmd->packet->flags,
-                                 tmpbuf->data, tmpbuf->len, TRUE);
+                                 tmpbuf->data, silc_buffer_len(tmpbuf));
 
          /* Reprocess this packet after received reply from router */
          silc_server_command_pending(server, SILC_COMMAND_JOIN,
@@ -2407,24 +2535,34 @@ SILC_SERVER_CMD_FUNC(join)
          cmd->pending = TRUE;
           silc_command_set_ident(cmd->payload, old_ident);
          silc_buffer_free(tmpbuf);
-         silc_free(client_id);
          goto out;
        }
 
        /* We are router and the channel does not seem exist so we will check
           our global list as well for the channel. */
        channel = silc_idlist_find_channel_by_name(server->global_list,
-                                                  channel_name, NULL);
+                                                  channel_namec, NULL);
        if (!channel) {
          /* Channel really does not exist, create it */
          channel = silc_server_create_new_channel(server, server->id, cipher,
                                                   hmac, channel_name, TRUE);
          if (!channel) {
-           silc_server_command_send_status_data(
-                                      cmd, SILC_COMMAND_JOIN,
-                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
-                                      2, cipher, strlen(cipher));
-           silc_free(client_id);
+           if (cipher) {
+             silc_server_command_send_status_data(
+                                     cmd, SILC_COMMAND_JOIN,
+                                     SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
+                                     0, 2, cipher, strlen(cipher));
+           } else if (hmac) {
+             silc_server_command_send_status_data(
+                                     cmd, SILC_COMMAND_JOIN,
+                                     SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
+                                     0, 2, hmac, strlen(hmac));
+           } else {
+             silc_server_command_send_status_reply(
+                                     cmd, SILC_COMMAND_JOIN,
+                                     SILC_STATUS_ERR_RESOURCE_LIMIT,
+                                     0);
+           }
            goto out;
          }
 
@@ -2441,26 +2579,35 @@ SILC_SERVER_CMD_FUNC(join)
       /* If the command came from router and we are normal server then
         something went wrong with the joining as the channel was not found.
         We can't do anything else but ignore this. */
-      if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
-         server->server_type != SILC_ROUTER) {
-       silc_free(client_id);
+      if (idata->conn_type == SILC_CONN_ROUTER ||
+         server->server_type != SILC_ROUTER)
        goto out;
-      }
 
       /* We are router and the channel does not seem exist so we will check
         our global list as well for the channel. */
       channel = silc_idlist_find_channel_by_name(server->global_list,
-                                                channel_name, NULL);
+                                                channel_namec, NULL);
       if (!channel) {
        /* Channel really does not exist, create it */
        channel = silc_server_create_new_channel(server, server->id, cipher,
                                                 hmac, channel_name, TRUE);
        if (!channel) {
-         silc_server_command_send_status_data(
-                                      cmd, SILC_COMMAND_JOIN,
-                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
-                                      2, cipher, strlen(cipher));
-         silc_free(client_id);
+         if (cipher) {
+           silc_server_command_send_status_data(
+                                     cmd, SILC_COMMAND_JOIN,
+                                     SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
+                                     0, 2, cipher, strlen(cipher));
+         } else if (hmac) {
+           silc_server_command_send_status_data(
+                                     cmd, SILC_COMMAND_JOIN,
+                                     SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
+                                     0, 2, hmac, strlen(hmac));
+         } else {
+           silc_server_command_send_status_reply(
+                                     cmd, SILC_COMMAND_JOIN,
+                                     SILC_STATUS_ERR_RESOURCE_LIMIT,
+                                     0);
+         }
          goto out;
        }
 
@@ -2506,13 +2653,12 @@ SILC_SERVER_CMD_FUNC(join)
     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
 
   /* Join to the channel */
-  silc_server_command_join_channel(server, cmd, channel, client_id,
+  silc_server_command_join_channel(server, cmd, channel, SILC_ID_GET_ID(id),
                                   created, create_key, umode,
                                   auth, auth_len, cauth, cauth_len);
 
-  silc_free(client_id);
-
  out:
+  silc_free(channel_namec);
   silc_server_command_free(cmd);
 }
 
@@ -2523,8 +2669,8 @@ SILC_SERVER_CMD_FUNC(motd)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcBuffer packet, idp;
-  char *motd, *dest_server;
+  SilcBuffer idp;
+  char *motd, *dest_server = NULL;
   SilcUInt32 motd_len;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
 
@@ -2539,7 +2685,17 @@ SILC_SERVER_CMD_FUNC(motd)
     goto out;
   }
 
-  if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
+  /* Check server name */
+  dest_server = silc_identifier_check(dest_server, strlen(dest_server),
+                                     SILC_STRING_UTF8, 256, NULL);
+  if (!dest_server) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
+                                         SILC_STATUS_ERR_BAD_SERVER,
+                                         0);
+    goto out;
+  }
+
+  if (!memcmp(dest_server, server->server_name, strlen(dest_server))) {
     /* Send our MOTD */
 
     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
@@ -2549,26 +2705,25 @@ SILC_SERVER_CMD_FUNC(motd)
       /* Send motd */
       motd = silc_file_readfile(server->config->server_info->motd_file,
                                &motd_len);
-      if (!motd)
+      if (!motd) {
+       /* No motd */
+       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_MOTD,
+                                      SILC_STATUS_OK, 0, ident, 1,
+                                      2, idp->data, silc_buffer_len(idp));
        goto out;
+      }
 
       motd[motd_len] = 0;
-      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                   SILC_STATUS_OK, 0,
-                                                   ident, 2,
-                                                   2, idp, idp->len,
-                                                   3, motd, motd_len);
+      silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_MOTD,
+                                    SILC_STATUS_OK, 0, ident, 2,
+                                    2, idp->data, silc_buffer_len(idp),
+                                    3, motd, motd_len);
     } else {
       /* No motd */
-      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                   SILC_STATUS_OK, 0,
-                                                   ident, 1,
-                                                   2, idp, idp->len);
+      silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_MOTD,
+                                    SILC_STATUS_OK, 0, ident, 1,
+                                    2, idp->data, silc_buffer_len(idp));
     }
-
-    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);
   } else {
     SilcServerEntry entry;
@@ -2587,13 +2742,16 @@ SILC_SERVER_CMD_FUNC(motd)
       SilcBuffer tmpbuf;
       SilcUInt16 old_ident;
 
+      /* Statistics */
+      cmd->server->stat.commands_sent++;
+
       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, entry->connection,
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_MOTD,
@@ -2606,18 +2764,24 @@ SILC_SERVER_CMD_FUNC(motd)
       goto out;
     }
 
-    if (!entry && !cmd->pending && !server->standalone) {
+    /* Send to primary router only if we don't know the server
+     * the client requested or if the server is not locally connected */
+    if ((!entry || !(entry->data.status & SILC_IDLIST_STATUS_LOCAL))
+       && !cmd->pending && !server->standalone) {
       /* Send to the primary router */
       SilcBuffer tmpbuf;
       SilcUInt16 old_ident;
 
+      /* Statistics */
+      cmd->server->stat.commands_sent++;
+
       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, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_MOTD,
@@ -2631,27 +2795,28 @@ SILC_SERVER_CMD_FUNC(motd)
     }
 
     if (!entry) {
+      silc_free(dest_server);
+      dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
                                           SILC_STATUS_ERR_NO_SUCH_SERVER, 0,
                                           2, dest_server,
                                           strlen(dest_server));
+      dest_server = NULL;
       goto out;
     }
 
-    idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
-    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                 SILC_STATUS_OK, 0, 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);
+    idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
+    silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_MOTD,
+                                  SILC_STATUS_OK, 0, ident, 2,
+                                  2, idp->data, silc_buffer_len(idp),
+                                  3, entry->motd,
+                                  entry->motd ?
+                                  strlen(entry->motd) : 0);
     silc_buffer_free(idp);
   }
 
  out:
+  silc_free(dest_server);
   silc_server_command_free(cmd);
 }
 
@@ -2663,14 +2828,13 @@ SILC_SERVER_CMD_FUNC(umode)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  SilcBuffer packet;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   unsigned char *tmp_mask, m[4];
   SilcUInt32 mask = 0;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
-  bool set_mask = FALSE;
+  SilcBool set_mask = FALSE;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_UMODE, cmd, 1, 2);
@@ -2691,18 +2855,11 @@ SILC_SERVER_CMD_FUNC(umode)
     }
 
     /* Anonymous mode cannot be set by client */
-    if (mask & SILC_UMODE_ANONYMOUS) {
-      if (!(client->mode & SILC_UMODE_ANONYMOUS)) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
-                                             SILC_STATUS_ERR_PERM_DENIED, 0);
-       goto out;
-      }
-    } else {
-      if (client->mode & SILC_UMODE_ANONYMOUS) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
-                                             SILC_STATUS_ERR_PERM_DENIED, 0);
-       goto out;
-      }
+    if (mask & SILC_UMODE_ANONYMOUS &&
+       !(client->mode & SILC_UMODE_ANONYMOUS)) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
+                                           SILC_STATUS_ERR_PERM_DENIED, 0);
+      goto out;
     }
 
     /* Update statistics */
@@ -2714,6 +2871,10 @@ SILC_SERVER_CMD_FUNC(umode)
        server->stat.my_aways--;
     }
 
+    /* If the client has anonymous mode set, preserve it. */
+    if (client->mode & SILC_UMODE_ANONYMOUS)
+      mask |= SILC_UMODE_ANONYMOUS;
+
     /* Change the mode */
     client->mode = mask;
 
@@ -2730,12 +2891,9 @@ SILC_SERVER_CMD_FUNC(umode)
 
   /* Send command reply to sender */
   SILC_PUT32_MSB(client->mode, m);
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_UMODE,
-                                               SILC_STATUS_OK, 0, ident, 1,
-                                               2, m, sizeof(m));
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
-                         packet->data, packet->len, FALSE);
-  silc_buffer_free(packet);
+  silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_UMODE,
+                                SILC_STATUS_OK, 0, ident, 1,
+                                2, m, sizeof(m));
 
  out:
   silc_server_command_free(cmd);
@@ -2747,17 +2905,17 @@ SILC_SERVER_CMD_FUNC(cmode)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   SilcIDListData idata = (SilcIDListData)client;
-  SilcChannelID *channel_id = NULL;
+  SilcID id;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
-  SilcBuffer packet, cidp;
+  SilcBuffer cidp;
   unsigned char *tmp, *tmp_id, *tmp_mask, *chpkdata = NULL;
-  char *cipher = NULL, *hmac = NULL, *passphrase = NULL;
+  char *cipher = NULL, *hmac = NULL, *passphrase = NULL, ulimit[4];
   SilcUInt32 mode_mask = 0, old_mask = 0, tmp_len, tmp_len2, chpklen;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
-  bool set_mask = FALSE, set_chpk = FALSE;
+  SilcBool set_mask = FALSE, set_chpk = FALSE;
   SilcPublicKey founder_key = NULL;
   SilcBuffer fkey = NULL, chpklist = NULL;
   SilcBufferStruct chpk;
@@ -2770,15 +2928,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 1, 9);
 
   /* Get Channel ID */
-  tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
-  if (!tmp_id) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-    silc_server_command_free(cmd);
-    return;
-  }
-  channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2, NULL);
-  if (!channel_id) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
     silc_server_command_free(cmd);
@@ -2787,15 +2937,15 @@ SILC_SERVER_CMD_FUNC(cmode)
 
   /* Get channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
+      tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_CMODE,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
                                           0, 2, tmp_id, tmp_len2);
-      silc_free(channel_id);
       silc_server_command_free(cmd);
       return;
     }
@@ -2811,6 +2961,7 @@ SILC_SERVER_CMD_FUNC(cmode)
 
   /* Check whether this client is on the channel */
   if (!silc_server_client_on_channel(client, channel, &chl)) {
+    tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_CMODE,
                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
                                         2, tmp_id, tmp_len2);
@@ -2821,6 +2972,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   if (set_mask && !silc_server_check_cmode_rights(server, channel, chl,
                                                  mode_mask)) {
     SILC_LOG_DEBUG(("Client does not have rights to change mode"));
+    tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
     silc_server_command_send_status_data(
                             cmd, SILC_COMMAND_CMODE,
                             (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) ?
@@ -2836,22 +2988,19 @@ SILC_SERVER_CMD_FUNC(cmode)
     unsigned char m[4];
     SILC_PUT32_MSB(channel->mode, m);
     if (channel->founder_key)
-      fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
+      fkey = silc_public_key_payload_encode(channel->founder_key);
     if (channel->channel_pubkeys)
       chpklist = silc_server_get_channel_pk_list(server, channel,
                                                 FALSE, FALSE);
-    packet =
-      silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
-                                          SILC_STATUS_OK, 0, ident, 4,
-                                          2, tmp_id, tmp_len2,
-                                          3, m, sizeof(m),
-                                          4, fkey ? fkey->data : NULL,
-                                          fkey ? fkey->len : 0,
-                                          5, chpklist ? chpklist->data : NULL,
-                                          chpklist ? chpklist->len : 0);
-    silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
-                           packet->data, packet->len, FALSE);
-    silc_buffer_free(packet);
+    tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
+    silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_CMODE,
+                                  SILC_STATUS_OK, 0, ident, 4,
+                                  2, tmp_id, tmp_len2,
+                                  3, m, sizeof(m),
+                                  4, fkey ? fkey->data : NULL,
+                                  fkey ? silc_buffer_len(fkey) : 0,
+                                  5, chpklist ? chpklist->data : NULL,
+                                  chpklist ? silc_buffer_len(chpklist) : 0);
     goto out;
   }
 
@@ -2870,6 +3019,10 @@ SILC_SERVER_CMD_FUNC(cmode)
         new channel key. Clients are not using private channel keys
         anymore after this. */
 
+      /* if we don't remove the flag from the mode
+       * silc_server_create_channel_key won't create a new key */
+      channel->mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
+
       /* Re-generate channel key */
       if (!silc_server_create_channel_key(server, channel, 0))
        goto out;
@@ -2880,7 +3033,7 @@ SILC_SERVER_CMD_FUNC(cmode)
                                   server->server_type == SILC_ROUTER ?
                                   FALSE : !server->standalone);
 
-      cipher = (char *)silc_cipher_get_name(channel->channel_key);
+      cipher = (char *)silc_cipher_get_name(channel->send_key);
       hmac = (char *)silc_hmac_get_name(channel->hmac);
     }
   }
@@ -2933,7 +3086,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
       /* Cipher to use protect the traffic */
-      SilcCipher newkey, oldkey;
+      SilcCipher send_key, receive_key, olds, oldr;
 
       /* Get cipher */
       cipher = silc_argument_get_arg_type(cmd->args, 5, NULL);
@@ -2944,7 +3097,14 @@ SILC_SERVER_CMD_FUNC(cmode)
       }
 
       /* Delete old cipher and allocate the new one */
-      if (!silc_cipher_alloc(cipher, &newkey)) {
+      if (!silc_cipher_alloc(cipher, &send_key)) {
+       silc_server_command_send_status_data(
+                                        cmd, SILC_COMMAND_CMODE,
+                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
+                                        2, cipher, strlen(cipher));
+       goto out;
+      }
+      if (!silc_cipher_alloc(cipher, &receive_key)) {
        silc_server_command_send_status_data(
                                         cmd, SILC_COMMAND_CMODE,
                                         SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
@@ -2952,18 +3112,22 @@ SILC_SERVER_CMD_FUNC(cmode)
        goto out;
       }
 
-      oldkey = channel->channel_key;
-      channel->channel_key = newkey;
+      olds = channel->send_key;
+      oldr = channel->receive_key;
+      channel->send_key = send_key;
+      channel->receive_key = receive_key;
 
       /* Re-generate channel key */
       if (!silc_server_create_channel_key(server, channel, 0)) {
        /* We don't have new key, revert to old one */
-       channel->channel_key = oldkey;
+       channel->send_key = olds;
+       channel->receive_key = oldr;
        goto out;
       }
 
       /* Remove old channel key for good */
-      silc_cipher_free(oldkey);
+      silc_cipher_free(olds);
+      silc_cipher_free(oldr);
 
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
@@ -2975,11 +3139,20 @@ SILC_SERVER_CMD_FUNC(cmode)
     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
       /* Cipher mode is unset. Remove the cipher and revert back to
         default cipher */
-      SilcCipher newkey, oldkey;
+      SilcCipher send_key, receive_key, olds, oldr;
       cipher = channel->cipher;
 
       /* Delete old cipher and allocate default one */
-      if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER, &newkey)) {
+      if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER,
+                            &send_key)) {
+       silc_server_command_send_status_data(
+                                     cmd, SILC_COMMAND_CMODE,
+                                     SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
+                                     2, cipher, strlen(cipher));
+       goto out;
+      }
+      if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER,
+                            &receive_key)) {
        silc_server_command_send_status_data(
                                      cmd, SILC_COMMAND_CMODE,
                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
@@ -2987,18 +3160,22 @@ SILC_SERVER_CMD_FUNC(cmode)
        goto out;
       }
 
-      oldkey = channel->channel_key;
-      channel->channel_key = newkey;
+      olds = channel->send_key;
+      oldr = channel->receive_key;
+      channel->send_key = send_key;
+      channel->receive_key = receive_key;
 
       /* Re-generate channel key */
       if (!silc_server_create_channel_key(server, channel, 0)) {
        /* We don't have new key, revert to old one */
-       channel->channel_key = oldkey;
+       channel->send_key = olds;
+       channel->receive_key = oldr;
        goto out;
       }
 
       /* Remove old channel key for good */
-      silc_cipher_free(oldkey);
+      silc_cipher_free(olds);
+      silc_cipher_free(oldr);
 
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
@@ -3011,7 +3188,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   if (mode_mask & SILC_CHANNEL_MODE_HMAC) {
     if (!(channel->mode & SILC_CHANNEL_MODE_HMAC)) {
       /* HMAC to use protect the traffic */
-      unsigned char hash[32];
+      unsigned char hash[SILC_HASH_MAXLEN];
       SilcHmac newhmac;
 
       /* Get hmac */
@@ -3047,7 +3224,7 @@ SILC_SERVER_CMD_FUNC(cmode)
       /* Hmac mode is unset. Remove the hmac and revert back to
         default hmac */
       SilcHmac newhmac;
-      unsigned char hash[32];
+      unsigned char hash[SILC_HASH_MAXLEN];
       hmac = channel->hmac_name;
 
       /* Delete old hmac and allocate default one */
@@ -3079,7 +3256,7 @@ SILC_SERVER_CMD_FUNC(cmode)
       founder_key = idata->public_key;
       tmp = silc_argument_get_arg_type(cmd->args, 8, &tmp_len);
       if (tmp) {
-       if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key)) {
+       if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key)) {
          silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                                SILC_STATUS_ERR_AUTH_FAILED,
                                                0);
@@ -3125,7 +3302,7 @@ SILC_SERVER_CMD_FUNC(cmode)
        goto out;
       }
 
-      fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
+      fkey = silc_public_key_payload_encode(channel->founder_key);
       if (!fkey) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                              SILC_STATUS_ERR_AUTH_FAILED,
@@ -3134,7 +3311,6 @@ SILC_SERVER_CMD_FUNC(cmode)
        channel->founder_key = NULL;
        goto out;
       }
-    has_founder:
     }
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
@@ -3145,6 +3321,7 @@ SILC_SERVER_CMD_FUNC(cmode)
       }
     }
   }
+ has_founder:
 
   if (mode_mask & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
@@ -3164,7 +3341,6 @@ SILC_SERVER_CMD_FUNC(cmode)
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, st, 0);
        goto out;
       }
-    has_pk_list:
     }
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
@@ -3176,24 +3352,31 @@ SILC_SERVER_CMD_FUNC(cmode)
       }
     }
   }
+ has_pk_list:
 
   /* Finally, set the mode */
   old_mask = channel->mode = mode_mask;
 
   /* Send CMODE_CHANGE notify. */
   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+  if (mode_mask & SILC_CHANNEL_MODE_ULIMIT)
+    SILC_PUT32_MSB(channel->user_limit, ulimit);
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
-                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 7,
-                                    cidp->data, cidp->len,
+                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 8,
+                                    cidp->data, silc_buffer_len(cidp),
                                     tmp_mask, 4,
                                     cipher, cipher ? strlen(cipher) : 0,
                                     hmac, hmac ? strlen(hmac) : 0,
                                     passphrase, passphrase ?
                                     strlen(passphrase) : 0,
                                     fkey ? fkey->data : NULL,
-                                    fkey ? fkey->len : 0,
+                                    fkey ? silc_buffer_len(fkey) : 0,
                                     chpkdata ? chpkdata : NULL,
-                                    chpkdata ? chpklen : 0);
+                                    chpkdata ? chpklen : 0,
+                                    mode_mask & SILC_CHANNEL_MODE_ULIMIT ?
+                                    ulimit : NULL,
+                                    mode_mask & SILC_CHANNEL_MODE_ULIMIT ?
+                                    sizeof(ulimit) : 0);
 
   /* Set CMODE notify type to network */
   if (chpkdata && chpklen)
@@ -3208,26 +3391,28 @@ SILC_SERVER_CMD_FUNC(cmode)
     chpklist = silc_server_get_channel_pk_list(server, channel, FALSE, FALSE);
 
   /* Send command reply to sender */
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
-                                               SILC_STATUS_OK, 0, ident, 4,
-                                               2, tmp_id, tmp_len2,
-                                               3, tmp_mask, 4,
-                                               4, fkey ? fkey->data : NULL,
-                                               fkey ? fkey->len : 0,
-                                               5, chpklist ? chpklist->data :
-                                               NULL, chpklist ? chpklist->len
-                                               : 0);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
-                         packet->data, packet->len, FALSE);
-
-  silc_buffer_free(packet);
+  tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
+  silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_CMODE,
+                                SILC_STATUS_OK, 0, ident, 5,
+                                2, tmp_id, tmp_len2,
+                                3, tmp_mask, 4,
+                                4, fkey ? fkey->data : NULL,
+                                fkey ? silc_buffer_len(fkey) : 0,
+                                5, chpklist ? chpklist->data :
+                                NULL, chpklist ? silc_buffer_len(chpklist)
+                                : 0,
+                                6, (mode_mask &
+                                    SILC_CHANNEL_MODE_ULIMIT ?
+                                    ulimit : NULL),
+                                (mode_mask &
+                                 SILC_CHANNEL_MODE_ULIMIT ?
+                                 sizeof(ulimit) : 0));
   silc_buffer_free(cidp);
 
  out:
   channel->mode = old_mask;
   silc_buffer_free(chpklist);
   silc_buffer_free(fkey);
-  silc_free(channel_id);
   silc_server_command_free(cmd);
 }
 
@@ -3237,13 +3422,12 @@ SILC_SERVER_CMD_FUNC(cumode)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  SilcChannelID *channel_id = NULL;
-  SilcClientID *client_id = NULL;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
+  SilcID id, id2;
   SilcChannelEntry channel;
   SilcClientEntry target_client;
   SilcChannelClientEntry chl;
-  SilcBuffer packet, idp;
+  SilcBuffer idp;
   unsigned char *tmp_id, *tmp_ch_id, *tmp_mask;
   SilcUInt32 target_mask, sender_mask = 0, tmp_len, tmp_ch_len;
   int notify = FALSE;
@@ -3257,14 +3441,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CUMODE, cmd, 3, 4);
 
   /* Get Channel ID */
-  tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
-  if (!tmp_ch_id) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-    goto out;
-  }
-  channel_id = silc_id_payload_parse_id(tmp_ch_id, tmp_ch_len, NULL);
-  if (!channel_id) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
     goto out;
@@ -3272,11 +3449,12 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* Get channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
+      tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
                                           0, 2, tmp_ch_id, tmp_ch_len);
@@ -3286,6 +3464,7 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* Check whether sender is on the channel */
   if (!silc_server_client_on_channel(client, channel, &chl)) {
+    tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
                                         2, tmp_ch_id, tmp_ch_len);
@@ -3304,14 +3483,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   SILC_GET32_MSB(target_mask, tmp_mask);
 
   /* Get target Client ID */
-  tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
-  if (!tmp_id) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_NO_CLIENT_ID, 0);
-    goto out;
-  }
-  client_id = silc_id_payload_parse_id(tmp_id, tmp_len, NULL);
-  if (!client_id) {
+  if (!silc_argument_get_decoded(cmd->args, 3, SILC_ARGUMENT_ID, &id2, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                          SILC_STATUS_ERR_NO_CLIENT_ID, 0);
     goto out;
@@ -3319,17 +3491,19 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* Get target client's entry */
   target_client = silc_idlist_find_client_by_id(server->local_list,
-                                               client_id, TRUE, NULL);
-  if (!target_client) {
+                                               SILC_ID_GET_ID(id2),
+                                               TRUE, NULL);
+  if (!target_client)
     target_client = silc_idlist_find_client_by_id(server->global_list,
-                                                 client_id, TRUE, NULL);
-  }
+                                                 SILC_ID_GET_ID(id2),
+                                                 TRUE, NULL);
 
   if (target_client != client &&
       !(sender_mask & SILC_CHANNEL_UMODE_CHANFO) &&
       !(sender_mask & SILC_CHANNEL_UMODE_CHANOP)) {
+    tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
-                                        SILC_STATUS_ERR_NO_CHANNEL_PRIV, 0,
+                                        SILC_STATUS_ERR_NOT_YOU, 0,
                                         2, tmp_ch_id, tmp_ch_len);
     goto out;
   }
@@ -3337,6 +3511,8 @@ SILC_SERVER_CMD_FUNC(cumode)
   /* Check whether target client is on the channel */
   if (target_client != client) {
     if (!silc_server_client_on_channel(target_client, channel, &chl)) {
+      tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
+      tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
       silc_server_command_send_status_data2(
                                  cmd, SILC_COMMAND_CUMODE,
                                  SILC_STATUS_ERR_USER_NOT_ON_CHANNEL, 0,
@@ -3353,6 +3529,7 @@ 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 && client != target_client) {
+    tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
                                         SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
                                         0, 2, tmp_ch_id, tmp_ch_len);
@@ -3362,7 +3539,8 @@ SILC_SERVER_CMD_FUNC(cumode)
   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
     if (target_client != client) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                           SILC_STATUS_ERR_NOT_YOU, 0);
+                                           SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
+                                           0);
       goto out;
     }
 
@@ -3398,7 +3576,7 @@ SILC_SERVER_CMD_FUNC(cumode)
 
       notify = TRUE;
       founder_key = channel->founder_key;
-      fkey = silc_pkcs_public_key_payload_encode(founder_key);
+      fkey = silc_public_key_payload_encode(founder_key);
       if (!fkey) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                              SILC_STATUS_ERR_AUTH_FAILED, 0);
@@ -3406,16 +3584,23 @@ SILC_SERVER_CMD_FUNC(cumode)
       }
 
       /* There cannot be anyone else as founder on the channel now.  This
-        client is definitely the founder due to this authentication */
-      silc_hash_table_list(channel->user_list, &htl);
-      while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
-       if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
-         chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
-         silc_server_force_cumode_change(server, NULL, channel, chl2,
-                                         chl2->mode);
-         break;
-       }
-      silc_hash_table_list_reset(&htl);
+        client is definitely the founder due to this authentication.  This
+        is done only on router, not on server, since server cannot know
+        whether router will accept this mode change or not.  XXX This
+        probably shouldn't be done anymore at all, may cause problems in
+        router-router connections too (maybe just AUTH_FAILED error should
+        be returned). -Pekka */
+      if (server->server_type == SILC_ROUTER) {
+       silc_hash_table_list(channel->user_list, &htl);
+       while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
+         if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
+           chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+           silc_server_force_cumode_change(server, NULL, channel, chl2,
+                                           chl2->mode);
+           break;
+         }
+       silc_hash_table_list_reset(&htl);
+      }
 
       sender_mask = chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
     }
@@ -3438,6 +3623,7 @@ SILC_SERVER_CMD_FUNC(cumode)
     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
       if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
           !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+       tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
         silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV,
                                             0, 2, tmp_ch_id, tmp_ch_len);
@@ -3451,6 +3637,7 @@ SILC_SERVER_CMD_FUNC(cumode)
     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
       if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
           !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+       tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
         silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV,
                                             0, 2, tmp_ch_id, tmp_ch_len);
@@ -3559,16 +3746,17 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+  tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
 
   /* Send notify to channel, notify only if mode was actually changed. */
   if (notify) {
     silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                       SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
-                                      idp->data, idp->len,
+                                      idp->data, silc_buffer_len(idp),
                                       tmp_mask, 4,
                                       tmp_id, tmp_len,
                                       fkey ? fkey->data : NULL,
-                                      fkey ? fkey->len : 0);
+                                      fkey ? silc_buffer_len(fkey) : 0);
 
     /* Set CUMODE notify type to network */
     silc_server_send_notify_cumode(server, SILC_PRIMARY_ROUTE(server),
@@ -3578,20 +3766,14 @@ SILC_SERVER_CMD_FUNC(cumode)
   }
 
   /* Send command reply to sender */
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
-                                               SILC_STATUS_OK, 0, ident, 3,
-                                               2, tmp_mask, 4,
-                                               3, tmp_ch_id, tmp_ch_len,
-                                               4, tmp_id, tmp_len);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
-                         packet->data, packet->len, FALSE);
-
-  silc_buffer_free(packet);
+  silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_CUMODE,
+                                SILC_STATUS_OK, 0, ident, 3,
+                                2, tmp_mask, 4,
+                                3, tmp_ch_id, tmp_ch_len,
+                                4, tmp_id, tmp_len);
   silc_buffer_free(idp);
 
  out:
-  silc_free(channel_id);
-  silc_free(client_id);
   silc_buffer_free(fkey);
   silc_server_command_free(cmd);
 }
@@ -3602,13 +3784,12 @@ SILC_SERVER_CMD_FUNC(kick)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   SilcClientEntry target_client;
-  SilcChannelID *channel_id;
-  SilcClientID *client_id;
+  SilcID id, id2;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
-  SilcBuffer idp, packet;
+  SilcBuffer idp;
   SilcUInt32 tmp_len, target_idp_len, clen;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   unsigned char *tmp, *comment, *target_idp;
@@ -3619,27 +3800,20 @@ SILC_SERVER_CMD_FUNC(kick)
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 3);
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
     goto out;
   }
-  channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!channel_id) {
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
-                                        SILC_STATUS_ERR_BAD_CHANNEL_ID, 0,
-                                         2, tmp, tmp_len);
-    goto out;
-  }
 
   /* Get channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->local_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
                                           0, 2, tmp, tmp_len);
@@ -3649,6 +3823,7 @@ SILC_SERVER_CMD_FUNC(kick)
 
   /* Check whether sender is on the channel */
   if (!silc_server_client_on_channel(client, channel, &chl)) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
                                         SILC_STATUS_ERR_NOT_ON_CHANNEL,
                                         0, 2, tmp, tmp_len);
@@ -3658,6 +3833,7 @@ SILC_SERVER_CMD_FUNC(kick)
   /* Check that the kicker is channel operator or channel founder */
   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV,
                                         0, 2, tmp, tmp_len);
@@ -3665,30 +3841,25 @@ SILC_SERVER_CMD_FUNC(kick)
   }
 
   /* Get target Client ID */
-  target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
-  if (!target_idp) {
+  if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id2, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
                                          SILC_STATUS_ERR_NO_CLIENT_ID, 0);
     goto out;
   }
-  client_id = silc_id_payload_parse_id(target_idp, target_idp_len, NULL);
-  if (!client_id) {
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
-                                        SILC_STATUS_ERR_BAD_CLIENT_ID,
-                                        0, 2, target_idp, target_idp_len);
-    goto out;
-  }
 
   /* Get target client's entry */
   target_client = silc_idlist_find_client_by_id(server->local_list,
-                                               client_id, TRUE, NULL);
-  if (!target_client) {
+                                               SILC_ID_GET_ID(id2),
+                                               TRUE, NULL);
+  if (!target_client)
     target_client = silc_idlist_find_client_by_id(server->global_list,
-                                                 client_id, TRUE, NULL);
-  }
+                                                 SILC_ID_GET_ID(id2),
+                                                 TRUE, NULL);
 
   /* Check whether target client is on the channel */
   if (!silc_server_client_on_channel(target_client, channel, &chl)) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+    target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
     silc_server_command_send_status_data2(cmd, SILC_COMMAND_KICK,
                                          SILC_STATUS_ERR_USER_NOT_ON_CHANNEL,
                                          0, 2, target_idp, target_idp_len,
@@ -3699,6 +3870,7 @@ SILC_SERVER_CMD_FUNC(kick)
   /* Check that the target client is not channel founder. Channel founder
      cannot be kicked from the channel. */
   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
                                         SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
                                         0, 2, tmp, tmp_len);
@@ -3710,20 +3882,13 @@ SILC_SERVER_CMD_FUNC(kick)
   if (clen > 128)
     comment = NULL;
 
-
   /* Send the reply back to the client */
-  packet =
-    silc_command_reply_payload_encode_va(SILC_COMMAND_KICK,
-                                        SILC_STATUS_OK, 0, ident, 2,
-                                        2, tmp, tmp_len,
-                                        3, target_idp, target_idp_len);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
-                         packet->data, packet->len, FALSE);
-  silc_buffer_free(packet);
-
-  /* Send command reply to sender */
-  silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
-                                       SILC_STATUS_OK, 0);
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
+  silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_KICK,
+                                SILC_STATUS_OK, 0, ident, 2,
+                                2, tmp, tmp_len,
+                                3, target_idp, target_idp_len);
 
   /* Send KICKED notify to local clients on the channel */
   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
@@ -3731,7 +3896,7 @@ SILC_SERVER_CMD_FUNC(kick)
                                     SILC_NOTIFY_TYPE_KICKED, 3,
                                     target_idp, target_idp_len,
                                     comment, comment ? strlen(comment) : 0,
-                                    idp->data, idp->len);
+                                    idp->data, silc_buffer_len(idp));
   silc_buffer_free(idp);
 
   /* Send KICKED notify to primary route */
@@ -3744,7 +3909,8 @@ SILC_SERVER_CMD_FUNC(kick)
     SilcBuffer ab =
       silc_argument_payload_encode_one(NULL, target_idp, target_idp_len, 3);
     SilcArgumentPayload args =
-      silc_argument_payload_parse(ab->data, ab->len, 1);
+      silc_argument_payload_parse(ab->data, silc_buffer_len(ab), 1);
+
     silc_server_inviteban_process(server, channel->invite_list, 1, args);
     silc_buffer_free(ab);
     silc_argument_payload_free(args);
@@ -3780,19 +3946,23 @@ SILC_SERVER_CMD_FUNC(oper)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  unsigned char *username, *auth;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
+  unsigned char *username = NULL, *auth;
   SilcUInt32 tmp_len;
   SilcServerConfigAdmin *admin;
   SilcIDListData idata = (SilcIDListData)client;
-  bool result = FALSE;
+  SilcBool result = FALSE;
   SilcPublicKey cached_key;
+  const char *hostname, *ip;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
 
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock),
+                             NULL, &hostname, &ip, NULL);
+
   /* Get the username */
   username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
   if (!username) {
@@ -3802,11 +3972,21 @@ SILC_SERVER_CMD_FUNC(oper)
     goto out;
   }
 
+  /* Check username */
+  username = silc_identifier_check(username, strlen(username),
+                                  SILC_STRING_UTF8, 128, &tmp_len);
+  if (!username) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+                                         SILC_STATUS_ERR_BAD_USERNAME,
+                                         0);
+    goto out;
+  }
+
   /* Get the admin configuration */
-  admin = silc_server_config_find_admin(server, cmd->sock->ip,
+  admin = silc_server_config_find_admin(server, (char *)ip,
                                        username, client->nickname);
   if (!admin) {
-    admin = silc_server_config_find_admin(server, cmd->sock->hostname,
+    admin = silc_server_config_find_admin(server, (char *)hostname,
                                          username, client->nickname);
     if (!admin) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
@@ -3814,7 +3994,7 @@ SILC_SERVER_CMD_FUNC(oper)
                                            0);
       SILC_LOG_INFO(("OPER authentication failed for username '%s' by "
                     "nickname '%s' from %s", username,
-                    client->nickname, cmd->sock->hostname));
+                    client->nickname, hostname));
       goto out;
     }
   }
@@ -3835,7 +4015,9 @@ SILC_SERVER_CMD_FUNC(oper)
                                   admin->passphrase, admin->passphrase_len,
                                   idata->hash, client->id, SILC_ID_CLIENT);
   if (!result && admin->publickeys) {
-    cached_key = silc_server_get_public_key(server, admin->publickeys);
+    cached_key =
+      silc_server_get_public_key(server,
+                                SILC_SKR_USAGE_SERVICE_AUTHORIZATION, admin);
     if (!cached_key)
       goto out;
     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY,
@@ -3874,6 +4056,7 @@ SILC_SERVER_CMD_FUNC(oper)
                                        SILC_STATUS_OK, 0);
 
  out:
+  silc_free(username);
   silc_server_command_free(cmd);
 }
 
@@ -3883,21 +4066,16 @@ SILC_TASK_CALLBACK(silc_server_command_detach_cb)
   QuitInternal q = (QuitInternal)context;
   SilcClientID *client_id = (SilcClientID *)q->sock;
   SilcClientEntry client;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
 
   client = silc_idlist_find_client_by_id(server->local_list, client_id,
                                         TRUE, NULL);
   if (client && client->connection) {
     sock = client->connection;
 
-    /* If there is pending outgoing data for the client then purge it
-       to the network before closing connection. */
-    silc_server_packet_queue_purge(server, sock);
-
     /* Close the connection on our side */
     client->router = NULL;
     client->connection = NULL;
-    sock->user_data = NULL;
     silc_server_close_connection(server, sock);
   }
 
@@ -3931,7 +4109,7 @@ SILC_SERVER_CMD_FUNC(detach)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   QuitInternal q;
 
   if (server->config->detach_disabled) {
@@ -3941,7 +4119,7 @@ SILC_SERVER_CMD_FUNC(detach)
     goto out;
   }
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_DETACH, cmd, 0, 0);
@@ -3969,16 +4147,16 @@ SILC_SERVER_CMD_FUNC(detach)
 
   q = silc_calloc(1, sizeof(*q));
   q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
-  silc_schedule_task_add(server->schedule, 0, silc_server_command_detach_cb,
-                        q, 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_command_detach_cb,
+                                q, 0, 200000);
 
   if (server->config->detach_timeout) {
     q = silc_calloc(1, sizeof(*q));
     q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
-    silc_schedule_task_add(server->schedule, 0,
-                          silc_server_command_detach_timeout,
-                          q, server->config->detach_timeout * 60,
-                          0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_command_detach_timeout,
+                                  q, server->config->detach_timeout * 60, 0);
   }
 
   /* Send reply to the sender */
@@ -3996,11 +4174,11 @@ SILC_SERVER_CMD_FUNC(watch)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   char *add_nick, *del_nick;
-  SilcUInt32 add_nick_len, del_nick_len, tmp_len;
-  char nick[128 + 1];
-  unsigned char hash[16], *tmp;
+  SilcUInt32 add_nick_len, del_nick_len, tmp_len, pk_len;
+  unsigned char hash[SILC_HASH_MAXLEN], *tmp,  *pk, *nick;
   SilcClientEntry client;
-  SilcClientID *client_id = NULL;
+  SilcID id;
+  SilcUInt16 old_ident;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WATCH, cmd, 1, 3);
 
@@ -4008,17 +4186,24 @@ SILC_SERVER_CMD_FUNC(watch)
     if (!cmd->pending) {
       /* Send the command to router */
       SilcBuffer tmpbuf;
-      SilcUInt16 old_ident;
+
+      /* If backup receives this from primary, handle it locally */
+      if (server->server_type == SILC_BACKUP_ROUTER &&
+         cmd->sock == SILC_PRIMARY_ROUTE(server))
+       goto process_watch;
 
       SILC_LOG_DEBUG(("Forwarding WATCH to router"));
 
+      /* Statistics */
+      cmd->server->stat.commands_sent++;
+
       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, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_WATCH,
@@ -4028,68 +4213,83 @@ SILC_SERVER_CMD_FUNC(watch)
       cmd->pending = TRUE;
       silc_command_set_ident(cmd->payload, old_ident);
       silc_buffer_free(tmpbuf);
-    } else if (context2) {
-      /* Received reply from router, just send same data to the client. */
+      goto out;
+    } else {
       SilcServerCommandReplyContext reply = context2;
       SilcStatus status;
 
-      SILC_LOG_DEBUG(("Received reply to WATCH from router"));
+      if (!reply)
+        goto out;
+
       silc_command_get_status(reply->payload, &status, NULL);
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, status,
-                                           0);
-    }
 
-    goto out;
+      /* Backup router handles the WATCH command also. */
+      if (server->server_type != SILC_BACKUP_ROUTER ||
+         SILC_STATUS_IS_ERROR(status)) {
+       /* Received reply from router, just send same data to the client. */
+       SILC_LOG_DEBUG(("Received reply to WATCH from router"));
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, status,
+                                             0);
+       goto out;
+      }
+    }
   }
 
   /* We are router and keep the watch list for local cell */
+ process_watch:
 
   /* Get the client ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
                                          0);
     goto out;
   }
-  client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!client_id) {
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
-                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                        0, 2, tmp, tmp_len);
-    goto out;
-  }
 
   /* Get the client entry which must be in local list */
   client = silc_idlist_find_client_by_id(server->local_list,
-                                        client_id, TRUE, NULL);
+                                        SILC_ID_GET_ID(id), TRUE, NULL);
   if (!client) {
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
-                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0,
-                                        2, tmp, tmp_len);
-    goto out;
+    /* Backup checks global list also */
+    if (server->server_type == SILC_BACKUP_ROUTER)
+      client = silc_idlist_find_client_by_id(server->global_list,
+                                            SILC_ID_GET_ID(id), TRUE, NULL);
+    if (!client) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
+                                          SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+                                          0, 2, tmp, tmp_len);
+      goto out;
+    }
   }
 
+  /* Take public key for watching by public key */
+  pk = silc_argument_get_arg_type(cmd->args, 4, &pk_len);
+
   /* Take nickname */
   add_nick = silc_argument_get_arg_type(cmd->args, 2, &add_nick_len);
   del_nick = silc_argument_get_arg_type(cmd->args, 3, &del_nick_len);
-  if (!add_nick && !del_nick) {
+  if (!add_nick && !del_nick && !pk) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
                                          0);
     goto out;
   }
 
-  if (add_nick && add_nick_len > 128)
-    add_nick[128] = '\0';
-  if (del_nick && del_nick_len > 128)
-    del_nick[128] = '\0';
-
-  memset(nick, 0, sizeof(nick));
+  if (add_nick && add_nick_len > 128) {
+    add_nick_len = 128;
+    add_nick[add_nick_len - 1] = '\0';
+  }
+  if (del_nick && del_nick_len > 128) {
+    del_nick_len = 128;
+    del_nick[del_nick_len - 1] = '\0';
+  }
 
   /* Add new nickname to be watched in our cell */
   if (add_nick) {
-    if (silc_server_name_bad_chars(add_nick, strlen(add_nick)) == TRUE) {
+    nick = silc_identifier_check(add_nick, add_nick_len, SILC_STRING_UTF8, 128,
+                                &add_nick_len);
+    if (!nick) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
                                            SILC_STATUS_ERR_BAD_NICKNAME, 0);
       goto out;
@@ -4097,8 +4297,7 @@ SILC_SERVER_CMD_FUNC(watch)
 
     /* Hash the nick, we have the hash saved, not nicks because we can
        do one to one mapping to the nick from Client ID hash this way. */
-    silc_to_lower(add_nick, nick, sizeof(nick) - 1);
-    silc_hash_make(server->md5hash, nick, strlen(nick), hash);
+    silc_hash_make(server->md5hash, nick, add_nick_len, hash);
 
     /* Check whether this client is already watching this nickname */
     if (silc_hash_table_find_by_context(server->watcher_list, hash,
@@ -4107,21 +4306,25 @@ SILC_SERVER_CMD_FUNC(watch)
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
                                            SILC_STATUS_ERR_NICKNAME_IN_USE,
                                            0);
+      silc_free(nick);
       goto out;
     }
 
     /* Get the nickname from the watcher list and use the same key in
        new entries as well.  If key doesn't exist then create it. */
-    if (!silc_hash_table_find(server->watcher_list, hash, (void **)&tmp, NULL))
+    if (!silc_hash_table_find(server->watcher_list, hash, (void *)&tmp, NULL))
       tmp = silc_memdup(hash, CLIENTID_HASH_LEN);
 
     /* Add the client to the watcher list with the specified nickname hash. */
     silc_hash_table_add(server->watcher_list, tmp, client);
+    silc_free(nick);
   }
 
   /* Delete nickname from watch list */
   if (del_nick) {
-    if (silc_server_name_bad_chars(del_nick, strlen(del_nick)) == TRUE) {
+    nick = silc_identifier_check(del_nick, del_nick_len, SILC_STRING_UTF8, 128,
+                                &del_nick_len);
+    if (!nick) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
                                            SILC_STATUS_ERR_BAD_NICKNAME, 0);
       goto out;
@@ -4129,16 +4332,16 @@ SILC_SERVER_CMD_FUNC(watch)
 
     /* Hash the nick, we have the hash saved, not nicks because we can
        do one to one mapping to the nick from Client ID hash this way. */
-    silc_to_lower(del_nick, nick, sizeof(nick) - 1);
-    silc_hash_make(server->md5hash, nick, strlen(nick), hash);
+    silc_hash_make(server->md5hash, nick, del_nick_len, hash);
 
     /* Check that this client is watching for this nickname */
     if (!silc_hash_table_find_by_context(server->watcher_list, hash,
-                                        client, (void **)&tmp)) {
+                                        client, (void *)&tmp)) {
       /* Nickname is alredy being watched for this client */
       silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
                                           SILC_STATUS_ERR_NO_SUCH_NICK, 0,
-                                          2, nick, strlen(nick));
+                                          2, nick, del_nick_len);
+      silc_free(nick);
       goto out;
     }
 
@@ -4149,24 +4352,121 @@ SILC_SERVER_CMD_FUNC(watch)
        then free the key to not leak memory. */
     if (!silc_hash_table_find(server->watcher_list, hash, NULL, NULL))
       silc_free(tmp);
+    silc_free(nick);
   }
 
+  /* Add/del public key */
+  if (pk) {
+    SilcUInt16 pkargc;
+    SilcArgumentPayload pkargs;
+    SilcUInt32 type;
+    SilcPublicKey public_key, pkkey;
+
+    if (pk_len < 2) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                           0);
+      goto out;
+    }
+
+    /* Get the argument from the Argument List Payload */
+    SILC_GET16_MSB(pkargc, pk);
+    pkargs = silc_argument_payload_parse(pk + 2, pk_len - 2, pkargc);
+    if (!pkargs) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                           0);
+      goto out;
+    }
+
+    pk = silc_argument_get_next_arg(pkargs, &type, &pk_len);
+    while (pk) {
+      if (!silc_public_key_payload_decode(pk, pk_len, &public_key)) {
+        pk = silc_argument_get_next_arg(pkargs, &type, &pk_len);
+       continue;
+      }
+      if (type == 0x03)
+        type = 0x00;
+
+      if (type == 0x00) {
+       /* Add public key to watch list */
+
+       /* Check whether this client is already watching this public key */
+       if (silc_hash_table_find_by_context(server->watcher_list_pk,
+                                           public_key, client, NULL)) {
+         silc_pkcs_public_key_free(public_key);
+         silc_server_command_send_status_reply(
+                               cmd, SILC_COMMAND_WATCH,
+                               SILC_STATUS_ERR_NICKNAME_IN_USE, 0);
+         goto out;
+       }
+
+       /* Get the public key from the watcher list and use the same key in
+          new entries as well.  If key doesn't exist then create it. */
+       pkkey = NULL;
+       if (!silc_hash_table_find(server->watcher_list_pk, public_key,
+                                 (void *)&pkkey, NULL))
+         pkkey = public_key;
+       else
+         silc_pkcs_public_key_free(public_key);
+
+       /* Add the client to the watcher list with the specified public
+          key. */
+       silc_hash_table_add(server->watcher_list_pk, pkkey, client);
+
+      } else if (type == 0x01) {
+       /* Delete public key from watch list */
+
+       /* Check that this client is watching this public key */
+       if (silc_hash_table_find_by_context(server->watcher_list_pk,
+                                           public_key, client,
+                                           (void *)&pkkey)) {
+         silc_pkcs_public_key_free(public_key);
+         silc_server_command_send_status_reply(
+                               cmd, SILC_COMMAND_WATCH,
+                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+         goto out;
+       }
+
+       /* Delete the public key from the watcher list. */
+       silc_hash_table_del_by_context(server->watcher_list_pk,
+                                      public_key, client);
+
+       /* Now check whether there still exists entries with this key, if
+          not then free the key to not leak memory. */
+       if (!silc_hash_table_find(server->watcher_list_pk, hash, NULL, NULL))
+         silc_pkcs_public_key_free(pkkey);
+        silc_pkcs_public_key_free(public_key);
+      }
+
+      pk = silc_argument_get_next_arg(pkargs, &type, &pk_len);
+    }
+  }
+
+  /* Send reply */
+  silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
+                                       SILC_STATUS_OK, 0);
+
   /* Distribute the watch list to backup routers too */
   if (server->backup) {
     SilcBuffer tmpbuf;
+
+    /* Statistics */
+    cmd->server->stat.commands_sent++;
+
+    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_backup_send(server, NULL, SILC_PACKET_COMMAND,
-                           cmd->packet->flags, tmpbuf->data, tmpbuf->len,
+    silc_server_backup_send(server, silc_packet_get_context(cmd->sock),
+                           SILC_PACKET_COMMAND,
+                           cmd->packet->flags, tmpbuf->data,
+                           silc_buffer_len(tmpbuf),
                            FALSE, TRUE);
+    silc_command_set_ident(cmd->payload, old_ident);
     silc_buffer_free(tmpbuf);
   }
 
-  silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
-                                       SILC_STATUS_OK, 0);
-
  out:
-  silc_free(client_id);
   silc_server_command_free(cmd);
 }
 
@@ -4177,19 +4477,23 @@ SILC_SERVER_CMD_FUNC(silcoper)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  unsigned char *username, *auth;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
+  unsigned char *username = NULL, *auth;
   SilcUInt32 tmp_len;
   SilcServerConfigAdmin *admin;
   SilcIDListData idata = (SilcIDListData)client;
-  bool result = FALSE;
+  SilcBool result = FALSE;
   SilcPublicKey cached_key;
+  const char *hostname, *ip;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
 
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock),
+                             NULL, &hostname, &ip, NULL);
+
   if (server->server_type != SILC_ROUTER) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
                                          SILC_STATUS_ERR_AUTH_FAILED, 0);
@@ -4205,18 +4509,28 @@ SILC_SERVER_CMD_FUNC(silcoper)
     goto out;
   }
 
+  /* Check username */
+  username = silc_identifier_check(username, tmp_len, SILC_STRING_UTF8, 128,
+                                  &tmp_len);
+  if (!username) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+                                         SILC_STATUS_ERR_BAD_USERNAME,
+                                         0);
+    goto out;
+  }
+
   /* Get the admin configuration */
-  admin = silc_server_config_find_admin(server, cmd->sock->ip,
+  admin = silc_server_config_find_admin(server, (char *)ip,
                                        username, client->nickname);
   if (!admin) {
-    admin = silc_server_config_find_admin(server, cmd->sock->hostname,
+    admin = silc_server_config_find_admin(server, (char *)hostname,
                                          username, client->nickname);
     if (!admin) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
                                            SILC_STATUS_ERR_AUTH_FAILED, 0);
       SILC_LOG_INFO(("SILCOPER authentication failed for username '%s' by "
                     "nickname '%s' from %s", username,
-                    client->nickname, cmd->sock->hostname));
+                    client->nickname, hostname));
       goto out;
     }
   }
@@ -4237,7 +4551,9 @@ SILC_SERVER_CMD_FUNC(silcoper)
                                   admin->passphrase, admin->passphrase_len,
                                   idata->hash, client->id, SILC_ID_CLIENT);
   if (!result && admin->publickeys) {
-    cached_key = silc_server_get_public_key(server, admin->publickeys);
+    cached_key =
+      silc_server_get_public_key(server,
+                                SILC_SKR_USAGE_SERVICE_AUTHORIZATION, admin);
     if (!cached_key)
       goto out;
     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY,
@@ -4246,7 +4562,7 @@ SILC_SERVER_CMD_FUNC(silcoper)
   }
   if (!result) {
     /* Authentication failed */
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
                                          SILC_STATUS_ERR_AUTH_FAILED, 0);
     goto out;
   }
@@ -4275,6 +4591,7 @@ SILC_SERVER_CMD_FUNC(silcoper)
                                        SILC_STATUS_OK, 0);
 
  out:
+  silc_free(username);
   silc_server_command_free(cmd);
 }
 
@@ -4285,63 +4602,63 @@ SILC_SERVER_CMD_FUNC(ban)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  SilcBuffer packet, list, tmp2;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
+  SilcBuffer list, tmp2;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
-  SilcChannelID *channel_id = NULL;
-  unsigned char *id, *tmp, *atype = NULL;
+  SilcID id;
+  unsigned char *tmp_id, *tmp, *atype = NULL;
   SilcUInt32 id_len, len, len2;
   SilcArgumentPayload args;
   SilcHashTableList htl;
-  SilcUInt32 type;
+  void *type;
   SilcUInt16 argc = 0, ident = silc_command_get_ident(cmd->payload);
   SilcBufferStruct blist;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_BAN, cmd, 0, 3);
 
   /* Get Channel ID */
-  id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
-  if (id) {
-    channel_id = silc_id_payload_parse_id(id, id_len, NULL);
-    if (!channel_id) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
-                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-      goto out;
-    }
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
+    goto out;
   }
 
   /* Get channel entry. The server must know about the channel since the
      client is expected to be on the channel. */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
-      silc_server_command_send_status_data(cmd, SILC_COMMAND_BAN,
+      tmp_id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
+      silc_server_command_send_status_data(
+                                          cmd, SILC_COMMAND_BAN,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
-                                          0, 2, id, id_len);
+                                          0, 2, tmp_id, id_len);
       goto out;
     }
   }
 
   /* Check whether this client is on the channel */
   if (!silc_server_client_on_channel(client, channel, &chl)) {
+    tmp_id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_BAN,
                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
-                                        2, id, id_len);
+                                        2, tmp_id, id_len);
     goto out;
   }
 
   /* The client must be at least channel operator. */
   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+    tmp_id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_BAN,
                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV, 0,
-                                        2, id, id_len);
+                                        2, tmp_id, id_len);
     goto out;
   }
 
@@ -4380,8 +4697,14 @@ SILC_SERVER_CMD_FUNC(ban)
       }
 
       /* Now add or delete the information. */
-      silc_server_inviteban_process(server, channel->ban_list,
-                                   (SilcUInt8)atype[0], args);
+      if (!silc_server_inviteban_process(server, channel->ban_list,
+                                        (SilcUInt8)atype[0], args)) {
+       silc_server_command_send_status_reply(
+                                     cmd, SILC_COMMAND_BAN,
+                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                     0);
+       goto out;
+      }
     }
     silc_argument_payload_free(args);
   }
@@ -4395,12 +4718,15 @@ SILC_SERVER_CMD_FUNC(ban)
                                          channel->ban_list)),
                       SILC_STR_END);
     silc_hash_table_list(channel->ban_list, &htl);
-    while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2))
-      list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
-                                             type);
+    while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
+      list = silc_argument_payload_encode_one(list, tmp2->data,
+                                             silc_buffer_len(tmp2),
+                                             SILC_PTR_TO_32(type));
     silc_hash_table_list_reset(&htl);
   }
 
+  tmp_id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
+
   /* Send BAN notify type to local servers (but not clients) and to
      network. */
   if (atype && tmp && len2) {
@@ -4410,10 +4736,10 @@ SILC_SERVER_CMD_FUNC(ban)
     if (server->server_type == SILC_ROUTER)
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, FALSE,
                                          SILC_NOTIFY_TYPE_BAN, 3,
-                                        id, id_len,
+                                        tmp_id, id_len,
                                         atype, 1,
                                         tmp ? blist.data : NULL,
-                                        tmp ? blist.len : 0);
+                                        tmp ? silc_buffer_len(&blist) : 0);
 
     /* Send to network. */
     silc_server_send_notify_ban(server, SILC_PRIMARY_ROUTE(server),
@@ -4422,20 +4748,14 @@ SILC_SERVER_CMD_FUNC(ban)
   }
 
   /* Send the reply back to the client */
-  packet =
-    silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
-                                        SILC_STATUS_OK, 0, ident, 2,
-                                        2, id, id_len,
-                                        3, list ? list->data : NULL,
-                                        list ? list->len : 0);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
-                         packet->data, packet->len, FALSE);
-
-  silc_buffer_free(packet);
+  silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_BAN,
+                                SILC_STATUS_OK, 0, ident, 2,
+                                2, tmp_id, id_len,
+                                3, list ? list->data : NULL,
+                                list ? silc_buffer_len(list) : 0);
   silc_buffer_free(list);
 
  out:
-  silc_free(channel_id);
   silc_server_command_free(cmd);
 }
 
@@ -4445,37 +4765,33 @@ SILC_SERVER_CMD_FUNC(leave)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcSocketConnection sock = cmd->sock;
-  SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
-  SilcChannelID *id = NULL;
+  SilcPacketStream sock = cmd->sock;
+  SilcClientEntry id_entry = silc_packet_get_context(cmd->sock);
+  SilcID id;
   SilcChannelEntry channel;
   SilcUInt32 len;
   unsigned char *tmp;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !id_entry)
+  if (id_entry->data.conn_type != SILC_CONN_CLIENT || !id_entry)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 2);
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
-  if (!tmp) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
-                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-    goto out;
-  }
-  id = silc_id_payload_parse_id(tmp, len, NULL);
-  if (!id) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
     goto out;
   }
 
   /* Get channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
+  channel = silc_idlist_find_channel_by_id(server->local_list,
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
-    channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+    channel = silc_idlist_find_channel_by_id(server->global_list,
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
                                           0, 2, tmp, len);
@@ -4485,6 +4801,7 @@ SILC_SERVER_CMD_FUNC(leave)
 
   /* Check whether this client is on the channel */
   if (!silc_server_client_on_channel(id_entry, channel, NULL)) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
                                         2, tmp, len);
@@ -4496,6 +4813,7 @@ SILC_SERVER_CMD_FUNC(leave)
   silc_server_send_notify_leave(server, SILC_PRIMARY_ROUTE(server),
                                SILC_BROADCAST(server), channel, id_entry->id);
 
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
   silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
                                       SILC_STATUS_OK, 0, 2, tmp, len);
 
@@ -4517,7 +4835,6 @@ SILC_SERVER_CMD_FUNC(leave)
   }
 
  out:
-  silc_free(id);
   silc_server_command_free(cmd);
 }
 
@@ -4529,9 +4846,10 @@ SILC_SERVER_CMD_FUNC(users)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
+  SilcIDListData idata = silc_packet_get_context(cmd->sock);
   SilcChannelEntry channel;
-  SilcChannelID *id = NULL;
-  SilcBuffer packet, idp;
+  SilcID id;
+  SilcBuffer idp;
   unsigned char *channel_id;
   SilcUInt32 channel_id_len;
   SilcBuffer client_id_list;
@@ -4539,7 +4857,7 @@ SILC_SERVER_CMD_FUNC(users)
   unsigned char lc[4];
   SilcUInt32 list_count = 0;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
-  char *channel_name;
+  char *channel_name, *channel_namec = NULL;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_USERS, cmd, 1, 2);
 
@@ -4555,9 +4873,20 @@ SILC_SERVER_CMD_FUNC(users)
     goto out;
   }
 
+  /* Check channel name */
+  if (channel_name) {
+    channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
+                                           SILC_STRING_UTF8, 256, NULL);
+    if (!channel_namec) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
+                                           SILC_STATUS_ERR_BAD_CHANNEL, 0);
+      goto out;
+    }
+  }
+
+  /* Check Channel ID */
   if (channel_id) {
-    id = silc_id_payload_parse_id(channel_id, channel_id_len, NULL);
-    if (!id) {
+    if (!silc_id_payload_parse_id(channel_id, channel_id_len, &id)) {
       silc_server_command_send_status_data(cmd, SILC_COMMAND_USERS,
                                           SILC_STATUS_ERR_BAD_CHANNEL_ID, 0,
                                           2, channel_id, channel_id_len);
@@ -4568,11 +4897,12 @@ SILC_SERVER_CMD_FUNC(users)
   /* If we are server and we don't know about this channel we will send
      the command to our router. If we know about the channel then we also
      have the list of users already. */
-  if (id)
-    channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
+  if (channel_id)
+    channel = silc_idlist_find_channel_by_id(server->local_list,
+                                            SILC_ID_GET_ID(id), NULL);
   else
     channel = silc_idlist_find_channel_by_name(server->local_list,
-                                              channel_name, NULL);
+                                              channel_namec, NULL);
 
   if (!channel || (!server->standalone && (channel->disabled ||
                    !channel->users_resolved))) {
@@ -4580,13 +4910,16 @@ SILC_SERVER_CMD_FUNC(users)
        !cmd->pending) {
       SilcBuffer tmpbuf;
 
+      /* Statistics */
+      cmd->server->stat.commands_sent++;
+
       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       /* Send USERS command */
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply */
       silc_server_command_pending(server, SILC_COMMAND_USERS,
@@ -4596,19 +4929,19 @@ SILC_SERVER_CMD_FUNC(users)
       cmd->pending = TRUE;
       silc_command_set_ident(cmd->payload, ident);
       silc_buffer_free(tmpbuf);
-      silc_free(id);
       goto out;
     }
 
     /* Check the global list as well. */
-    if (id)
-      channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+    if (channel_id)
+      channel = silc_idlist_find_channel_by_id(server->global_list,
+                                              SILC_ID_GET_ID(id), NULL);
     else
       channel = silc_idlist_find_channel_by_name(server->global_list,
-                                                channel_name, NULL);
+                                                channel_namec, NULL);
     if (!channel) {
       /* Channel really does not exist */
-      if (id)
+      if (channel_id)
        silc_server_command_send_status_data(
                                    cmd, SILC_COMMAND_USERS,
                                    SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID, 0,
@@ -4624,9 +4957,9 @@ SILC_SERVER_CMD_FUNC(users)
 
   /* If the channel is private or secret do not send anything, unless the
      user requesting this command is on the channel or is server */
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+  if (idata->conn_type == SILC_CONN_CLIENT) {
     if (channel->mode & (SILC_CHANNEL_MODE_PRIVATE | SILC_CHANNEL_MODE_SECRET)
-       && !silc_server_client_on_channel(cmd->sock->user_data, channel,
+       && !silc_server_client_on_channel((SilcClientEntry)idata, channel,
                                          NULL)) {
       silc_server_command_send_status_data(cmd, SILC_COMMAND_USERS,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL, 0,
@@ -4649,30 +4982,26 @@ SILC_SERVER_CMD_FUNC(users)
 
   /* Send reply */
   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
-                                               SILC_STATUS_OK, 0, ident, 4,
-                                               2, idp->data, idp->len,
-                                               3, lc, 4,
-                                               4, client_id_list ?
-                                               client_id_list->data : NULL,
-                                               client_id_list ?
-                                               client_id_list->len : 0,
-                                               5, client_mode_list ?
-                                               client_mode_list->data : NULL,
-                                               client_mode_list ?
-                                               client_mode_list->len : 0);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
-                         packet->data, packet->len, FALSE);
-
+  silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_USERS,
+                                SILC_STATUS_OK, 0, ident, 4,
+                                2, idp->data, silc_buffer_len(idp),
+                                3, lc, 4,
+                                4, client_id_list ?
+                                client_id_list->data : NULL,
+                                client_id_list ?
+                                silc_buffer_len(client_id_list) : 0,
+                                5, client_mode_list ?
+                                client_mode_list->data : NULL,
+                                client_mode_list ?
+                                silc_buffer_len(client_mode_list) : 0);
   silc_buffer_free(idp);
-  silc_buffer_free(packet);
   if (client_id_list)
     silc_buffer_free(client_id_list);
   if (client_mode_list)
     silc_buffer_free(client_mode_list);
-  silc_free(id);
 
  out:
+  silc_free(channel_namec);
   silc_server_command_free(cmd);
 }
 
@@ -4683,11 +5012,10 @@ SILC_SERVER_CMD_FUNC(getkey)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcBuffer packet;
   SilcClientEntry client;
   SilcServerEntry server_entry;
-  SilcClientID *client_id = NULL;
-  SilcServerID *server_id = NULL;
+  SilcClientID client_id;
+  SilcServerID server_id;
   SilcIDPayload idp = NULL;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   unsigned char *tmp;
@@ -4713,15 +5041,15 @@ SILC_SERVER_CMD_FUNC(getkey)
 
   id_type = silc_id_payload_get_type(idp);
   if (id_type == SILC_ID_CLIENT) {
-    client_id = silc_id_payload_get_id(idp);
+    silc_id_payload_get_id(idp, &client_id, sizeof(client_id));
 
     /* If the client is not found from local list there is no chance it
        would be locally connected client so send the command further. */
     client = silc_idlist_find_client_by_id(server->local_list,
-                                          client_id, TRUE, NULL);
+                                          &client_id, TRUE, NULL);
     if (!client)
       client = silc_idlist_find_client_by_id(server->global_list,
-                                            client_id, TRUE, NULL);
+                                            &client_id, TRUE, NULL);
 
     if ((!client && !cmd->pending && !server->standalone) ||
        (client && !client->connection && !cmd->pending &&
@@ -4729,20 +5057,23 @@ SILC_SERVER_CMD_FUNC(getkey)
        (client && !client->data.public_key && !cmd->pending)) {
       SilcBuffer tmpbuf;
       SilcUInt16 old_ident;
-      SilcSocketConnection dest_sock;
+      SilcPacketStream dest_sock;
 
       dest_sock = silc_server_get_client_route(server, NULL, 0,
-                                              client_id, NULL, NULL);
+                                              &client_id, NULL, NULL);
       if (!dest_sock)
        goto out;
 
+      /* Statistics */
+      cmd->server->stat.commands_sent++;
+
       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, dest_sock,
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_GETKEY,
@@ -4767,17 +5098,17 @@ SILC_SERVER_CMD_FUNC(getkey)
        send just OK reply */
     public_key = client->data.public_key;
     if (public_key)
-      pk = silc_pkcs_public_key_payload_encode(public_key);
+      pk = silc_public_key_payload_encode(public_key);
   } else if (id_type == SILC_ID_SERVER) {
-    server_id = silc_id_payload_get_id(idp);
+    silc_id_payload_get_id(idp, &server_id, sizeof(server_id));
 
     /* If the server is not found from local list there is no chance it
        would be locally connected server so send the command further. */
     server_entry = silc_idlist_find_server_by_id(server->local_list,
-                                                server_id, TRUE, NULL);
+                                                &server_id, TRUE, NULL);
     if (!server_entry)
       server_entry = silc_idlist_find_server_by_id(server->global_list,
-                                                  server_id, TRUE, NULL);
+                                                  &server_id, TRUE, NULL);
 
     if (server_entry != server->id_entry &&
        ((!server_entry && !cmd->pending && !server->standalone) ||
@@ -4788,13 +5119,16 @@ SILC_SERVER_CMD_FUNC(getkey)
       SilcBuffer tmpbuf;
       SilcUInt16 old_ident;
 
+      /* Statistics */
+      cmd->server->stat.commands_sent++;
+
       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, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_GETKEY,
@@ -4819,27 +5153,66 @@ SILC_SERVER_CMD_FUNC(getkey)
                  (server_entry == server->id_entry ? server->public_key :
                   NULL) : server_entry->data.public_key);
     if (public_key)
-      pk = silc_pkcs_public_key_payload_encode(public_key);
+      pk = silc_public_key_payload_encode(public_key);
   } else {
     goto out;
   }
 
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_GETKEY,
-                                               SILC_STATUS_OK, 0, ident, 2,
-                                               2, tmp, tmp_len,
-                                               3, pk ? pk->data : NULL,
-                                               pk ? pk->len : 0);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
-                         packet->data, packet->len, FALSE);
-  silc_buffer_free(packet);
+  silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_GETKEY,
+                                SILC_STATUS_OK, 0, ident, 2,
+                                2, tmp, tmp_len,
+                                3, pk ? pk->data : NULL,
+                                pk ? silc_buffer_len(pk) : 0);
 
  out:
   if (idp)
     silc_id_payload_free(idp);
   silc_buffer_free(pk);
-  silc_free(client_id);
-  silc_free(server_id);
+  silc_server_command_free(cmd);
+}
+
+/* Server side of command SERVICE. */
+/* XXX currently this just sends empty reply back */
+
+SILC_SERVER_CMD_FUNC(service)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcUInt32 tmp_len, auth_len;
+  unsigned char *service_name, *auth;
+  SilcBool send_list = FALSE;
+  SilcUInt16 ident = silc_command_get_ident(cmd->payload);
+
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SERVICE, cmd, 0, 256);
+
+  /* Get requested service */
+  service_name = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (service_name && tmp_len) {
+    /* Verify service name */
+    if (!silc_identifier_verify(service_name, tmp_len,
+                               SILC_STRING_UTF8, 256)) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_SERVICE,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                           0);
+      goto out;
+    }
+  }
+
+  /* Get authentication payload if present */
+  auth = silc_argument_get_arg_type(cmd->args, 2, &auth_len);
+  if (auth) {
+    /* XXX */
+  }
+
+
+  send_list = TRUE;
+
+  /* Send our service list back */
+  silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_SERVICE,
+                                SILC_STATUS_OK, 0, ident, 0);
+
+ out:
   silc_server_command_free(cmd);
 }
 
@@ -4853,12 +5226,12 @@ SILC_SERVER_CMD_FUNC(connect)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   unsigned char *tmp, *host;
   SilcUInt32 tmp_len;
   SilcUInt32 port = SILC_PORT;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CONNECT, cmd, 1, 2);
@@ -4893,7 +5266,7 @@ SILC_SERVER_CMD_FUNC(connect)
     SILC_GET32_MSB(port, tmp);
 
   /* Create the connection. It is done with timeout and is async. */
-  silc_server_create_connection(server, host, port);
+  silc_server_create_connection(server, FALSE, FALSE, host, port, NULL, NULL);
 
   /* Send reply to the sender */
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
@@ -4909,15 +5282,15 @@ SILC_SERVER_CMD_FUNC(close)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   SilcServerEntry server_entry;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
   unsigned char *name;
   SilcUInt32 port = SILC_PORT;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CLOSE, cmd, 1, 2);
@@ -4946,10 +5319,10 @@ SILC_SERVER_CMD_FUNC(close)
     SILC_GET32_MSB(port, tmp);
 
   server_entry = silc_idlist_find_server_by_conn(server->local_list,
-                                                name, port, FALSE, NULL);
+                                                name, port, TRUE, NULL);
   if (!server_entry)
     server_entry = silc_idlist_find_server_by_conn(server->global_list,
-                                                  name, port, FALSE, NULL);
+                                                  name, port, TRUE, NULL);
   if (!server_entry) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
                                          SILC_STATUS_ERR_NO_SERVER_ID, 0);
@@ -4967,7 +5340,12 @@ SILC_SERVER_CMD_FUNC(close)
                                        SILC_STATUS_OK, 0);
 
   /* Close the connection to the server */
-  sock = (SilcSocketConnection)server_entry->connection;
+  sock = server_entry->connection;
+
+  if (server_entry->server_type == SILC_BACKUP_ROUTER) {
+    server->backup_closed = TRUE;
+    silc_server_backup_del(server, server_entry);
+  }
 
   server->backup_noswitch = TRUE;
   if (server->router == server_entry) {
@@ -4978,8 +5356,7 @@ SILC_SERVER_CMD_FUNC(close)
   silc_server_disconnect_remote(server, sock,
                                SILC_STATUS_ERR_BANNED_FROM_SERVER,
                                "Closed by administrator");
-  if (sock->user_data)
-    silc_server_free_sock_user_data(server, sock, NULL);
+  silc_server_free_sock_user_data(server, sock, NULL);
   server->backup_noswitch = FALSE;
 
  out:
@@ -4993,9 +5370,9 @@ SILC_SERVER_CMD_FUNC(shutdown)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_SHUTDOWN, cmd, 0, 0);