Added SILC Server library.
[silc.git] / lib / silcserver / server_st_command.c
diff --git a/lib/silcserver/server_st_command.c b/lib/silcserver/server_st_command.c
new file mode 100644 (file)
index 0000000..36c3d9e
--- /dev/null
@@ -0,0 +1,838 @@
+/*
+
+  server_st_command.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  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
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+/************************** Types and definitions ***************************/
+
+#define SILC_SERVER_COMMAND_CHECK(min, max)                                 \
+do {                                                                        \
+  SilcUInt32 _argc;                                                         \
+                                                                            \
+  SILC_LOG_DEBUG(("Start"));                                                \
+                                                                            \
+  _argc = silc_argument_get_arg_num(args);                                  \
+  if (_argc < min) {                                                        \
+    SILC_LOG_DEBUG(("Not enough parameters in command"));                   \
+    silc_server_command_send_status_reply(cmd,                              \
+                                         silc_command_get(cmd->payload),    \
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, \
+                                         0);                                \
+    silc_server_command_free(cmd);                                          \
+    return SILC_FSM_FINISH;                                                 \
+  }                                                                         \
+  if (_argc > max) {                                                        \
+    SILC_LOG_DEBUG(("Too many parameters in command"));                             \
+    silc_server_command_send_status_reply(cmd,                              \
+                                         silc_command_get(cmd->payload),    \
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS,   \
+                                         0);                                \
+    silc_server_command_free(cmd);                                          \
+    return SILC_FSM_FINISH;                                                 \
+  }                                                                         \
+} while(0)
+
+
+/************************ Static utility functions **************************/
+
+/* Sends simple status message as command reply packet */
+
+static void
+silc_server_command_send_status_reply(SilcServerCommand cmd,
+                                     SilcCommand command,
+                                     SilcStatus status,
+                                     SilcStatus error)
+{
+  SilcBuffer buffer;
+
+  /* Statistics */
+  cmd->thread->server->stat.commands_sent++;
+
+  SILC_LOG_DEBUG(("Sending command status %d", status));
+  buffer =
+    silc_command_reply_payload_encode_va(command, status, error,
+                                        silc_command_get_ident(cmd->payload),
+                                        0);
+  silc_packet_send(cmd->packet->stream, SILC_PACKET_COMMAND_REPLY, 0,
+                  buffer->data, silc_buffer_len(buffer));
+  silc_buffer_free(buffer);
+}
+
+/* Sends command status reply with one extra argument. The argument
+   type must be sent as argument. */
+
+static void
+silc_server_command_send_status_data(SilcServerCommand cmd,
+                                    SilcCommand command,
+                                    SilcStatus status,
+                                    SilcStatus error,
+                                    SilcUInt32 arg_type,
+                                    const unsigned char *arg,
+                                    SilcUInt32 arg_len)
+{
+  SilcBuffer buffer;
+
+  /* Statistics */
+  cmd->thread->server->stat.commands_sent++;
+
+  SILC_LOG_DEBUG(("Sending command status %d", status));
+
+  buffer =
+    silc_command_reply_payload_encode_va(command, status, 0,
+                                        silc_command_get_ident(cmd->payload),
+                                        1, arg_type, arg, arg_len);
+  silc_packet_send(cmd->packet->stream, SILC_PACKET_COMMAND_REPLY, 0,
+                  buffer->data, silc_buffer_len(buffer));
+  silc_buffer_free(buffer);
+}
+
+static void
+silc_server_command_send_status_data2(SilcServerCommand cmd,
+                                     SilcCommand command,
+                                     SilcStatus status,
+                                     SilcStatus error,
+                                     SilcUInt32 arg_type1,
+                                     const unsigned char *arg1,
+                                     SilcUInt32 arg_len1,
+                                     SilcUInt32 arg_type2,
+                                     const unsigned char *arg2,
+                                     SilcUInt32 arg_len2)
+{
+  SilcBuffer buffer;
+
+  /* Statistics */
+  cmd->thread->server->stat.commands_sent++;
+
+  SILC_LOG_DEBUG(("Sending command status %d", status));
+
+  buffer =
+    silc_command_reply_payload_encode_va(command, status, 0,
+                                        silc_command_get_ident(cmd->payload),
+                                        2, arg_type1, arg1, arg_len1,
+                                        arg_type2, arg2, arg_len2);
+  silc_packet_send(cmd->packet->stream, SILC_PACKET_COMMAND_REPLY, 0,
+                  buffer->data, silc_buffer_len(buffer));
+  silc_buffer_free(buffer);
+}
+
+void silc_server_command_pending_free(SilcServerThread thread,
+                                     SilcServerPending pending);
+
+
+/**************************** Utility functions *****************************/
+
+/* Gets command context from freelist or allocates a new one. */
+
+SilcServerCommand silc_server_command_alloc(SilcServerThread thread)
+{
+  SilcServerCommand cmd;
+
+  silc_mutex_lock(thread->server->lock);
+
+  /* Get command context from freelist or allocate new one. */
+  cmd = silc_list_get(thread->server->command_pool);
+  if (!cmd) {
+    silc_mutex_unlock(thread->server->lock);
+
+    cmd = silc_calloc(1, sizeof(*cmd));
+    if (!cmd)
+      return NULL;
+
+    SILC_LOG_DEBUG(("Allocating command context %p", cmd));
+
+    cmd->thread = thread;
+
+    return cmd;
+  }
+
+  SILC_LOG_DEBUG(("Get command context %p", cmd));
+
+  /* Delete from freelist */
+  silc_list_del(thread->server->command_pool, cmd);
+
+  cmd->thread = thread;
+
+  silc_mutex_unlock(thread->server->lock);
+
+  return cmd;
+}
+
+/* Puts the command context back to freelist */
+
+void silc_server_command_free(SilcServerCommand cmd)
+{
+  SilcServerThread thread = cmd->thread;
+
+  silc_mutex_lock(thread->server->lock);
+
+  /* Check for double free */
+#if defined(SILC_DEBUG)
+  assert(cmd->packet != NULL);
+#endif /* SILC_DEBUG */
+
+  if (cmd->packet)
+    silc_packet_free(cmd->packet);
+  cmd->packet = NULL;
+
+  if (cmd->pending)
+    silc_server_command_pending_free(thread, cmd->pending);
+
+  /* Put the packet back to freelist */
+  silc_list_add(thread->server->command_pool, cmd);
+
+  silc_mutex_unlock(thread->server->lock);
+}
+
+/* Returns pending context used to wait for a command reply. */
+
+SilcServerPending silc_server_command_pending(SilcServerThread thread,
+                                             SilcUInt16 cmd_ident)
+{
+  SilcServerPending pending;
+
+  silc_mutex_lock(thread->server->lock);
+
+  /* Check if pending already */
+  if (silc_hash_table_find(thread->server->pending_commands,
+                          SILC_32_TO_PTR(cmd_ident), NULL,
+                          (void **)&pending)) {
+    pending->refcnt++;
+    silc_mutex_unlock(thread->server->lock);
+    return pending;
+  }
+
+  pending = silc_calloc(1, sizeof(*pending));
+  if (!pending) {
+    silc_mutex_unlock(thread->server->lock);
+    return NULL;
+  }
+
+  silc_fsm_sema_init(&pending->wait_reply, &thread->fsm, 0);
+  pending->refcnt = 1;
+  pending->cmd_ident = cmd_ident;
+
+  /* Add to pending commands hash table */
+  if (!silc_hash_table_add(thread->server->pending_commands,
+                          SILC_32_TO_PTR(cmd_ident), pending)) {
+    silc_mutex_unlock(thread->server->lock);
+    silc_free(pending);
+    return NULL;
+  }
+
+  silc_mutex_unlock(thread->server->lock);
+
+  return pending;
+}
+
+/* Free's the pending command context */
+
+void silc_server_command_pending_free(SilcServerThread thread,
+                                     SilcServerPending pending)
+{
+  silc_mutex_lock(thread->server->lock);
+
+  pending->refcnt--;
+  if (pending->refcnt > 0) {
+    silc_mutex_unlock(thread->server->lock);
+    return;
+  }
+
+  /* If command reply context set, free it also */
+  if (pending->reply) {
+    pending->reply->pending = NULL;
+    silc_server_command_free(pending->reply);
+  }
+
+  /* Remove from pending commands */
+  silc_hash_table_del_by_context(thread->server->pending_commands,
+                                SILC_32_TO_PTR(pending->cmd_ident), pending);
+  silc_free(pending);
+
+  silc_mutex_unlock(thread->server->lock);
+}
+
+/* Returns pending command context for command identifier */
+
+SilcServerPending silc_server_command_pending_get(SilcServerThread thread,
+                                                 SilcUInt16 cmd_ident)
+{
+  SilcServerPending pending = NULL;
+
+  silc_mutex_lock(thread->server->lock);
+  silc_hash_table_find(thread->server->pending_commands,
+                      SILC_32_TO_PTR(cmd_ident), NULL, (void **)&pending);
+  silc_mutex_unlock(thread->server->lock);
+
+  return pending;
+}
+
+/* Signals pending command waiters.  Used by command reply routines. */
+
+void silc_server_command_pending_signal(SilcServerCommand cmd)
+{
+  SilcServerThread thread = cmd->thread;
+  SilcServerPending pending = cmd->pending;
+
+  if (!pending)
+    return;
+
+  silc_mutex_lock(thread->server->lock);
+
+  /* Signal */
+  pending->reply = cmd;
+  SILC_FSM_SEMA_POST(&pending->wait_reply);
+
+  /* Remove from pending */
+  silc_hash_table_del_by_context(thread->server->pending_commands,
+                                SILC_32_TO_PTR(pending->cmd_ident), pending);
+
+  silc_mutex_unlock(thread->server->lock);
+}
+
+
+/**************************** Command received ******************************/
+
+/* Received a COMMAND packet.  We parse the packet and process the
+   requested command. */
+
+SILC_FSM_STATE(silc_server_st_packet_command)
+{
+  SilcServerThread thread = fsm_context;
+  SilcPacket packet = state_context;
+  SilcEntryData data = silc_packet_get_context(packet->stream);
+  SilcServerCommand cmd;
+  SilcUInt32 timeout = 0;
+
+  /* Allocate command context. */
+  cmd = silc_server_command_alloc(thread);
+  if (!cmd) {
+    silc_packet_free(packet);
+    return SILC_FSM_FINISH;
+  }
+
+  cmd->packet = packet;
+
+  /* Parse the command payload in the packet */
+  cmd->payload = silc_command_payload_parse(packet->buffer.data,
+                                           silc_buffer_len(&packet->buffer));
+  if (!cmd->payload) {
+    SILC_LOG_ERROR(("Bad command payload"));
+    silc_server_command_free(cmd);
+    return SILC_FSM_FINISH;
+  }
+
+  /* If client executes commands more frequently than once in 2 seconds,
+     apply 0 - 2 seconds of timeout to prevent flooding. */
+  if (data->type == SILC_CONN_CLIENT) {
+    SilcClientEntry client = (SilcClientEntry)data;
+
+    if (client->last_command && (time(NULL) - client->last_command) < 2) {
+      client->fast_command++;
+      if (client->fast_command > 5)
+       timeout = (client->fast_command < 3 ? 0 :
+                  2 - (time(NULL) - client->last_command));
+    } else {
+      if (client->fast_command - 2 <= 0)
+       client->fast_command = 0;
+      else
+       client->fast_command -= 2;
+    }
+  }
+
+  silc_fsm_set_state_context(fsm, cmd);
+
+  SILC_LOG_DEBUG(("Processing %s command (%d timeout)",
+                 silc_get_command_name(silc_command_get(cmd->payload)),
+                 timeout));
+
+  /* Process command */
+  switch (silc_command_get(cmd->payload)) {
+
+  case SILC_COMMAND_WHOIS:
+    /** Command WHOIS */
+    silc_fsm_next_later(fsm, silc_server_st_command_whois, timeout, 0);
+    break;
+
+  case SILC_COMMAND_WHOWAS:
+    /** Command WHOWAS */
+    silc_fsm_next_later(fsm, silc_server_st_command_whowas, timeout, 0);
+    break;
+
+  case SILC_COMMAND_IDENTIFY:
+    /** Command IDENTIFY */
+    silc_fsm_next_later(fsm, silc_server_st_command_identify, timeout, 0);
+    break;
+
+  case SILC_COMMAND_NICK:
+    /** Command NICK */
+    silc_fsm_next_later(fsm, silc_server_st_command_nick, timeout, 0);
+    break;
+
+  case SILC_COMMAND_LIST:
+    /** Command LIST */
+    silc_fsm_next_later(fsm, silc_server_st_command_list, timeout, 0);
+    break;
+
+  case SILC_COMMAND_TOPIC:
+    /** Command TOPIC */
+    silc_fsm_next_later(fsm, silc_server_st_command_topic, timeout, 0);
+    break;
+
+  case SILC_COMMAND_INVITE:
+    /** Command INVITE */
+    silc_fsm_next_later(fsm, silc_server_st_command_invite, timeout, 0);
+    break;
+
+  case SILC_COMMAND_QUIT:
+    /** Command QUIT */
+    silc_fsm_next_later(fsm, silc_server_st_command_quit, timeout, 0);
+    break;
+
+  case SILC_COMMAND_KILL:
+    /** Command KILL */
+    silc_fsm_next_later(fsm, silc_server_st_command_kill, timeout, 0);
+    break;
+
+  case SILC_COMMAND_INFO:
+    /** Command INFO */
+    silc_fsm_next_later(fsm, silc_server_st_command_info, timeout, 0);
+    break;
+
+  case SILC_COMMAND_STATS:
+    /** Command STATS */
+    silc_fsm_next_later(fsm, silc_server_st_command_stats, timeout, 0);
+    break;
+
+  case SILC_COMMAND_PING:
+    /** Command INFO */
+    silc_fsm_next_later(fsm, silc_server_st_command_ping, timeout, 0);
+    break;
+
+  case SILC_COMMAND_OPER:
+    /** Command OPER */
+    silc_fsm_next_later(fsm, silc_server_st_command_oper, timeout, 0);
+    break;
+
+  case SILC_COMMAND_JOIN:
+    /** Command JOIN */
+    silc_fsm_next_later(fsm, silc_server_st_command_join, timeout, 0);
+    break;
+
+  case SILC_COMMAND_MOTD:
+    /** Command MOTD */
+    silc_fsm_next_later(fsm, silc_server_st_command_motd, timeout, 0);
+    break;
+
+  case SILC_COMMAND_UMODE:
+    /** Command UMODE */
+    silc_fsm_next_later(fsm, silc_server_st_command_umode, timeout, 0);
+    break;
+
+  case SILC_COMMAND_CMODE:
+    /** Command CMODE */
+    silc_fsm_next_later(fsm, silc_server_st_command_cmode, timeout, 0);
+    break;
+
+  case SILC_COMMAND_CUMODE:
+    /** Command CUMODE */
+    silc_fsm_next_later(fsm, silc_server_st_command_cumode, timeout, 0);
+    break;
+
+  case SILC_COMMAND_KICK:
+    /** Command KICK */
+    silc_fsm_next_later(fsm, silc_server_st_command_kick, timeout, 0);
+    break;
+
+  case SILC_COMMAND_BAN:
+    /** Command BAN */
+    silc_fsm_next_later(fsm, silc_server_st_command_ban, timeout, 0);
+    break;
+
+  case SILC_COMMAND_DETACH:
+    /** Command DETACH */
+    silc_fsm_next_later(fsm, silc_server_st_command_detach, timeout, 0);
+    break;
+
+  case SILC_COMMAND_WATCH:
+    /** Command WATCH */
+    silc_fsm_next_later(fsm, silc_server_st_command_watch, timeout, 0);
+    break;
+
+  case SILC_COMMAND_SILCOPER:
+    /** Command SILCOPER */
+    silc_fsm_next_later(fsm, silc_server_st_command_silcoper, timeout, 0);
+    break;
+
+  case SILC_COMMAND_LEAVE:
+    /** Command LEAVE */
+    silc_fsm_next_later(fsm, silc_server_st_command_leave, timeout, 0);
+    break;
+
+  case SILC_COMMAND_USERS:
+    /** Command USERS */
+    silc_fsm_next_later(fsm, silc_server_st_command_users, timeout, 0);
+    break;
+
+  case SILC_COMMAND_GETKEY:
+    /** Command GETKEY */
+    silc_fsm_next_later(fsm, silc_server_st_command_getkey, timeout, 0);
+    break;
+
+  case SILC_COMMAND_SERVICE:
+    /** Command SERVICE */
+    silc_fsm_next_later(fsm, silc_server_st_command_service, timeout, 0);
+    break;
+
+  default:
+    SILC_LOG_DEBUG(("Unknown command %d", silc_command_get(cmd->payload)));
+    silc_server_command_free(cmd);
+    return SILC_FSM_FINISH;
+    break;
+  }
+
+  /* Statistics */
+  thread->server->stat.commands_received++;
+
+  return timeout ? SILC_FSM_WAIT : SILC_FSM_CONTINUE;
+}
+
+
+/********************************** NICK ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_nick)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** LIST ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_list)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** TOPIC ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_topic)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************* INVITE ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_invite)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** QUIT ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_quit)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** KILL ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_kill)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** INFO ************************************/
+
+/* Server side of command INFO. This sends information about us to
+   the client.  If client requested specific server we will send the
+   command to that server. */
+
+SILC_FSM_STATE(silc_server_st_command_info)
+{
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** STATS ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_stats)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** PING ************************************/
+
+/* Server side of command PING. */
+
+SILC_FSM_STATE(silc_server_st_command_ping)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+  SilcUInt32 tmp_len;
+  unsigned char *tmp;
+  SilcServerID server_id;
+
+  SILC_SERVER_COMMAND_CHECK(1, 1);
+
+  /* Get Server ID */
+  tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, silc_command_get(cmd->payload),
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                         0);
+    goto out;
+  }
+  if (!silc_id_payload_parse_id(tmp, tmp_len, NULL, &server_id,
+                               sizeof(server_id))) {
+    silc_server_command_send_status_data(cmd, silc_command_get(cmd->payload),
+                                        SILC_STATUS_ERR_BAD_SERVER_ID, 0,
+                                        2, tmp, tmp_len);
+    goto out;
+  }
+
+  if (SILC_ID_SERVER_COMPARE(&server_id, &thread->server->id)) {
+    /* Send our reply */
+    silc_server_command_send_status_reply(cmd, silc_command_get(cmd->payload),
+                                         SILC_STATUS_OK, 0);
+  } else {
+    silc_server_command_send_status_data(cmd, silc_command_get(cmd->payload),
+                                        SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
+                                        2, tmp, tmp_len);
+  }
+
+ out:
+  silc_server_command_free(cmd);
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** OPER ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_oper)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** JOIN ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_join)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** MOTD ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_motd)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** UMODE **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_umode)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** CMODE **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_cmode)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** CUMODE **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_cumode)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** KICK ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_kick)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** BAN ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_ban)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** DETACH **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_detach)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** WATCH ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_watch)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************* SILCOPER *********************************/
+
+SILC_FSM_STATE(silc_server_st_command_silcoper)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** LEAVE ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_leave)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** USERS ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_users)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** GETKEY **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_getkey)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** SERVICE *********************************/
+
+SILC_FSM_STATE(silc_server_st_command_service)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}