--- /dev/null
+/*
+
+ 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;
+}