Merged silc_1_1_branch to trunk.
[silc.git] / lib / silcclient / command.c
index a10505566f57608c2d79d2461f0efa8b9a7be83c..85e33fe38217f0fe7b17c6c70a97270b1d3e2aca 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 */
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /* Command reply callback to continue with the execution of a command.
@@ -119,13 +119,36 @@ 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);
 }
 
+/* Dummy command callback.  Nothing interesting to do here.  Use this when
+   you just send command but don't care about reply. */
+
+SilcBool silc_client_command_called_dummy(SilcClient client,
+                                         SilcClientConnection conn,
+                                         SilcCommand command,
+                                         SilcStatus status,
+                                         SilcStatus error,
+                                         void *context,
+                                         va_list ap)
+{
+  return FALSE;
+}
+
+/* Dummy resolving callback.  Nothing interesting to do here.  Use this
+   when you just resolve entires but don't care about reply. */
+
+void silc_client_command_resolve_dummy(SilcClient client,
+                                      SilcClientConnection conn,
+                                      SilcStatus status,
+                                      SilcDList clients,
+                                      void *context)
+{
+  /* Nothing */
+}
+
 /* Register command to client */
 
 static SilcBool
@@ -393,7 +416,7 @@ SilcUInt16 silc_client_command_call(SilcClient client,
   char *arg;
 
   if (!conn) {
-    client->internal->ops->say(client, NULL, SILC_CLIENT_MESSAGE_ERROR,
+    client->internal->ops->say(client, NULL, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
       "You are not connected to a server, please connect to server");
     return 0;
   }
@@ -613,6 +636,7 @@ SILC_FSM_STATE(silc_client_command_whois)
   unsigned char count[4], *tmp = NULL;
   SilcBool details = FALSE, nick = FALSE;
   unsigned char *pubkey = NULL;
+  char *nickname = NULL;
   int i;
 
   /* Given without arguments fetches client's own information */
@@ -626,7 +650,7 @@ SILC_FSM_STATE(silc_client_command_whois)
 
     /** Wait for command reply */
     silc_fsm_next(fsm, silc_client_command_reply_wait);
-    SILC_FSM_CONTINUE;
+    return SILC_FSM_CONTINUE;
   }
 
   for (i = 1; i < cmd->argc; i++) {
@@ -673,7 +697,7 @@ SILC_FSM_STATE(silc_client_command_whois)
     SilcPublicKey pk;
 
     if (!silc_pkcs_load_public_key(pubkey, &pk)) {
-      SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+      SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
          "Could not load public key %s, check the filename",
          pubkey);
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
@@ -703,24 +727,32 @@ SILC_FSM_STATE(silc_client_command_whois)
                                           SILC_ATTRIBUTE_USER_PUBLIC_KEY,
                                           SILC_ATTRIBUTE_FLAG_VALID,
                                           &obj, sizeof(obj));
+    silc_free(obj.data);
+  }
+
+  if (nick) {
+    silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname);
+    if (!nickname)
+      nickname = strdup(cmd->argv[1]);
   }
 
   /* Send command */
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
-                             3, 1, nick ? cmd->argv[1] : NULL,
-                             nick ? cmd->argv_lens[1] : 0,
+                             3, 1, nick ? nickname : NULL,
+                             nick ? strlen(nickname) : 0,
                              2, tmp ? tmp : NULL, tmp ? 4 : 0,
                              3, silc_buffer_datalen(attrs));
+  silc_free(nickname);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /******************************** WHOWAS ************************************/
@@ -740,7 +772,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));
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
   }
 
   if (cmd->argc == 2) {
@@ -759,7 +791,7 @@ SILC_FSM_STATE(silc_client_command_whowas)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /******************************** IDENTIFY **********************************/
@@ -775,7 +807,7 @@ SILC_FSM_STATE(silc_client_command_identify)
   int c;
 
   if (cmd->argc < 2 || cmd->argc > 3)
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
 
   if (cmd->argc == 2) {
     silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
@@ -790,7 +822,7 @@ SILC_FSM_STATE(silc_client_command_identify)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** NICK ************************************/
@@ -800,7 +832,7 @@ SILC_FSM_STATE(silc_client_command_identify)
 
 SILC_FSM_STATE(silc_client_command_nick)
 {
-  SilcClientCommandContext cmd = fsm_context;
+  SilcClientCommandContext cmd2, cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
 
   if (cmd->argc < 2) {
@@ -828,6 +860,19 @@ SILC_FSM_STATE(silc_client_command_nick)
     goto out;
   }
 
+  /* If JOIN command is active, wait for it to finish before sending NICK.
+     To avoid problems locally with changing IDs while joining, we do this. */
+  silc_mutex_lock(conn->internal->lock);
+  silc_list_start(conn->internal->pending_commands);
+  while ((cmd2 = silc_list_get(conn->internal->pending_commands))) {
+    if (cmd2->cmd == SILC_COMMAND_JOIN) {
+      silc_mutex_unlock(conn->internal->lock);
+      silc_fsm_next_later(fsm, silc_client_command_nick, 0, 300000);
+      return SILC_FSM_WAIT;
+    }
+  }
+  silc_mutex_unlock(conn->internal->lock);
+
   if (cmd->argv_lens[1] > 128)
     cmd->argv_lens[1] = 128;
 
@@ -840,10 +885,10 @@ SILC_FSM_STATE(silc_client_command_nick)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************** LIST ************************************/
@@ -854,7 +899,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) {
@@ -871,13 +917,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);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** TOPIC ***********************************/
@@ -888,9 +935,10 @@ 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;
+  char *name, tmp[512];
 
   if (cmd->argc < 2 || cmd->argc > 3) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
@@ -905,7 +953,15 @@ SILC_FSM_STATE(silc_client_command_topic)
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
       goto out;
     }
-    name = conn->current_channel->channel_name;
+
+    if (client->internal->params->full_channel_names)
+      silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name);
+    else
+      silc_snprintf(tmp, sizeof(tmp), "%s%s%s",
+                   conn->current_channel->channel_name,
+                   conn->current_channel->server[0] ? "@" : "",
+                   conn->current_channel->server);
+    name = tmp;
   } else {
     name = cmd->argv[1];
   }
@@ -934,16 +990,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);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************* INVITE ***********************************/
@@ -957,7 +1014,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;
@@ -980,6 +1037,7 @@ SILC_FSM_STATE(silc_client_command_invite)
     }
 
     channel = conn->current_channel;
+    silc_client_ref_channel(client, conn, channel);
   } else {
     name = cmd->argv[1];
 
@@ -996,13 +1054,12 @@ SILC_FSM_STATE(silc_client_command_invite)
       silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
 
       /* Find client entry */
-      clients = silc_client_get_clients_local(client, conn, nickname,
-                                             cmd->argv[2]);
+      clients = silc_client_get_clients_local(client, conn, cmd->argv[2],
+                                             FALSE);
       if (!clients)
        /* Resolve client information */
        SILC_FSM_CALL(silc_client_get_clients(
-                                     client, conn, nickname,
-                                     cmd->argv[2],
+                                     client, conn, nickname, NULL,
                                      silc_client_command_resolve_continue,
                                      cmd));
 
@@ -1058,17 +1115,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);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
   silc_free(nickname);
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************** QUIT ************************************/
@@ -1079,26 +1137,20 @@ SILC_FSM_STATE(silc_client_command_quit_final)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
 
   SILC_LOG_DEBUG(("Quitting"));
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
-  /* Call connection callback */
-  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 */
+  conn->internal->status = SILC_CLIENT_CONN_DISCONNECTED;
   if (!conn->internal->disconnected) {
     conn->internal->disconnected = TRUE;
     SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
   }
 
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /* Command QUIT. Closes connection with current server. */
@@ -1119,12 +1171,11 @@ 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);
-  SILC_FSM_WAIT;
+  return SILC_FSM_WAIT;
 }
 
 /********************************** KILL ************************************/
 
-
 /* Command KILL. Router operator can use this command to remove an client
    fromthe SILC Network. */
 
@@ -1142,20 +1193,18 @@ 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);
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
   }
 
   /* Parse the typed nickname. */
   if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname))
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
 
   /* Get the target client */
-  clients = silc_client_get_clients_local(client, conn, nickname,
-                                         cmd->argv[1]);
+  clients = silc_client_get_clients_local(client, conn, cmd->argv[1], FALSE);
   if (!clients)
     /* Resolve client information */
-    SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname,
-                                         cmd->argv[1],
+    SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, NULL,
                                          silc_client_command_resolve_continue,
                                          cmd));
 
@@ -1192,7 +1241,7 @@ SILC_FSM_STATE(silc_client_command_kill)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** INFO ************************************/
@@ -1217,7 +1266,7 @@ SILC_FSM_STATE(silc_client_command_info)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** STATS ***********************************/
@@ -1239,7 +1288,7 @@ SILC_FSM_STATE(silc_client_command_stats)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** PING ************************************/
@@ -1253,7 +1302,7 @@ SILC_FSM_STATE(silc_client_command_ping)
 
   if (cmd->argc < 2) {
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
   }
 
   /* Send the command */
@@ -1269,7 +1318,7 @@ SILC_FSM_STATE(silc_client_command_ping)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** JOIN ************************************/
@@ -1278,9 +1327,10 @@ SILC_FSM_STATE(silc_client_command_ping)
 
 SILC_FSM_STATE(silc_client_command_join)
 {
-  SilcClientCommandContext cmd = fsm_context;
+  SilcClientCommandContext cmd2, 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;
@@ -1295,6 +1345,19 @@ SILC_FSM_STATE(silc_client_command_join)
   if (channel && silc_client_on_channel(channel, conn->local_entry))
     goto out;
 
+  /* If NICK command is active, wait for it to finish before sending JOIN.
+     To avoid problems locally with changing IDs while joining, we do this. */
+  silc_mutex_lock(conn->internal->lock);
+  silc_list_start(conn->internal->pending_commands);
+  while ((cmd2 = silc_list_get(conn->internal->pending_commands))) {
+    if (cmd2->cmd == SILC_COMMAND_NICK) {
+      silc_mutex_unlock(conn->internal->lock);
+      silc_fsm_next_later(fsm, silc_client_command_join, 0, 300000);
+      return SILC_FSM_WAIT;
+    }
+  }
+  silc_mutex_unlock(conn->internal->lock);
+
   if (cmd->argv_lens[1] > 256)
     cmd->argv_lens[1] = 256;
 
@@ -1326,7 +1389,7 @@ SILC_FSM_STATE(silc_client_command_join)
        }
        if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
                                &pubkey, &privkey)) {
-         SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+         SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
              "Could not load key pair, check your arguments");
          COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
          goto out;
@@ -1378,16 +1441,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);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
-  SILC_FSM_FINISH;
+  silc_client_unref_channel(client, conn, channel);
+  return SILC_FSM_FINISH;
 }
 
 /********************************** MOTD ************************************/
@@ -1404,7 +1469,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));
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
   }
 
   /* Send the command */
@@ -1421,7 +1486,7 @@ SILC_FSM_STATE(silc_client_command_motd)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** UMODE ***********************************/
@@ -1441,7 +1506,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);
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
   }
 
   mode = conn->local_entry->mode;
@@ -1542,7 +1607,7 @@ SILC_FSM_STATE(silc_client_command_umode)
       break;
     default:
       COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
-      SILC_FSM_FINISH;
+      return SILC_FSM_FINISH;
       break;
     }
   }
@@ -1560,7 +1625,7 @@ SILC_FSM_STATE(silc_client_command_umode)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** CMODE ***********************************/
@@ -1574,7 +1639,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;
@@ -1594,6 +1659,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
     }
 
     channel = conn->current_channel;
+    silc_client_ref_channel(client, conn, channel);
   } else {
     name = cmd->argv[1];
 
@@ -1743,7 +1809,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
            pass = cmd->argv[5];
          if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
                                  &pubkey, &privkey)) {
-           SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+           SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
                "Could not load key pair, check your arguments");
            COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
            goto out;
@@ -1778,10 +1844,14 @@ SILC_FSM_STATE(silc_client_command_cmode)
                                      NULL, NULL, 1,
                                      1, silc_buffer_datalen(chidp));
          silc_buffer_free(chidp);
+         silc_client_unref_channel(client, conn, channel);
 
          /* Notify application */
          COMMAND(SILC_STATUS_OK);
-         goto out;
+
+         /** Wait for command reply */
+         silc_fsm_next(fsm, silc_client_command_reply_wait);
+         return SILC_FSM_CONTINUE;
        }
 
        if (cmd->argc >= 4) {
@@ -1795,7 +1865,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
          if (cmd->argv[k][0] == '+')
            chadd = TRUE;
          if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) {
-           SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+           SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
                "Could not load public key %s, check the filename",
                cmd->argv[k]);
            COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
@@ -1847,16 +1917,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);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
-  SILC_FSM_FINISH;
+  silc_client_unref_channel(client, conn, channel);
+  return SILC_FSM_FINISH;
 }
 
 /********************************* CUMODE ***********************************/
@@ -1868,7 +1940,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;
@@ -1892,6 +1964,7 @@ SILC_FSM_STATE(silc_client_command_cumode)
     }
 
     channel = conn->current_channel;
+    silc_client_ref_channel(client, conn, channel);
   } else {
     name = cmd->argv[1];
 
@@ -1906,11 +1979,10 @@ SILC_FSM_STATE(silc_client_command_cumode)
   silc_client_nickname_parse(client, conn, cmd->argv[3], &nickname);
 
   /* Find client entry */
-  clients = silc_client_get_clients_local(client, conn, nickname,
-                                         cmd->argv[3]);
+  clients = silc_client_get_clients_local(client, conn, cmd->argv[3], FALSE);
   if (!clients)
     /* Resolve client information */
-    SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3],
+    SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, NULL,
                                          silc_client_command_resolve_continue,
                                          cmd));
 
@@ -1954,7 +2026,7 @@ SILC_FSM_STATE(silc_client_command_cumode)
            pass = cmd->argv[6];
          if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
                                  &pubkey, &privkey)) {
-           SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+           SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
                "Could not load key pair, check your arguments");
            COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
            goto out;
@@ -2026,18 +2098,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);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
+  silc_client_unref_channel(client, conn, channel);
   silc_client_list_free(client, conn, clients);
   silc_free(nickname);
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************** KICK ************************************/
@@ -2049,12 +2123,11 @@ 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;
-  char *name;
-  char *nickname = NULL;
+  char *name, tmp[512];
 
   if (cmd->argc < 3) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
@@ -2068,7 +2141,15 @@ SILC_FSM_STATE(silc_client_command_kick)
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
       goto out;
     }
-    name = conn->current_channel->channel_name;
+
+    if (client->internal->params->full_channel_names)
+      silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name);
+    else
+      silc_snprintf(tmp, sizeof(tmp), "%s%s%s",
+                   conn->current_channel->channel_name,
+                   conn->current_channel->server[0] ? "@" : "",
+                   conn->current_channel->server);
+    name = tmp;
   } else {
     name = cmd->argv[1];
   }
@@ -2085,12 +2166,8 @@ SILC_FSM_STATE(silc_client_command_kick)
     goto out;
   }
 
-  /* Parse the typed nickname. */
-  silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
-
   /* Get the target client */
-  clients = silc_client_get_clients_local(client, conn, nickname,
-                                         cmd->argv[2]);
+  clients = silc_client_get_clients_local(client, conn, cmd->argv[2], FALSE);
   if (!clients) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "No such client: %s", cmd->argv[2]);
@@ -2114,19 +2191,19 @@ SILC_FSM_STATE(silc_client_command_kick)
 
   silc_buffer_free(idp);
   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);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
-  silc_free(nickname);
-  SILC_FSM_FINISH;
+  silc_client_unref_channel(client, conn, channel);
+  return SILC_FSM_FINISH;
 }
 
 /***************************** OPER & SILCOPER ******************************/
@@ -2138,7 +2215,7 @@ typedef struct {
 
 /* Ask passphrase callback */
 
-static void silc_client_command_oper_cb(unsigned char *data,
+static void silc_client_command_oper_cb(const unsigned char *data,
                                        SilcUInt32 data_len, void *context)
 {
   SilcClientCommandContext cmd = context;
@@ -2191,7 +2268,7 @@ SILC_FSM_STATE(silc_client_command_oper_send)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /* OPER command. Used to obtain server operator privileges. */
@@ -2206,22 +2283,23 @@ 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);
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
   }
 
+  silc_fsm_next(fsm, silc_client_command_oper_send);
+
   /* Get passphrase */
   if (cmd->argc < 3) {
     oper = silc_calloc(1, sizeof(*oper));
     if (!oper)
-      SILC_FSM_FINISH;
+      return SILC_FSM_FINISH;
     cmd->context = oper;
     SILC_FSM_CALL(conn->client->internal->
                  ops->ask_passphrase(conn->client, conn,
                                      silc_client_command_oper_cb, cmd));
   }
 
-  silc_fsm_next(fsm, silc_client_command_oper_send);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /* SILCOPER command. Used to obtain router operator privileges. */
@@ -2236,22 +2314,23 @@ 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);
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
   }
 
+  silc_fsm_next(fsm, silc_client_command_oper_send);
+
   /* Get passphrase */
   if (cmd->argc < 3) {
     oper = silc_calloc(1, sizeof(*oper));
     if (!oper)
-      SILC_FSM_FINISH;
+      return SILC_FSM_FINISH;
     cmd->context = oper;
     SILC_FSM_CALL(conn->client->internal->
                  ops->ask_passphrase(conn->client, conn,
                                      silc_client_command_oper_cb, cmd));
   }
 
-  silc_fsm_next(fsm, silc_client_command_oper_send);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /*********************************** BAN ************************************/
@@ -2262,6 +2341,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;
@@ -2283,6 +2363,7 @@ SILC_FSM_STATE(silc_client_command_ban)
     }
 
     channel = conn->current_channel;
+    silc_client_ref_channel(client, conn, channel);
   } else {
     name = cmd->argv[1];
 
@@ -2332,16 +2413,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);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************* DETACH ***********************************/
@@ -2360,7 +2442,7 @@ SILC_FSM_STATE(silc_client_command_detach)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** WATCH ***********************************/
@@ -2400,7 +2482,7 @@ SILC_FSM_STATE(silc_client_command_watch)
     SilcBuffer buffer;
 
     if (!silc_pkcs_load_public_key(pubkey, &pk)) {
-      SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+      SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
          "Could not load public key %s, check the filename", pubkey);
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
       goto out;
@@ -2417,6 +2499,12 @@ SILC_FSM_STATE(silc_client_command_watch)
     silc_pkcs_public_key_free(pk);
   }
 
+  /* If watching by nickname, resolve all users with that nickname so that
+     we get their information immediately. */
+  if (type == 2)
+    silc_client_get_clients(conn->client, conn, cmd->argv[2], NULL,
+                           silc_client_command_resolve_dummy, NULL);
+
   /* Send the commmand */
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
                              1, silc_buffer_datalen(conn->internal->
@@ -2432,10 +2520,10 @@ SILC_FSM_STATE(silc_client_command_watch)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************** LEAVE ***********************************/
@@ -2446,9 +2534,10 @@ 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;
+  char *name, tmp[512];
 
   if (cmd->argc != 2) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
@@ -2462,7 +2551,15 @@ SILC_FSM_STATE(silc_client_command_leave)
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
       goto out;
     }
-    name = conn->current_channel->channel_name;
+
+    if (client->internal->params->full_channel_names)
+      silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name);
+    else
+      silc_snprintf(tmp, sizeof(tmp), "%s%s%s",
+                   conn->current_channel->channel_name,
+                   conn->current_channel->server[0] ? "@" : "",
+                   conn->current_channel->server);
+    name = tmp;
   } else {
     name = cmd->argv[1];
   }
@@ -2488,12 +2585,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);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************** USERS ***********************************/
@@ -2505,7 +2604,7 @@ SILC_FSM_STATE(silc_client_command_users)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
-  char *name;
+  char *name, tmp[512];
 
   if (cmd->argc != 2) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
@@ -2519,7 +2618,15 @@ SILC_FSM_STATE(silc_client_command_users)
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
       goto out;
     }
-    name = conn->current_channel->channel_name;
+
+    if (conn->client->internal->params->full_channel_names)
+      silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name);
+    else
+      silc_snprintf(tmp, sizeof(tmp), "%s%s%s",
+                   conn->current_channel->channel_name,
+                   conn->current_channel->server[0] ? "@" : "",
+                   conn->current_channel->server);
+    name = tmp;
   } else {
     name = cmd->argv[1];
   }
@@ -2533,10 +2640,10 @@ SILC_FSM_STATE(silc_client_command_users)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************* GETKEY ***********************************/
@@ -2551,25 +2658,17 @@ SILC_FSM_STATE(silc_client_command_getkey)
   SilcClientEntry client_entry;
   SilcServerEntry server_entry;
   SilcDList clients;
-  char *nickname = NULL;
   SilcBuffer idp;
 
   if (cmd->argc < 2) {
     client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
                     "Usage: /GETKEY <nickname or server name>");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    SILC_FSM_FINISH;
-  }
-
-  /* Parse the typed nickname. */
-  if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname)) {
-    COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
   }
 
   /* Find client entry */
-  clients = silc_client_get_clients_local(client, conn, nickname,
-                                         cmd->argv[1]);
+  clients = silc_client_get_clients_local(client, conn, cmd->argv[1], FALSE);
   if (!clients) {
     /* Check whether user requested server */
     server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
@@ -2579,7 +2678,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);
-       SILC_FSM_FINISH;
+       return SILC_FSM_FINISH;
       }
 
       /* No client or server exist with this name, query for both. */
@@ -2607,14 +2706,13 @@ SILC_FSM_STATE(silc_client_command_getkey)
                              1, silc_buffer_datalen(idp));
 
   silc_buffer_free(idp);
-  silc_free(nickname);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************* SERVICE **********************************/
@@ -2634,7 +2732,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);
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
   }
 
   name = cmd->argv[1];
@@ -2654,7 +2752,7 @@ SILC_FSM_STATE(silc_client_command_service)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /* Register all default commands provided by the client library for the
@@ -2736,7 +2834,6 @@ static void silc_client_command_process_whois(SilcClient client,
                                              SilcCommandPayload payload,
                                              SilcArgumentPayload args)
 {
-#if 0
   SilcDList attrs;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
@@ -2760,18 +2857,25 @@ static void silc_client_command_process_whois(SilcClient client,
     return;
   }
 
-  /* Send the attributes back */
+  /* Send the attributes back in COMMAND_REPLY packet */
   packet =
     silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
                                         SILC_STATUS_OK, 0,
                                         silc_command_get_ident(payload),
-                                        1, 11, buffer->data, buffer->len);
-  silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
-                         NULL, 0, NULL, NULL, packet->data,
-                         packet->len, TRUE);
+                                        1, 11, buffer->data,
+                                        silc_buffer_len(buffer));
+  if (!packet) {
+    silc_buffer_free(buffer);
+    return;
+  }
+
+  SILC_LOG_DEBUG(("Sending back requested WHOIS attributes"));
+
+  silc_packet_send(conn->stream, SILC_PACKET_COMMAND_REPLY, 0,
+                  silc_buffer_datalen(packet));
+
   silc_buffer_free(packet);
   silc_buffer_free(buffer);
-#endif /* 0 */
 }
 
 /* Client is able to receive some command packets even though they are
@@ -2795,7 +2899,7 @@ SILC_FSM_STATE(silc_client_command)
                                       silc_buffer_len(&packet->buffer));
   if (!payload) {
     SILC_LOG_DEBUG(("Bad command packet"));
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
   }
 
   /* Get arguments */
@@ -2818,5 +2922,5 @@ SILC_FSM_STATE(silc_client_command)
   }
 
   silc_command_payload_free(payload);
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }