updates.
[silc.git] / lib / silcclient / command.c
index 607ff9fc8151b8ad01a5e38efe8ee3b9a795582a..3e6839fad2fb0fe9a206909c22d3c7e032acade2 100644 (file)
@@ -63,7 +63,7 @@ SilcClientCommand silc_command_list[] =
 };
 
 #define SILC_NOT_CONNECTED(x, c) \
-  x->ops->say((x), (c), \
+  x->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
           "You are not connected to a server, use /SERVER to connect");
 
 /* Command operation that is called at the end of all commands. 
@@ -195,6 +195,8 @@ void silc_client_command_free(SilcClientCommandContext ctx)
 
     for (i = 0; i < ctx->argc; i++)
       silc_free(ctx->argv[i]);
+    silc_free(ctx->argv_lens);
+    silc_free(ctx->argv_types);
     silc_free(ctx);
   }
 }
@@ -242,10 +244,13 @@ SILC_CLIENT_CMD_FUNC(whois)
     goto out;
   }
 
-  if (cmd->argc < 2 || cmd->argc > 3) {
-    cmd->client->ops->say(cmd->client, conn, 
-            "Usage: /WHOIS <nickname>[@<server>] [<count>]");
-    COMMAND_ERROR;
+  /* Given without arguments fetches client's own information */
+  if (cmd->argc < 2) {
+    buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
+    silc_client_send_command(cmd->client, cmd->conn, SILC_COMMAND_WHOIS, 
+                            ++conn->cmd_ident,
+                            1, 3, buffer->data, buffer->len);
+    silc_buffer_free(buffer);
     goto out;
   }
 
@@ -284,7 +289,7 @@ SILC_CLIENT_CMD_FUNC(whowas)
   }
 
   if (cmd->argc < 2 || cmd->argc > 3) {
-    cmd->client->ops->say(cmd->client, conn, 
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
             "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
     COMMAND_ERROR;
     goto out;
@@ -325,7 +330,7 @@ SILC_CLIENT_CMD_FUNC(identify)
   }
 
   if (cmd->argc < 2 || cmd->argc > 3) {
-    cmd->client->ops->say(cmd->client, conn,
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
             "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
     COMMAND_ERROR;
     goto out;
@@ -365,17 +370,23 @@ SILC_CLIENT_CMD_FUNC(nick)
     goto out;
   }
 
+  if (cmd->argc < 2) {
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /NICK <nickname>");
+    COMMAND_ERROR;
+    goto out;
+  }
+
   if (!strcmp(conn->nickname, cmd->argv[1]))
     goto out;
 
   /* Show current nickname */
   if (cmd->argc < 2) {
     if (cmd->conn) {
-      cmd->client->ops->say(cmd->client, conn, 
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                            "Your nickname is %s on server %s", 
                            conn->nickname, conn->remote_host);
     } else {
-      cmd->client->ops->say(cmd->client, conn, 
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                            "Your nickname is %s", conn->nickname);
     }
 
@@ -474,7 +485,7 @@ SILC_CLIENT_CMD_FUNC(topic)
   }
 
   if (cmd->argc < 2 || cmd->argc > 3) {
-    cmd->client->ops->say(cmd->client, conn,
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
                          "Usage: /TOPIC <channel> [<topic>]");
     COMMAND_ERROR;
     goto out;
@@ -482,7 +493,7 @@ SILC_CLIENT_CMD_FUNC(topic)
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
       COMMAND_ERROR;
       goto out;
     }
@@ -492,14 +503,14 @@ SILC_CLIENT_CMD_FUNC(topic)
   }
 
   if (!conn->current_channel) {
-    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
     COMMAND_ERROR;
     goto out;
   }
 
   /* Get the Channel ID of the channel */
   if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
-    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
     COMMAND_ERROR;
     goto out;
   }
@@ -509,14 +520,15 @@ SILC_CLIENT_CMD_FUNC(topic)
   /* Send TOPIC command to the server */
   idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
   if (cmd->argc > 2)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 0, 2, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 
+                                           ++conn->cmd_ident, 2, 
                                            1, idp->data, idp->len,
                                            2, cmd->argv[2], 
                                            strlen(cmd->argv[2]));
   else
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 1, 
-                                           1, idp->data, idp->len,
-                                           0);
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 
+                                           ++conn->cmd_ident, 1,
+                                           1, idp->data, idp->len);
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
@@ -551,7 +563,7 @@ SILC_CLIENT_CMD_FUNC(invite)
   }
 
   if (cmd->argc < 2) {
-    cmd->client->ops->say(cmd->client, conn,
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
                   "Usage: /INVITE <channel> [<nickname>[@server>]"
                   "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
     COMMAND_ERROR;
@@ -560,7 +572,7 @@ SILC_CLIENT_CMD_FUNC(invite)
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
       COMMAND_ERROR;
       goto out;
     }
@@ -571,7 +583,7 @@ SILC_CLIENT_CMD_FUNC(invite)
 
     channel = silc_client_get_channel(cmd->client, conn, name);
     if (!channel) {
-      cmd->client->ops->say(cmd->client, conn, "You are on that channel");
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are on that channel");
       COMMAND_ERROR;
       goto out;
     }
@@ -581,7 +593,7 @@ SILC_CLIENT_CMD_FUNC(invite)
   if (cmd->argc == 3) {
     if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
       if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
-       cmd->client->ops->say(cmd->client, conn, "Bad nickname");
+       cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
        COMMAND_ERROR;
        goto out;
       }
@@ -610,10 +622,6 @@ SILC_CLIENT_CMD_FUNC(invite)
        cmd->pending = 1;
        return;
       }
-      
-      cmd->client->ops->say(cmd->client, conn, 
-                           "Inviting %s to channel %s", cmd->argv[2], 
-                           channel->channel_name);
     } else {
       invite = cmd->argv[2];
       invite++;
@@ -736,7 +744,7 @@ SILC_CLIENT_CMD_FUNC(kill)
   }
 
   if (cmd->argc < 2) {
-    cmd->client->ops->say(cmd->client, conn, 
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                          "Usage: /KILL <nickname> [<comment>]");
     COMMAND_ERROR;
     goto out;
@@ -744,7 +752,8 @@ SILC_CLIENT_CMD_FUNC(kill)
 
   /* Parse the typed nickname. */
   if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
-    cmd->client->ops->say(cmd->client, conn, "Bad nickname");
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+                         "Bad nickname");
     COMMAND_ERROR;
     goto out;
   }
@@ -848,7 +857,6 @@ SILC_CLIENT_CMD_FUNC(ping)
   SilcBuffer buffer;
   void *id;
   int i;
-  char *name = NULL;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -856,9 +864,6 @@ SILC_CLIENT_CMD_FUNC(ping)
     goto out;
   }
 
-  if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
-    name = strdup(conn->remote_host);
-
   /* Send the command */
   buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1, 
                                          1, conn->remote_id_data, 
@@ -881,7 +886,7 @@ SILC_CLIENT_CMD_FUNC(ping)
     if (conn->ping[i].dest_id == NULL) {
       conn->ping[i].start_time = time(NULL);
       conn->ping[i].dest_id = id;
-      conn->ping[i].dest_name = name;
+      conn->ping[i].dest_name = strdup(conn->remote_host);
       conn->ping_count++;
       break;
     }
@@ -891,7 +896,7 @@ SILC_CLIENT_CMD_FUNC(ping)
     conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
     conn->ping[i].start_time = time(NULL);
     conn->ping[i].dest_id = id;
-    conn->ping[i].dest_name = name;
+    conn->ping[i].dest_name = strdup(conn->remote_host);
     conn->ping_count++;
   }
   
@@ -930,10 +935,10 @@ SILC_CLIENT_CMD_FUNC(join)
   /* See if we have joined to the requested channel already */
   if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
                                    &id_cache)) {
-    cmd->client->ops->say(cmd->client, conn, 
+#if 0
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                          "You are talking to channel %s", cmd->argv[1]);
     conn->current_channel = (SilcChannelEntry)id_cache->context;
-#if 0
     cmd->client->screen->bottom_line->channel = cmd->argv[1];
     silc_screen_print_bottom_line(cmd->client->screen, 0);
 #endif
@@ -990,7 +995,7 @@ SILC_CLIENT_CMD_FUNC(motd)
   }
 
   if (cmd->argc < 1 || cmd->argc > 2) {
-    cmd->client->ops->say(cmd->client, conn,
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
                          "Usage: /MOTD [<server>]");
     COMMAND_ERROR;
     goto out;
@@ -1035,7 +1040,7 @@ SILC_CLIENT_CMD_FUNC(umode)
   }
 
   if (cmd->argc < 2) {
-    cmd->client->ops->say(cmd->client, conn, 
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                  "Usage: /UMODE +|-<modes>");
     COMMAND_ERROR;
     goto out;
@@ -1130,7 +1135,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
   }
 
   if (cmd->argc < 3) {
-    cmd->client->ops->say(cmd->client, conn, 
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                  "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
     COMMAND_ERROR;
     goto out;
@@ -1138,7 +1143,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
       COMMAND_ERROR;
       goto out;
     }
@@ -1149,7 +1154,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
 
     channel = silc_client_get_channel(cmd->client, conn, name);
     if (!channel) {
-      cmd->client->ops->say(cmd->client, conn, "You are on that channel");
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are on that channel");
       COMMAND_ERROR;
       goto out;
     }
@@ -1206,6 +1211,12 @@ SILC_CLIENT_CMD_FUNC(cmode)
        int ll;
        mode |= SILC_CHANNEL_MODE_ULIMIT;
        type = 3;
+       if (cmd->argc < 4) {
+         cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+              "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
+         COMMAND_ERROR;
+         goto out;
+       }
        ll = atoi(cmd->argv[3]);
        SILC_PUT32_MSB(ll, tmp);
        arg = tmp;
@@ -1218,6 +1229,12 @@ SILC_CLIENT_CMD_FUNC(cmode)
       if (add) {
        mode |= SILC_CHANNEL_MODE_PASSPHRASE;
        type = 4;
+       if (cmd->argc < 4) {
+         cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+              "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
+         COMMAND_ERROR;
+         goto out;
+       }
        arg = cmd->argv[3];
        arg_len = cmd->argv_lens[3];
       } else {
@@ -1228,6 +1245,12 @@ SILC_CLIENT_CMD_FUNC(cmode)
       if (add) {
        mode |= SILC_CHANNEL_MODE_CIPHER;
        type = 5;
+       if (cmd->argc < 4) {
+         cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+              "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
+         COMMAND_ERROR;
+         goto out;
+       }
        arg = cmd->argv[3];
        arg_len = cmd->argv_lens[3];
       } else {
@@ -1238,6 +1261,12 @@ SILC_CLIENT_CMD_FUNC(cmode)
       if (add) {
        mode |= SILC_CHANNEL_MODE_HMAC;
        type = 6;
+       if (cmd->argc < 4) {
+         cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+              "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
+         COMMAND_ERROR;
+         goto out;
+       }
        arg = cmd->argv[3];
        arg_len = cmd->argv_lens[3];
       } else {
@@ -1249,6 +1278,13 @@ SILC_CLIENT_CMD_FUNC(cmode)
        mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
        type = 7;
 
+       if (cmd->argc < 4) {
+         cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+              "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
+         COMMAND_ERROR;
+         goto out;
+       }
+
        if (!strcasecmp(cmd->argv[3], "-pubkey")) {
          auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
                                                    cmd->client->private_key,
@@ -1273,11 +1309,6 @@ SILC_CLIENT_CMD_FUNC(cmode)
     }
   }
 
-  if (type && cmd->argc < 3) {
-    COMMAND_ERROR;
-    goto out;
-  }
-
   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
   SILC_PUT32_MSB(mode, modebuf);
 
@@ -1333,7 +1364,7 @@ SILC_CLIENT_CMD_FUNC(cumode)
   }
 
   if (cmd->argc < 4) {
-    cmd->client->ops->say(cmd->client, conn, 
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                  "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
     COMMAND_ERROR;
     goto out;
@@ -1341,7 +1372,7 @@ SILC_CLIENT_CMD_FUNC(cumode)
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
       COMMAND_ERROR;
       goto out;
     }
@@ -1352,7 +1383,7 @@ SILC_CLIENT_CMD_FUNC(cumode)
 
     channel = silc_client_get_channel(cmd->client, conn, name);
     if (!channel) {
-      cmd->client->ops->say(cmd->client, conn, "You are on that channel");
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are on that channel");
       COMMAND_ERROR;
       goto out;
     }
@@ -1360,7 +1391,7 @@ SILC_CLIENT_CMD_FUNC(cumode)
 
   /* Parse the typed nickname. */
   if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
-    cmd->client->ops->say(cmd->client, conn, "Bad nickname");
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
     COMMAND_ERROR;
     goto out;
   }
@@ -1385,9 +1416,10 @@ SILC_CLIENT_CMD_FUNC(cumode)
     return;
   }
   
+  /* Get the current mode */
   while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
     if (chu->client == client_entry) {
-      chu->mode = mode;
+      mode = chu->mode;
       break;
     }
   }
@@ -1496,7 +1528,7 @@ SILC_CLIENT_CMD_FUNC(kick)
   }
 
   if (cmd->argc < 3) {
-    cmd->client->ops->say(cmd->client, conn, 
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                          "Usage: /KICK <channel> <nickname> [<comment>]");
     COMMAND_ERROR;
     goto out;
@@ -1504,7 +1536,7 @@ SILC_CLIENT_CMD_FUNC(kick)
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
       COMMAND_ERROR;
       goto out;
     }
@@ -1514,14 +1546,14 @@ SILC_CLIENT_CMD_FUNC(kick)
   }
 
   if (!conn->current_channel) {
-    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
     COMMAND_ERROR;
     goto out;
   }
 
   /* Get the Channel ID of the channel */
   if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
-    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
     COMMAND_ERROR;
     goto out;
   }
@@ -1530,7 +1562,7 @@ SILC_CLIENT_CMD_FUNC(kick)
 
   /* Parse the typed nickname. */
   if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
-    cmd->client->ops->say(cmd->client, conn, "Bad nickname");
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
     COMMAND_ERROR;
     goto out;
   }
@@ -1539,7 +1571,7 @@ SILC_CLIENT_CMD_FUNC(kick)
   target = silc_idlist_get_client(cmd->client, conn, nickname, 
                                  server, num, FALSE);
   if (!target) {
-    cmd->client->ops->say(cmd->client, conn, "No such client: %s",
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "No such client: %s",
                          cmd->argv[2]);
     COMMAND_ERROR;
     goto out;
@@ -1575,15 +1607,44 @@ SILC_CLIENT_CMD_FUNC(kick)
   silc_client_command_free(cmd);
 }
 
+static void silc_client_command_oper_send(unsigned char *data,
+                                         uint32 data_len, void *context)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcBuffer buffer, auth;
+
+  if (cmd->argc == 3) {
+    /* Pulic key auth XXX TODO */
+    auth = NULL;
+  } else {
+    /* Encode the authentication payload */
+    auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
+                                   data, data_len);
+  }
+
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2, 
+                                         1, cmd->argv[1], 
+                                         strlen(cmd->argv[1]),
+                                         2, auth->data, auth->len);
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+                         0, NULL, NULL, buffer->data, buffer->len, TRUE);
+
+  silc_buffer_free(buffer);
+  silc_buffer_free(auth);
+
+  /* Notify application */
+  COMMAND;
+}
+
 /* OPER command. Used to obtain server operator privileges. */
 
 SILC_CLIENT_CMD_FUNC(oper)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
-  SilcBuffer buffer;
   unsigned char *auth_data;
-  SilcBuffer auth;
+  uint32 auth_data_len = 0;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -1592,7 +1653,7 @@ SILC_CLIENT_CMD_FUNC(oper)
   }
 
   if (cmd->argc < 2) {
-    cmd->client->ops->say(cmd->client, conn, 
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                          "Usage: /OPER <username> [<public key>]");
     COMMAND_ERROR;
     goto out;
@@ -1605,19 +1666,41 @@ SILC_CLIENT_CMD_FUNC(oper)
     goto out;
   } else {
     /* Get passphrase */
+    cmd->client->ops->ask_passphrase(cmd->client, conn,
+                                    silc_client_command_oper_send,
+                                    context);
+    return;
+  }
 
-    auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
-    if (!auth_data) {
-      COMMAND_ERROR;
-      goto out;
-    }
+  silc_client_command_oper_send(auth_data, auth_data_len, context);
+
+  memset(auth_data, 0, auth_data_len);
+  silc_free(auth_data);
 
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+static void silc_client_command_silcoper_send(unsigned char *data,
+                                             uint32 data_len, void *context)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcBuffer buffer, auth;
+
+  if (cmd->argc == 3) {
+    /* Pulic key auth XXX TODO */
+    auth = NULL;
+  } else {
     /* Encode the authentication payload */
     auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
-                                   auth_data, strlen(auth_data));
+                                   data, data_len);
   }
 
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2, 
                                          1, cmd->argv[1], 
                                          strlen(cmd->argv[1]),
                                          2, auth->data, auth->len);
@@ -1626,14 +1709,9 @@ SILC_CLIENT_CMD_FUNC(oper)
 
   silc_buffer_free(buffer);
   silc_buffer_free(auth);
-  memset(auth_data, 0, strlen(auth_data));
-  silc_free(auth_data);
 
   /* Notify application */
   COMMAND;
-
- out:
-  silc_client_command_free(cmd);
 }
 
 /* SILCOPER command. Used to obtain router operator privileges. */
@@ -1642,9 +1720,8 @@ SILC_CLIENT_CMD_FUNC(silcoper)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
-  SilcBuffer buffer;
   unsigned char *auth_data;
-  SilcBuffer auth;
+  uint32 auth_data_len = 0;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -1653,7 +1730,7 @@ SILC_CLIENT_CMD_FUNC(silcoper)
   }
 
   if (cmd->argc < 2) {
-    cmd->client->ops->say(cmd->client, conn, 
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                          "Usage: /SILCOPER <username> [<public key>]");
     COMMAND_ERROR;
     goto out;
@@ -1666,28 +1743,15 @@ SILC_CLIENT_CMD_FUNC(silcoper)
     goto out;
   } else {
     /* Get passphrase */
-
-    auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
-    if (!auth_data) {
-      COMMAND_ERROR;
-      goto out;
-    }
-
-    /* Encode the authentication payload */
-    auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
-                                   auth_data, strlen(auth_data));
+    cmd->client->ops->ask_passphrase(cmd->client, conn,
+                                    silc_client_command_silcoper_send,
+                                    context);
+    return;
   }
 
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2, 
-                                         1, cmd->argv[1], 
-                                         strlen(cmd->argv[1]),
-                                         2, auth->data, auth->len);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
-                         0, NULL, NULL, buffer->data, buffer->len, TRUE);
+  silc_client_command_silcoper_send(auth_data, auth_data_len, context);
 
-  silc_buffer_free(buffer);
-  silc_buffer_free(auth);
-  memset(auth_data, 0, strlen(auth_data));
+  memset(auth_data, 0, auth_data_len);
   silc_free(auth_data);
 
   /* Notify application */
@@ -1714,7 +1778,7 @@ SILC_CLIENT_CMD_FUNC(connect)
   }
 
   if (cmd->argc < 2) {
-    cmd->client->ops->say(cmd->client, conn, 
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                          "Usage: /CONNECT <server> [<port>]");
     COMMAND_ERROR;
     goto out;
@@ -1763,7 +1827,7 @@ SILC_CLIENT_CMD_FUNC(ban)
   }
 
   if (cmd->argc < 2) {
-    cmd->client->ops->say(cmd->client, conn, 
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                   "Usage: /BAN <channel> "
                   "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
     COMMAND_ERROR;
@@ -1772,7 +1836,7 @@ SILC_CLIENT_CMD_FUNC(ban)
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
       COMMAND_ERROR;
       goto out;
     }
@@ -1783,7 +1847,7 @@ SILC_CLIENT_CMD_FUNC(ban)
 
     channel = silc_client_get_channel(cmd->client, conn, name);
     if (!channel) {
-      cmd->client->ops->say(cmd->client, conn, "You are on that channel");
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are on that channel");
       COMMAND_ERROR;
       goto out;
     }
@@ -1839,7 +1903,7 @@ SILC_CLIENT_CMD_FUNC(close)
   }
 
   if (cmd->argc < 2) {
-    cmd->client->ops->say(cmd->client, conn, 
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                          "Usage: /CLOSE <server> [<port>]");
     COMMAND_ERROR;
     goto out;
@@ -1911,14 +1975,14 @@ SILC_CLIENT_CMD_FUNC(leave)
   }
 
   if (cmd->argc != 2) {
-    cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /LEAVE <channel>");
     COMMAND_ERROR;
     goto out;
   }
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
       COMMAND_ERROR;
       goto out;
     }
@@ -1927,15 +1991,9 @@ SILC_CLIENT_CMD_FUNC(leave)
     name = cmd->argv[1];
   }
 
-  if (!conn->current_channel) {
-    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
-    COMMAND_ERROR;
-    goto out;
-  }
-
   /* Get the Channel ID of the channel */
   if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
-    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
     COMMAND_ERROR;
     goto out;
   }
@@ -1951,10 +2009,11 @@ SILC_CLIENT_CMD_FUNC(leave)
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
 
-  /* We won't talk anymore on this channel */
-  cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
+  /* Notify application */
+  COMMAND;
 
-  conn->current_channel = NULL;
+  if (conn->current_channel == channel)
+    conn->current_channel = NULL;
 
   silc_idcache_del_by_id(conn->channel_cache, channel->id);
   silc_free(channel->channel_name);
@@ -1963,9 +2022,6 @@ SILC_CLIENT_CMD_FUNC(leave)
   silc_cipher_free(channel->channel_key);
   silc_free(channel);
 
-  /* Notify application */
-  COMMAND;
-
  out:
   silc_client_command_free(cmd);
 }
@@ -1989,14 +2045,14 @@ SILC_CLIENT_CMD_FUNC(users)
   }
 
   if (cmd->argc != 2) {
-    cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /USERS <channel>");
     COMMAND_ERROR;
     goto out;
   }
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
       COMMAND_ERROR;
       goto out;
     }
@@ -2006,7 +2062,7 @@ SILC_CLIENT_CMD_FUNC(users)
   }
 
   if (!conn->current_channel) {
-    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
     COMMAND_ERROR;
     goto out;
   }
@@ -2014,7 +2070,7 @@ SILC_CLIENT_CMD_FUNC(users)
   /* Get the Channel ID of the channel */
   if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
     /* XXX should resolve the channel ID; LIST command */
-    cmd->client->ops->say(cmd->client, conn, 
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
                          "You are not on that channel", name);
     COMMAND_ERROR;
     goto out;
@@ -2071,14 +2127,14 @@ SILC_CLIENT_CMD_FUNC(getkey)
   }
 
   if (cmd->argc < 2) {
-    client->ops->say(client, conn, "Usage: /GETKEY <nickname>");
+    client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /GETKEY <nickname>");
     COMMAND_ERROR;
     goto out;
   }
 
   /* Parse the typed nickname. */
   if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
-    client->ops->say(client, conn, "Bad nickname");
+    client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
     COMMAND_ERROR;
     goto out;
   }