Return correct command type in SILCOPER in case of error.
[silc.git] / apps / silcd / command.c
index e33a8cef41ca846eb07806861326b3b7ad8eb8d8..a42d254c8e195314d730a87cbf7a40a1572a973d 100644 (file)
@@ -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),
@@ -421,7 +422,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);
 
@@ -488,6 +489,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 =
@@ -514,6 +518,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 =
@@ -540,6 +547,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 =
@@ -569,6 +579,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,
@@ -623,7 +636,7 @@ 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;
   unsigned char *nick, *nickc = NULL;
@@ -658,7 +671,8 @@ SILC_SERVER_CMD_FUNC(nick)
   }
 
   /* Check for same nickname */
-  if (!memcmp(client->nickname, nick, nick_len)) {
+  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;
@@ -719,14 +733,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, nick_len);
-  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);
@@ -745,7 +756,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);
@@ -800,18 +811,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++;
   }
@@ -839,18 +845,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++;
   }
@@ -878,6 +879,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);
@@ -937,7 +941,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);
@@ -1044,16 +1048,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);
 
@@ -1077,7 +1077,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;
@@ -1264,8 +1264,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);
   }
@@ -1325,15 +1331,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:
@@ -1549,7 +1552,7 @@ 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 = NULL, *server_info = NULL, *server_name;
@@ -1637,6 +1640,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);
@@ -1661,6 +1667,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);
@@ -1702,18 +1711,14 @@ 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:
@@ -1802,9 +1807,14 @@ SILC_SERVER_CMD_FUNC(stats)
      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);
@@ -1845,13 +1855,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:
@@ -2088,6 +2095,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,
@@ -2261,6 +2269,9 @@ static void silc_server_command_join_channel(SilcServer server,
   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
@@ -2363,8 +2374,8 @@ SILC_SERVER_CMD_FUNC(join)
 
   /* Check for valid channel name.  This is cached, the original is saved
      in the channel context. */
-  channel_namec = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8, 256,
-                                       NULL);
+  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);
@@ -2406,6 +2417,18 @@ SILC_SERVER_CMD_FUNC(join)
       goto out;
     }
 
+#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 */
+
     silc_free(client_id);
     client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
 
@@ -2420,10 +2443,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));
+           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);
+           }
            silc_free(client_id);
            goto out;
          }
@@ -2450,6 +2485,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);
@@ -2481,10 +2519,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));
+           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);
+           }
            silc_free(client_id);
            goto out;
          }
@@ -2517,10 +2567,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));
+         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);
+         }
          silc_free(client_id);
          goto out;
        }
@@ -2585,7 +2647,7 @@ SILC_SERVER_CMD_FUNC(motd)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcBuffer packet, idp;
+  SilcBuffer idp;
   char *motd, *dest_server = NULL;
   SilcUInt32 motd_len;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
@@ -2621,26 +2683,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, idp->len);
        goto out;
+      }
 
       motd[motd_len] = 0;
-      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                   SILC_STATUS_OK, 0,
-                                                   ident, 2,
-                                                   2, idp->data, 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->data, 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;
@@ -2659,6 +2720,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);
@@ -2686,6 +2750,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);
@@ -2717,15 +2784,12 @@ SILC_SERVER_CMD_FUNC(motd)
     }
 
     idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
-    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                 SILC_STATUS_OK, 0, ident, 2,
-                                                 2, idp->data, 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);
+    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);
   }
 
@@ -2743,7 +2807,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);
@@ -2806,12 +2869,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);
@@ -2828,7 +2888,7 @@ 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, ulimit[4];
   SilcUInt32 mode_mask = 0, old_mask = 0, tmp_len, tmp_len2, chpklen;
@@ -2916,18 +2976,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;
   }
 
@@ -2946,6 +3002,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;
@@ -3087,7 +3147,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 */
@@ -3123,7 +3183,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 */
@@ -3290,26 +3350,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, 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_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:
@@ -3332,7 +3387,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;
@@ -3674,15 +3729,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:
@@ -3704,7 +3755,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;
@@ -3808,14 +3859,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);
+  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);
@@ -3837,6 +3884,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);
@@ -4097,13 +4145,13 @@ SILC_SERVER_CMD_FUNC(detach)
 SILC_SERVER_CMD_FUNC(watch)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  SilcServerEntry server_entry;
   SilcServer server = cmd->server;
   char *add_nick, *del_nick;
   SilcUInt32 add_nick_len, del_nick_len, tmp_len, pk_len;
-  unsigned char hash[16], *tmp,  *pk, *nick;
+  unsigned char hash[SILC_HASH_MAXLEN], *tmp,  *pk, *nick;
   SilcClientEntry client;
   SilcClientID *client_id = NULL;
+  SilcUInt16 old_ident;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WATCH, cmd, 1, 3);
 
@@ -4111,10 +4159,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);
@@ -4131,20 +4186,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);
+
+      /* 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;
+      }
     }
-    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);
@@ -4166,10 +4231,16 @@ 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 */
@@ -4350,20 +4421,27 @@ SILC_SERVER_CMD_FUNC(watch)
     }
   }
 
+  /* 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, 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);
@@ -4408,7 +4486,7 @@ SILC_SERVER_CMD_FUNC(silcoper)
   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_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
                                          SILC_STATUS_ERR_BAD_USERNAME,
                                          0);
     goto out;
@@ -4455,7 +4533,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;
   }
@@ -4496,7 +4574,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;
@@ -4590,8 +4668,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);
   }
@@ -4632,16 +4716,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:
@@ -4741,7 +4820,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;
@@ -4767,8 +4846,8 @@ SILC_SERVER_CMD_FUNC(users)
 
   /* Check channel name */
   if (channel_name) {
-    channel_namec = silc_identifier_check(channel_name, strlen(channel_name),
-                                         SILC_STRING_UTF8, 256, NULL);
+    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);
@@ -4802,6 +4881,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);
 
@@ -4871,23 +4953,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)
@@ -4906,7 +4984,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;
@@ -4959,6 +5036,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);
@@ -5011,6 +5091,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);
@@ -5048,14 +5131,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)
@@ -5066,6 +5146,50 @@ SILC_SERVER_CMD_FUNC(getkey)
   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;
+  bool 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);
+}
+
 
 /* Private range commands, specific to this implementation */