Fixed silc_nickname_parse to return valid nickname when it returns
[silc.git] / lib / silcclient / command.c
index 91f35f3275c194e51d47a2d46491bde70d96ce8b..a50ab52304b83e575d2dc274cea5d8e75e038170 100644 (file)
@@ -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_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.
 }
 
 /* Command reply callback to continue with the execution of a command.
@@ -123,6 +123,32 @@ static void silc_client_command_resolve_continue(SilcClient client,
   SILC_FSM_CALL_CONTINUE(&cmd->thread);
 }
 
   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
 /* Register command to client */
 
 static SilcBool
@@ -390,7 +416,7 @@ SilcUInt16 silc_client_command_call(SilcClient client,
   char *arg;
 
   if (!conn) {
   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;
   }
       "You are not connected to a server, please connect to server");
     return 0;
   }
@@ -610,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;
   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 */
   int i;
 
   /* Given without arguments fetches client's own information */
@@ -623,7 +650,7 @@ SILC_FSM_STATE(silc_client_command_whois)
 
     /** Wait for command reply */
     silc_fsm_next(fsm, silc_client_command_reply_wait);
 
     /** 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++) {
   }
 
   for (i = 1; i < cmd->argc; i++) {
@@ -669,8 +696,8 @@ SILC_FSM_STATE(silc_client_command_whois)
     SilcAttributeObjPk obj;
     SilcPublicKey pk;
 
     SilcAttributeObjPk obj;
     SilcPublicKey pk;
 
-    if (!silc_pkcs_load_public_key(pubkey, &pk)) {
-      SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+    if (!silc_pkcs_load_public_key(pubkey, SILC_PKCS_ANY, &pk)) {
+      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);
          "Could not load public key %s, check the filename",
          pubkey);
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
@@ -694,30 +721,37 @@ SILC_FSM_STATE(silc_client_command_whois)
       goto out;
       break;
     }
       goto out;
       break;
     }
-    obj.data = silc_pkcs_public_key_encode(pk, &obj.data_len);
+    obj.data = silc_pkcs_public_key_encode(NULL, pk, &obj.data_len);
 
     attrs = silc_attribute_payload_encode(attrs,
                                           SILC_ATTRIBUTE_USER_PUBLIC_KEY,
                                           SILC_ATTRIBUTE_FLAG_VALID,
                                           &obj, sizeof(obj));
 
     attrs = silc_attribute_payload_encode(attrs,
                                           SILC_ATTRIBUTE_USER_PUBLIC_KEY,
                                           SILC_ATTRIBUTE_FLAG_VALID,
                                           &obj, sizeof(obj));
+    silc_free(obj.data);
+  }
+
+  if (nick) {
+    if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname))
+      goto out;
   }
 
   /* Send command */
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
   }
 
   /* 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));
                              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);
 
   /* 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:
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /******************************** WHOWAS ************************************/
 }
 
 /******************************** WHOWAS ************************************/
@@ -737,7 +771,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));
        "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) {
   }
 
   if (cmd->argc == 2) {
@@ -756,7 +790,7 @@ SILC_FSM_STATE(silc_client_command_whowas)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /******************************** IDENTIFY **********************************/
 }
 
 /******************************** IDENTIFY **********************************/
@@ -772,7 +806,7 @@ SILC_FSM_STATE(silc_client_command_identify)
   int c;
 
   if (cmd->argc < 2 || cmd->argc > 3)
   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,
 
   if (cmd->argc == 2) {
     silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
@@ -787,7 +821,7 @@ SILC_FSM_STATE(silc_client_command_identify)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** NICK ************************************/
 }
 
 /********************************** NICK ************************************/
@@ -797,7 +831,7 @@ SILC_FSM_STATE(silc_client_command_identify)
 
 SILC_FSM_STATE(silc_client_command_nick)
 {
 
 SILC_FSM_STATE(silc_client_command_nick)
 {
-  SilcClientCommandContext cmd = fsm_context;
+  SilcClientCommandContext cmd2, cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
 
   if (cmd->argc < 2) {
   SilcClientConnection conn = cmd->conn;
 
   if (cmd->argc < 2) {
@@ -825,6 +859,19 @@ SILC_FSM_STATE(silc_client_command_nick)
     goto out;
   }
 
     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;
 
   if (cmd->argv_lens[1] > 128)
     cmd->argv_lens[1] = 128;
 
@@ -837,10 +884,10 @@ SILC_FSM_STATE(silc_client_command_nick)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************** LIST ************************************/
 }
 
 /********************************** LIST ************************************/
@@ -876,7 +923,7 @@ SILC_FSM_STATE(silc_client_command_list)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** TOPIC ***********************************/
 }
 
 /********************************** TOPIC ***********************************/
@@ -890,7 +937,7 @@ SILC_FSM_STATE(silc_client_command_topic)
   SilcClient client = conn->client;
   SilcChannelEntry channel;
   SilcBuffer idp;
   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,
 
   if (cmd->argc < 2 || cmd->argc > 3) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
@@ -905,7 +952,15 @@ SILC_FSM_STATE(silc_client_command_topic)
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
       goto out;
     }
       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];
   }
   } else {
     name = cmd->argv[1];
   }
@@ -941,10 +996,10 @@ SILC_FSM_STATE(silc_client_command_topic)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************* INVITE ***********************************/
 }
 
 /********************************* INVITE ***********************************/
@@ -995,16 +1050,18 @@ SILC_FSM_STATE(silc_client_command_invite)
   /* Parse the typed nickname. */
   if (cmd->argc == 3) {
     if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
   /* Parse the typed nickname. */
   if (cmd->argc == 3) {
     if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
-      silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
+      if (!silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname)) {
+       silc_client_unref_channel(client, conn, channel);
+       goto out;
+      }
 
       /* Find client entry */
 
       /* 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(
       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));
 
                                      silc_client_command_resolve_continue,
                                      cmd));
 
@@ -1016,7 +1073,7 @@ SILC_FSM_STATE(silc_client_command_invite)
        action[0] = 0x01;
 
       /* Check if it is public key file to be added to invite list */
        action[0] = 0x01;
 
       /* Check if it is public key file to be added to invite list */
-      silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
+      silc_pkcs_load_public_key(cmd->argv[2] + 1, SILC_PKCS_ANY, &pubkey);
       invite = cmd->argv[2];
       if (!pubkey)
        invite++;
       invite = cmd->argv[2];
       if (!pubkey)
        invite++;
@@ -1029,7 +1086,7 @@ SILC_FSM_STATE(silc_client_command_invite)
                       SILC_STR_UI_SHORT(1),
                       SILC_STR_END);
     if (pubkey) {
                       SILC_STR_UI_SHORT(1),
                       SILC_STR_END);
     if (pubkey) {
-      chidp = silc_public_key_payload_encode(pubkey);
+      chidp = silc_public_key_payload_encode(NULL, pubkey);
       args = silc_argument_payload_encode_one(args, silc_buffer_data(chidp),
                                              silc_buffer_len(chidp), 2);
       silc_buffer_free(chidp);
       args = silc_argument_payload_encode_one(args, silc_buffer_data(chidp),
                                              silc_buffer_len(chidp), 2);
       silc_buffer_free(chidp);
@@ -1067,11 +1124,11 @@ SILC_FSM_STATE(silc_client_command_invite)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
   silc_free(nickname);
 
  out:
   silc_free(nickname);
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************** QUIT ************************************/
 }
 
 /********************************** QUIT ************************************/
@@ -1082,26 +1139,20 @@ SILC_FSM_STATE(silc_client_command_quit_final)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
-  SilcClient client = conn->client;
 
   SILC_LOG_DEBUG(("Quitting"));
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
 
   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 */
   /* 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);
   }
 
   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. */
 }
 
 /* Command QUIT. Closes connection with current server. */
@@ -1122,11 +1173,59 @@ 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);
 
   /* 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 ************************************/
 
 }
 
 /********************************** KILL ************************************/
 
+/* Signature callback */
+
+static void silc_client_command_kill_signed(const SilcBuffer buffer,
+                                           void *context)
+{
+  SilcClientCommandContext cmd = context;
+
+  if (!buffer) {
+    silc_fsm_finish(&cmd->thread);
+    return;
+  }
+
+  silc_fsm_set_state_context(&cmd->thread, buffer);
+  SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
+}
+
+/* Send KILL command */
+
+SILC_FSM_STATE(silc_client_command_kill_send)
+{
+  SilcClientCommandContext cmd = fsm_context;
+  SilcClientConnection conn = cmd->conn;
+  SilcClient client = conn->client;
+  SilcBuffer idp, auth = state_context;
+  SilcClientEntry target = cmd->context;
+  char *comment = NULL;
+
+  if (cmd->argc >= 3)
+    if (strcasecmp(cmd->argv[2], "-pubkey"))
+      comment = cmd->argv[2];
+
+  /* Send the KILL command to the server */
+  idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
+  silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
+                             1, silc_buffer_datalen(idp),
+                             2, comment, comment ? strlen(comment) : 0,
+                             3, silc_buffer_datalen(auth));
+
+  silc_buffer_free(idp);
+  silc_client_unref_client(client, conn, target);
+
+  /* Notify application */
+  COMMAND(SILC_STATUS_OK);
+
+  /** Wait for command reply */
+  silc_fsm_next(fsm, silc_client_command_reply_wait);
+  return SILC_FSM_CONTINUE;
+}
 
 /* Command KILL. Router operator can use this command to remove an client
    fromthe SILC Network. */
 
 /* Command KILL. Router operator can use this command to remove an client
    fromthe SILC Network. */
@@ -1136,66 +1235,55 @@ SILC_FSM_STATE(silc_client_command_kill)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
-  SilcBuffer idp, auth = NULL;
   SilcClientEntry target;
   SilcDList clients;
   SilcClientEntry target;
   SilcDList clients;
-  char *nickname = NULL, *comment = NULL;
+  char *nickname = NULL;
 
   if (cmd->argc < 2) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /KILL <nickname> [<comment>] [-pubkey]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
 
   if (cmd->argc < 2) {
     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))
   }
 
   /* 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 */
 
   /* 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 */
   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));
 
   target = silc_dlist_get(clients);
                                          silc_client_command_resolve_continue,
                                          cmd));
 
   target = silc_dlist_get(clients);
+  cmd->context = silc_client_ref_client(client, conn, target);
 
 
-  if (cmd->argc >= 3) {
-    if (strcasecmp(cmd->argv[2], "-pubkey"))
-      comment = cmd->argv[2];
+  silc_free(nickname);
+  silc_client_list_free(client, conn, clients);
+
+  /** Send KILL */
+  silc_fsm_next(fsm, silc_client_command_kill_send);
 
 
+  if (cmd->argc >= 3) {
     if (!strcasecmp(cmd->argv[2], "-pubkey") ||
        (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
       /* Encode the public key authentication payload */
     if (!strcasecmp(cmd->argv[2], "-pubkey") ||
        (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
       /* Encode the public key authentication payload */
-      auth = silc_auth_public_key_auth_generate(conn->public_key,
-                                               conn->private_key,
-                                               conn->client->rng,
-                                               conn->internal->sha1hash,
-                                               &target->id, SILC_ID_CLIENT);
+      SILC_FSM_CALL(silc_auth_public_key_auth_generate(
+                                        conn->public_key,
+                                        conn->private_key,
+                                        conn->client->rng,
+                                        conn->internal->sha1hash,
+                                        &target->id, SILC_ID_CLIENT,
+                                        silc_client_command_kill_signed,
+                                        cmd));
+      /* NOT REACHED */
     }
   }
 
     }
   }
 
-  /* Send the KILL command to the server */
-  idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
-  silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
-                             1, silc_buffer_datalen(idp),
-                             2, comment, comment ? strlen(comment) : 0,
-                             3, silc_buffer_datalen(auth));
-  silc_buffer_free(idp);
-  silc_buffer_free(auth);
-  silc_free(nickname);
-  silc_client_list_free(client, conn, clients);
-
-  /* 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;
 }
 
 /********************************** INFO ************************************/
 }
 
 /********************************** INFO ************************************/
@@ -1220,7 +1308,7 @@ SILC_FSM_STATE(silc_client_command_info)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** STATS ***********************************/
 }
 
 /********************************** STATS ***********************************/
@@ -1242,7 +1330,7 @@ SILC_FSM_STATE(silc_client_command_stats)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** PING ************************************/
 }
 
 /********************************** PING ************************************/
@@ -1256,7 +1344,7 @@ SILC_FSM_STATE(silc_client_command_ping)
 
   if (cmd->argc < 2) {
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
 
   if (cmd->argc < 2) {
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
   }
 
   /* Send the command */
   }
 
   /* Send the command */
@@ -1272,19 +1360,47 @@ SILC_FSM_STATE(silc_client_command_ping)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** JOIN ************************************/
 
 }
 
 /********************************** JOIN ************************************/
 
+typedef struct {
+  int type;
+  SilcBuffer auth;
+  SilcBuffer cauth;
+} *SilcClientJoinContext;
+
+/* Signature callback */
+
+static void silc_client_command_join_signed(const SilcBuffer buffer,
+                                           void *context)
+{
+  SilcClientCommandContext cmd = context;
+  SilcClientJoinContext j = cmd->context;
+
+  if (!buffer) {
+    silc_fsm_finish(&cmd->thread);
+    return;
+  }
+
+  if (!j->type)
+    j->auth = silc_buffer_copy(buffer);
+  else
+    j->cauth = silc_buffer_copy(buffer);
+
+  SILC_FSM_CALL_CONTINUE(&cmd->thread);
+}
+
 /* Command JOIN. Joins to a channel. */
 
 SILC_FSM_STATE(silc_client_command_join)
 {
 /* Command JOIN. Joins to a channel. */
 
 SILC_FSM_STATE(silc_client_command_join)
 {
-  SilcClientCommandContext cmd = fsm_context;
+  SilcClientCommandContext cmd2, cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
   SilcChannelEntry channel = NULL;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
   SilcChannelEntry channel = NULL;
+  SilcClientJoinContext j = cmd->context;
   SilcBuffer auth = NULL, cauth = NULL;
   char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
   int i, passphrase_len = 0;
   SilcBuffer auth = NULL, cauth = NULL;
   char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
   int i, passphrase_len = 0;
@@ -1299,6 +1415,19 @@ SILC_FSM_STATE(silc_client_command_join)
   if (channel && silc_client_on_channel(channel, conn->local_entry))
     goto out;
 
   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;
 
   if (cmd->argv_lens[1] > 256)
     cmd->argv_lens[1] = 256;
 
@@ -1310,46 +1439,77 @@ SILC_FSM_STATE(silc_client_command_join)
     } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
       hmac = cmd->argv[++i];
     } else if (!strcasecmp(cmd->argv[i], "-founder")) {
     } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
       hmac = cmd->argv[++i];
     } else if (!strcasecmp(cmd->argv[i], "-founder")) {
-      auth = silc_auth_public_key_auth_generate(conn->public_key,
-                                               conn->private_key,
-                                               conn->client->rng,
-                                               conn->internal->sha1hash,
-                                               conn->local_id,
-                                               SILC_ID_CLIENT);
+      if (!j || !j->auth) {
+       if (!j) {
+         j = silc_calloc(1, sizeof(*j));
+         if (!j)
+           goto out;
+         cmd->context = j;
+       }
+       j->type = 0;
+       silc_free(passphrase);
+       silc_client_unref_channel(client, conn, channel);
+       SILC_FSM_CALL(silc_auth_public_key_auth_generate(
+                                          conn->public_key,
+                                          conn->private_key,
+                                          conn->client->rng,
+                                          conn->internal->sha1hash,
+                                          conn->local_id,
+                                          SILC_ID_CLIENT,
+                                          silc_client_command_join_signed,
+                                          cmd));
+       /* NOT REACHED */
+      }
     } else if (!strcasecmp(cmd->argv[i], "-auth")) {
       SilcPublicKey pubkey = conn->public_key;
       SilcPrivateKey privkey = conn->private_key;
     } else if (!strcasecmp(cmd->argv[i], "-auth")) {
       SilcPublicKey pubkey = conn->public_key;
       SilcPrivateKey privkey = conn->private_key;
-      unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
+      unsigned char *pk, pkhash[SILC_HASH_MAXLEN], pubdata[128];
       SilcUInt32 pk_len;
 
       SilcUInt32 pk_len;
 
-      if (cmd->argc >= i + 3) {
-       char *pass = "";
-       if (cmd->argc >= i + 4) {
-         pass = cmd->argv[i + 3];
-         i++;
+      if (!j || !j->cauth) {
+       if (!j) {
+         j = silc_calloc(1, sizeof(*j));
+         if (!j)
+           goto out;
+         cmd->context = j;
        }
        }
-       if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
-                               &pubkey, &privkey)) {
-         SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
-             "Could not load key pair, check your arguments");
-         COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-         goto out;
+
+       if (cmd->argc >= i + 3) {
+         char *pass = "";
+         if (cmd->argc >= i + 4) {
+           pass = cmd->argv[i + 3];
+           i++;
+         }
+         if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
+                                 &pubkey, &privkey)) {
+           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;
+         }
+         i += 2;
        }
        }
-       i += 2;
-      }
 
 
-      pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
-      silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
-      silc_free(pk);
-      pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
-      memcpy(pubdata, pkhash, 20);
-      cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
-                                                     pubdata, 128,
-                                                     conn->internal->sha1hash,
-                                                     conn->local_id,
-                                                     SILC_ID_CLIENT);
-      memset(pubdata, 0, 128);
-      silc_free(pubdata);
+       j->type = 1;
+       pk = silc_pkcs_public_key_encode(NULL, pubkey, &pk_len);
+       silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
+       silc_free(pk);
+       silc_rng_get_rn_data(conn->client->rng, sizeof(pubdata), pubdata,
+                            sizeof(pubdata));
+       memcpy(pubdata, pkhash, 20);
+       silc_free(passphrase);
+       silc_client_unref_channel(client, conn, channel);
+       SILC_FSM_CALL(silc_auth_public_key_auth_generate_wpub(
+                                          pubkey, privkey,
+                                          pubdata, sizeof(pubdata),
+                                          conn->internal->sha1hash,
+                                          client->rng,
+                                          conn->local_id,
+                                          SILC_ID_CLIENT,
+                                          silc_client_command_join_signed,
+                                          cmd));
+       /* NOT REACHED */
+      }
     } else {
       /* Passphrases must be UTF-8 encoded, so encode if it is not */
       if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
     } else {
       /* Passphrases must be UTF-8 encoded, so encode if it is not */
       if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
@@ -1377,23 +1537,26 @@ SILC_FSM_STATE(silc_client_command_join)
                              6, silc_buffer_datalen(auth),
                              7, silc_buffer_datalen(cauth));
 
                              6, silc_buffer_datalen(auth),
                              7, silc_buffer_datalen(cauth));
 
-  silc_buffer_free(auth);
-  silc_buffer_free(cauth);
   if (passphrase)
     memset(passphrase, 0, strlen(passphrase));
   silc_free(passphrase);
   silc_client_unref_channel(client, conn, channel);
   if (passphrase)
     memset(passphrase, 0, strlen(passphrase));
   silc_free(passphrase);
   silc_client_unref_channel(client, conn, channel);
+  if (j) {
+    silc_buffer_free(j->auth);
+    silc_buffer_free(j->cauth);
+    silc_free(j);
+  }
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /* 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);
 
  out:
   silc_client_unref_channel(client, conn, channel);
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************** MOTD ************************************/
 }
 
 /********************************** MOTD ************************************/
@@ -1410,7 +1573,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));
        "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 */
   }
 
   /* Send the command */
@@ -1427,7 +1590,7 @@ SILC_FSM_STATE(silc_client_command_motd)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** UMODE ***********************************/
 }
 
 /********************************** UMODE ***********************************/
@@ -1447,7 +1610,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);
     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;
   }
 
   mode = conn->local_entry->mode;
@@ -1548,7 +1711,7 @@ SILC_FSM_STATE(silc_client_command_umode)
       break;
     default:
       COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
       break;
     default:
       COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
-      SILC_FSM_FINISH;
+      return SILC_FSM_FINISH;
       break;
     }
   }
       break;
     }
   }
@@ -1566,11 +1729,27 @@ SILC_FSM_STATE(silc_client_command_umode)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** CMODE ***********************************/
 
 }
 
 /********************************** CMODE ***********************************/
 
+/* Signature callback */
+
+static void silc_client_command_cmode_signed(const SilcBuffer buffer,
+                                            void *context)
+{
+  SilcClientCommandContext cmd = context;
+
+  if (!buffer) {
+    silc_fsm_finish(&cmd->thread);
+    return;
+  }
+
+  silc_fsm_set_state_context(&cmd->thread, buffer);
+  SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
+}
+
 /* CMODE command. Sets channel mode. Modes that does not require any arguments
    can be set several at once. Those modes that require argument must be set
    separately (unless set with modes that does not require arguments). */
 /* CMODE command. Sets channel mode. Modes that does not require any arguments
    can be set several at once. Those modes that require argument must be set
    separately (unless set with modes that does not require arguments). */
@@ -1580,8 +1759,9 @@ SILC_FSM_STATE(silc_client_command_cmode)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
+  SilcBuffer auth = state_context;
   SilcChannelEntry channel = NULL;
   SilcChannelEntry channel = NULL;
-  SilcBuffer chidp, auth = NULL, pk = NULL;
+  SilcBuffer chidp, pk = NULL;
   unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
   SilcUInt32 mode, add, type, len, arg_len = 0;
   int i;
   unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
   SilcUInt32 mode, add, type, len, arg_len = 0;
   int i;
@@ -1738,31 +1918,38 @@ SILC_FSM_STATE(silc_client_command_cmode)
       break;
     case 'f':
       if (add) {
       break;
     case 'f':
       if (add) {
-       SilcPublicKey pubkey = conn->public_key;
-       SilcPrivateKey privkey = conn->private_key;
-
-       mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
-       type = 7;
-
-       if (cmd->argc >= 5) {
-         char *pass = "";
-         if (cmd->argc >= 6)
-           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,
-               "Could not load key pair, check your arguments");
-           COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-           goto out;
+       if (!auth) {
+         SilcPublicKey pubkey = conn->public_key;
+         SilcPrivateKey privkey = conn->private_key;
+
+         mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
+         type = 7;
+
+         if (cmd->argc >= 5) {
+           char *pass = "";
+           if (cmd->argc >= 6)
+             pass = cmd->argv[5];
+           if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
+                                   &pubkey, &privkey)) {
+             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;
+           }
          }
          }
-       }
 
 
-       pk = silc_public_key_payload_encode(pubkey);
-       auth = silc_auth_public_key_auth_generate(pubkey, privkey,
-                                                 conn->client->rng,
-                                                 conn->internal->sha1hash,
-                                                 conn->local_id,
-                                                 SILC_ID_CLIENT);
+         pk = silc_public_key_payload_encode(NULL, pubkey);
+         silc_client_unref_channel(client, conn, channel);
+         SILC_FSM_CALL(silc_auth_public_key_auth_generate(
+                                            pubkey, privkey,
+                                            conn->client->rng,
+                                            conn->internal->sha1hash,
+                                            conn->local_id,
+                                            SILC_ID_CLIENT,
+                                            silc_client_command_cmode_signed,
+                                            cmd));
+         /* NOT REACHED */
+       }
        arg = silc_buffer_data(auth);
        arg_len = silc_buffer_len(auth);
       } else {
        arg = silc_buffer_data(auth);
        arg_len = silc_buffer_len(auth);
       } else {
@@ -1785,10 +1972,14 @@ SILC_FSM_STATE(silc_client_command_cmode)
                                      NULL, NULL, 1,
                                      1, silc_buffer_datalen(chidp));
          silc_buffer_free(chidp);
                                      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);
 
          /* 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) {
        }
 
        if (cmd->argc >= 4) {
@@ -1801,8 +1992,9 @@ SILC_FSM_STATE(silc_client_command_cmode)
        for (k = 3; k < cmd->argc; k++) {
          if (cmd->argv[k][0] == '+')
            chadd = TRUE;
        for (k = 3; k < cmd->argc; k++) {
          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,
+         if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, SILC_PKCS_ANY,
+                                        &chpk)) {
+           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);
                "Could not load public key %s, check the filename",
                cmd->argv[k]);
            COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
@@ -1811,7 +2003,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
          }
 
          if (chpk) {
          }
 
          if (chpk) {
-           pk = silc_public_key_payload_encode(chpk);
+           pk = silc_public_key_payload_encode(NULL, chpk);
            auth = silc_argument_payload_encode_one(auth,
                                                    silc_buffer_datalen(pk),
                                                    chadd ? 0x00 : 0x01);
            auth = silc_argument_payload_encode_one(auth,
                                                    silc_buffer_datalen(pk),
                                                    chadd ? 0x00 : 0x01);
@@ -1861,15 +2053,31 @@ SILC_FSM_STATE(silc_client_command_cmode)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** 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);
 
  out:
   silc_client_unref_channel(client, conn, channel);
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************* CUMODE ***********************************/
 
 }
 
 /********************************* CUMODE ***********************************/
 
+/* Signature callback */
+
+static void silc_client_command_cumode_signed(const SilcBuffer buffer,
+                                             void *context)
+{
+  SilcClientCommandContext cmd = context;
+
+  if (!buffer) {
+    silc_fsm_finish(&cmd->thread);
+    return;
+  }
+
+  silc_fsm_set_state_context(&cmd->thread, buffer);
+  SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
+}
+
 /* CUMODE command. Changes client's mode on a channel. */
 
 SILC_FSM_STATE(silc_client_command_cumode)
 /* CUMODE command. Changes client's mode on a channel. */
 
 SILC_FSM_STATE(silc_client_command_cumode)
@@ -1877,10 +2085,11 @@ SILC_FSM_STATE(silc_client_command_cumode)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
+  SilcBuffer auth = state_context;
   SilcChannelEntry channel = NULL;
   SilcChannelUser chu;
   SilcClientEntry client_entry;
   SilcChannelEntry channel = NULL;
   SilcChannelUser chu;
   SilcClientEntry client_entry;
-  SilcBuffer clidp, chidp, auth = NULL;
+  SilcBuffer clidp, chidp;
   SilcDList clients = NULL;
   unsigned char *name, *cp, modebuf[4];
   SilcUInt32 mode = 0, add, len;
   SilcDList clients = NULL;
   unsigned char *name, *cp, modebuf[4];
   SilcUInt32 mode = 0, add, len;
@@ -1913,14 +2122,14 @@ SILC_FSM_STATE(silc_client_command_cumode)
   }
 
   /* Parse the typed nickname. */
   }
 
   /* Parse the typed nickname. */
-  silc_client_nickname_parse(client, conn, cmd->argv[3], &nickname);
+  if (!silc_client_nickname_parse(client, conn, cmd->argv[3], &nickname))
+    goto out;
 
   /* Find client entry */
 
   /* 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 */
   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));
 
                                          silc_client_command_resolve_continue,
                                          cmd));
 
@@ -1955,27 +2164,38 @@ SILC_FSM_STATE(silc_client_command_cumode)
       break;
     case 'f':
       if (add) {
       break;
     case 'f':
       if (add) {
-       SilcPublicKey pubkey = conn->public_key;
-       SilcPrivateKey privkey = conn->private_key;
-
-       if (cmd->argc >= 6) {
-         char *pass = "";
-         if (cmd->argc >= 7)
-           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,
-               "Could not load key pair, check your arguments");
-           COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-           goto out;
+       if (!auth) {
+         SilcPublicKey pubkey = conn->public_key;
+         SilcPrivateKey privkey = conn->private_key;
+
+         if (cmd->argc >= 6) {
+           char *pass = "";
+           if (cmd->argc >= 7)
+             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_COMMAND_ERROR,
+                 "Could not load key pair, check your arguments");
+             COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+             goto out;
+           }
          }
          }
+
+         silc_free(nickname);
+         silc_client_list_free(client, conn, clients);
+         silc_client_unref_channel(client, conn, channel);
+
+         SILC_FSM_CALL(silc_auth_public_key_auth_generate(
+                                            pubkey, privkey,
+                                            conn->client->rng,
+                                            conn->internal->sha1hash,
+                                            conn->local_id,
+                                            SILC_ID_CLIENT,
+                                            silc_client_command_cumode_signed,
+                                            cmd));
+         /* NOT REACHED */
        }
 
        }
 
-       auth = silc_auth_public_key_auth_generate(pubkey, privkey,
-                                                 conn->client->rng,
-                                                 conn->internal->sha1hash,
-                                                 conn->local_id,
-                                                 SILC_ID_CLIENT);
        mode |= SILC_CHANNEL_UMODE_CHANFO;
       } else {
        mode &= ~SILC_CHANNEL_UMODE_CHANFO;
        mode |= SILC_CHANNEL_UMODE_CHANFO;
       } else {
        mode &= ~SILC_CHANNEL_UMODE_CHANFO;
@@ -2043,13 +2263,13 @@ SILC_FSM_STATE(silc_client_command_cumode)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** 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);
 
  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 ************************************/
 }
 
 /********************************** KICK ************************************/
@@ -2065,8 +2285,7 @@ SILC_FSM_STATE(silc_client_command_kick)
   SilcBuffer idp, idp2;
   SilcClientEntry target;
   SilcDList clients = 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,
 
   if (cmd->argc < 3) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
@@ -2080,7 +2299,15 @@ SILC_FSM_STATE(silc_client_command_kick)
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
       goto out;
     }
       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];
   }
   } else {
     name = cmd->argv[1];
   }
@@ -2097,12 +2324,8 @@ SILC_FSM_STATE(silc_client_command_kick)
     goto out;
   }
 
     goto out;
   }
 
-  /* Parse the typed nickname. */
-  silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
-
   /* Get the target client */
   /* 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]);
   if (!clients) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "No such client: %s", cmd->argv[2]);
@@ -2126,7 +2349,6 @@ SILC_FSM_STATE(silc_client_command_kick)
 
   silc_buffer_free(idp);
   silc_buffer_free(idp2);
 
   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);
 
   silc_client_list_free(client, conn, clients);
   silc_client_unref_channel(client, conn, channel);
 
@@ -2135,12 +2357,11 @@ SILC_FSM_STATE(silc_client_command_kick)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** 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);
 
  out:
   silc_client_unref_channel(client, conn, channel);
-  silc_free(nickname);
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /***************************** OPER & SILCOPER ******************************/
 }
 
 /***************************** OPER & SILCOPER ******************************/
@@ -2148,11 +2369,12 @@ SILC_FSM_STATE(silc_client_command_kick)
 typedef struct {
   unsigned char *passphrase;
   SilcUInt32 passphrase_len;
 typedef struct {
   unsigned char *passphrase;
   SilcUInt32 passphrase_len;
+  SilcBuffer auth;
 } *SilcClientCommandOper;
 
 /* Ask passphrase callback */
 
 } *SilcClientCommandOper;
 
 /* 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;
                                        SilcUInt32 data_len, void *context)
 {
   SilcClientCommandContext cmd = context;
@@ -2166,6 +2388,19 @@ static void silc_client_command_oper_cb(unsigned char *data,
   SILC_FSM_CALL_CONTINUE(&cmd->thread);
 }
 
   SILC_FSM_CALL_CONTINUE(&cmd->thread);
 }
 
+static void silc_client_command_oper_sign_cb(const SilcBuffer data,
+                                            void *context)
+{
+  SilcClientCommandContext cmd = context;
+  SilcClientCommandOper oper = cmd->context;
+
+  if (data)
+    oper->auth = silc_buffer_copy(data);
+
+  /* Continue */
+  SILC_FSM_CALL_CONTINUE(&cmd->thread);
+}
+
 /* Send OPER/SILCOPER command */
 
 SILC_FSM_STATE(silc_client_command_oper_send)
 /* Send OPER/SILCOPER command */
 
 SILC_FSM_STATE(silc_client_command_oper_send)
@@ -2173,21 +2408,7 @@ SILC_FSM_STATE(silc_client_command_oper_send)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClientCommandOper oper = cmd->context;
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClientCommandOper oper = cmd->context;
-  SilcBuffer auth;
-
-  if (!oper || !oper->passphrase) {
-    /* Encode the public key authentication payload */
-    auth = silc_auth_public_key_auth_generate(conn->public_key,
-                                             conn->private_key,
-                                             conn->client->rng,
-                                             conn->internal->hash,
-                                             conn->local_id,
-                                             SILC_ID_CLIENT);
-  } else {
-    /* Encode the password authentication payload */
-    auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
-                                   oper->passphrase, oper->passphrase_len);
-  }
+  SilcBuffer auth = oper ? oper->auth : NULL;
 
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
                              1, cmd->argv[1], strlen(cmd->argv[1]),
 
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
                              1, cmd->argv[1], strlen(cmd->argv[1]),
@@ -2205,7 +2426,37 @@ SILC_FSM_STATE(silc_client_command_oper_send)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
+}
+
+/* Get authentication data */
+
+SILC_FSM_STATE(silc_client_command_oper_get_auth)
+{
+  SilcClientCommandContext cmd = fsm_context;
+  SilcClientConnection conn = cmd->conn;
+  SilcClientCommandOper oper = cmd->context;
+
+  silc_fsm_next(fsm, silc_client_command_oper_send);
+
+  if (!oper || !oper->passphrase) {
+    /* Encode the public key authentication payload */
+    SILC_FSM_CALL(silc_auth_public_key_auth_generate(
+                                      conn->public_key,
+                                      conn->private_key,
+                                      conn->client->rng,
+                                      conn->internal->hash,
+                                      conn->local_id, SILC_ID_CLIENT,
+                                      silc_client_command_oper_sign_cb,
+                                      oper));
+    /* NOT REACHED */
+  }
+
+  /* Encode the password authentication payload */
+  oper->auth = silc_auth_payload_encode(NULL, SILC_AUTH_PASSWORD, NULL, 0,
+                                       oper->passphrase, oper->passphrase_len);
+
+  return SILC_FSM_CONTINUE;
 }
 
 /* OPER command. Used to obtain server operator privileges. */
 }
 
 /* OPER command. Used to obtain server operator privileges. */
@@ -2220,22 +2471,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);
     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_get_auth);
+
   /* Get passphrase */
   if (cmd->argc < 3) {
     oper = silc_calloc(1, sizeof(*oper));
     if (!oper)
   /* 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));
   }
 
     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. */
 }
 
 /* SILCOPER command. Used to obtain router operator privileges. */
@@ -2250,22 +2502,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);
     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)
   /* 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));
   }
 
     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 ************************************/
 }
 
 /*********************************** BAN ************************************/
@@ -2316,7 +2569,7 @@ SILC_FSM_STATE(silc_client_command_ban)
       action[0] = 0x01;
 
     /* Check if it is public key file to be added to invite list */
       action[0] = 0x01;
 
     /* Check if it is public key file to be added to invite list */
-    silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
+    silc_pkcs_load_public_key(cmd->argv[2] + 1, SILC_PKCS_ANY, &pubkey);
     ban = cmd->argv[2];
     if (!pubkey)
       ban++;
     ban = cmd->argv[2];
     if (!pubkey)
       ban++;
@@ -2328,7 +2581,7 @@ SILC_FSM_STATE(silc_client_command_ban)
                       SILC_STR_UI_SHORT(1),
                       SILC_STR_END);
     if (pubkey) {
                       SILC_STR_UI_SHORT(1),
                       SILC_STR_END);
     if (pubkey) {
-      chidp = silc_public_key_payload_encode(pubkey);
+      chidp = silc_public_key_payload_encode(NULL, pubkey);
       args = silc_argument_payload_encode_one(args,
                                              silc_buffer_datalen(chidp), 2);
       silc_buffer_free(chidp);
       args = silc_argument_payload_encode_one(args,
                                              silc_buffer_datalen(chidp), 2);
       silc_buffer_free(chidp);
@@ -2355,10 +2608,10 @@ SILC_FSM_STATE(silc_client_command_ban)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************* DETACH ***********************************/
 }
 
 /********************************* DETACH ***********************************/
@@ -2377,7 +2630,7 @@ SILC_FSM_STATE(silc_client_command_detach)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 }
 
 /********************************** WATCH ***********************************/
 }
 
 /********************************** WATCH ***********************************/
@@ -2416,8 +2669,8 @@ SILC_FSM_STATE(silc_client_command_watch)
     SilcPublicKey pk;
     SilcBuffer buffer;
 
     SilcPublicKey pk;
     SilcBuffer buffer;
 
-    if (!silc_pkcs_load_public_key(pubkey, &pk)) {
-      SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+    if (!silc_pkcs_load_public_key(pubkey, SILC_PKCS_ANY, &pk)) {
+      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;
          "Could not load public key %s, check the filename", pubkey);
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
       goto out;
@@ -2427,13 +2680,19 @@ SILC_FSM_STATE(silc_client_command_watch)
     silc_buffer_format(args,
                       SILC_STR_UI_SHORT(1),
                       SILC_STR_END);
     silc_buffer_format(args,
                       SILC_STR_UI_SHORT(1),
                       SILC_STR_END);
-    buffer = silc_public_key_payload_encode(pk);
+    buffer = silc_public_key_payload_encode(NULL, pk);
     args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
                                            pubkey_add ? 0x00 : 0x01);
     silc_buffer_free(buffer);
     silc_pkcs_public_key_free(pk);
   }
 
     args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
                                            pubkey_add ? 0x00 : 0x01);
     silc_buffer_free(buffer);
     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->
   /* Send the commmand */
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
                              1, silc_buffer_datalen(conn->internal->
@@ -2449,10 +2708,10 @@ SILC_FSM_STATE(silc_client_command_watch)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************** LEAVE ***********************************/
 }
 
 /********************************** LEAVE ***********************************/
@@ -2466,7 +2725,7 @@ SILC_FSM_STATE(silc_client_command_leave)
   SilcClient client = conn->client;
   SilcChannelEntry channel;
   SilcBuffer idp;
   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,
 
   if (cmd->argc != 2) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
@@ -2480,7 +2739,15 @@ SILC_FSM_STATE(silc_client_command_leave)
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
       goto out;
     }
       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];
   }
   } else {
     name = cmd->argv[1];
   }
@@ -2510,10 +2777,10 @@ SILC_FSM_STATE(silc_client_command_leave)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************** USERS ***********************************/
 }
 
 /********************************** USERS ***********************************/
@@ -2525,7 +2792,7 @@ SILC_FSM_STATE(silc_client_command_users)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
 {
   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,
 
   if (cmd->argc != 2) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
@@ -2539,7 +2806,15 @@ SILC_FSM_STATE(silc_client_command_users)
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
       goto out;
     }
       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];
   }
   } else {
     name = cmd->argv[1];
   }
@@ -2553,10 +2828,10 @@ SILC_FSM_STATE(silc_client_command_users)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
-  SILC_FSM_CONTINUE;
+  return SILC_FSM_CONTINUE;
 
  out:
 
  out:
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 
 /********************************* GETKEY ***********************************/
 }
 
 /********************************* GETKEY ***********************************/
@@ -2571,25 +2846,17 @@ SILC_FSM_STATE(silc_client_command_getkey)
   SilcClientEntry client_entry;
   SilcServerEntry server_entry;
   SilcDList clients;
   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);
   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 */
   }
 
   /* 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]);
   if (!clients) {
     /* Check whether user requested server */
     server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
@@ -2599,7 +2866,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);
           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. */
       }
 
       /* No client or server exist with this name, query for both. */
@@ -2627,14 +2894,13 @@ SILC_FSM_STATE(silc_client_command_getkey)
                              1, silc_buffer_datalen(idp));
 
   silc_buffer_free(idp);
                              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);
 
   /* 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 **********************************/
 }
 
 /********************************* SERVICE **********************************/
@@ -2654,7 +2920,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);
     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];
   }
 
   name = cmd->argv[1];
@@ -2674,7 +2940,7 @@ SILC_FSM_STATE(silc_client_command_service)
 
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
 
   /** 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
 }
 
 /* Register all default commands provided by the client library for the
@@ -2749,18 +3015,60 @@ void silc_client_commands_unregister(SilcClient client)
 
 /****************** Client Side Incoming Command Handling *******************/
 
 
 /****************** Client Side Incoming Command Handling *******************/
 
-/* Reply to WHOIS command from server */
+typedef struct {
+  SilcClientConnection conn;
+  SilcUInt16 cmd_ident;
+} *SilcClientProcessWhois;
+
+/* Send reply to WHOIS from server */
+
+static void
+silc_client_command_process_whois_send(SilcBool success,
+                                      const unsigned char *data,
+                                      SilcUInt32 data_len, void *context)
+{
+  SilcClientProcessWhois w = context;
+  SilcBufferStruct buffer;
+  SilcBuffer packet;
+
+  if (!data) {
+    silc_free(w);
+    return;
+  }
+
+  silc_buffer_set(&buffer, (unsigned char *)data, data_len);
+
+  /* Send the attributes back in COMMAND_REPLY packet */
+  packet =
+    silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
+                                        SILC_STATUS_OK, 0, w->cmd_ident,
+                                        1, 11, buffer.data,
+                                        silc_buffer_len(&buffer));
+  if (!packet) {
+    silc_free(w);
+    return;
+  }
+
+  SILC_LOG_DEBUG(("Sending back requested WHOIS attributes"));
+
+  silc_packet_send(w->conn->stream, SILC_PACKET_COMMAND_REPLY, 0,
+                  silc_buffer_datalen(packet));
+
+  silc_buffer_free(packet);
+  silc_free(w);
+}
+
+/* Process WHOIS command from server */
 
 static void silc_client_command_process_whois(SilcClient client,
                                              SilcClientConnection conn,
                                              SilcCommandPayload payload,
                                              SilcArgumentPayload args)
 {
 
 static void silc_client_command_process_whois(SilcClient client,
                                              SilcClientConnection conn,
                                              SilcCommandPayload payload,
                                              SilcArgumentPayload args)
 {
-#if 0
+  SilcClientProcessWhois w;
   SilcDList attrs;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
   SilcDList attrs;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
-  SilcBuffer buffer, packet;
 
   SILC_LOG_DEBUG(("Received WHOIS command"));
 
 
   SILC_LOG_DEBUG(("Received WHOIS command"));
 
@@ -2773,25 +3081,18 @@ static void silc_client_command_process_whois(SilcClient client,
   if (!attrs)
     return;
 
   if (!attrs)
     return;
 
-  /* Process requested attributes */
-  buffer = silc_client_attributes_process(client, conn, attrs);
-  if (!buffer) {
+  w = silc_calloc(1, sizeof(*w));
+  if (!w) {
     silc_attribute_payload_list_free(attrs);
     return;
   }
     silc_attribute_payload_list_free(attrs);
     return;
   }
+  w->conn = conn;
+  w->cmd_ident = silc_command_get_ident(payload);
 
 
-  /* Send the attributes back */
-  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);
-  silc_buffer_free(packet);
-  silc_buffer_free(buffer);
-#endif /* 0 */
+  /* Process requested attributes */
+  silc_client_attributes_process(client, conn, attrs,
+                                silc_client_command_process_whois_send, w);
+  silc_attribute_payload_list_free(attrs);
 }
 
 /* Client is able to receive some command packets even though they are
 }
 
 /* Client is able to receive some command packets even though they are
@@ -2815,7 +3116,7 @@ SILC_FSM_STATE(silc_client_command)
                                       silc_buffer_len(&packet->buffer));
   if (!payload) {
     SILC_LOG_DEBUG(("Bad command packet"));
                                       silc_buffer_len(&packet->buffer));
   if (!payload) {
     SILC_LOG_DEBUG(("Bad command packet"));
-    SILC_FSM_FINISH;
+    return SILC_FSM_FINISH;
   }
 
   /* Get arguments */
   }
 
   /* Get arguments */
@@ -2838,5 +3139,5 @@ SILC_FSM_STATE(silc_client_command)
   }
 
   silc_command_payload_free(payload);
   }
 
   silc_command_payload_free(payload);
-  SILC_FSM_FINISH;
+  return SILC_FSM_FINISH;
 }
 }