Merged from silc_1_0_branch.
[silc.git] / lib / silcclient / command.c
index f033dc25d0dd53770b8c7d983472c9ca827dccda..3131900efdc680fb6379fb6dafc5765c79639bef 100644 (file)
@@ -48,6 +48,8 @@ void silc_client_command_send(SilcClient client, SilcClientConnection conn,
   SilcBuffer packet;
   va_list ap;
 
+  assert(client && conn);
+
   va_start(ap, argc);
 
   packet = silc_command_payload_encode_vap(command, ident, argc, ap);
@@ -65,25 +67,93 @@ SilcClientCommand silc_client_command_find(SilcClient client,
 {
   SilcClientCommand cmd;
 
+  assert(client);
+
   silc_list_start(client->internal->commands);
   while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
-    if (cmd->name && !strcmp(cmd->name, name))
+    if (cmd->name && !strcasecmp(cmd->name, name))
       return cmd;
   }
 
   return NULL;
 }
 
-/* Calls the command (executes it).  Application can call this after
-   it has allocated the SilcClientCommandContext with the function
-   silc_client_command_alloc and found the command from the client
-   library by calling silc_client_command_find.  This will execute
-   the command. */
+/* Executes a command */
 
-void silc_client_command_call(SilcClientCommand command, 
-                             SilcClientCommandContext cmd)
+bool silc_client_command_call(SilcClient client,
+                             SilcClientConnection conn,
+                             const char *command_line, ...)
 {
-  (*command->command)((void *)cmd, NULL);
+  va_list va;
+  SilcUInt32 argc = 0;
+  unsigned char **argv = NULL;
+  SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
+  SilcClientCommand cmd;
+  SilcClientCommandContext ctx;
+  char *arg;
+
+  assert(client);
+
+  /* Parse arguments */
+  va_start(va, command_line);
+  if (command_line) {
+    char *command_name;
+
+    /* Get command name */
+    command_name = silc_memdup(command_line, strcspn(command_line, " "));
+    if (!command_name)
+      return FALSE;
+
+    /* Find command by name */
+    cmd = silc_client_command_find(client, command_name);
+    if (!cmd) {
+      silc_free(command_name);
+      return FALSE;
+    }
+
+    /* Parse command line */
+    silc_parse_command_line((char *)command_line, &argv, &argv_lens,
+                           &argv_types, &argc, cmd->max_args);
+
+    silc_free(command_name);
+  } else {
+    arg = va_arg(va, char *);
+    if (!arg)
+      return FALSE;
+
+    /* Find command by name */
+    cmd = silc_client_command_find(client, arg);
+    if (!cmd)
+      return FALSE;
+
+    while (arg) {
+      argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
+      argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
+      argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
+      argv[argc] = silc_memdup(arg, strlen(arg));
+      argv_lens[argc] = strlen(arg);
+      argv_types[argc] = argc;
+      argc++;
+      arg = va_arg(va, char *);
+    }
+  }
+
+  /* Allocate command context. */
+  ctx = silc_client_command_alloc();
+  ctx->client = client;
+  ctx->conn = conn;
+  ctx->command = cmd;
+  ctx->argc = argc;
+  ctx->argv = argv;
+  ctx->argv_lens = argv_lens;
+  ctx->argv_types = argv_types;
+  
+  /* Call the command */
+  cmd->command(ctx, NULL);
+
+  va_end(va);
+
+  return TRUE;
 }
 
 /* Add new pending command to be executed when reply to a command has been
@@ -103,12 +173,13 @@ void silc_client_command_pending(SilcClientConnection conn,
 {
   SilcClientCommandPending *reply;
 
+  assert(conn);
   reply = silc_calloc(1, sizeof(*reply));
   reply->reply_cmd = reply_cmd;
   reply->ident = ident;
   reply->context = context;
   reply->callback = callback;
-  silc_dlist_add(conn->pending_commands, reply);
+  silc_dlist_add(conn->internal->pending_commands, reply);
 }
 
 /* Deletes pending command by reply command type. */
@@ -119,15 +190,16 @@ void silc_client_command_pending_del(SilcClientConnection conn,
 {
   SilcClientCommandPending *r;
 
-  if (!conn->pending_commands)
+  if (!conn->internal->pending_commands)
     return;
 
-  silc_dlist_start(conn->pending_commands);
-  while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
+  silc_dlist_start(conn->internal->pending_commands);
+  while ((r = silc_dlist_get(conn->internal->pending_commands))
+        != SILC_LIST_END) {
     if ((r->reply_cmd == reply_cmd || (r->reply_cmd == SILC_COMMAND_NONE &&
                                       r->reply_check))
        && r->ident == ident) {
-      silc_dlist_del(conn->pending_commands, r);
+      silc_dlist_del(conn->internal->pending_commands, r);
       silc_free(r);
     }
   }
@@ -147,8 +219,9 @@ silc_client_command_pending_check(SilcClientConnection conn,
   SilcClientCommandPendingCallbacks callbacks = NULL;
   int i = 0;
 
-  silc_dlist_start(conn->pending_commands);
-  while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
+  silc_dlist_start(conn->internal->pending_commands);
+  while ((r = silc_dlist_get(conn->internal->pending_commands))
+        != SILC_LIST_END) {
     if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
        && r->ident == ident) {
       callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
@@ -185,6 +258,7 @@ void silc_client_command_free(SilcClientCommandContext ctx)
 
     for (i = 0; i < ctx->argc; i++)
       silc_free(ctx->argv[i]);
+    silc_free(ctx->argv);
     silc_free(ctx->argv_lens);
     silc_free(ctx->argv_types);
     silc_free(ctx);
@@ -438,7 +512,8 @@ SILC_CLIENT_CMD_FUNC(list)
     name = cmd->argv[1];
 
     /* Get the Channel ID of the channel */
-    if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
+    if (silc_idcache_find_by_name_one(conn->internal->channel_cache,
+                                     name, &id_cache)) {
       channel = (SilcChannelEntry)id_cache->context;
       idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
     }
@@ -507,7 +582,8 @@ SILC_CLIENT_CMD_FUNC(topic)
   }
 
   /* Get the Channel ID of the channel */
-  if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
+  if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
+                                    name, &id_cache)) {
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
     goto out;
   }
@@ -548,10 +624,11 @@ SILC_CLIENT_CMD_FUNC(invite)
   SilcClientConnection conn = cmd->conn;
   SilcClientEntry client_entry = NULL;
   SilcChannelEntry channel;
-  SilcBuffer buffer, clidp, chidp;
-  SilcUInt32 type = 0;
+  SilcBuffer buffer, clidp, chidp, args = NULL;
+  SilcPublicKey pubkey = NULL;
   char *nickname = NULL, *name;
   char *invite = NULL;
+  unsigned char action[1];
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -611,12 +688,35 @@ SILC_CLIENT_CMD_FUNC(invite)
        goto out;
       }
     } else {
-      invite = cmd->argv[2];
-      invite++;
       if (cmd->argv[2][0] == '+')
-       type = 3;
+       action[0] = 0x00;
       else
-       type = 4;
+       action[0] = 0x01;
+
+      /* Check if it is public key file to be added to invite list */
+      if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
+                                    SILC_PKCS_FILE_PEM))
+       silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
+                                 SILC_PKCS_FILE_BIN);
+      invite = cmd->argv[2];
+      if (!pubkey)
+       invite++;
+    }
+  }
+
+  if (invite) {
+    args = silc_buffer_alloc_size(2);
+    silc_buffer_format(args,
+                      SILC_STR_UI_SHORT(1),
+                      SILC_STR_END);
+    if (pubkey) {
+      chidp = silc_pkcs_public_key_payload_encode(pubkey);
+      args = silc_argument_payload_encode_one(args, chidp->data,
+                                             chidp->len, 2);
+      silc_buffer_free(chidp);
+      silc_pkcs_public_key_free(pubkey);
+    } else {
+      args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1);
     }
   }
 
@@ -625,24 +725,29 @@ SILC_CLIENT_CMD_FUNC(invite)
   if (client_entry) {
     clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
     buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 
-                                           ++conn->cmd_ident, 3,
+                                           ++conn->cmd_ident, 4,
                                            1, chidp->data, chidp->len,
                                            2, clidp->data, clidp->len,
-                                           type, invite, invite ?
-                                           strlen(invite) : 0);
+                                           3, args ? action : NULL,
+                                           args ? 1 : 0,
+                                           4, args ? args->data : NULL,
+                                           args ? args->len : 0);
     silc_buffer_free(clidp);
   } else {
     buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 
-                                           ++conn->cmd_ident, 2,
+                                           ++conn->cmd_ident, 3,
                                            1, chidp->data, chidp->len,
-                                           type, invite, invite ?
-                                           strlen(invite) : 0);
+                                           3, args ? action : NULL,
+                                           args ? 1 : 0,
+                                           4, args ? args->data : NULL,
+                                           args ? args->len : 0);
   }
 
   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(chidp);
+  silc_buffer_free(args),
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -770,9 +875,9 @@ SILC_CLIENT_CMD_FUNC(kill)
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClient client = cmd->client;
   SilcClientConnection conn = cmd->conn;
-  SilcBuffer buffer, idp;
+  SilcBuffer buffer, idp, auth = NULL;
   SilcClientEntry target;
-  char *nickname = NULL;
+  char *nickname = NULL, *comment = NULL;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -782,7 +887,7 @@ SILC_CLIENT_CMD_FUNC(kill)
 
   if (cmd->argc < 2) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
-       "Usage: /KILL <nickname> [<comment>]");
+       "Usage: /KILL <nickname> [<comment>] [-pubkey]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
@@ -812,22 +917,35 @@ SILC_CLIENT_CMD_FUNC(kill)
     goto out;
   }
 
+  if (cmd->argc >= 3) {
+    if (strcasecmp(cmd->argv[2], "-pubkey"))
+      comment = cmd->argv[2];
+
+    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(cmd->client->public_key,
+                                               cmd->client->private_key,
+                                               cmd->client->rng,
+                                               client->sha1hash,
+                                               target->id, SILC_ID_CLIENT);
+    }
+  }
+
   /* 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, 
-                                           ++conn->cmd_ident, 1, 
-                                           1, idp->data, idp->len);
-  else
-    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]));
+  buffer =
+    silc_command_payload_encode_va(SILC_COMMAND_KILL, 
+                                  ++conn->cmd_ident, 3, 
+                                  1, idp->data, idp->len,
+                                  2, comment, comment ? strlen(comment) : 0,
+                                  3, auth ? auth->data : NULL,
+                                  auth ? auth->len : 0);
   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(idp);
+  silc_buffer_free(auth);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -921,7 +1039,7 @@ SILC_CLIENT_CMD_FUNC(ping)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
-  SilcBuffer buffer;
+  SilcBuffer buffer, idp;
   void *id;
   int i;
 
@@ -931,14 +1049,15 @@ SILC_CLIENT_CMD_FUNC(ping)
     goto out;
   }
 
+  idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER); 
+
   /* Send the command */
   buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1, 
-                                         1, conn->remote_id_data, 
-                                         silc_id_get_len(conn->remote_id,
-                                                         SILC_ID_SERVER));
+                                         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);
+  silc_buffer_free(idp);
 
   id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
                      SILC_ID_SERVER);
@@ -949,21 +1068,23 @@ SILC_CLIENT_CMD_FUNC(ping)
   }
 
   /* Start counting time */
-  for (i = 0; i < conn->ping_count; i++) {
-    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 = strdup(conn->remote_host);
+  for (i = 0; i < conn->internal->ping_count; i++) {
+    if (conn->internal->ping[i].dest_id == NULL) {
+      conn->internal->ping[i].start_time = time(NULL);
+      conn->internal->ping[i].dest_id = id;
+      conn->internal->ping[i].dest_name = strdup(conn->remote_host);
       break;
     }
   }
-  if (i >= conn->ping_count) {
-    i = conn->ping_count;
-    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 = strdup(conn->remote_host);
-    conn->ping_count++;
+  if (i >= conn->internal->ping_count) {
+    i = conn->internal->ping_count;
+    conn->internal->ping =
+      silc_realloc(conn->internal->ping,
+                  sizeof(*conn->internal->ping) * (i + 1));
+    conn->internal->ping[i].start_time = time(NULL);
+    conn->internal->ping[i].dest_id = id;
+    conn->internal->ping[i].dest_name = strdup(conn->remote_host);
+    conn->internal->ping_count++;
   }
   
   /* Notify application */
@@ -1263,7 +1384,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
   SilcChannelEntry channel;
-  SilcBuffer buffer, chidp, auth = NULL;
+  SilcBuffer buffer, chidp, auth = NULL, pk = NULL;
   unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
   SilcUInt32 mode, add, type, len, arg_len = 0;
   int i;
@@ -1425,10 +1546,27 @@ SILC_CLIENT_CMD_FUNC(cmode)
       break;
     case 'f':
       if (add) {
+       SilcPublicKey pubkey = cmd->client->public_key;
+       SilcPrivateKey privkey = cmd->client->private_key;
+
        mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
        type = 7;
-       auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
-                                                 cmd->client->private_key,
+
+       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,
+                                 NULL, &pubkey, &privkey)) {
+           SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+               "Could not load key pair, check your arguments");
+           COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+           goto out;
+         }
+       }
+
+       pk = silc_pkcs_public_key_payload_encode(pubkey);
+       auth = silc_auth_public_key_auth_generate(pubkey, privkey,
                                                  cmd->client->rng, 
                                                  cmd->client->sha1hash,
                                                  conn->local_id,
@@ -1453,13 +1591,15 @@ SILC_CLIENT_CMD_FUNC(cmode)
      that requires an argument. */
   if (type && arg) {
     buffer = 
-      silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3, 
+      silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 4,
                                     1, chidp->data, chidp->len, 
                                     2, modebuf, sizeof(modebuf),
-                                    type, arg, arg_len);
+                                    type, arg, arg_len,
+                                    8, pk ? pk->data : NULL,
+                                    pk ? pk->len : 0);
   } else {
     buffer = 
-      silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2, 
+      silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
                                     1, chidp->data, chidp->len, 
                                     2, modebuf, sizeof(modebuf));
   }
@@ -1468,8 +1608,8 @@ SILC_CLIENT_CMD_FUNC(cmode)
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(chidp);
-  if (auth)
-    silc_buffer_free(auth);
+  silc_buffer_free(auth);
+  silc_buffer_free(pk);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -1578,8 +1718,23 @@ SILC_CLIENT_CMD_FUNC(cumode)
       break;
     case 'f':
       if (add) {
-       auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
-                                                 cmd->client->private_key,
+       SilcPublicKey pubkey = cmd->client->public_key;
+       SilcPrivateKey privkey = cmd->client->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,
+                                 NULL, &pubkey, &privkey)) {
+           SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+               "Could not load key pair, check your arguments");
+           COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+           goto out;
+         }
+       }
+
+       auth = silc_auth_public_key_auth_generate(pubkey, privkey,
                                                  cmd->client->rng,
                                                  cmd->client->sha1hash,
                                                  conn->local_id,
@@ -1699,7 +1854,8 @@ SILC_CLIENT_CMD_FUNC(kick)
   }
 
   /* Get the Channel ID of the channel */
-  if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
+  if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
+                                    name, &id_cache)) {
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
     goto out;
   }
@@ -1760,7 +1916,8 @@ static void silc_client_command_oper_send(unsigned char *data,
     /* Encode the public key authentication payload */
     auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
                                              cmd->client->private_key,
-                                             cmd->client->rng, conn->hash,
+                                             cmd->client->rng,
+                                             conn->internal->hash,
                                              conn->local_id,
                                              SILC_ID_CLIENT);
   } else {
@@ -1830,7 +1987,8 @@ static void silc_client_command_silcoper_send(unsigned char *data,
     /* Encode the public key authentication payload */
     auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
                                              cmd->client->private_key,
-                                             cmd->client->rng, conn->hash,
+                                             cmd->client->rng,
+                                             conn->internal->hash,
                                              conn->local_id,
                                              SILC_ID_CLIENT);
   } else {
@@ -1895,10 +2053,11 @@ SILC_CLIENT_CMD_FUNC(ban)
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
   SilcChannelEntry channel;
-  SilcBuffer buffer, chidp;
-  int type = 0;
+  SilcBuffer buffer, chidp, args = NULL;
   char *name, *ban = NULL;
-
+  unsigned char action[1];
+  SilcPublicKey pubkey = NULL;
+  
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
@@ -1932,25 +2091,51 @@ SILC_CLIENT_CMD_FUNC(ban)
 
   if (cmd->argc == 3) {
     if (cmd->argv[2][0] == '+')
-      type = 2;
+      action[0] = 0x00;
     else
-      type = 3;
+      action[0] = 0x01;
 
+    /* Check if it is public key file to be added to invite list */
+    if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
+                                  SILC_PKCS_FILE_PEM))
+      silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
+                               SILC_PKCS_FILE_BIN);
     ban = cmd->argv[2];
-    ban++;
+    if (!pubkey)
+      ban++;
+  }
+
+  if (ban) {
+    args = silc_buffer_alloc_size(2);
+    silc_buffer_format(args,
+                      SILC_STR_UI_SHORT(1),
+                      SILC_STR_END);
+    if (pubkey) {
+      chidp = silc_pkcs_public_key_payload_encode(pubkey);
+      args = silc_argument_payload_encode_one(args, chidp->data,
+                                             chidp->len, 2);
+      silc_buffer_free(chidp);
+      silc_pkcs_public_key_free(pubkey);
+    } else {
+      args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
+    }
   }
 
   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
 
   /* Send the command */
   buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 
-                                         ++conn->cmd_ident, 2,
+                                         ++conn->cmd_ident, 3,
                                          1, chidp->data, chidp->len,
-                                         type, ban, ban ? strlen(ban) : 0);
+                                         2, args ? action : NULL,
+                                         args ? 1 : 0,
+                                         3, args ? args->data : NULL,
+                                         args ? args->len : 0);
   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(chidp);
+  silc_buffer_free(args);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -2468,7 +2653,7 @@ void silc_client_commands_register(SilcClient client)
   SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
   SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
   SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
-  SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
+  SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
   SILC_CLIENT_CMD(info, INFO, "INFO", 2);
   SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
   SILC_CLIENT_CMD(ping, PING, "PING", 2);
@@ -2476,8 +2661,8 @@ void silc_client_commands_register(SilcClient client)
   SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
   SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
   SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
-  SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
-  SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
+  SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
+  SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
   SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
   SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
   SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);