Merge commit 'origin/silc.1.1.branch'
[silc.git] / lib / silcclient / command.c
index 19b9fc6c07646ace947e14477d9593e2b893e639..b5827f22819405d28285b296fdb10e15997d93c9 100644 (file)
@@ -411,6 +411,7 @@ SilcUInt16 silc_client_command_call(SilcClient client,
   SilcUInt32 argc = 0;
   unsigned char **argv = NULL;
   SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
+  SilcUInt16 cmd_ident;
   SilcClientCommand command;
   SilcClientCommandContext cmd;
   char *arg;
@@ -480,7 +481,7 @@ SilcUInt16 silc_client_command_call(SilcClient client,
   cmd->argv = argv;
   cmd->argv_lens = argv_lens;
   cmd->argv_types = argv_types;
-  cmd->cmd_ident = silc_client_cmd_ident(conn);
+  cmd_ident = cmd->cmd_ident = silc_client_cmd_ident(conn);
   cmd->called = TRUE;
   cmd->verbose = TRUE;
   silc_list_init(cmd->reply_callbacks,
@@ -492,7 +493,7 @@ SilcUInt16 silc_client_command_call(SilcClient client,
                       silc_client_command_destructor, NULL, FALSE);
   silc_fsm_start_sync(&cmd->thread, command->command);
 
-  return cmd->cmd_ident;
+  return cmd_ident;
 }
 
 /* Generic function to send any command. The arguments must be sent already
@@ -696,7 +697,7 @@ SILC_FSM_STATE(silc_client_command_whois)
     SilcAttributeObjPk obj;
     SilcPublicKey pk;
 
-    if (!silc_pkcs_load_public_key(pubkey, &pk)) {
+    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);
@@ -721,17 +722,19 @@ SILC_FSM_STATE(silc_client_command_whois)
       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));
+    silc_free(obj.data);
   }
 
-  silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname);
-  if (!nickname)
-    nickname = strdup(cmd->argv[1]);
+  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,
@@ -935,7 +938,7 @@ SILC_FSM_STATE(silc_client_command_topic)
   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,
@@ -950,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];
   }
@@ -1040,7 +1051,10 @@ SILC_FSM_STATE(silc_client_command_invite)
   /* 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 */
       clients = silc_client_get_clients_local(client, conn, cmd->argv[2],
@@ -1060,7 +1074,7 @@ SILC_FSM_STATE(silc_client_command_invite)
        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++;
@@ -1073,7 +1087,7 @@ SILC_FSM_STATE(silc_client_command_invite)
                       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);
@@ -1165,6 +1179,55 @@ SILC_FSM_STATE(silc_client_command_quit)
 
 /********************************** 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. */
 
@@ -1173,10 +1236,9 @@ SILC_FSM_STATE(silc_client_command_kill)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
-  SilcBuffer idp, auth = NULL;
   SilcClientEntry target;
   SilcDList clients;
-  char *nickname = NULL, *comment = NULL;
+  char *nickname = NULL;
 
   if (cmd->argc < 2) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
@@ -1198,38 +1260,30 @@ SILC_FSM_STATE(silc_client_command_kill)
                                          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 */
-      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);
   return SILC_FSM_CONTINUE;
 }
 
@@ -1312,6 +1366,33 @@ SILC_FSM_STATE(silc_client_command_ping)
 
 /********************************** 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)
@@ -1320,6 +1401,7 @@ SILC_FSM_STATE(silc_client_command_join)
   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;
@@ -1358,46 +1440,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")) {
-      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;
-      unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
+      unsigned char *pk, pkhash[SILC_HASH_MAXLEN], pubdata[128];
       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_COMMAND_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])) {
@@ -1425,12 +1538,15 @@ SILC_FSM_STATE(silc_client_command_join)
                              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 (j) {
+    silc_buffer_free(j->auth);
+    silc_buffer_free(j->cauth);
+    silc_free(j);
+  }
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -1619,6 +1735,22 @@ SILC_FSM_STATE(silc_client_command_umode)
 
 /********************************** 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). */
@@ -1628,8 +1760,9 @@ SILC_FSM_STATE(silc_client_command_cmode)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
+  SilcBuffer auth = state_context;
   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;
@@ -1786,31 +1919,38 @@ SILC_FSM_STATE(silc_client_command_cmode)
       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_COMMAND_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 {
@@ -1833,10 +1973,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) {
@@ -1849,7 +1993,8 @@ SILC_FSM_STATE(silc_client_command_cmode)
        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)) {
+         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]);
@@ -1859,7 +2004,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
          }
 
          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);
@@ -1918,6 +2063,22 @@ SILC_FSM_STATE(silc_client_command_cmode)
 
 /********************************* 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)
@@ -1925,10 +2086,11 @@ SILC_FSM_STATE(silc_client_command_cumode)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
+  SilcBuffer auth = state_context;
   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;
@@ -1961,7 +2123,8 @@ SILC_FSM_STATE(silc_client_command_cumode)
   }
 
   /* 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 */
   clients = silc_client_get_clients_local(client, conn, cmd->argv[3], FALSE);
@@ -2002,27 +2165,38 @@ SILC_FSM_STATE(silc_client_command_cumode)
       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_COMMAND_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;
@@ -2112,7 +2286,7 @@ SILC_FSM_STATE(silc_client_command_kick)
   SilcBuffer idp, idp2;
   SilcClientEntry target;
   SilcDList clients = NULL;
-  char *name;
+  char *name, tmp[512];
 
   if (cmd->argc < 3) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
@@ -2126,7 +2300,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];
   }
@@ -2188,11 +2370,12 @@ SILC_FSM_STATE(silc_client_command_kick)
 typedef struct {
   unsigned char *passphrase;
   SilcUInt32 passphrase_len;
+  SilcBuffer auth;
 } *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;
@@ -2206,6 +2389,19 @@ static void silc_client_command_oper_cb(unsigned char *data,
   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)
@@ -2213,21 +2409,7 @@ SILC_FSM_STATE(silc_client_command_oper_send)
   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]),
@@ -2248,6 +2430,36 @@ SILC_FSM_STATE(silc_client_command_oper_send)
   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. */
 
 SILC_FSM_STATE(silc_client_command_oper)
@@ -2263,7 +2475,7 @@ SILC_FSM_STATE(silc_client_command_oper)
     return SILC_FSM_FINISH;
   }
 
-  silc_fsm_next(fsm, silc_client_command_oper_send);
+  silc_fsm_next(fsm, silc_client_command_oper_get_auth);
 
   /* Get passphrase */
   if (cmd->argc < 3) {
@@ -2358,7 +2570,7 @@ SILC_FSM_STATE(silc_client_command_ban)
       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++;
@@ -2370,7 +2582,7 @@ SILC_FSM_STATE(silc_client_command_ban)
                       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);
@@ -2458,7 +2670,7 @@ SILC_FSM_STATE(silc_client_command_watch)
     SilcPublicKey pk;
     SilcBuffer buffer;
 
-    if (!silc_pkcs_load_public_key(pubkey, &pk)) {
+    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);
@@ -2469,7 +2681,7 @@ SILC_FSM_STATE(silc_client_command_watch)
     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);
@@ -2514,7 +2726,7 @@ SILC_FSM_STATE(silc_client_command_leave)
   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,
@@ -2528,7 +2740,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];
   }
@@ -2573,7 +2793,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,
@@ -2587,7 +2807,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];
   }
@@ -2788,17 +3016,60 @@ void silc_client_commands_unregister(SilcClient client)
 
 /****************** 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)
 {
+  SilcClientProcessWhois w;
   SilcDList attrs;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
-  SilcBuffer buffer, packet;
 
   SILC_LOG_DEBUG(("Received WHOIS command"));
 
@@ -2811,32 +3082,18 @@ static void silc_client_command_process_whois(SilcClient client,
   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;
   }
+  w->conn = conn;
+  w->cmd_ident = silc_command_get_ident(payload);
 
-  /* 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,
-                                        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);
+  /* 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