Created SILC Crypto Toolkit git repository.
[crypto.git] / lib / silcclient / command_reply.c
diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c
deleted file mode 100644 (file)
index bf80d06..0000000
+++ /dev/null
@@ -1,2173 +0,0 @@
-/*
-
-  command_reply.c
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  Copyright (C) 1997 - 2007 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.
-
-*/
-/* $Id$ */
-
-#include "silc.h"
-#include "silcclient.h"
-#include "client_internal.h"
-
-/************************** Types and definitions ***************************/
-
-/* Calls error command reply callback back to command sender. */
-#define ERROR_CALLBACK(err)                                    \
-do {                                                           \
-  void *arg1 = NULL, *arg2 = NULL;                             \
-  if (cmd->status != SILC_STATUS_OK)                           \
-    silc_status_get_args(cmd->status, args, &arg1, &arg2);     \
-  else                                                         \
-    cmd->status = cmd->error = err;                            \
-  SILC_LOG_DEBUG(("Error in command reply: %s",                        \
-                silc_get_status_message(cmd->status)));        \
-  silc_client_command_callback(cmd, arg1, arg2);               \
-} while(0)
-
-/* Check for error */
-#define CHECK_STATUS(msg)                                              \
-  SILC_LOG_DEBUG(("%s", silc_get_command_name(cmd->cmd)));             \
-  if (cmd->error != SILC_STATUS_OK) {                                  \
-    if (cmd->verbose)                                                  \
-      SAY(cmd->conn->client, cmd->conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, \
-         msg "%s", silc_get_status_message(cmd->error));               \
-    ERROR_CALLBACK(cmd->error);                                                \
-    silc_client_command_process_error(cmd, state_context, cmd->error); \
-    silc_fsm_next(fsm, silc_client_command_reply_processed);           \
-    return SILC_FSM_CONTINUE;                                          \
-  }
-
-/* Check for correct arguments */
-#define CHECK_ARGS(min, max)                                   \
-  if (silc_argument_get_arg_num(args) < min ||                 \
-      silc_argument_get_arg_num(args) > max) {                 \
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);         \
-    silc_fsm_next(fsm, silc_client_command_reply_processed);   \
-    return SILC_FSM_CONTINUE;                                  \
-  }
-
-#define SAY cmd->conn->client->internal->ops->say
-
-/************************ Static utility functions **************************/
-
-/* Delivers the command reply back to application */
-
-static inline void
-silc_client_command_callback(SilcClientCommandContext cmd, ...)
-{
-  SilcClientCommandReplyCallback cb;
-  SilcList list;
-  va_list ap, cp;
-
-  va_start(ap, cmd);
-
-  /* Default reply callback */
-  if (cmd->called) {
-    silc_va_copy(cp, ap);
-    cmd->conn->client->internal->ops->command_reply(
-                      cmd->conn->client, cmd->conn, cmd->cmd, cmd->status,
-                      cmd->error, cp);
-    va_end(cp);
-  }
-
-  /* Reply callback */
-  list = cmd->reply_callbacks;
-  silc_list_start(list);
-  while ((cb = silc_list_get(list)))
-    if (!cb->do_not_call) {
-      silc_va_copy(cp, ap);
-      cb->do_not_call = !cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
-                                  cmd->status, cmd->error, cb->context, cp);
-      va_end(cp);
-    }
-
-  va_end(ap);
-}
-
-/* Handles common error status types. */
-
-static void silc_client_command_process_error(SilcClientCommandContext cmd,
-                                             SilcCommandPayload payload,
-                                             SilcStatus error)
-{
-  SilcClient client = cmd->conn->client;
-  SilcClientConnection conn = cmd->conn;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcID id;
-
-  if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
-    SilcClientEntry client_entry;
-
-    /* Remove unknown client entry from cache */
-    if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
-      return;
-
-    client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
-    if (client_entry) {
-      silc_client_remove_from_channels(client, conn, client_entry);
-      silc_client_del_client(client, conn, client_entry);
-      silc_client_unref_client(client, conn, client_entry);
-    }
-    return;
-  }
-
-  if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) {
-    SilcChannelEntry channel;
-
-    /* Remove unknown channel entry from cache */
-    if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
-      return;
-
-    channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
-    if (channel) {
-      silc_client_empty_channel(client, conn, channel);
-      silc_client_del_channel(client, conn, channel);
-      silc_client_unref_channel(client, conn, channel);
-    }
-    return;
-  }
-
-  if (cmd->error == SILC_STATUS_ERR_NO_SUCH_SERVER_ID) {
-    SilcServerEntry server_entry;
-
-    /* Remove unknown server entry from cache */
-    if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
-      return;
-
-    server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
-    if (server_entry) {
-      silc_client_del_server(client, conn, server_entry);
-      silc_client_unref_server(client, conn, server_entry);
-    }
-    return;
-  }
-}
-
-/***************************** Command Reply ********************************/
-
-/* Process received command reply packet */
-
-SILC_FSM_STATE(silc_client_command_reply)
-{
-  SilcClientConnection conn = fsm_context;
-  SilcPacket packet = state_context;
-  SilcClientCommandContext cmd;
-  SilcCommandPayload payload;
-  SilcCommand command;
-  SilcUInt16 cmd_ident;
-
-  /* Get command reply payload from packet */
-  payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
-  silc_packet_free(packet);
-  if (!payload) {
-    SILC_LOG_DEBUG(("Bad command reply packet"));
-    return SILC_FSM_FINISH;
-  }
-
-  cmd_ident = silc_command_get_ident(payload);
-  command = silc_command_get(payload);
-
-  /* Find the command pending reply */
-  silc_mutex_lock(conn->internal->lock);
-  silc_list_start(conn->internal->pending_commands);
-  while ((cmd = silc_list_get(conn->internal->pending_commands))) {
-    if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
-       && cmd->cmd_ident == cmd_ident) {
-      silc_list_del(conn->internal->pending_commands, cmd);
-      break;
-    }
-  }
-  silc_mutex_unlock(conn->internal->lock);
-
-  if (!cmd) {
-    SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
-                   silc_get_command_name(command), cmd_ident));
-    silc_command_payload_free(payload);
-    return SILC_FSM_FINISH;
-  }
-
-  /* Signal command thread that command reply has arrived.  We continue
-     command reply processing synchronously because we save the command
-     payload into state context.  No other reply may arrive to this command
-     while we're processing this reply. */
-  silc_fsm_set_state_context(&cmd->thread, payload);
-  silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
-  silc_fsm_continue_sync(&cmd->thread);
-
-  return SILC_FSM_FINISH;
-}
-
-/* Wait here for command reply to arrive from remote host */
-
-SILC_FSM_STATE(silc_client_command_reply_wait)
-{
-  SilcClientCommandContext cmd = fsm_context;
-
-  SILC_LOG_DEBUG(("Wait for command reply"));
-
-  /** Wait for command reply */
-  silc_fsm_set_state_context(fsm, NULL);
-  silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
-                     cmd->cmd != SILC_COMMAND_PING ? 40 : 60, 0);
-  return SILC_FSM_WAIT;
-}
-
-/* Timeout occurred while waiting command reply */
-
-SILC_FSM_STATE(silc_client_command_reply_timeout)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcArgumentPayload args = NULL;
-
-  if (conn->internal->disconnected) {
-    SILC_LOG_DEBUG(("Command %s canceled", silc_get_command_name(cmd->cmd)));
-    silc_list_del(conn->internal->pending_commands, cmd);
-    if (!cmd->called)
-      ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
-    return SILC_FSM_FINISH;
-  }
-
-  SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
-
-  /* Timeout, reply not received in timely fashion */
-  silc_list_del(conn->internal->pending_commands, cmd);
-  ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
-  return SILC_FSM_FINISH;
-}
-
-/* Process received command reply payload */
-
-SILC_FSM_STATE(silc_client_command_reply_process)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcCommandPayload payload = state_context;
-
-  silc_command_get_status(payload, &cmd->status, &cmd->error);
-
-  switch (cmd->cmd) {
-  case SILC_COMMAND_WHOIS:
-    /** WHOIS */
-    silc_fsm_next(fsm, silc_client_command_reply_whois);
-    break;
-  case SILC_COMMAND_WHOWAS:
-    /** WHOWAS */
-    silc_fsm_next(fsm, silc_client_command_reply_whowas);
-    break;
-  case SILC_COMMAND_IDENTIFY:
-    /** IDENTIFY */
-    silc_fsm_next(fsm, silc_client_command_reply_identify);
-    break;
-  case SILC_COMMAND_NICK:
-    /** NICK */
-    silc_fsm_next(fsm, silc_client_command_reply_nick);
-    break;
-  case SILC_COMMAND_LIST:
-    /** LIST */
-    silc_fsm_next(fsm, silc_client_command_reply_list);
-    break;
-  case SILC_COMMAND_TOPIC:
-    /** TOPIC */
-    silc_fsm_next(fsm, silc_client_command_reply_topic);
-    break;
-  case SILC_COMMAND_INVITE:
-    /** INVITE */
-    silc_fsm_next(fsm, silc_client_command_reply_invite);
-    break;
-  case SILC_COMMAND_QUIT:
-    /** QUIT */
-    silc_fsm_next(fsm, silc_client_command_reply_quit);
-    break;
-  case SILC_COMMAND_KILL:
-    /** KILL */
-    silc_fsm_next(fsm, silc_client_command_reply_kill);
-    break;
-  case SILC_COMMAND_INFO:
-    /** INFO */
-    silc_fsm_next(fsm, silc_client_command_reply_info);
-    break;
-  case SILC_COMMAND_STATS:
-    /** STATS */
-    silc_fsm_next(fsm, silc_client_command_reply_stats);
-    break;
-  case SILC_COMMAND_PING:
-    /** PING */
-    silc_fsm_next(fsm, silc_client_command_reply_ping);
-    break;
-  case SILC_COMMAND_OPER:
-    /** OPER */
-    silc_fsm_next(fsm, silc_client_command_reply_oper);
-    break;
-  case SILC_COMMAND_JOIN:
-    /** JOIN */
-    silc_fsm_next(fsm, silc_client_command_reply_join);
-    break;
-  case SILC_COMMAND_MOTD:
-    /** MOTD */
-    silc_fsm_next(fsm, silc_client_command_reply_motd);
-    break;
-  case SILC_COMMAND_UMODE:
-    /** UMODE */
-    silc_fsm_next(fsm, silc_client_command_reply_umode);
-    break;
-  case SILC_COMMAND_CMODE:
-    /** CMODE */
-    silc_fsm_next(fsm, silc_client_command_reply_cmode);
-    break;
-  case SILC_COMMAND_CUMODE:
-    /** CUMODE */
-    silc_fsm_next(fsm, silc_client_command_reply_cumode);
-    break;
-  case SILC_COMMAND_KICK:
-    /** KICK */
-    silc_fsm_next(fsm, silc_client_command_reply_kick);
-    break;
-  case SILC_COMMAND_BAN:
-    /** BAN */
-    silc_fsm_next(fsm, silc_client_command_reply_ban);
-    break;
-  case SILC_COMMAND_DETACH:
-    /** DETACH */
-    silc_fsm_next(fsm, silc_client_command_reply_detach);
-    break;
-  case SILC_COMMAND_WATCH:
-    /** WATCH */
-    silc_fsm_next(fsm, silc_client_command_reply_watch);
-    break;
-  case SILC_COMMAND_SILCOPER:
-    /** SILCOPER */
-    silc_fsm_next(fsm, silc_client_command_reply_silcoper);
-    break;
-  case SILC_COMMAND_LEAVE:
-    /** LEAVE */
-    silc_fsm_next(fsm, silc_client_command_reply_leave);
-    break;
-  case SILC_COMMAND_USERS:
-    /** USERS */
-    silc_fsm_next(fsm, silc_client_command_reply_users);
-    break;
-  case SILC_COMMAND_GETKEY:
-    /** GETKEY */
-    silc_fsm_next(fsm, silc_client_command_reply_getkey);
-    break;
-  case SILC_COMMAND_SERVICE:
-    /** SERVICE */
-    silc_fsm_next(fsm, silc_client_command_reply_service);
-    break;
-  default:
-    return SILC_FSM_FINISH;
-  }
-
-  return SILC_FSM_CONTINUE;
-}
-
-/* Completes command reply processing */
-
-SILC_FSM_STATE(silc_client_command_reply_processed)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcCommandPayload payload = state_context;
-
-  silc_command_payload_free(payload);
-
-  if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
-      SILC_STATUS_IS_ERROR(cmd->status))
-    return SILC_FSM_FINISH;
-
-  /* Add back to pending command reply list */
-  silc_mutex_lock(conn->internal->lock);
-  cmd->resolved = FALSE;
-  silc_list_add(conn->internal->pending_commands, cmd);
-  silc_mutex_unlock(conn->internal->lock);
-
-  /** Wait more command payloads */
-  silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
-}
-
-/******************************** WHOIS *************************************/
-
-/* Received reply for WHOIS command. */
-
-SILC_FSM_STATE(silc_client_command_reply_whois)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcClientEntry client_entry = NULL;
-  SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
-  SilcBufferStruct channels, ch_user_modes;
-  SilcBool has_channels = FALSE;
-  SilcDList channel_list = NULL;
-  SilcID id;
-  char *nickname = NULL, *username = NULL, *realname = NULL;
-  unsigned char *fingerprint, *tmp;
-
-  CHECK_STATUS("WHOIS: ");
-  CHECK_ARGS(5, 11);
-
-  /* Get Client ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get names */
-  nickname = silc_argument_get_arg_type(args, 3, NULL);
-  username = silc_argument_get_arg_type(args, 4, NULL);
-  realname = silc_argument_get_arg_type(args, 5, NULL);
-  if (!nickname || !username || !realname) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get joined channel list */
-  memset(&channels, 0, sizeof(channels));
-  tmp = silc_argument_get_arg_type(args, 6, &len);
-  if (tmp) {
-    has_channels = TRUE;
-    silc_buffer_set(&channels, tmp, len);
-
-    /* Get channel user mode list */
-    tmp = silc_argument_get_arg_type(args, 10, &len);
-    if (!tmp) {
-      ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-      goto out;
-    }
-    silc_buffer_set(&ch_user_modes, tmp, len);
-  }
-
-  /* Get user mode */
-  tmp = silc_argument_get_arg_type(args, 7, &len);
-  if (tmp)
-    SILC_GET32_MSB(mode, tmp);
-
-  /* Get idle time */
-  tmp = silc_argument_get_arg_type(args, 8, &len);
-  if (tmp)
-    SILC_GET32_MSB(idle, tmp);
-
-  /* Get fingerprint */
-  fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
-
-  /* Check if we have this client cached already. */
-  client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
-  if (!client_entry) {
-    SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
-    client_entry =
-      silc_client_add_client(client, conn, nickname, username, realname,
-                            &id.u.client_id, mode);
-    if (!client_entry) {
-      ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
-      goto out;
-    }
-    silc_client_ref_client(client, conn, client_entry);
-  } else {
-    silc_client_update_client(client, conn, client_entry,
-                             nickname, username, realname, mode);
-  }
-
-  silc_rwlock_wrlock(client_entry->internal.lock);
-
-  if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
-    memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
-
-  /* Get user attributes */
-  tmp = silc_argument_get_arg_type(args, 11, &len);
-  if (tmp) {
-    if (client_entry->attrs)
-      silc_attribute_payload_list_free(client_entry->attrs);
-    client_entry->attrs = silc_attribute_payload_parse(tmp, len);
-  }
-
-  silc_rwlock_unlock(client_entry->internal.lock);
-
-  /* Parse channel and channel user mode list */
-  if (has_channels) {
-    channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
-                                                  silc_buffer_len(&channels));
-    if (channel_list)
-      silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
-                        &umodes);
-  }
-
-  /* Notify application */
-  silc_client_command_callback(cmd, client_entry, nickname, username,
-                              realname, channel_list, mode, idle, fingerprint,
-                              umodes, client_entry->attrs);
-
-  silc_client_unref_client(client, conn, client_entry);
-  if (has_channels) {
-    silc_channel_payload_list_free(channel_list);
-    silc_free(umodes);
-  }
-
- out:
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/******************************** WHOWAS ************************************/
-
-/* Received reply for WHOWAS command. */
-
-SILC_FSM_STATE(silc_client_command_reply_whowas)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcClientEntry client_entry = NULL;
-  SilcID id;
-  char *nickname, *username;
-  char *realname = NULL;
-
-  CHECK_STATUS("WHOWAS: ");
-  CHECK_ARGS(4, 5);
-
-  /* Get Client ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get the client entry */
-  client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
-
-  /* Get names */
-  nickname = silc_argument_get_arg_type(args, 3, NULL);
-  username = silc_argument_get_arg_type(args, 4, NULL);
-  realname = silc_argument_get_arg_type(args, 5, NULL);
-  if (!nickname || !username) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Notify application. We don't save any history information to any
-     cache. Just pass the data to the application. */
-  silc_client_command_callback(cmd, client_entry, nickname, username,
-                              realname);
-
- out:
-  silc_client_unref_client(client, conn, client_entry);
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/******************************** IDENTIFY **********************************/
-
-/* Received reply for IDENTIFY command. */
-
-SILC_FSM_STATE(silc_client_command_reply_identify)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcClientEntry client_entry;
-  SilcServerEntry server_entry;
-  SilcChannelEntry channel_entry;
-  SilcUInt32 len;
-  SilcID id;
-  char *name = NULL, *info = NULL;
-
-  CHECK_STATUS("IDENTIFY: ");
-  CHECK_ARGS(2, 4);
-
-  /* Get the ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get names */
-  name = silc_argument_get_arg_type(args, 3, &len);
-  info = silc_argument_get_arg_type(args, 4, &len);
-
-  switch (id.type) {
-  case SILC_ID_CLIENT:
-    SILC_LOG_DEBUG(("Received client information"));
-
-    /* Check if we have this client cached already. */
-    client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
-    if (!client_entry) {
-      SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
-      client_entry =
-       silc_client_add_client(client, conn, name, info, NULL,
-                              &id.u.client_id, 0);
-      if (!client_entry) {
-       ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
-       goto out;
-      }
-      silc_client_ref_client(client, conn, client_entry);
-    } else {
-      silc_client_update_client(client, conn, client_entry,
-                               name, info, NULL, 0);
-    }
-
-    /* Notify application */
-    silc_client_command_callback(cmd, client_entry, name, info);
-    silc_client_unref_client(client, conn, client_entry);
-    break;
-
-  case SILC_ID_SERVER:
-    SILC_LOG_DEBUG(("Received server information"));
-
-    /* Check if we have this server cached already. */
-    server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
-    if (!server_entry) {
-      SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
-      server_entry = silc_client_add_server(client, conn, name, info,
-                                           &id.u.server_id);
-      if (!server_entry) {
-       ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-       goto out;
-      }
-      silc_client_ref_server(client, conn, server_entry);
-    } else {
-      silc_client_update_server(client, conn, server_entry, name, info);
-    }
-    server_entry->internal.resolve_cmd_ident = 0;
-
-    /* Notify application */
-    silc_client_command_callback(cmd, server_entry, name, info);
-    silc_client_unref_server(client, conn, server_entry);
-    break;
-
-  case SILC_ID_CHANNEL:
-    SILC_LOG_DEBUG(("Received channel information"));
-
-    /* Check if we have this channel cached already. */
-    channel_entry = silc_client_get_channel_by_id(client, conn,
-                                                 &id.u.channel_id);
-    if (!channel_entry) {
-      SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY)"));
-
-      if (!name) {
-       ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-       goto out;
-      }
-
-      /* Add new channel entry */
-      channel_entry = silc_client_add_channel(client, conn, name, 0,
-                                             &id.u.channel_id);
-      if (!channel_entry) {
-       ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-       goto out;
-      }
-      silc_client_ref_channel(client, conn, channel_entry);
-    }
-
-    /* Notify application */
-    silc_client_command_callback(cmd, channel_entry,
-                                channel_entry->channel_name, info);
-    silc_client_unref_channel(client, conn, channel_entry);
-    break;
-  }
-
- out:
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** NICK ************************************/
-
-/* Received reply for command NICK. */
-
-SILC_FSM_STATE(silc_client_command_reply_nick)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  unsigned char *nick, *idp;
-  SilcUInt32 len, idp_len;
-  SilcClientID old_client_id;
-  SilcID id;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot set nickname: ");
-  CHECK_ARGS(2, 3);
-
-  /* Take received Client ID */
-  idp = silc_argument_get_arg_type(args, 2, &idp_len);
-  if (!idp) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Take the new nickname */
-  nick = silc_argument_get_arg_type(args, 3, &len);
-  if (!nick) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  silc_rwlock_wrlock(conn->local_entry->internal.lock);
-
-  /* Change the nickname */
-  old_client_id = *conn->local_id;
-  if (!silc_client_change_nickname(client, conn, conn->local_entry,
-                                  nick, &id.u.client_id, idp, idp_len)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
-    silc_rwlock_unlock(conn->local_entry->internal.lock);
-    goto out;
-  }
-
-  silc_rwlock_unlock(conn->local_entry->internal.lock);
-
-  /* Notify application */
-  silc_client_command_callback(cmd, conn->local_entry,
-                              conn->local_entry->nickname, &old_client_id);
-
- out:
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** LIST ************************************/
-
-/* Received reply to the LIST command. */
-
-SILC_FSM_STATE(silc_client_command_reply_list)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  unsigned char *tmp, *name, *topic;
-  SilcUInt32 usercount = 0;
-  SilcChannelEntry channel_entry = NULL;
-  SilcID id;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot list channels: ");
-
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    /* There were no channels in the network. */
-    silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
-    silc_fsm_next(fsm, silc_client_command_reply_processed);
-    return SILC_FSM_CONTINUE;
-  }
-
-  CHECK_ARGS(3, 5);
-
-  name = silc_argument_get_arg_type(args, 3, NULL);
-  if (!name) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  topic = silc_argument_get_arg_type(args, 4, NULL);
-  tmp = silc_argument_get_arg_type(args, 5, NULL);
-  if (tmp)
-    SILC_GET32_MSB(usercount, tmp);
-
-  /* Check whether the channel exists, and add it to cache if it doesn't. */
-  channel_entry = silc_client_get_channel_by_id(client, conn,
-                                               &id.u.channel_id);
-  if (!channel_entry) {
-    /* Add new channel entry */
-    channel_entry = silc_client_add_channel(client, conn, name, 0,
-                                           &id.u.channel_id);
-    if (!channel_entry) {
-      ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-      goto out;
-    }
-    silc_client_ref_channel(client, conn, channel_entry);
-  }
-
-  /* Notify application */
-  silc_client_command_callback(cmd, channel_entry, channel_entry->channel_name,
-                              topic, usercount);
-
- out:
-  silc_client_unref_channel(client, conn, channel_entry);
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************* TOPIC ************************************/
-
-/* Received reply to topic command. */
-
-SILC_FSM_STATE(silc_client_command_reply_topic)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcChannelEntry channel = NULL;
-  char *topic;
-  SilcUInt32 len;
-  SilcID id;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot set topic: ");
-  CHECK_ARGS(2, 3);
-
-  /* Take Channel ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get the channel entry */
-  channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
-  if (!channel) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  silc_rwlock_wrlock(channel->internal.lock);
-
-  /* Take topic */
-  topic = silc_argument_get_arg_type(args, 3, &len);
-  if (topic) {
-    silc_free(channel->topic);
-    channel->topic = silc_memdup(topic, len);
-  }
-
-  silc_rwlock_unlock(channel->internal.lock);
-
-  /* Notify application */
-  silc_client_command_callback(cmd, channel, channel->topic);
-
- out:
-  silc_client_unref_channel(client, conn, channel);
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************* INVITE ***********************************/
-
-/* Received reply to invite command. */
-
-SILC_FSM_STATE(silc_client_command_reply_invite)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcChannelEntry channel = NULL;
-  unsigned char *tmp;
-  SilcUInt32 len;
-  SilcArgumentPayload invite_args = NULL;
-  SilcID id;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot invite: ");
-  CHECK_ARGS(2, 3);
-
-  /* Take Channel ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get the channel entry */
-  channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
-  if (!channel) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get the invite list */
-  tmp = silc_argument_get_arg_type(args, 3, &len);
-  if (tmp)
-    invite_args = silc_argument_list_parse(tmp, len);
-
-  /* Notify application */
-  silc_client_command_callback(cmd, channel, invite_args);
-
-  if (invite_args)
-    silc_argument_payload_free(invite_args);
-
- out:
-  silc_client_unref_channel(client, conn, channel);
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** KILL ************************************/
-
-/* Received reply to the KILL command. */
-
-SILC_FSM_STATE(silc_client_command_reply_kill)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcClientEntry client_entry;
-  SilcID id;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot kill: ");
-  CHECK_ARGS(2, 2);
-
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get the client entry, if exists */
-  client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
-
-  /* Notify application */
-  silc_client_command_callback(cmd, client_entry);
-
-  /* Remove the client */
-  if (client_entry) {
-    silc_client_remove_from_channels(client, conn, client_entry);
-    silc_client_del_client(client, conn, client_entry);
-    silc_client_unref_client(client, conn, client_entry);
-  }
-
- out:
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** INFO ************************************/
-
-/* Received reply to INFO command. We receive the server ID and some
-   information about the server user requested. */
-
-SILC_FSM_STATE(silc_client_command_reply_info)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcServerEntry server;
-  char *server_name, *server_info;
-  SilcID id;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot get info: ");
-  CHECK_ARGS(4, 4);
-
-  /* Get server ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get server name */
-  server_name = silc_argument_get_arg_type(args, 3, NULL);
-  if (!server_name) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get server info */
-  server_info = silc_argument_get_arg_type(args, 4, NULL);
-  if (!server_info) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* See whether we have this server cached. If not create it. */
-  server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
-  if (!server) {
-    SILC_LOG_DEBUG(("Add new server entry (INFO)"));
-    server = silc_client_add_server(client, conn, server_name,
-                                   server_info, &id.u.server_id);
-    if (!server)
-      goto out;
-    silc_client_ref_server(client, conn, server);
-  }
-
-  /* Notify application */
-  silc_client_command_callback(cmd, server, server->server_name,
-                              server->server_info);
-  silc_client_unref_server(client, conn, server);
-
- out:
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** STATS ***********************************/
-
-/* Received reply to STATS command. */
-
-SILC_FSM_STATE(silc_client_command_reply_stats)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcClientStats stats;
-  unsigned char *buf = NULL;
-  SilcUInt32 buf_len = 0;
-  SilcBufferStruct b;
-  SilcID id;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot get stats: ");
-  CHECK_ARGS(2, 3);
-
-  /* Get server ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get statistics structure */
-  memset(&stats, 0, sizeof(stats));
-  buf = silc_argument_get_arg_type(args, 3, &buf_len);
-  if (buf) {
-    silc_buffer_set(&b, buf, buf_len);
-    silc_buffer_unformat(&b,
-                        SILC_STR_UI_INT(&stats.starttime),
-                        SILC_STR_UI_INT(&stats.uptime),
-                        SILC_STR_UI_INT(&stats.my_clients),
-                        SILC_STR_UI_INT(&stats.my_channels),
-                        SILC_STR_UI_INT(&stats.my_server_ops),
-                        SILC_STR_UI_INT(&stats.my_router_ops),
-                        SILC_STR_UI_INT(&stats.cell_clients),
-                        SILC_STR_UI_INT(&stats.cell_channels),
-                        SILC_STR_UI_INT(&stats.cell_servers),
-                        SILC_STR_UI_INT(&stats.clients),
-                        SILC_STR_UI_INT(&stats.channels),
-                        SILC_STR_UI_INT(&stats.servers),
-                        SILC_STR_UI_INT(&stats.routers),
-                        SILC_STR_UI_INT(&stats.server_ops),
-                        SILC_STR_UI_INT(&stats.router_ops),
-                        SILC_STR_END);
-  }
-
-  /* Notify application */
-  silc_client_command_callback(cmd, &stats);
-
- out:
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** PING ************************************/
-
-/* Received reply to PING command. */
-
-SILC_FSM_STATE(silc_client_command_reply_ping)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcInt64 diff;
-
-  diff = silc_time() - SILC_PTR_TO_64(cmd->context);
-  if (cmd->verbose)
-    SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
-       "Ping reply from %s: %d second%s", conn->remote_host,
-       (int)diff, diff == 1 ? "" : "s");
-
-  /* Notify application */
-  silc_client_command_callback(cmd);
-
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** JOIN ************************************/
-
-/* Continue JOIN command reply processing after resolving unknown users */
-
-static void
-silc_client_command_reply_join_resolved(SilcClient client,
-                                       SilcClientConnection conn,
-                                       SilcStatus status,
-                                       SilcDList clients,
-                                       void *context)
-{
-  SilcClientCommandContext cmd = context;
-  SilcChannelEntry channel = cmd->context;
-  SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcUInt32 list_count;
-  unsigned char *tmp;
-  char msg[512];
-
-  if (!clients) {
-    silc_snprintf(msg, sizeof(msg), "Error resolving channel %s user list",
-                 channel->channel_name);
-    SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, msg);
-  } else {
-    tmp = silc_argument_get_arg_type(args, 12, NULL);
-    if (tmp) {
-      SILC_GET32_MSB(list_count, tmp);
-      if (list_count - silc_dlist_count(clients) > 5) {
-       silc_snprintf(msg, sizeof(msg),
-                     "Channel %s user list was not fully resolved. "
-                     "The channel may not be fully synced.",
-                     channel->channel_name);
-       SAY(client, conn, SILC_CLIENT_MESSAGE_WARNING, msg);
-      }
-    }
-  }
-
-  channel->internal.resolve_cmd_ident = 0;
-  silc_client_unref_channel(client, conn, channel);
-
-  SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
-}
-
-
-/* Received reply for JOIN command. */
-
-SILC_FSM_STATE(silc_client_command_reply_join)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcChannelEntry channel;
-  SilcUInt32 mode = 0, len, list_count;
-  char *topic, *tmp, *channel_name = NULL, *hmac;
-  const char *cipher;
-  SilcBufferStruct client_id_list, client_mode_list, keyp;
-  SilcHashTableList htl;
-  SilcID id;
-  int i;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot join channel: ");
-  CHECK_ARGS(9, 17);
-
-  /* Get channel name */
-  channel_name = silc_argument_get_arg_type(args, 2, NULL);
-  if (!channel_name) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get Channel ID */
-  if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Check whether we have this channel entry already. */
-  channel = silc_client_get_channel(client, conn, channel_name);
-  if (channel) {
-    if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
-      silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
-  } else {
-    /* Create new channel entry */
-    channel = silc_client_add_channel(client, conn, channel_name,
-                                     mode, &id.u.channel_id);
-    if (!channel) {
-      ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
-      goto out;
-    }
-    silc_client_ref_channel(client, conn, channel);
-  }
-
-  /* Get the list count */
-  tmp = silc_argument_get_arg_type(args, 12, &len);
-  if (!tmp || len != 4) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  SILC_GET32_MSB(list_count, tmp);
-
-  /* Get Client ID list */
-  tmp = silc_argument_get_arg_type(args, 13, &len);
-  if (!tmp) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  silc_buffer_set(&client_id_list, tmp, len);
-
-  /* Resolve users we do not know about */
-  if (!cmd->resolved) {
-    cmd->resolved = TRUE;
-    cmd->context = channel;
-    SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
-                 silc_client_get_clients_by_list(
-                         client, conn, list_count, &client_id_list,
-                         silc_client_command_reply_join_resolved, cmd));
-    /* NOT REACHED */
-  }
-
-  /* Get client mode list */
-  tmp = silc_argument_get_arg_type(args, 14, &len);
-  if (!tmp) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  silc_buffer_set(&client_mode_list, tmp, len);
-
-  silc_rwlock_wrlock(channel->internal.lock);
-
-  /* Add clients we received in the reply to the channel */
-  for (i = 0; i < list_count; i++) {
-    SilcUInt16 idp_len;
-    SilcID id;
-    SilcClientEntry client_entry;
-
-    /* Client ID */
-    SILC_GET16_MSB(idp_len, client_id_list.data + 2);
-    idp_len += 4;
-    if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
-      continue;
-
-    /* Mode */
-    SILC_GET32_MSB(mode, client_mode_list.data);
-
-    /* Get client entry */
-    client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
-    if (client_entry && client_entry->internal.valid) {
-      /* Join client to the channel */
-      silc_rwlock_wrlock(client_entry->internal.lock);
-      silc_client_add_to_channel(client, conn, channel, client_entry, mode);
-      silc_rwlock_unlock(client_entry->internal.lock);
-    }
-    silc_client_unref_client(client, conn, client_entry);
-
-    if (!silc_buffer_pull(&client_id_list, idp_len)) {
-      silc_rwlock_unlock(channel->internal.lock);
-      goto out;
-    }
-    if (!silc_buffer_pull(&client_mode_list, 4)) {
-      silc_rwlock_unlock(channel->internal.lock);
-      goto out;
-    }
-  }
-
-  /* Get hmac */
-  hmac = silc_argument_get_arg_type(args, 11, NULL);
-  if (hmac) {
-    if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
-      if (cmd->verbose)
-       SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
-           "Cannot join channel: Unsupported HMAC `%s'", hmac);
-      ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
-      silc_rwlock_unlock(channel->internal.lock);
-      goto out;
-    }
-  }
-
-  /* Get channel mode */
-  tmp = silc_argument_get_arg_type(args, 5, &len);
-  if (tmp && len == 4)
-    SILC_GET32_MSB(mode, tmp);
-  channel->mode = mode;
-
-  /* Get channel key and save it */
-  tmp = silc_argument_get_arg_type(args, 7, &len);
-  if (tmp) {
-    /* If channel key already exists on the channel then while resolving
-       the user list we have already received new key from server.  Don't
-       replace it with this old key. */
-    if (!channel->internal.send_key) {
-      silc_buffer_set(&keyp, tmp, len);
-      silc_client_save_channel_key(client, conn, &keyp, channel);
-    }
-  }
-
-  /* Get topic */
-  topic = silc_argument_get_arg_type(args, 10, NULL);
-  if (topic) {
-    silc_free(channel->topic);
-    channel->topic = silc_memdup(topic, strlen(topic));
-  }
-
-  /* Get founder key */
-  tmp = silc_argument_get_arg_type(args, 15, &len);
-  if (tmp) {
-    if (channel->founder_key)
-      silc_pkcs_public_key_free(channel->founder_key);
-    channel->founder_key = NULL;
-    silc_public_key_payload_decode(tmp, len, &channel->founder_key);
-  }
-
-  /* Get user limit */
-  tmp = silc_argument_get_arg_type(args, 17, &len);
-  if (tmp && len == 4)
-    SILC_GET32_MSB(channel->user_limit, tmp);
-  if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
-    channel->user_limit = 0;
-
-  /* Get channel public key list */
-  tmp = silc_argument_get_arg_type(args, 16, &len);
-  if (tmp)
-    silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
-
-  /* Set current channel */
-  conn->current_channel = channel;
-
-  silc_rwlock_unlock(channel->internal.lock);
-
-  cipher = (channel->internal.send_key ?
-           silc_cipher_get_name(channel->internal.send_key) : NULL);
-  silc_hash_table_list(channel->user_list, &htl);
-
-  /* Notify application */
-  silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl,
-                              topic, cipher, hmac, channel->founder_key,
-                              channel->channel_pubkeys, channel->user_limit);
-
-  silc_hash_table_list_reset(&htl);
-  silc_client_unref_channel(client, conn, channel);
-
- out:
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** MOTD ************************************/
-
-/* Received reply for MOTD command */
-
-SILC_FSM_STATE(silc_client_command_reply_motd)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcUInt32 i;
-  char *motd = NULL, *cp, line[256];
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot get motd: ");
-  CHECK_ARGS(2, 3);
-
-  if (silc_argument_get_arg_num(args) == 3) {
-    motd = silc_argument_get_arg_type(args, 3, NULL);
-    if (!motd) {
-      ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-      goto out;
-    }
-
-    i = 0;
-    cp = motd;
-    while(cp[i] != 0) {
-      if (cp[i++] == '\n') {
-       memset(line, 0, sizeof(line));
-       silc_strncat(line, sizeof(line), cp, i - 1);
-       cp += i;
-
-       if (i == 2)
-         line[0] = ' ';
-
-       if (cmd->verbose)
-         SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
-
-       if (!strlen(cp))
-         break;
-       i = 0;
-      }
-    }
-  }
-
-  /* Notify application */
-  silc_client_command_callback(cmd, motd);
-
- out:
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** UMODE ***********************************/
-
-/* Received reply to the UMODE command. Save the current user mode */
-
-SILC_FSM_STATE(silc_client_command_reply_umode)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  unsigned char *tmp;
-  SilcUInt32 mode, len;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot change mode: ");
-  CHECK_ARGS(2, 2);
-
-  tmp = silc_argument_get_arg_type(args, 2, &len);
-  if (!tmp || len != 4) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  SILC_GET32_MSB(mode, tmp);
-  silc_rwlock_wrlock(conn->local_entry->internal.lock);
-  conn->local_entry->mode = mode;
-  silc_rwlock_unlock(conn->local_entry->internal.lock);
-
-  /* Notify application */
-  silc_client_command_callback(cmd, mode);
-
- out:
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** CMODE ***********************************/
-
-/* Received reply for CMODE command. */
-
-SILC_FSM_STATE(silc_client_command_reply_cmode)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  unsigned char *tmp;
-  SilcUInt32 mode;
-  SilcChannelEntry channel = NULL;
-  SilcUInt32 len;
-  SilcPublicKey public_key = NULL;
-  SilcID id;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot change mode: ");
-  CHECK_ARGS(3, 6);
-
-  /* Take Channel ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get the channel entry */
-  channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
-  if (!channel) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get founder public key */
-  tmp = silc_argument_get_arg_type(args, 4, &len);
-  if (tmp)
-    silc_public_key_payload_decode(tmp, len, &public_key);
-
-  /* Get channel mode */
-  tmp = silc_argument_get_arg_type(args, 3, &len);
-  if (!tmp || len != 4) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  SILC_GET32_MSB(mode, tmp);
-
-  silc_rwlock_wrlock(channel->internal.lock);
-
-  /* Get user limit */
-  tmp = silc_argument_get_arg_type(args, 6, &len);
-  if (tmp && len == 4)
-    SILC_GET32_MSB(channel->user_limit, tmp);
-  if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
-    channel->user_limit = 0;
-
-  /* Get channel public key(s) */
-  tmp = silc_argument_get_arg_type(args, 5, &len);
-  if (tmp)
-    silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
-  else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
-    silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
-
-  /* Save the mode */
-  channel->mode = mode;
-
-  silc_rwlock_unlock(channel->internal.lock);
-
-  /* Notify application */
-  silc_client_command_callback(cmd, channel, mode, public_key,
-                              channel->channel_pubkeys, channel->user_limit);
-
-  silc_rwlock_wrlock(channel->internal.lock);
-
-  /* If founder key changed, update it */
-  if (public_key &&
-      (!channel->founder_key ||
-       !silc_pkcs_public_key_compare(public_key, channel->founder_key))) {
-    if (channel->founder_key)
-      silc_pkcs_public_key_free(channel->founder_key);
-    channel->founder_key = public_key;
-    public_key = NULL;
-  }
-
-  silc_rwlock_unlock(channel->internal.lock);
-
- out:
-  silc_client_unref_channel(client, conn, channel);
-  if (public_key)
-    silc_pkcs_public_key_free(public_key);
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** CUMODE **********************************/
-
-/* Received reply for CUMODE command */
-
-SILC_FSM_STATE(silc_client_command_reply_cumode)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcClientEntry client_entry;
-  SilcChannelEntry channel = NULL;
-  SilcChannelUser chu;
-  unsigned char *modev;
-  SilcUInt32 len, mode;
-  SilcID id;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot change mode: ");
-  CHECK_ARGS(4, 4);
-
-  /* Get channel mode */
-  modev = silc_argument_get_arg_type(args, 2, &len);
-  if (!modev || len != 4) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  SILC_GET32_MSB(mode, modev);
-
-  /* Take Channel ID */
-  if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get the channel entry */
-  channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
-  if (!channel) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get Client ID */
-  if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get client entry */
-  client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
-  if (!client_entry) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Save the mode */
-  silc_rwlock_wrlock(channel->internal.lock);
-  chu = silc_client_on_channel(channel, client_entry);
-  if (chu)
-    chu->mode = mode;
-  silc_rwlock_unlock(channel->internal.lock);
-
-  /* Notify application */
-  silc_client_command_callback(cmd, mode, channel, client_entry);
-
-  silc_client_unref_client(client, conn, client_entry);
-
- out:
-  silc_client_unref_channel(client, conn, channel);
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** KICK ************************************/
-
-SILC_FSM_STATE(silc_client_command_reply_kick)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcClientEntry client_entry;
-  SilcChannelEntry channel = NULL;
-  SilcID id;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot kick: ");
-  CHECK_ARGS(3, 3);
-
-  /* Take Channel ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get the channel entry */
-  channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
-  if (!channel) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get Client ID */
-  if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get client entry */
-  client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
-  if (!client_entry) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Notify application */
-  silc_client_command_callback(cmd, channel, client_entry);
-
-  silc_client_unref_client(client, conn, client_entry);
-
- out:
-  silc_client_unref_channel(client, conn, channel);
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/******************************** SILCOPER **********************************/
-
-SILC_FSM_STATE(silc_client_command_reply_silcoper)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot change mode: ");
-  CHECK_ARGS(1, 1);
-
-  /* Set user mode */
-  cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
-
-  /* Notify application */
-  silc_client_command_callback(cmd);
-
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** OPER ************************************/
-
-SILC_FSM_STATE(silc_client_command_reply_oper)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot change mode: ");
-  CHECK_ARGS(1, 1);
-
-  /* Set user mode */
-  cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
-
-  /* Notify application */
-  silc_client_command_callback(cmd);
-
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************* DETACH ***********************************/
-
-SILC_FSM_STATE(silc_client_command_reply_detach)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcBuffer detach;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot detach: ");
-  CHECK_ARGS(1, 1);
-
-  /* Get detachment data */
-  detach = silc_client_get_detach_data(client, conn);
-  if (!detach) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
-    goto out;
-  }
-
-  /* Notify application */
-  silc_client_command_callback(cmd, detach);
-  silc_buffer_free(detach);
-
- out:
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** WATCH ***********************************/
-
-SILC_FSM_STATE(silc_client_command_reply_watch)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot set watch: ");
-  CHECK_ARGS(1, 1);
-
-  /* Notify application */
-  silc_client_command_callback(cmd);
-
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/*********************************** BAN ************************************/
-
-SILC_FSM_STATE(silc_client_command_reply_ban)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcChannelEntry channel = NULL;
-  unsigned char *tmp;
-  SilcUInt32 len;
-  SilcArgumentPayload invite_args = NULL;
-  SilcID id;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot set ban: ");
-  CHECK_ARGS(2, 3);
-
-  /* Take Channel ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get the channel entry */
-  channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
-  if (!channel) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get the invite list */
-  tmp = silc_argument_get_arg_type(args, 3, &len);
-  if (tmp)
-    invite_args = silc_argument_list_parse(tmp, len);
-
-  /* Notify application */
-  silc_client_command_callback(cmd, channel, invite_args);
-
-  if (invite_args)
-    silc_argument_payload_free(invite_args);
-
- out:
-  silc_client_unref_channel(client, conn, channel);
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** LEAVE ***********************************/
-
-/* Reply to LEAVE command. */
-
-SILC_FSM_STATE(silc_client_command_reply_leave)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcChannelEntry channel;
-  SilcCipher key;
-  SilcHmac hmac;
-  SilcID id;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot set leave: ");
-  CHECK_ARGS(2, 2);
-
-  /* Get Channel ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get the channel entry */
-  channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
-  if (!channel) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Remove us from this channel. */
-  silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
-
-  /* Notify application */
-  silc_client_command_callback(cmd, channel);
-
-  /* Remove old keys and stuff.  The channel may remain even after leaving
-     but we want to remove these always. */
-  if (channel->internal.send_key)
-    silc_cipher_free(channel->internal.send_key);
-  channel->internal.send_key = NULL;
-  if (channel->internal.receive_key)
-    silc_cipher_free(channel->internal.receive_key);
-  channel->internal.receive_key = NULL;
-  if (channel->internal.hmac)
-    silc_hmac_free(channel->internal.hmac);
-  channel->internal.hmac = NULL;
-  if (channel->internal.old_channel_keys) {
-    silc_dlist_start(channel->internal.old_channel_keys);
-    while ((key = silc_dlist_get(channel->internal.old_channel_keys)))
-      silc_cipher_free(key);
-    silc_dlist_uninit(channel->internal.old_channel_keys);
-  }
-  channel->internal.old_channel_keys = NULL;
-  if (channel->internal.old_hmacs) {
-    silc_dlist_start(channel->internal.old_hmacs);
-    while ((hmac = silc_dlist_get(channel->internal.old_hmacs)))
-      silc_hmac_free(hmac);
-    silc_dlist_uninit(channel->internal.old_hmacs);
-  }
-  channel->internal.old_hmacs = NULL;
-
-  /* Now delete the channel. */
-  silc_client_empty_channel(client, conn, channel);
-  silc_client_del_channel(client, conn, channel);
-
- out:
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************* USERS ************************************/
-
-/* Continue USERS command reply processing after resolving unknown users */
-
-static void
-silc_client_command_reply_users_resolved(SilcClient client,
-                                        SilcClientConnection conn,
-                                        SilcStatus status,
-                                        SilcDList clients,
-                                        void *context)
-{
-  SilcClientCommandContext cmd = context;
-  SILC_FSM_CALL_CONTINUE(&cmd->thread);
-}
-
-
-/* Continue USERS command after resolving unknown channel */
-
-static void
-silc_client_command_reply_users_continue(SilcClient client,
-                                        SilcClientConnection conn,
-                                        SilcStatus status,
-                                        SilcDList channels,
-                                        void *context)
-{
-  SilcClientCommandContext cmd = context;
-
-  if (!channels) {
-    SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
-    SilcArgumentPayload args = silc_command_get_args(payload);
-
-    cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
-    ERROR_CALLBACK(cmd->status);
-    silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
-  }
-
-  SILC_FSM_CALL_CONTINUE(&cmd->thread);
-}
-
-/* Reply to USERS command. Received list of client ID's and theirs modes
-   on the channel we requested. */
-
-SILC_FSM_STATE(silc_client_command_reply_users)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  unsigned char *tmp;
-  SilcUInt32 tmp_len, list_count, mode;
-  SilcUInt16 idp_len;
-  SilcHashTableList htl;
-  SilcBufferStruct client_id_list, client_mode_list;
-  SilcChannelEntry channel = NULL;
-  SilcClientEntry client_entry;
-  SilcID id;
-  int i;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot get users: ");
-  CHECK_ARGS(5, 5);
-
-  /* Get channel ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get channel entry */
-  channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
-  if (!channel) {
-    /* Resolve the channel from server */
-    SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
-                       client, conn, &id.u.channel_id,
-                       silc_client_command_reply_users_continue, cmd));
-    /* NOT REACHED */
-  }
-
-  /* Get the list count */
-  tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
-  if (!tmp || tmp_len != 4) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  SILC_GET32_MSB(list_count, tmp);
-
-  /* Get Client ID list */
-  tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
-  if (!tmp) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  silc_buffer_set(&client_id_list, tmp, tmp_len);
-
-  /* Resolve users we do not know about */
-  if (!cmd->resolved) {
-    cmd->resolved = TRUE;
-    silc_client_unref_channel(client, conn, channel);
-    SILC_FSM_CALL(silc_client_get_clients_by_list(
-                         client, conn, list_count, &client_id_list,
-                         silc_client_command_reply_users_resolved, cmd));
-    /* NOT REACHED */
-  }
-
-  /* Get client mode list */
-  tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
-  if (!tmp) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  silc_buffer_set(&client_mode_list, tmp, tmp_len);
-
-  SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
-
-  silc_rwlock_wrlock(channel->internal.lock);
-
-  /* Cache the received Client ID's and modes. */
-  for (i = 0; i < list_count; i++) {
-    SILC_GET16_MSB(idp_len, client_id_list.data + 2);
-    idp_len += 4;
-    if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
-      goto out;
-
-    /* Mode */
-    SILC_GET32_MSB(mode, client_mode_list.data);
-
-    /* Save the client on this channel.  Unknown clients are ignored as they
-       clearly do not exist since the resolving didn't find them. */
-    client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
-    if (client_entry && client_entry->internal.valid) {
-      silc_rwlock_wrlock(client_entry->internal.lock);
-      silc_client_add_to_channel(client, conn, channel, client_entry, mode);
-      silc_rwlock_unlock(client_entry->internal.lock);
-    }
-    silc_client_unref_client(client, conn, client_entry);
-
-    if (!silc_buffer_pull(&client_id_list, idp_len)) {
-      silc_rwlock_unlock(channel->internal.lock);
-      goto out;
-    }
-    if (!silc_buffer_pull(&client_mode_list, 4)) {
-      silc_rwlock_unlock(channel->internal.lock);
-      goto out;
-    }
-  }
-
-  silc_rwlock_unlock(channel->internal.lock);
-
-  /* Notify application */
-  silc_hash_table_list(channel->user_list, &htl);
-  silc_client_command_callback(cmd, channel, &htl);
-  silc_hash_table_list_reset(&htl);
-
- out:
-  silc_client_unref_channel(client, conn, channel);
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** GETKEY **********************************/
-
-/* Received command reply to GETKEY command. WE've received the remote
-   client's public key. */
-
-SILC_FSM_STATE(silc_client_command_reply_getkey)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcClientEntry client_entry;
-  SilcServerEntry server_entry;
-  unsigned char *tmp;
-  SilcUInt32 len;
-  SilcPublicKey public_key;
-  SilcID id;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot get key: ");
-  CHECK_ARGS(2, 3);
-
-  /* Get the ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  /* Get the public key */
-  tmp = silc_argument_get_arg_type(args, 3, &len);
-  if (!tmp) {
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
-    SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
-        "Cannot decode public key: malformed/unsupported public key");
-    ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-
-  if (id.type == SILC_ID_CLIENT) {
-    /* Received client's public key */
-    client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
-    if (!client_entry) {
-      ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-      goto out;
-    }
-
-    silc_rwlock_wrlock(client_entry->internal.lock);
-
-    /* Save fingerprint */
-    if (!client_entry->fingerprint)
-      silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
-                    client_entry->fingerprint);
-    if (!client_entry->public_key) {
-      client_entry->public_key = public_key;
-      public_key = NULL;
-    }
-
-    silc_rwlock_unlock(client_entry->internal.lock);
-
-    /* Notify application */
-    silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
-                                client_entry->public_key);
-    silc_client_unref_client(client, conn, client_entry);
-  } else if (id.type == SILC_ID_SERVER) {
-    /* Received server's public key */
-    server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
-    if (!server_entry) {
-      ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-      goto out;
-    }
-
-    silc_rwlock_wrlock(server_entry->internal.lock);
-
-    if (!server_entry->public_key) {
-      server_entry->public_key = public_key;
-      public_key = NULL;
-    }
-
-    silc_rwlock_unlock(server_entry->internal.lock);
-
-    /* Notify application */
-    silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
-                                server_entry->public_key);
-    silc_client_unref_server(client, conn, server_entry);
-  }
-
- out:
-  if (public_key)
-    silc_pkcs_public_key_free(public_key);
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/********************************** SERVICE *********************************/
-
-/* Reply to SERVICE command. */
-/* XXX incomplete */
-
-SILC_FSM_STATE(silc_client_command_reply_service)
-{
-  SilcClientCommandContext cmd = fsm_context;
-  SilcCommandPayload payload = state_context;
-  SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcUInt32 tmp_len;
-  unsigned char *service_list, *name;
-
-  /* Sanity checks */
-  CHECK_STATUS("Cannot get service: ");
-
-  /* Get service list */
-  service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
-
-  /* Get requested service name */
-  name = silc_argument_get_arg_type(args, 3, &tmp_len);
-
-  /* Notify application */
-  silc_client_command_callback(cmd, service_list, name);
-
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}
-
-/*********************************** QUIT ***********************************/
-
-/* QUIT command reply stub */
-
-SILC_FSM_STATE(silc_client_command_reply_quit)
-{
-  silc_fsm_next(fsm, silc_client_command_reply_processed);
-  return SILC_FSM_CONTINUE;
-}