updates.
[silc.git] / lib / silcclient / command.c
index cb9519375a955209e904bd869d6ff5b7928b1e1d..781607e3ae676af4807153be70907c11804b9638 100644 (file)
@@ -219,16 +219,6 @@ static void silc_client_command_destructor(void *context)
   silc_client_command_free((SilcClientCommandContext)context);
 }
 
-/* silc_client_get_client completion callback */
-void silc_client_command_completion(SilcClient client,
-                                   SilcClientConnection conn,
-                                   SilcClientEntry clients,
-                                   uint32 clients_count,
-                                   void *context)
-{
-
-}
-
 /* Command WHOIS. This command is used to query information about 
    specific user. */
 
@@ -330,8 +320,6 @@ SILC_CLIENT_CMD_FUNC(identify)
   }
 
   if (cmd->argc < 2 || cmd->argc > 3) {
-    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
-            "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
     COMMAND_ERROR;
     goto out;
   }
@@ -397,7 +385,6 @@ SILC_CLIENT_CMD_FUNC(nick)
                            "Your nickname is %s", conn->nickname);
     }
 
-    /* XXX Notify application */
     COMMAND;
     goto out;
   }
@@ -500,7 +487,8 @@ SILC_CLIENT_CMD_FUNC(topic)
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "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;
     }
@@ -510,14 +498,16 @@ SILC_CLIENT_CMD_FUNC(topic)
   }
 
   if (!conn->current_channel) {
-    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "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, SILC_CLIENT_MESSAGE_INFO, "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;
   }
@@ -559,8 +549,8 @@ SILC_CLIENT_CMD_FUNC(invite)
   SilcClientEntry client_entry = NULL;
   SilcChannelEntry channel;
   SilcBuffer buffer, clidp, chidp;
-  uint32 num = 0, type = 0;
-  char *nickname = NULL, *server = NULL, *name;
+  uint32 type = 0;
+  char *nickname = NULL, *name;
   char *invite = NULL;
 
   if (!cmd->conn) {
@@ -579,7 +569,8 @@ SILC_CLIENT_CMD_FUNC(invite)
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "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;
     }
@@ -590,7 +581,8 @@ SILC_CLIENT_CMD_FUNC(invite)
 
     channel = silc_client_get_channel(cmd->client, conn, name);
     if (!channel) {
-      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "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;
     }
@@ -599,25 +591,20 @@ SILC_CLIENT_CMD_FUNC(invite)
   /* Parse the typed nickname. */
   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, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
-       COMMAND_ERROR;
-       goto out;
-      }
-      
+      if (client->params->nickname_parse)
+       client->params->nickname_parse(cmd->argv[2], &nickname);
+      else
+       nickname = strdup(cmd->argv[2]);
+
       /* Find client entry */
       client_entry = silc_idlist_get_client(client, conn, nickname, 
-                                           server, num, TRUE);
+                                           cmd->argv[2], TRUE);
       if (!client_entry) {
-       if (nickname)
-         silc_free(nickname);
-       if (server)
-         silc_free(server);
-       
        if (cmd->pending) {
          COMMAND_ERROR;
          goto out;
        }
+       silc_free(nickname);
       
        /* Client entry not found, it was requested thus mark this to be
           pending command. */
@@ -667,10 +654,7 @@ SILC_CLIENT_CMD_FUNC(invite)
   COMMAND;
 
  out:
-  if (nickname)
-    silc_free(nickname);
-  if (server)
-    silc_free(server);
+  silc_free(nickname);
   silc_client_command_free(cmd);
 }
 
@@ -720,10 +704,13 @@ SILC_CLIENT_CMD_FUNC(quit)
   q->client = cmd->client;
   q->conn = cmd->conn;
 
+  /* Sleep for a while */
+  sleep(2);
+
   /* We quit the connection with little timeout */
-  silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
-                    silc_client_command_quit_cb, (void *)q,
-                    1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
+                        silc_client_command_quit_cb, (void *)q,
+                        1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 
   /* Notify application */
   COMMAND;
@@ -732,17 +719,67 @@ SILC_CLIENT_CMD_FUNC(quit)
   silc_client_command_free(cmd);
 }
 
+/* Timeout callback to remove the killed client from cache */
+
+SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClient client = cmd->client;
+  SilcClientConnection conn = cmd->conn;
+  SilcClientEntry target;
+  char *nickname = NULL;
+  
+  /* Parse the typed nickname. */
+  if (client->params->nickname_parse)
+    client->params->nickname_parse(cmd->argv[1], &nickname);
+  else
+    nickname = strdup(cmd->argv[1]);
+
+  /* Get the target client */
+  target = silc_idlist_get_client(cmd->client, conn, nickname, 
+                                 cmd->argv[1], FALSE);
+  if (target) {
+    silc_client_remove_from_channels(client, conn, target);
+    silc_client_del_client(client, conn, target);
+  }
+
+  silc_free(nickname);
+  silc_client_command_free(cmd);
+}
+
+/* Kill command's pending command callback to actually remove the killed
+   client from our local cache. */
+
+SILC_CLIENT_CMD_FUNC(kill_remove)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientCommandReplyContext reply = 
+    (SilcClientCommandReplyContext)context2;
+  SilcCommandStatus status;
+
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
+  if (status == SILC_STATUS_OK) {
+    /* Remove with timeout */
+    silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
+                          silc_client_command_kill_remove_later, context,
+                          1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+    return;
+  }
+
+  silc_client_command_free(cmd);
+}
+
 /* Command KILL. Router operator can use this command to remove an client
    fromthe SILC Network. */
 
 SILC_CLIENT_CMD_FUNC(kill)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClient client = cmd->client;
   SilcClientConnection conn = cmd->conn;
   SilcBuffer buffer, idp;
   SilcClientEntry target;
-  uint32 num = 0;
-  char *nickname = NULL, *server = NULL;
+  char *nickname = NULL;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -758,26 +795,22 @@ 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, SILC_CLIENT_MESSAGE_INFO, 
-                         "Bad nickname");
-    COMMAND_ERROR;
-    goto out;
-  }
+  if (client->params->nickname_parse)
+    client->params->nickname_parse(cmd->argv[1], &nickname);
+  else
+    nickname = strdup(cmd->argv[1]);
 
   /* Get the target client */
   target = silc_idlist_get_client(cmd->client, conn, nickname, 
-                                 server, num, TRUE);
+                                 cmd->argv[1], TRUE);
   if (!target) {
-    silc_free(nickname);
-    if (server)
-      silc_free(server);
-
     if (cmd->pending) {
       COMMAND_ERROR;
       goto out;
     }
 
+    silc_free(nickname);
+
     /* Client entry not found, it was requested thus mark this to be
        pending command. */
     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
@@ -792,10 +825,12 @@ SILC_CLIENT_CMD_FUNC(kill)
   /* Send the KILL command to the server */
   idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
   if (cmd->argc == 2)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 
+                                           ++conn->cmd_ident, 1, 
                                            1, idp->data, idp->len);
   else
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 
+                                           ++conn->cmd_ident, 2, 
                                            1, idp->data, idp->len,
                                            2, cmd->argv[2], 
                                            strlen(cmd->argv[2]));
@@ -807,11 +842,14 @@ SILC_CLIENT_CMD_FUNC(kill)
   /* Notify application */
   COMMAND;
 
+  /* Register a pending callback that will actually remove the killed
+     client from our cache. */
+  silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
+                             NULL, silc_client_command_kill_remove,
+                             silc_client_command_dup(cmd));
+
  out:
-  if (nickname)
-    silc_free(nickname);
-  if (server)
-    silc_free(server);
+  silc_free(nickname);
   silc_client_command_free(cmd);
 }
 
@@ -914,10 +952,6 @@ SILC_CLIENT_CMD_FUNC(ping)
   silc_client_command_free(cmd);
 }
 
-SILC_CLIENT_CMD_FUNC(notice)
-{
-}
-
 /* Command JOIN. Joins to a channel. */
 
 SILC_CLIENT_CMD_FUNC(join)
@@ -933,23 +967,12 @@ SILC_CLIENT_CMD_FUNC(join)
     goto out;
   }
 
-  if (cmd->argc < 2) {
-    /* Show channels currently joined to */
-
-    goto out;
-  }
-
   /* 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)) {
-#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;
-    cmd->client->screen->bottom_line->channel = cmd->argv[1];
-    silc_screen_print_bottom_line(cmd->client->screen, 0);
-#endif
-    goto out;
+    SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
+    if (channel->on_channel)
+      goto out;
   }
 
   idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
@@ -1150,7 +1173,8 @@ SILC_CLIENT_CMD_FUNC(cmode)
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "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;
     }
@@ -1161,7 +1185,8 @@ SILC_CLIENT_CMD_FUNC(cmode)
 
     channel = silc_client_get_channel(cmd->client, conn, name);
     if (!channel) {
-      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "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;
     }
@@ -1353,6 +1378,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
 SILC_CLIENT_CMD_FUNC(cumode)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClient client = cmd->client;
   SilcClientConnection conn = cmd->conn;
   SilcChannelEntry channel;
   SilcChannelUser chu;
@@ -1360,8 +1386,7 @@ SILC_CLIENT_CMD_FUNC(cumode)
   SilcBuffer buffer, clidp, chidp, auth = NULL;
   unsigned char *name, *cp, modebuf[4];
   uint32 mode = 0, add, len;
-  char *nickname = NULL, *server = NULL;
-  uint32 num = 0;
+  char *nickname = NULL;
   int i;
 
   if (!cmd->conn) {
@@ -1379,7 +1404,8 @@ SILC_CLIENT_CMD_FUNC(cumode)
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "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;
     }
@@ -1390,28 +1416,30 @@ SILC_CLIENT_CMD_FUNC(cumode)
 
     channel = silc_client_get_channel(cmd->client, conn, name);
     if (!channel) {
-      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "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;
     }
   }
 
   /* Parse the typed nickname. */
-  if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
-    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
-    COMMAND_ERROR;
-    goto out;
-  }
+  if (client->params->nickname_parse)
+    client->params->nickname_parse(cmd->argv[3], &nickname);
+  else
+    nickname = strdup(cmd->argv[3]);
 
   /* Find client entry */
-  client_entry = silc_idlist_get_client(cmd->client, conn, 
-                                       nickname, server, num, TRUE);
+  client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
+                                       cmd->argv[3], TRUE);
   if (!client_entry) {
     if (cmd->pending) {
       COMMAND_ERROR;
       goto out;
     }
 
+    silc_free(nickname);
+
     /* Client entry not found, it was requested thus mark this to be
        pending command. */
     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
@@ -1424,6 +1452,7 @@ SILC_CLIENT_CMD_FUNC(cumode)
   }
   
   /* Get the current mode */
+  silc_list_start(channel->clients);
   while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
     if (chu->client == client_entry) {
       mode = chu->mode;
@@ -1488,7 +1517,8 @@ SILC_CLIENT_CMD_FUNC(cumode)
 
   /* Send the command packet. We support sending only one mode at once
      that requires an argument. */
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 
+                                         auth ? 4 : 3, 
                                          1, chidp->data, chidp->len, 
                                          2, modebuf, 4,
                                          3, clidp->data, clidp->len,
@@ -1507,10 +1537,7 @@ SILC_CLIENT_CMD_FUNC(cumode)
   COMMAND;
 
  out:
-  if (nickname)
-    silc_free(nickname);
-  if (server)
-    silc_free(server);
+  silc_free(nickname);
   silc_client_command_free(cmd);
 }
 
@@ -1519,14 +1546,14 @@ SILC_CLIENT_CMD_FUNC(cumode)
 SILC_CLIENT_CMD_FUNC(kick)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClient client = cmd->client;
   SilcClientConnection conn = cmd->conn;
   SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel;
   SilcBuffer buffer, idp, idp2;
   SilcClientEntry target;
   char *name;
-  uint32 num = 0;
-  char *nickname = NULL, *server = NULL;
+  char *nickname = NULL;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -1543,7 +1570,8 @@ SILC_CLIENT_CMD_FUNC(kick)
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "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;
     }
@@ -1553,14 +1581,16 @@ SILC_CLIENT_CMD_FUNC(kick)
   }
 
   if (!conn->current_channel) {
-    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "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, SILC_CLIENT_MESSAGE_INFO, "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;
   }
@@ -1568,17 +1598,17 @@ SILC_CLIENT_CMD_FUNC(kick)
   channel = (SilcChannelEntry)id_cache->context;
 
   /* Parse the typed nickname. */
-  if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
-    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
-    COMMAND_ERROR;
-    goto out;
-  }
+  if (client->params->nickname_parse)
+    client->params->nickname_parse(cmd->argv[2], &nickname);
+  else
+    nickname = strdup(cmd->argv[2]);
 
   /* Get the target client */
   target = silc_idlist_get_client(cmd->client, conn, nickname, 
-                                 server, num, FALSE);
+                                 cmd->argv[2], FALSE);
   if (!target) {
-    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "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;
@@ -1607,10 +1637,7 @@ SILC_CLIENT_CMD_FUNC(kick)
   COMMAND;
 
  out:
-  if (nickname)
-    silc_free(nickname);
-  if (server)
-    silc_free(server);
+  silc_free(nickname);
   silc_client_command_free(cmd);
 }
 
@@ -1621,11 +1648,15 @@ static void silc_client_command_oper_send(unsigned char *data,
   SilcClientConnection conn = cmd->conn;
   SilcBuffer buffer, auth;
 
-  if (cmd->argc == 3) {
-    /* Pulic key auth XXX TODO */
-    auth = NULL;
+  if (cmd->argc >= 3) {
+    /* Encode the public key authentication payload */
+    auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+                                             cmd->client->private_key,
+                                             conn->hash,
+                                             conn->local_id,
+                                             SILC_ID_CLIENT);
   } else {
-    /* Encode the authentication payload */
+    /* Encode the password authentication payload */
     auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
                                    data, data_len);
   }
@@ -1650,8 +1681,6 @@ SILC_CLIENT_CMD_FUNC(oper)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
-  unsigned char *auth_data;
-  uint32 auth_data_len = 0;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -1661,17 +1690,12 @@ SILC_CLIENT_CMD_FUNC(oper)
 
   if (cmd->argc < 2) {
     cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
-                         "Usage: /OPER <username> [<public key>]");
+                         "Usage: /OPER <username> [-pubkey]");
     COMMAND_ERROR;
     goto out;
   }
 
-  if (cmd->argc == 3) {
-    /* XXX Get public key */
-    auth_data = NULL;
-    COMMAND_ERROR;
-    goto out;
-  } else {
+  if (cmd->argc < 3) {
     /* Get passphrase */
     cmd->client->ops->ask_passphrase(cmd->client, conn,
                                     silc_client_command_oper_send,
@@ -1679,13 +1703,7 @@ SILC_CLIENT_CMD_FUNC(oper)
     return;
   }
 
-  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;
+  silc_client_command_oper_send(NULL, 0, context);
 
  out:
   silc_client_command_free(cmd);
@@ -1698,11 +1716,15 @@ static void silc_client_command_silcoper_send(unsigned char *data,
   SilcClientConnection conn = cmd->conn;
   SilcBuffer buffer, auth;
 
-  if (cmd->argc == 3) {
-    /* Pulic key auth XXX TODO */
-    auth = NULL;
+  if (cmd->argc >= 3) {
+    /* Encode the public key authentication payload */
+    auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+                                             cmd->client->private_key,
+                                             conn->hash,
+                                             conn->local_id,
+                                             SILC_ID_CLIENT);
   } else {
-    /* Encode the authentication payload */
+    /* Encode the password authentication payload */
     auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
                                    data, data_len);
   }
@@ -1727,8 +1749,6 @@ SILC_CLIENT_CMD_FUNC(silcoper)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
-  unsigned char *auth_data;
-  uint32 auth_data_len = 0;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -1738,17 +1758,12 @@ SILC_CLIENT_CMD_FUNC(silcoper)
 
   if (cmd->argc < 2) {
     cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
-                         "Usage: /SILCOPER <username> [<public key>]");
+                         "Usage: /SILCOPER <username> [-pubkey]");
     COMMAND_ERROR;
     goto out;
   }
 
-  if (cmd->argc == 3) {
-    /* XXX Get public key */
-    auth_data = NULL;
-    COMMAND_ERROR;
-    goto out;
-  } else {
+  if (cmd->argc < 3) {
     /* Get passphrase */
     cmd->client->ops->ask_passphrase(cmd->client, conn,
                                     silc_client_command_silcoper_send,
@@ -1756,13 +1771,7 @@ SILC_CLIENT_CMD_FUNC(silcoper)
     return;
   }
 
-  silc_client_command_silcoper_send(auth_data, auth_data_len, context);
-
-  memset(auth_data, 0, auth_data_len);
-  silc_free(auth_data);
-
-  /* Notify application */
-  COMMAND;
+  silc_client_command_silcoper_send(NULL, 0, context);
 
  out:
   silc_client_command_free(cmd);
@@ -1843,7 +1852,8 @@ SILC_CLIENT_CMD_FUNC(ban)
 
   if (cmd->argv[1][0] == '*') {
     if (!conn->current_channel) {
-      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "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;
     }
@@ -1854,7 +1864,8 @@ SILC_CLIENT_CMD_FUNC(ban)
 
     channel = silc_client_get_channel(cmd->client, conn, name);
     if (!channel) {
-      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "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;
     }
@@ -2009,6 +2020,7 @@ SILC_CLIENT_CMD_FUNC(leave)
   }
 
   channel = (SilcChannelEntry)id_cache->context;
+  channel->on_channel = FALSE;
 
   /* Send LEAVE command to the server */
   idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
@@ -2025,12 +2037,7 @@ SILC_CLIENT_CMD_FUNC(leave)
   if (conn->current_channel == channel)
     conn->current_channel = NULL;
 
-  silc_idcache_del_by_id(conn->channel_cache, channel->id);
-  silc_free(channel->channel_name);
-  silc_free(channel->id);
-  silc_free(channel->key);
-  silc_cipher_free(channel->channel_key);
-  silc_free(channel);
+  silc_client_del_channel(cmd->client, cmd->conn, channel);
 
  out:
   silc_client_command_free(cmd);
@@ -2096,8 +2103,7 @@ SILC_CLIENT_CMD_FUNC(getkey)
   SilcClient client = cmd->client;
   SilcClientEntry client_entry = NULL;
   SilcServerEntry server_entry = NULL;
-  uint32 num = 0;
-  char *nickname = NULL, *server = NULL;
+  char *nickname = NULL;
   SilcBuffer idp, buffer;
 
   if (!cmd->conn) {
@@ -2113,44 +2119,60 @@ SILC_CLIENT_CMD_FUNC(getkey)
     goto out;
   }
 
-  /* Parse the typed nickname. */
-  if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
-    client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
-    COMMAND_ERROR;
-    goto out;
+  if (cmd->pending) {
+    SilcClientCommandReplyContext reply = 
+      (SilcClientCommandReplyContext)context2;
+    SilcCommandStatus status;
+    unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
+    SILC_GET16_MSB(status, tmp);
+    
+    if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
+       status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
+      cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+                           "%s", 
+                           silc_client_command_status_message(status));
+      COMMAND_ERROR;
+      goto out;
+    }
   }
 
+  /* Parse the typed nickname. */
+  if (client->params->nickname_parse)
+    client->params->nickname_parse(cmd->argv[1], &nickname);
+  else
+    nickname = strdup(cmd->argv[1]);
+
   /* Find client entry */
-  client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
+  client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
                                        FALSE);
   if (!client_entry) {
     /* Check whether user requested server actually */
-    server_entry = silc_client_get_server(client, conn, nickname);
+    server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
 
-    if (!server_entry) {
+    if (!server_entry && !cmd->pending) {
       /* No. what ever user wants we don't have it, so resolve it. We
         will try to resolve both client and server, one of them is
         bound to be wrong. */
 
       /* This will send the IDENTIFY command */
-      silc_idlist_get_client(client, conn, nickname, server, num, TRUE);
+      silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
       silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
                                  conn->cmd_ident,  
                                  silc_client_command_destructor,
                                  silc_client_command_getkey, 
                                  silc_client_command_dup(cmd));
 
-      /* This sends the INFO command to resolve the server. */
-      silc_client_send_command(client, conn, SILC_COMMAND_INFO,
+      /* This sends the IDENTIFY command to resolve the server. */
+      silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
                               ++conn->cmd_ident, 1, 
-                              1, nickname, strlen(nickname));
+                              2, cmd->argv[1], cmd->argv_lens[1]);
       silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
-                                 conn->cmd_ident,  
-                                 silc_client_command_destructor,
+                                 conn->cmd_ident, NULL,
                                  silc_client_command_getkey, 
                                  silc_client_command_dup(cmd));
 
       cmd->pending = 1;
+      silc_free(nickname);
       return;
     }
 
@@ -2170,5 +2192,6 @@ SILC_CLIENT_CMD_FUNC(getkey)
   COMMAND;
 
  out:
+  silc_free(nickname);
   silc_client_command_free(cmd);
 }