Merged silc_1_0_branch to trunk.
[silc.git] / apps / silcd / command.c
index 0d594b9d9891049af8823d33408054cd9316dc73..c11e549777c0eab75d36b8fe2e98df05f0a7475f 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2003 Pekka Riikonen
+  Copyright (C) 1997 - 2005 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
@@ -206,7 +206,12 @@ void silc_server_command_process(SilcServer server,
   ctx->payload = silc_command_payload_parse(packet->buffer->data,
                                            packet->buffer->len);
   if (!ctx->payload) {
-    SILC_LOG_ERROR(("Bad command payload, packet dropped"));
+    SILC_LOG_ERROR(("Bad command payload, dropped (%s:%d [%s])",
+                  sock->hostname, sock->port,
+                  (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                   sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                   sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                   "Router")));
     silc_packet_context_free(packet);
     silc_socket_free(ctx->sock);
     silc_free(ctx);
@@ -416,7 +421,7 @@ bool silc_server_command_pending_timed(SilcServer server,
   reply->timeout =
     silc_schedule_task_add(server->schedule, 0,
                           silc_server_command_pending_timeout, reply,
-                          timeout ? timeout : 10, 0,
+                          timeout ? timeout : 12, 0,
                           SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
   silc_dlist_add(server->pending_commands, reply);
 
@@ -483,6 +488,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 =
@@ -509,6 +517,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 =
@@ -535,6 +546,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 =
@@ -564,6 +578,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,
@@ -618,51 +635,57 @@ SILC_SERVER_CMD_FUNC(nick)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   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)
     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)
+
+  /* Truncate over long nicks */
+  if (nick_len > 128) {
     nick[128] = '\0';
-  if (silc_server_name_bad_chars(nick, nick_len) == TRUE) {
+    nick_len = 128;
+  }
+
+  /* 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
@@ -689,7 +712,7 @@ SILC_SERVER_CMD_FUNC(nick)
   client->nickname = strdup(nick);
 
   /* Update client cache */
-  silc_idcache_add(server->local_list->clients, client->nickname,
+  silc_idcache_add(server->local_list->clients, nickc,
                   client->id, (void *)client, 0, NULL);
 
   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
@@ -709,14 +732,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, nidp->len,
+                                3, nick, nick_len);
   silc_buffer_free(nidp);
   if (oidp)
     silc_buffer_free(oidp);
@@ -735,7 +755,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 +777,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 +810,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, idp->len,
+                                  3, entry->channel_name,
+                                  strlen(entry->channel_name),
+                                  4, topic, topic ? strlen(topic) : 0,
+                                  5, usercount, 4);
     silc_buffer_free(idp);
     k++;
   }
@@ -823,18 +844,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, idp->len,
+                                  3, entry->channel_name,
+                                  strlen(entry->channel_name),
+                                  4, topic, topic ? strlen(topic) : 0,
+                                  5, usercount, 4);
     silc_buffer_free(idp);
     k++;
   }
@@ -862,6 +878,9 @@ 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);
@@ -921,7 +940,7 @@ SILC_SERVER_CMD_FUNC(topic)
   SilcChannelID *channel_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);
@@ -978,6 +997,13 @@ SILC_SERVER_CMD_FUNC(topic)
       goto out;
     }
 
+    if (!silc_utf8_valid(tmp, strlen(tmp))) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                           0);
+      goto out;
+    }
+
     /* See whether the client is on channel and has rights to change topic */
     if (!silc_server_client_on_channel(client, channel, &chl)) {
       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
@@ -1021,16 +1047,12 @@ 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);
+  silc_server_send_command_reply(cmd->server, cmd->sock, SILC_COMMAND_TOPIC,
+                                SILC_STATUS_OK, 0, ident, 2,
+                                2, idp->data, idp->len,
+                                3, channel->topic,
+                                channel->topic ?
+                                strlen(channel->topic) : 0);
   silc_buffer_free(idp);
   silc_free(channel_id);
 
@@ -1054,7 +1076,7 @@ SILC_SERVER_CMD_FUNC(invite)
   SilcIDListData idata;
   SilcArgumentPayload args;
   SilcHashTableList htl;
-  SilcBuffer packet, list, tmp2;
+  SilcBuffer list, tmp2;
   SilcBufferStruct alist;
   unsigned char *tmp, *atype = NULL;
   SilcUInt32 len, type, len2;
@@ -1174,7 +1196,7 @@ SILC_SERVER_CMD_FUNC(invite)
 
     /* Check if the ID is in the list already */
     silc_hash_table_list(channel->invite_list, &htl);
-    while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) {
+    while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2)) {
       if (type == 3 && !memcmp(tmp2->data, tmp, len)) {
        tmp = NULL;
        break;
@@ -1241,8 +1263,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,7 +1284,7 @@ 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))
+    while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
       list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
                                              type);
     silc_hash_table_list_reset(&htl);
@@ -1302,15 +1330,12 @@ SILC_SERVER_CMD_FUNC(invite)
 
   /* 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, type && list ?
+                                list->data : NULL,
+                                type && list ? list->len : 0);
   silc_buffer_free(list);
 
  out:
@@ -1332,14 +1357,17 @@ SILC_TASK_CALLBACK(silc_server_command_quit_cb)
   SilcServer server = app_context;
   QuitInternal q = (QuitInternal)context;
 
-  /* 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;
+  if (q->sock->user_data) {
+    /* 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 (!SILC_IS_DISCONNECTED(q->sock))
+    /* Close the connection on our side */
+    silc_server_close_connection(server, q->sock);
 
   silc_socket_free(q->sock);
   silc_free(q->signoff);
@@ -1523,10 +1551,10 @@ 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;
@@ -1535,6 +1563,16 @@ SILC_SERVER_CMD_FUNC(info)
 
   /* Get server name */
   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  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_BAD_SERVER, 0);
+      goto out;
+    }
+  }
 
   /* Get Server ID */
   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
@@ -1570,7 +1608,7 @@ SILC_SERVER_CMD_FUNC(info)
   if ((!dest_server && !server_id && !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,6 +1639,9 @@ 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);
@@ -1625,6 +1666,9 @@ 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);
@@ -1648,11 +1692,15 @@ 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 +1710,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, idp->len,
+                                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);
 }
 
@@ -1761,6 +1806,9 @@ SILC_SERVER_CMD_FUNC(stats)
      statistical information. */
   if (!cmd->pending && server->server_type != SILC_ROUTER &&
       !server->standalone) {
+    /* Statistics */
+    cmd->server->stat.commands_sent++;
+
     /* Send request to our router */
     SilcBuffer idp = silc_id_payload_encode(server->router->id,
                                            SILC_ID_SERVER);
@@ -1804,13 +1852,10 @@ 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);
+  silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_STATS,
+                                SILC_STATUS_OK, 0, ident, 2,
+                                2, tmp, tmp_len,
+                                3, stats->data, stats->len);
   silc_buffer_free(stats);
 
  out:
@@ -1836,7 +1881,7 @@ static void silc_server_command_join_channel(SilcServer server,
   SilcSocketConnection sock = cmd->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;
@@ -1863,9 +1908,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;
       }
 
@@ -1962,7 +2009,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),
@@ -2042,6 +2092,7 @@ 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,
@@ -2116,6 +2167,8 @@ 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);
@@ -2143,7 +2196,7 @@ 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 *)&tmp_len, (void *)&reply))
       invite_list = silc_argument_payload_encode_one(invite_list,
                                                     reply->data,
                                                     reply->len, tmp_len);
@@ -2162,7 +2215,7 @@ 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 *)&tmp_len, (void *)&reply))
       ban_list = silc_argument_payload_encode_one(ban_list,
                                                  reply->data,
                                                  reply->len, tmp_len);
@@ -2174,7 +2227,7 @@ 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,
@@ -2201,12 +2254,21 @@ static void silc_server_command_join_channel(SilcServer server,
                                         15, fkey ? fkey->data : NULL,
                                         fkey ? fkey->len : 0,
                                         16, chpklist ? chpklist->data : NULL,
-                                        chpklist ? chpklist->len : 0);
+                                        chpklist ? chpklist->len : 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);
 
+  /* 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
      already. However since we've added the client already to our channel
@@ -2283,7 +2345,7 @@ SILC_SERVER_CMD_FUNC(join)
   SilcServer server = cmd->server;
   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;
   SilcChannelEntry channel;
   SilcUInt32 umode = 0;
   bool created = FALSE, create_key = TRUE;
@@ -2299,12 +2361,19 @@ 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[256] = '\0';
+    tmp_len = 256;
+  }
+  channel_name = tmp;
 
-  if (silc_server_name_bad_chchars(channel_name, tmp_len) == TRUE) {
+  /* Check for valid channel name.  This is cached, the original is saved
+     in the channel context. */
+  channel_namec = silc_channel_name_check(tmp, tmp_len, 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;
@@ -2314,15 +2383,15 @@ SILC_SERVER_CMD_FUNC(join)
   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
   if (!tmp) {
     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;
   }
   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,
-                                         0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
+                                        SILC_STATUS_ERR_BAD_CLIENT_ID, 0,
+                                        2, tmp, tmp_len);
     goto out;
   }
 
@@ -2334,7 +2403,7 @@ 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;
@@ -2389,6 +2458,9 @@ SILC_SERVER_CMD_FUNC(join)
            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);
@@ -2414,7 +2486,7 @@ SILC_SERVER_CMD_FUNC(join)
        /* 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,
@@ -2450,7 +2522,7 @@ SILC_SERVER_CMD_FUNC(join)
       /* 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,
@@ -2513,6 +2585,7 @@ SILC_SERVER_CMD_FUNC(join)
   silc_free(client_id);
 
  out:
+  silc_free(channel_namec);
   silc_server_command_free(cmd);
 }
 
@@ -2523,8 +2596,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 +2612,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);
@@ -2553,22 +2636,16 @@ SILC_SERVER_CMD_FUNC(motd)
        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, idp->len,
+                                    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, idp->len);
     }
-
-    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,6 +2664,9 @@ 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);
@@ -2606,11 +2686,17 @@ 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);
@@ -2631,27 +2717,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, idp->len,
+                                  3, entry->motd,
+                                  entry->motd ?
+                                  strlen(entry->motd) : 0);
     silc_buffer_free(idp);
   }
 
  out:
+  silc_free(dest_server);
   silc_server_command_free(cmd);
 }
 
@@ -2664,7 +2751,6 @@ SILC_SERVER_CMD_FUNC(umode)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  SilcBuffer packet;
   unsigned char *tmp_mask, m[4];
   SilcUInt32 mask = 0;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
@@ -2691,18 +2777,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 +2793,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 +2813,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);
@@ -2752,9 +2832,9 @@ SILC_SERVER_CMD_FUNC(cmode)
   SilcChannelID *channel_id = NULL;
   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;
@@ -2840,18 +2920,14 @@ SILC_SERVER_CMD_FUNC(cmode)
     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);
+    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 ? fkey->len : 0,
+                                  5, chpklist ? chpklist->data : NULL,
+                                  chpklist ? chpklist->len : 0);
     goto out;
   }
 
@@ -3134,7 +3210,6 @@ SILC_SERVER_CMD_FUNC(cmode)
        channel->founder_key = NULL;
        goto out;
       }
-    has_founder:
     }
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
@@ -3145,6 +3220,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 +3240,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,14 +3251,17 @@ 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,
+                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 8,
                                     cidp->data, cidp->len,
                                     tmp_mask, 4,
                                     cipher, cipher ? strlen(cipher) : 0,
@@ -3193,7 +3271,11 @@ SILC_SERVER_CMD_FUNC(cmode)
                                     fkey ? fkey->data : NULL,
                                     fkey ? fkey->len : 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,19 +3290,21 @@ 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);
+  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 ? fkey->len : 0,
+                                5, chpklist ? chpklist->data :
+                                NULL, chpklist ? chpklist->len
+                                : 0,
+                                6, (mode_mask &
+                                    SILC_CHANNEL_MODE_ULIMIT ?
+                                    ulimit : NULL),
+                                (mode_mask &
+                                 SILC_CHANNEL_MODE_ULIMIT ?
+                                 sizeof(ulimit) : 0));
   silc_buffer_free(cidp);
 
  out:
@@ -3243,7 +3327,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   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;
@@ -3320,16 +3404,15 @@ 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) {
+  if (!target_client)
     target_client = silc_idlist_find_client_by_id(server->global_list,
                                                  client_id, TRUE, NULL);
-  }
 
   if (target_client != client &&
       !(sender_mask & SILC_CHANNEL_UMODE_CHANFO) &&
       !(sender_mask & SILC_CHANNEL_UMODE_CHANOP)) {
     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;
   }
@@ -3362,7 +3445,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;
     }
 
@@ -3406,16 +3490,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;
     }
@@ -3578,15 +3669,11 @@ 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:
@@ -3608,7 +3695,7 @@ SILC_SERVER_CMD_FUNC(kick)
   SilcClientID *client_id;
   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;
@@ -3712,18 +3799,10 @@ SILC_SERVER_CMD_FUNC(kick)
 
 
   /* 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);
+  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);
@@ -3745,6 +3824,7 @@ SILC_SERVER_CMD_FUNC(kick)
       silc_argument_payload_encode_one(NULL, target_idp, target_idp_len, 3);
     SilcArgumentPayload args =
       silc_argument_payload_parse(ab->data, ab->len, 1);
+
     silc_server_inviteban_process(server, channel->invite_list, 1, args);
     silc_buffer_free(ab);
     silc_argument_payload_free(args);
@@ -3781,7 +3861,7 @@ SILC_SERVER_CMD_FUNC(oper)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  unsigned char *username, *auth;
+  unsigned char *username = NULL, *auth;
   SilcUInt32 tmp_len;
   SilcServerConfigAdmin *admin;
   SilcIDListData idata = (SilcIDListData)client;
@@ -3802,6 +3882,16 @@ 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,
                                        username, client->nickname);
@@ -3874,6 +3964,7 @@ SILC_SERVER_CMD_FUNC(oper)
                                        SILC_STATUS_OK, 0);
 
  out:
+  silc_free(username);
   silc_server_command_free(cmd);
 }
 
@@ -3996,11 +4087,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[16], *tmp,  *pk, *nick;
   SilcClientEntry client;
   SilcClientID *client_id = NULL;
+  SilcUInt16 old_ident;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WATCH, cmd, 1, 3);
 
@@ -4008,10 +4099,17 @@ 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);
@@ -4028,21 +4126,30 @@ 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);
@@ -4064,32 +4171,45 @@ SILC_SERVER_CMD_FUNC(watch)
   client = silc_idlist_find_client_by_id(server->local_list,
                                         client_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,
+                                            client_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;
+    }
   }
 
+  /* 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)
+  if (add_nick && add_nick_len > 128) {
     add_nick[128] = '\0';
-  if (del_nick && del_nick_len > 128)
+    add_nick_len = 128;
+  }
+  if (del_nick && del_nick_len > 128) {
     del_nick[128] = '\0';
-
-  memset(nick, 0, sizeof(nick));
+    del_nick_len = 128;
+  }
 
   /* 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 +4217,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 +4226,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 +4252,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,22 +4272,116 @@ 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_pkcs_public_key_payload_decode(pk, pk_len, &public_key))
+       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,
+    silc_server_backup_send(server, cmd->sock->user_data, SILC_PACKET_COMMAND,
                            cmd->packet->flags, tmpbuf->data, tmpbuf->len,
                            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);
@@ -4178,7 +4395,7 @@ SILC_SERVER_CMD_FUNC(silcoper)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  unsigned char *username, *auth;
+  unsigned char *username = NULL, *auth;
   SilcUInt32 tmp_len;
   SilcServerConfigAdmin *admin;
   SilcIDListData idata = (SilcIDListData)client;
@@ -4205,6 +4422,16 @@ 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_OPER,
+                                         SILC_STATUS_ERR_BAD_USERNAME,
+                                         0);
+    goto out;
+  }
+
   /* Get the admin configuration */
   admin = silc_server_config_find_admin(server, cmd->sock->ip,
                                        username, client->nickname);
@@ -4275,6 +4502,7 @@ SILC_SERVER_CMD_FUNC(silcoper)
                                        SILC_STATUS_OK, 0);
 
  out:
+  silc_free(username);
   silc_server_command_free(cmd);
 }
 
@@ -4286,7 +4514,7 @@ SILC_SERVER_CMD_FUNC(ban)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  SilcBuffer packet, list, tmp2;
+  SilcBuffer list, tmp2;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcChannelID *channel_id = NULL;
@@ -4380,8 +4608,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,7 +4629,7 @@ 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))
+    while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
       list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
                                              type);
     silc_hash_table_list_reset(&htl);
@@ -4422,16 +4656,11 @@ 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, id, id_len,
+                                3, list ? list->data : NULL,
+                                list ? list->len : 0);
   silc_buffer_free(list);
 
  out:
@@ -4531,7 +4760,7 @@ SILC_SERVER_CMD_FUNC(users)
   SilcServer server = cmd->server;
   SilcChannelEntry channel;
   SilcChannelID *id = NULL;
-  SilcBuffer packet, idp;
+  SilcBuffer idp;
   unsigned char *channel_id;
   SilcUInt32 channel_id_len;
   SilcBuffer client_id_list;
@@ -4539,7 +4768,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,6 +4784,18 @@ 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) {
@@ -4572,7 +4813,7 @@ SILC_SERVER_CMD_FUNC(users)
     channel = silc_idlist_find_channel_by_id(server->local_list, 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,6 +4821,9 @@ 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);
 
@@ -4605,7 +4849,7 @@ SILC_SERVER_CMD_FUNC(users)
       channel = silc_idlist_find_channel_by_id(server->global_list, 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)
@@ -4649,23 +4893,19 @@ 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, 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_buffer_free(idp);
-  silc_buffer_free(packet);
   if (client_id_list)
     silc_buffer_free(client_id_list);
   if (client_mode_list)
@@ -4673,6 +4913,7 @@ SILC_SERVER_CMD_FUNC(users)
   silc_free(id);
 
  out:
+  silc_free(channel_namec);
   silc_server_command_free(cmd);
 }
 
@@ -4683,7 +4924,6 @@ SILC_SERVER_CMD_FUNC(getkey)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcBuffer packet;
   SilcClientEntry client;
   SilcServerEntry server_entry;
   SilcClientID *client_id = NULL;
@@ -4736,6 +4976,9 @@ SILC_SERVER_CMD_FUNC(getkey)
       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);
@@ -4788,6 +5031,9 @@ 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);
@@ -4825,14 +5071,11 @@ SILC_SERVER_CMD_FUNC(getkey)
   }
 
   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 ? pk->len : 0);
 
  out:
   if (idp)
@@ -4946,10 +5189,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);
@@ -4969,6 +5212,11 @@ SILC_SERVER_CMD_FUNC(close)
   /* Close the connection to the server */
   sock = (SilcSocketConnection)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) {
     server->id_entry->router = NULL;