Added connection authentication request support.
[silc.git] / lib / silcclient / command.c
index 7ffa52fa36f471a90d84ecfcb6f5014447a41bfb..91f35f3275c194e51d47a2d46491bde70d96ce8b 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2006 Pekka Riikonen
+  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
@@ -68,7 +68,7 @@ static SilcUInt16 silc_client_cmd_ident(SilcClientConnection conn)
 SILC_FSM_STATE(silc_client_command_continue_error)
 {
   /* Destructor will free all resources */
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }
 
 /* Command reply callback to continue with the execution of a command.
@@ -119,9 +119,6 @@ static void silc_client_command_resolve_continue(SilcClient client,
   if (status != SILC_STATUS_OK)
     silc_fsm_next(&cmd->thread, silc_client_command_continue_error);
 
-  if (clients)
-    silc_dlist_uninit(clients);
-
   /* Continue with the command */
   SILC_FSM_CALL_CONTINUE(&cmd->thread);
 }
@@ -203,7 +200,14 @@ static void silc_client_command_destructor(SilcFSMThread thread,
                                           void *fsm_context,
                                           void *destructor_context)
 {
-  silc_client_command_free(fsm_context);
+  SilcClientCommandContext cmd = fsm_context;
+  SilcClientConnection conn = cmd->conn;
+
+  /* Removes commands that aren't waiting for reply but are waiting
+     for something.  They may not have been removed yet. */
+  silc_list_del(conn->internal->pending_commands, cmd);
+
+  silc_client_command_free(cmd);
 }
 
 /* Add a command pending a command reply.  Used internally by the library. */
@@ -254,6 +258,9 @@ static SilcUInt16 silc_client_command_send_vap(SilcClient client,
 
   SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
 
+  if (conn->internal->disconnected)
+    return 0;
+
   if (!cmd->cmd_ident)
     cmd->cmd_ident = silc_client_cmd_ident(conn);
 
@@ -297,6 +304,9 @@ silc_client_command_send_arg_array(SilcClient client,
 
   SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
 
+  if (conn->internal->disconnected)
+    return 0;
+
   if (!cmd->cmd_ident)
     cmd->cmd_ident = silc_client_cmd_ident(conn);
 
@@ -352,12 +362,6 @@ void silc_client_command_free(SilcClientCommandContext cmd)
   SilcClientCommandReplyCallback cb;
   int i;
 
-  /* If command is running, finish it.  Destructor will free the context. */
-  if (silc_fsm_is_started(&cmd->thread)) {
-    silc_fsm_finish(&cmd->thread);
-    return;
-  }
-
   for (i = 0; i < cmd->argc; i++)
     silc_free(cmd->argv[i]);
   silc_free(cmd->argv);
@@ -619,7 +623,7 @@ SILC_FSM_STATE(silc_client_command_whois)
 
     /** Wait for command reply */
     silc_fsm_next(fsm, silc_client_command_reply_wait);
-    return SILC_FSM_CONTINUE;
+    SILC_FSM_CONTINUE;
   }
 
   for (i = 1; i < cmd->argc; i++) {
@@ -710,10 +714,10 @@ SILC_FSM_STATE(silc_client_command_whois)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 
  out:
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }
 
 /******************************** WHOWAS ************************************/
@@ -733,7 +737,7 @@ SILC_FSM_STATE(silc_client_command_whowas)
        "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
     COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
                   SILC_STATUS_ERR_TOO_MANY_PARAMS));
-    return SILC_FSM_FINISH;
+    SILC_FSM_FINISH;
   }
 
   if (cmd->argc == 2) {
@@ -752,7 +756,7 @@ SILC_FSM_STATE(silc_client_command_whowas)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /******************************** IDENTIFY **********************************/
@@ -768,7 +772,7 @@ SILC_FSM_STATE(silc_client_command_identify)
   int c;
 
   if (cmd->argc < 2 || cmd->argc > 3)
-    return SILC_FSM_FINISH;
+    SILC_FSM_FINISH;
 
   if (cmd->argc == 2) {
     silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
@@ -783,7 +787,7 @@ SILC_FSM_STATE(silc_client_command_identify)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /********************************** NICK ************************************/
@@ -833,10 +837,10 @@ SILC_FSM_STATE(silc_client_command_nick)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 
  out:
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }
 
 /********************************** LIST ************************************/
@@ -847,7 +851,8 @@ SILC_FSM_STATE(silc_client_command_list)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
-  SilcChannelEntry channel;
+  SilcClient client = conn->client;
+  SilcChannelEntry channel = NULL;
   SilcBuffer idp = NULL;
 
   if (cmd->argc == 2) {
@@ -864,13 +869,14 @@ SILC_FSM_STATE(silc_client_command_list)
                                1, 1, silc_buffer_datalen(idp));
 
   silc_buffer_free(idp);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /********************************** TOPIC ***********************************/
@@ -881,6 +887,7 @@ SILC_FSM_STATE(silc_client_command_topic)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
+  SilcClient client = conn->client;
   SilcChannelEntry channel;
   SilcBuffer idp;
   char *name;
@@ -927,16 +934,17 @@ SILC_FSM_STATE(silc_client_command_topic)
                                1, silc_buffer_datalen(idp));
 
   silc_buffer_free(idp);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 
  out:
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }
 
 /********************************* INVITE ***********************************/
@@ -950,7 +958,7 @@ SILC_FSM_STATE(silc_client_command_invite)
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
   SilcClientEntry client_entry = NULL;
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   SilcBuffer clidp, chidp, args = NULL;
   SilcPublicKey pubkey = NULL;
   SilcDList clients = NULL;
@@ -973,6 +981,7 @@ SILC_FSM_STATE(silc_client_command_invite)
     }
 
     channel = conn->current_channel;
+    silc_client_ref_channel(client, conn, channel);
   } else {
     name = cmd->argv[1];
 
@@ -986,10 +995,7 @@ SILC_FSM_STATE(silc_client_command_invite)
   /* Parse the typed nickname. */
   if (cmd->argc == 3) {
     if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
-      if (client->internal->params->nickname_parse)
-       client->internal->params->nickname_parse(cmd->argv[2], &nickname);
-      else
-       nickname = strdup(cmd->argv[2]);
+      silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
 
       /* Find client entry */
       clients = silc_client_get_clients_local(client, conn, nickname,
@@ -1054,17 +1060,18 @@ SILC_FSM_STATE(silc_client_command_invite)
   silc_buffer_free(args);
   silc_free(nickname);
   silc_client_list_free(client, conn, clients);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 
  out:
   silc_free(nickname);
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }
 
 /********************************** QUIT ************************************/
@@ -1077,20 +1084,24 @@ SILC_FSM_STATE(silc_client_command_quit_final)
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
 
+  SILC_LOG_DEBUG(("Quitting"));
+
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
   /* Call connection callback */
-  conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED,
-                0, NULL, conn->callback_context);
+  if (!conn->internal->callback_called)
+    conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED,
+                  0, NULL, conn->callback_context);
+  conn->internal->callback_called = TRUE;
 
   /* Signal to close connection */
   if (!conn->internal->disconnected) {
     conn->internal->disconnected = TRUE;
-    SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+    SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
   }
 
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }
 
 /* Command QUIT. Closes connection with current server. */
@@ -1111,7 +1122,7 @@ SILC_FSM_STATE(silc_client_command_quit)
 
   /* We close the connection with a little timeout */
   silc_fsm_next_later(fsm, silc_client_command_quit_final, 2, 0);
-  return SILC_FSM_WAIT;
+  SILC_FSM_WAIT;
 }
 
 /********************************** KILL ************************************/
@@ -1134,16 +1145,12 @@ SILC_FSM_STATE(silc_client_command_kill)
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /KILL <nickname> [<comment>] [-pubkey]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    return SILC_FSM_FINISH;
+    SILC_FSM_FINISH;
   }
 
   /* Parse the typed nickname. */
-  if (client->internal->params->nickname_parse)
-    client->internal->params->nickname_parse(cmd->argv[1], &nickname);
-  else
-    nickname = strdup(cmd->argv[1]);
-  if (!nickname)
-    return SILC_FSM_FINISH;
+  if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname))
+    SILC_FSM_FINISH;
 
   /* Get the target client */
   clients = silc_client_get_clients_local(client, conn, nickname,
@@ -1188,7 +1195,7 @@ SILC_FSM_STATE(silc_client_command_kill)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /********************************** INFO ************************************/
@@ -1213,7 +1220,7 @@ SILC_FSM_STATE(silc_client_command_info)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /********************************** STATS ***********************************/
@@ -1235,7 +1242,7 @@ SILC_FSM_STATE(silc_client_command_stats)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /********************************** PING ************************************/
@@ -1249,7 +1256,7 @@ SILC_FSM_STATE(silc_client_command_ping)
 
   if (cmd->argc < 2) {
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    return SILC_FSM_FINISH;
+    SILC_FSM_FINISH;
   }
 
   /* Send the command */
@@ -1265,7 +1272,7 @@ SILC_FSM_STATE(silc_client_command_ping)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /********************************** JOIN ************************************/
@@ -1276,7 +1283,8 @@ SILC_FSM_STATE(silc_client_command_join)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
-  SilcChannelEntry channel;
+  SilcClient client = conn->client;
+  SilcChannelEntry channel = NULL;
   SilcBuffer auth = NULL, cauth = NULL;
   char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
   int i, passphrase_len = 0;
@@ -1374,16 +1382,18 @@ SILC_FSM_STATE(silc_client_command_join)
   if (passphrase)
     memset(passphrase, 0, strlen(passphrase));
   silc_free(passphrase);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 
  out:
-  return SILC_FSM_FINISH;
+  silc_client_unref_channel(client, conn, channel);
+  SILC_FSM_FINISH;
 }
 
 /********************************** MOTD ************************************/
@@ -1400,7 +1410,7 @@ SILC_FSM_STATE(silc_client_command_motd)
        "Usage: /MOTD [<server>]");
     COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
                   SILC_STATUS_ERR_TOO_MANY_PARAMS));
-    return SILC_FSM_FINISH;
+    SILC_FSM_FINISH;
   }
 
   /* Send the command */
@@ -1417,7 +1427,7 @@ SILC_FSM_STATE(silc_client_command_motd)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /********************************** UMODE ***********************************/
@@ -1437,7 +1447,7 @@ SILC_FSM_STATE(silc_client_command_umode)
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /UMODE +|-<modes>");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    return SILC_FSM_FINISH;
+    SILC_FSM_FINISH;
   }
 
   mode = conn->local_entry->mode;
@@ -1538,7 +1548,7 @@ SILC_FSM_STATE(silc_client_command_umode)
       break;
     default:
       COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
-      return SILC_FSM_FINISH;
+      SILC_FSM_FINISH;
       break;
     }
   }
@@ -1556,7 +1566,7 @@ SILC_FSM_STATE(silc_client_command_umode)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /********************************** CMODE ***********************************/
@@ -1570,7 +1580,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   SilcBuffer chidp, auth = NULL, pk = NULL;
   unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
   SilcUInt32 mode, add, type, len, arg_len = 0;
@@ -1590,6 +1600,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
     }
 
     channel = conn->current_channel;
+    silc_client_ref_channel(client, conn, channel);
   } else {
     name = cmd->argv[1];
 
@@ -1843,16 +1854,18 @@ SILC_FSM_STATE(silc_client_command_cmode)
   silc_buffer_free(chidp);
   silc_buffer_free(auth);
   silc_buffer_free(pk);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 
  out:
-  return SILC_FSM_FINISH;
+  silc_client_unref_channel(client, conn, channel);
+  SILC_FSM_FINISH;
 }
 
 /********************************* CUMODE ***********************************/
@@ -1864,7 +1877,7 @@ SILC_FSM_STATE(silc_client_command_cumode)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   SilcChannelUser chu;
   SilcClientEntry client_entry;
   SilcBuffer clidp, chidp, auth = NULL;
@@ -1888,6 +1901,7 @@ SILC_FSM_STATE(silc_client_command_cumode)
     }
 
     channel = conn->current_channel;
+    silc_client_ref_channel(client, conn, channel);
   } else {
     name = cmd->argv[1];
 
@@ -1899,10 +1913,7 @@ SILC_FSM_STATE(silc_client_command_cumode)
   }
 
   /* Parse the typed nickname. */
-  if (client->internal->params->nickname_parse)
-    client->internal->params->nickname_parse(cmd->argv[3], &nickname);
-  else
-    nickname = strdup(cmd->argv[3]);
+  silc_client_nickname_parse(client, conn, cmd->argv[3], &nickname);
 
   /* Find client entry */
   clients = silc_client_get_clients_local(client, conn, nickname,
@@ -2025,18 +2036,20 @@ SILC_FSM_STATE(silc_client_command_cumode)
     silc_buffer_free(auth);
   silc_free(nickname);
   silc_client_list_free(client, conn, clients);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 
  out:
+  silc_client_unref_channel(client, conn, channel);
   silc_client_list_free(client, conn, clients);
   silc_free(nickname);
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }
 
 /********************************** KICK ************************************/
@@ -2048,7 +2061,7 @@ SILC_FSM_STATE(silc_client_command_kick)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   SilcBuffer idp, idp2;
   SilcClientEntry target;
   SilcDList clients = NULL;
@@ -2085,10 +2098,7 @@ SILC_FSM_STATE(silc_client_command_kick)
   }
 
   /* Parse the typed nickname. */
-  if (client->internal->params->nickname_parse)
-    client->internal->params->nickname_parse(cmd->argv[2], &nickname);
-  else
-    nickname = strdup(cmd->argv[2]);
+  silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
 
   /* Get the target client */
   clients = silc_client_get_clients_local(client, conn, nickname,
@@ -2118,17 +2128,19 @@ SILC_FSM_STATE(silc_client_command_kick)
   silc_buffer_free(idp2);
   silc_free(nickname);
   silc_client_list_free(client, conn, clients);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 
  out:
+  silc_client_unref_channel(client, conn, channel);
   silc_free(nickname);
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }
 
 /***************************** OPER & SILCOPER ******************************/
@@ -2193,7 +2205,7 @@ SILC_FSM_STATE(silc_client_command_oper_send)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /* OPER command. Used to obtain server operator privileges. */
@@ -2208,14 +2220,14 @@ SILC_FSM_STATE(silc_client_command_oper)
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /OPER <username> [-pubkey]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    return SILC_FSM_FINISH;
+    SILC_FSM_FINISH;
   }
 
   /* Get passphrase */
   if (cmd->argc < 3) {
     oper = silc_calloc(1, sizeof(*oper));
     if (!oper)
-      return SILC_FSM_FINISH;
+      SILC_FSM_FINISH;
     cmd->context = oper;
     SILC_FSM_CALL(conn->client->internal->
                  ops->ask_passphrase(conn->client, conn,
@@ -2223,7 +2235,7 @@ SILC_FSM_STATE(silc_client_command_oper)
   }
 
   silc_fsm_next(fsm, silc_client_command_oper_send);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /* SILCOPER command. Used to obtain router operator privileges. */
@@ -2238,14 +2250,14 @@ SILC_FSM_STATE(silc_client_command_silcoper)
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /SILCOPER <username> [-pubkey]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    return SILC_FSM_FINISH;
+    SILC_FSM_FINISH;
   }
 
   /* Get passphrase */
   if (cmd->argc < 3) {
     oper = silc_calloc(1, sizeof(*oper));
     if (!oper)
-      return SILC_FSM_FINISH;
+      SILC_FSM_FINISH;
     cmd->context = oper;
     SILC_FSM_CALL(conn->client->internal->
                  ops->ask_passphrase(conn->client, conn,
@@ -2253,7 +2265,7 @@ SILC_FSM_STATE(silc_client_command_silcoper)
   }
 
   silc_fsm_next(fsm, silc_client_command_oper_send);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /*********************************** BAN ************************************/
@@ -2264,6 +2276,7 @@ SILC_FSM_STATE(silc_client_command_ban)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
+  SilcClient client = conn->client;
   SilcChannelEntry channel;
   SilcBuffer chidp, args = NULL;
   char *name, *ban = NULL;
@@ -2285,6 +2298,7 @@ SILC_FSM_STATE(silc_client_command_ban)
     }
 
     channel = conn->current_channel;
+    silc_client_ref_channel(client, conn, channel);
   } else {
     name = cmd->argv[1];
 
@@ -2334,16 +2348,17 @@ SILC_FSM_STATE(silc_client_command_ban)
 
   silc_buffer_free(chidp);
   silc_buffer_free(args);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 
  out:
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }
 
 /********************************* DETACH ***********************************/
@@ -2362,7 +2377,7 @@ SILC_FSM_STATE(silc_client_command_detach)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /********************************** WATCH ***********************************/
@@ -2434,10 +2449,10 @@ SILC_FSM_STATE(silc_client_command_watch)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 
  out:
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }
 
 /********************************** LEAVE ***********************************/
@@ -2448,6 +2463,7 @@ SILC_FSM_STATE(silc_client_command_leave)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
+  SilcClient client = conn->client;
   SilcChannelEntry channel;
   SilcBuffer idp;
   char *name;
@@ -2490,12 +2506,14 @@ SILC_FSM_STATE(silc_client_command_leave)
   if (conn->current_channel == channel)
     conn->current_channel = NULL;
 
+  silc_client_unref_channel(client, conn, channel);
+
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 
  out:
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }
 
 /********************************** USERS ***********************************/
@@ -2535,10 +2553,10 @@ SILC_FSM_STATE(silc_client_command_users)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 
  out:
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }
 
 /********************************* GETKEY ***********************************/
@@ -2560,17 +2578,13 @@ SILC_FSM_STATE(silc_client_command_getkey)
     client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
                     "Usage: /GETKEY <nickname or server name>");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    return SILC_FSM_FINISH;
+    SILC_FSM_FINISH;
   }
 
   /* Parse the typed nickname. */
-  if (client->internal->params->nickname_parse)
-    client->internal->params->nickname_parse(cmd->argv[1], &nickname);
-  else
-    nickname = strdup(cmd->argv[1]);
-  if (!nickname) {
+  if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname)) {
     COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
-    return SILC_FSM_FINISH;
+    SILC_FSM_FINISH;
   }
 
   /* Find client entry */
@@ -2585,7 +2599,7 @@ SILC_FSM_STATE(silc_client_command_getkey)
           errors are handled in the resolving callback. */
        COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
        COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_SERVER);
-       return SILC_FSM_FINISH;
+       SILC_FSM_FINISH;
       }
 
       /* No client or server exist with this name, query for both. */
@@ -2620,7 +2634,7 @@ SILC_FSM_STATE(silc_client_command_getkey)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /********************************* SERVICE **********************************/
@@ -2640,7 +2654,7 @@ SILC_FSM_STATE(silc_client_command_service)
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /SERVICE [<service name>] [-pubkey]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    return SILC_FSM_FINISH;
+    SILC_FSM_FINISH;
   }
 
   name = cmd->argv[1];
@@ -2660,7 +2674,7 @@ SILC_FSM_STATE(silc_client_command_service)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 /* Register all default commands provided by the client library for the
@@ -2801,7 +2815,7 @@ SILC_FSM_STATE(silc_client_command)
                                       silc_buffer_len(&packet->buffer));
   if (!payload) {
     SILC_LOG_DEBUG(("Bad command packet"));
-    return SILC_FSM_FINISH;
+    SILC_FSM_FINISH;
   }
 
   /* Get arguments */
@@ -2813,7 +2827,7 @@ SILC_FSM_STATE(silc_client_command)
 
   case SILC_COMMAND_WHOIS:
     /* Ignore everything if requested by application */
-    if (client->internal->params->ignore_requested_attributes)
+    if (conn->internal->params.ignore_requested_attributes)
       break;
 
     silc_client_command_process_whois(client, conn, payload, args);
@@ -2824,5 +2838,5 @@ SILC_FSM_STATE(silc_client_command)
   }
 
   silc_command_payload_free(payload);
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }