updates. silc.server.0.7.2
authorPekka Riikonen <priikone@silcnet.org>
Mon, 17 Dec 2001 19:14:55 +0000 (19:14 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 17 Dec 2001 19:14:55 +0000 (19:14 +0000)
13 files changed:
CHANGES
TODO
apps/irssi/src/silc/core/client_ops.c
apps/irssi/src/silc/core/silc-core.c
apps/silcd/command.c
apps/silcd/command.h
apps/silcd/server.c
apps/silcd/server_internal.h
lib/silcclient/client_notify.c
lib/silcclient/command.c
lib/silcclient/idlist.c
lib/silccore/silcchannel.c
lib/silccore/silccommand.c

diff --git a/CHANGES b/CHANGES
index b449fa480e48572f23328f8e48a947afcb33e503..d284fe5e55fb7b4bdc1b8131a7bc4b0908d4bd13 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,33 @@
+Mon Dec 17 18:24:27 EET 2001  Pekka Riikonen <priikone@silcnet.org>
+
+       * Fixed JOIN command parsing not to crash.  Affected file
+         lib/silcclient/command.c.
+
+       * Fied the NICK_CHANGE notify to add the new client entry
+         even it is resolved.  This removes an <[unknown]> nick
+         thingy bug in the client.  Affected file is 
+         lib/silcclient/client_notify.c.
+
+       * Do not try to allocate 0 bytes (efence does not like it)
+         in lib/silccore/silccomand.c when encoding payload.
+
+       * Do not take IRCNICK as nickname in Irssi SILC client since
+         it is not possible to set nickname before hand connecting
+         the server (TODO has an entry about adding auto-nicking
+         support).
+
+       * Changed the silc_server_command_pending to check whether
+         there already exists an pending entry with the specified
+         command, command identifier and pending callback.  This is
+         to fix IDENTIFY and WHOIS related crashes that may register
+         multiple pending commands with same identifier.  Affected
+         file silcd/command.c.
+
+       * Fixed the server to reconnect to the router even if it
+         was already reconnecting and EOF was received.  This to
+         fix a possibility that the server wouldn't ever try to
+         auto-reconnect to the router.  Affected file silcd/server.c.
+
 Sat Dec 15 20:31:50 EET 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Fixed the server's password authentication to use the
 Sat Dec 15 20:31:50 EET 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Fixed the server's password authentication to use the
diff --git a/TODO b/TODO
index 757b9c127bc9f5a41b70ac22ea9c2c935e4ca0de..a4d0dbb34ef23e8ad6ebd1909a96d269d51f79ae 100644 (file)
--- a/TODO
+++ b/TODO
@@ -17,6 +17,10 @@ TODO/bugs in Irssi SILC client
    cipher, hash, hmac and pkcs configuration to the Irssi SILC's config
    file.
 
    cipher, hash, hmac and pkcs configuration to the Irssi SILC's config
    file.
 
+ o Add auto-nick support to Irssi, so that the user specified nickname
+   would be sent to the server immediately (automatically) after the
+   client is connected to the server.
+
  o Add PERL scripting support from Irssi CVS.
 
  o Extend the /HELP command to support sub commands or something.  So
  o Add PERL scripting support from Irssi CVS.
 
  o Extend the /HELP command to support sub commands or something.  So
@@ -35,17 +39,18 @@ TODO/bugs In SILC Client Library
    behaviour and maybe should be removed.  The changer should always
    get the one it wants and not have the formatted nickname.
 
    behaviour and maybe should be removed.  The changer should always
    get the one it wants and not have the formatted nickname.
 
+ o Additions to do after protocol version 1.1:
 
 
-TODO/bugs In SILC Server
-========================
+       o Fix the NICK_CHANGE notify handling not to create new entry
+         for the changed client, but take the nickname from the notify
+         (removes need for resolving as well).  Protocol TODO entry 3.
 
 
- o It is possible that IDENTIFy's check_client will register two pending       
-   callbacks for same ident, which must not happen.  Check same for WHOIS
-   as well.
+       o Add support for list of errors in command replies.  Protocol
+         TODO entry 1.
 
 
- o If auto-reconnecting to router and EOF is received during the
-   connecting phase the server will not try to auto-reconnect anymore
-   after that.  Fix to auto-reconnect.
+
+TODO/bugs In SILC Server
+========================
 
  o Backup router related issues
 
 
  o Backup router related issues
 
@@ -93,34 +98,45 @@ TODO/bugs In SILC Libraries
 TODO in SILC Protocol
 =====================
 
 TODO in SILC Protocol
 =====================
 
- o Add "request parameters" or similar to the WHOIS command, which can
-   be used to request various parameters (something not returned by
-   standard WHOIS command) about clients (info that could be fetched
-   even from clients).  Additional specification (or appendix) should 
-   be done to define the payload and the parameters.  It could be used
-   to make the WHOIS command support various search conditions as well.
-   This would be the way to extend the WHOIS command to support various
-   new features without always making the command incompatible to previous
-   version.  To be included in protocol version 1.1.
-
- o Re-define the Status Payload: it is now 16 bits, split it into two
-   8 bits fields.  First field includes status types from 0 - 9 and
-   10 - n *if* it is not an list of errors.  If it is list of errors then
-   the first field includes 1, 2 and/or 3, and the second field includes
-   the error status 10 - n.  This way it is possible to send multiple
-   errors (list of errors) and we have a way to tell the receiver that
-   there will be other errors as well.  The second field is used only
-   if there is list of errors.  If normal status, or normal (single)
-   error status the second field is set to zero, and must be ignored.
-   Hence, the status works same way as now except for list of errors.
-   To be included in protocol version 1.1.
-
- o Define that WHOIS and IDENTIFY commands must send list of errors
-   if multiple Client ID (or Channel ID and Server ID for IDENTIFY) was
-   requested and was not found.  Each unfound entry must cause an error
-   command reply to the sender.  Also define that errors must be sent
-   *after* sending successfully found entries (this way receiver may
-   ignore them).  To be included in protocol version 1.1.
+Current protocol version is 1.0.  However, it is far from being perfect,
+and needs to include additional features.  Following protocol TODO entries
+describe new stuff to be added to protocol versions 1.x.
+
+ 1. Re-define the Status Payload: it is now 16 bits, split it into two
+    8 bits fields.  First field includes status types from 0 - 9 and
+    10 - n *if* it is not an list of errors.  If it is list of errors then
+    the first field includes 1, 2 and/or 3, and the second field includes
+    the error status 10 - n.  This way it is possible to send multiple
+    errors (list of errors) and we have a way to tell the receiver that
+    there will be other errors as well.  The second field is used only
+    if there is list of errors.  If normal status, or normal (single)
+    error status the second field is set to zero, and must be ignored.
+    Hence, the status works same way as now except for list of errors.
+    To be included in protocol version 1.1.
+
+ 2. Define that WHOIS and IDENTIFY commands must send list of errors
+    if multiple Client ID (or Channel ID and Server ID for IDENTIFY) was
+    requested and was not found.  Each unfound entry must cause an error
+    command reply to the sender.  Also define that errors must be sent
+    *after* sending successfully found entries (this way receiver may
+    ignore them).  To be included in protocol version 1.1.
+
+ 3. Define the NICK_CHANGE notify to send the changed nickname as a new
+    third argument.  This will make the NICK_CHANGE notify handling easier
+    in the receiver's end (client primarily) since it removes the
+    requirement that receiver must resolve (using IDENTIFY or WHOIS) the
+    new Client ID received in the notify (because of the new nickname is
+    unknown).  To be included in protocol version 1.1.
+
+ 4. Add "request parameters" or similar to the WHOIS command, which can
+    be used to request various parameters (something not returned by
+    standard WHOIS command) about clients (info that could be fetched
+    even from clients).  Additional specification (or appendix) should 
+    be done to define the payload and the parameters.  It could be used
+    to make the WHOIS command support various search conditions as well.
+    This would be the way to extend the WHOIS command to support various
+    new features without always making the command incompatible to previous
+    version.  To be included in protocol version 1.1.
 
 
 TODO After 1.0
 
 
 TODO After 1.0
index f6dac8aec0db84efb94381362710eabde81fb464..5fadb888aa505d7905a6fb0788fe1fbc6fdc96f9 100644 (file)
@@ -93,7 +93,8 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
   
   nick = silc_nicklist_find(chanrec, sender);
   if (!nick) {
   
   nick = silc_nicklist_find(chanrec, sender);
   if (!nick) {
-    /* We didn't find client but it clearly exists, add it. */
+    /* We didn't find client but it clearly exists, add it. It must be
+       found on the channel->clients list. */
     SilcChannelUser chu;
 
     silc_list_start(channel->clients);
     SilcChannelUser chu;
 
     silc_list_start(channel->clients);
index 3dddc6e44c6a2795acbc4bf33bb045c72a236b8f..f5ea52a34107de8b04d65317fc37919442084ea1 100644 (file)
@@ -120,13 +120,15 @@ static void silc_init_userinfo(void)
     
     user_name = settings_get_str("user_name");
   }
     
     user_name = settings_get_str("user_name");
   }
-         
+
   /* nick */
   /* nick */
+  /* Actually take SILCUSER or IRCUSER since nickname cannot be set
+     beforehand in SILC (XXX auto-nicking support should be added to Irssi). */
   nick = settings_get_str("nick");
   if (nick == NULL || *nick == '\0') {
   nick = settings_get_str("nick");
   if (nick == NULL || *nick == '\0') {
-    str = g_getenv("SILCNICK");
+    str = g_getenv("SILCUSER");
     if (!str)
     if (!str)
-      str = g_getenv("IRCNICK");
+      str = g_getenv("IRCUSER");
     settings_set_str("nick", str != NULL ? str : user_name);
     
     nick = settings_get_str("nick");
     settings_set_str("nick", str != NULL ? str : user_name);
     
     nick = settings_get_str("nick");
index 38d7a74e2f92a8963800972a92594275d031de55..6ed2dc5ea6fce902900669b1e29c0a4ca1edad0f 100644 (file)
@@ -297,9 +297,11 @@ silc_server_command_dup(SilcServerCommandContext ctx)
    with `context' when reply has been received.  It can be SILC_COMMAND_NONE
    to match any command with the `ident'.  If `ident' is non-zero
    the `callback' will be executed when received reply with command
    with `context' when reply has been received.  It can be SILC_COMMAND_NONE
    to match any command with the `ident'.  If `ident' is non-zero
    the `callback' will be executed when received reply with command
-   identifier `ident'. */
+   identifier `ident'. If there already exists pending command for the
+   specified command, ident, callback and context this function has no
+   effect. */
 
 
-void silc_server_command_pending(SilcServer server,
+bool silc_server_command_pending(SilcServer server,
                                 SilcCommand reply_cmd,
                                 uint16 ident,
                                 SilcServerPendingDestructor destructor,
                                 SilcCommand reply_cmd,
                                 uint16 ident,
                                 SilcServerPendingDestructor destructor,
@@ -308,6 +310,16 @@ void silc_server_command_pending(SilcServer server,
 {
   SilcServerCommandPending *reply;
 
 {
   SilcServerCommandPending *reply;
 
+  /* Check whether identical pending already exists for same command,
+     ident, callback and callback context. If it does then it would be
+     error to register it again. */
+  silc_dlist_start(server->pending_commands);
+  while ((reply = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
+    if (reply->reply_cmd == reply_cmd && reply->ident == ident &&
+       reply->callback == callback && reply->context == context)
+      return FALSE;
+  }
+
   reply = silc_calloc(1, sizeof(*reply));
   reply->reply_cmd = reply_cmd;
   reply->ident = ident;
   reply = silc_calloc(1, sizeof(*reply));
   reply->reply_cmd = reply_cmd;
   reply->ident = ident;
@@ -315,6 +327,8 @@ void silc_server_command_pending(SilcServer server,
   reply->callback = callback;
   reply->destructor = destructor;
   silc_dlist_add(server->pending_commands, reply);
   reply->callback = callback;
   reply->destructor = destructor;
   silc_dlist_add(server->pending_commands, reply);
+
+  return TRUE;
 }
 
 /* Deletes pending command by reply command type. */
 }
 
 /* Deletes pending command by reply command type. */
index da7a3ea737b96775ae255265838a5e3acce104a7..b842e7eec18440b101bcd4d3831f389d48dc4652 100644 (file)
@@ -122,7 +122,7 @@ SilcServerCommandContext silc_server_command_alloc();
 void silc_server_command_free(SilcServerCommandContext ctx);
 SilcServerCommandContext 
 silc_server_command_dup(SilcServerCommandContext ctx);
 void silc_server_command_free(SilcServerCommandContext ctx);
 SilcServerCommandContext 
 silc_server_command_dup(SilcServerCommandContext ctx);
-void silc_server_command_pending(SilcServer server,
+bool silc_server_command_pending(SilcServer server,
                                 SilcCommand reply_cmd,
                                 uint16 ident,
                                 SilcServerPendingDestructor destructor,
                                 SilcCommand reply_cmd,
                                 uint16 ident,
                                 SilcServerPendingDestructor destructor,
index f90aca67e2ba55daa6568bd6ea54f9dbf4777fd8..d6a4d4e220e7cc229ec04618143537b92a54f083 100644 (file)
@@ -689,6 +689,9 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
        sconn->backup_replace_port = ptr->backup_replace_port;
       }
 
        sconn->backup_replace_port = ptr->backup_replace_port;
       }
 
+      if (!server->router_conn && !sconn->backup)
+       server->router_conn = sconn;
+
       silc_schedule_task_add(server->schedule, fd, 
                             silc_server_connect_router,
                             (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
       silc_schedule_task_add(server->schedule, fd, 
                             silc_server_connect_router,
                             (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
@@ -988,6 +991,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
     silc_free(sconn->backup_replace_ip);
     silc_free(sconn);
   }
     silc_free(sconn->backup_replace_ip);
     silc_free(sconn);
   }
+  if (sconn == server->router_conn)
+    server->router_conn = NULL;
 
   /* Free the protocol object */
   if (sock->protocol == protocol)
 
   /* Free the protocol object */
   if (sock->protocol == protocol)
@@ -1556,6 +1561,14 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
 
     if (sock->user_data)
       silc_server_free_sock_user_data(server, sock);
 
     if (sock->user_data)
       silc_server_free_sock_user_data(server, sock);
+    else if (server->router_conn && server->router_conn->sock == sock &&
+            !server->router && server->standalone)
+      silc_schedule_task_add(server->schedule, 0, 
+                            silc_server_connect_to_router, 
+                            server, 1, 0,
+                            SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+
     silc_server_close_connection(server, sock);
     return;
   }
     silc_server_close_connection(server, sock);
     return;
   }
@@ -2365,7 +2378,7 @@ void silc_server_free_sock_user_data(SilcServer server,
        /* Check whether we have a backup router connection */
        if (!backup_router || backup_router == user_data) {
          silc_schedule_task_add(server->schedule, 0, 
        /* Check whether we have a backup router connection */
        if (!backup_router || backup_router == user_data) {
          silc_schedule_task_add(server->schedule, 0, 
-                                silc_server_connect_to_router,
+                                silc_server_connect_to_router, 
                                 server, 1, 0,
                                 SILC_TASK_TIMEOUT,
                                 SILC_TASK_PRI_NORMAL);
                                 server, 1, 0,
                                 SILC_TASK_TIMEOUT,
                                 SILC_TASK_PRI_NORMAL);
index a40adec6a835bb3028befe18935fe658b5d5375d..8001cf382e1c7c1cabcc2ff1cbf32f5be3f528e7 100644 (file)
@@ -80,6 +80,8 @@ struct SilcServerStruct {
   bool backup_router;               /* TRUE if this is backup router */
   bool backup_primary;              /* TRUE if we've switched our primary
                                        router to a backup router. */
   bool backup_router;               /* TRUE if this is backup router */
   bool backup_primary;              /* TRUE if we've switched our primary
                                        router to a backup router. */
+  SilcServerConnection router_conn; /* non-NULL when connecting to the
+                                      primary router, and NULL otherwise. */
 
   /* Current command identifier, 0 not used */
   uint16 cmd_ident;
 
   /* Current command identifier, 0 not used */
   uint16 cmd_ident;
index 49c315c51fc46e5cddd0c3230447885d822776c4..8b3663b979e5492162b6513cd7e84f13d349dd37 100644 (file)
@@ -41,6 +41,8 @@ static void silc_client_notify_by_server_pending(void *context, void *context2)
   SilcClientCommandReplyContext reply = 
     (SilcClientCommandReplyContext)context2;
 
   SilcClientCommandReplyContext reply = 
     (SilcClientCommandReplyContext)context2;
 
+  SILC_LOG_DEBUG(("Start"));
+
   if (reply) {
     SilcCommandStatus status;
     unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
   if (reply) {
     SilcCommandStatus status;
     unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
@@ -472,26 +474,37 @@ void silc_client_notify_by_server(SilcClient client,
     /* Find Client entry and if not found resolve it */
     client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
     if (!client_entry2) {
     /* Find Client entry and if not found resolve it */
     client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
     if (!client_entry2) {
+      /* Resolve the entry information */
       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
-      goto out;
+
+      /* Add the new entry even though we resolved it. This is because we
+        want to replace the old entry with the new entry here right now. */
+      client_entry2 = 
+       silc_client_add_client(client, conn, NULL, NULL, NULL, 
+                              silc_id_dup(client_id, SILC_ID_CLIENT), 
+                              client_entry->mode);
+
+      /* Replace old ID entry with new one on all channels. */
+      silc_client_replace_from_channels(client, conn, client_entry,
+                                       client_entry2);
     } else {
       if (client_entry2 != conn->local_entry)
        silc_client_nickname_format(client, conn, client_entry2);
     } else {
       if (client_entry2 != conn->local_entry)
        silc_client_nickname_format(client, conn, client_entry2);
-    }
 
 
-    /* Remove the old from cache */
-    silc_idcache_del_by_context(conn->client_cache, client_entry);
+      /* Remove the old from cache */
+      silc_idcache_del_by_context(conn->client_cache, client_entry);
 
 
-    /* Replace old ID entry with new one on all channels. */
-    silc_client_replace_from_channels(client, conn, client_entry,
-                                     client_entry2);
+      /* Replace old ID entry with new one on all channels. */
+      silc_client_replace_from_channels(client, conn, client_entry,
+                                       client_entry2);
 
 
-    /* Notify application */
-    client->internal->ops->notify(client, conn, type, 
-                                 client_entry, client_entry2);
+      /* Notify application */
+      client->internal->ops->notify(client, conn, type, 
+                                   client_entry, client_entry2);
 
 
-    /* Free data */
-    silc_client_del_client_entry(client, conn, client_entry);
+      /* Free data */
+      silc_client_del_client_entry(client, conn, client_entry);
+    }
     break;
 
   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
     break;
 
   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
index da743a42c2ec70247f970baca10f15d345a0a9bc..37ea4d6fff9744b1a1482f13475d326af447e8ff 100644 (file)
@@ -997,13 +997,13 @@ SILC_CLIENT_CMD_FUNC(join)
   name = cmd->argv[1];
 
   for (i = 2; i < cmd->argc; i++) {
   name = cmd->argv[1];
 
   for (i = 2; i < cmd->argc; i++) {
-    if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc >= i + 1) {
+    if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
       cipher = cmd->argv[i + 1];
       i++;
       cipher = cmd->argv[i + 1];
       i++;
-    } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc >= i + 1) {
+    } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
       hmac = cmd->argv[i + 1];
       i++;
       hmac = cmd->argv[i + 1];
       i++;
-    } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc >= i + 1) {
+    } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
       if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
        auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
                                                  cmd->client->private_key,
       if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
        auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
                                                  cmd->client->private_key,
index 2c520d148031f9cc3a4611145d4dc9fcad805ec0..d56421c2bfabeb5865546016462cefc707b2aa51 100644 (file)
@@ -747,6 +747,8 @@ SilcChannelEntry silc_client_get_channel(SilcClient client,
 
   entry = (SilcChannelEntry)id_cache->context;
 
 
   entry = (SilcChannelEntry)id_cache->context;
 
+  SILC_LOG_DEBUG(("Found"));
+
   return entry;
 }
 
   return entry;
 }
 
@@ -769,6 +771,8 @@ SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
 
   entry = (SilcChannelEntry)id_cache->context;
 
 
   entry = (SilcChannelEntry)id_cache->context;
 
+  SILC_LOG_DEBUG(("Found"));
+
   return entry;
 }
 
   return entry;
 }
 
index def0d53bdb9eac2e7e5c24de32fd14246d1e6c69..79419968176b334d0a64a13c514d98dcff7f8ec4 100644 (file)
@@ -429,7 +429,7 @@ unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
 
 /* Return MAC. The caller knows the length of the MAC */
 
 
 /* Return MAC. The caller knows the length of the MAC */
 
-unsigned char *silc_channel_mesage_get_mac(SilcChannelMessagePayload payload)
+unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload)
 {
   return payload->mac;
 }
 {
   return payload->mac;
 }
index e1c2fc2bf1fe3a6a9e6db0677c74be1516ed9799..0d64787d06cd8d3ad778757ae0d3c05864d19562 100644 (file)
@@ -207,31 +207,33 @@ SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
                                           uint16 ident, 
                                           uint32 argc, va_list ap)
 {
                                           uint16 ident, 
                                           uint32 argc, va_list ap)
 {
-  unsigned char **argv;
+  unsigned char **argv = NULL;
   uint32 *argv_lens = NULL, *argv_types = NULL;
   unsigned char *x;
   uint32 x_len;
   uint32 x_type;
   SilcBuffer buffer;
   uint32 *argv_lens = NULL, *argv_types = NULL;
   unsigned char *x;
   uint32 x_len;
   uint32 x_type;
   SilcBuffer buffer;
-  int i, k;
-
-  argv = silc_calloc(argc, sizeof(unsigned char *));
-  argv_lens = silc_calloc(argc, sizeof(uint32));
-  argv_types = silc_calloc(argc, sizeof(uint32));
-
-  for (i = 0, k = 0; i < argc; i++) {
-    x_type = va_arg(ap, uint32);
-    x = va_arg(ap, unsigned char *);
-    x_len = va_arg(ap, uint32);
+  int i, k = 0;
 
 
-    if (!x_type || !x || !x_len)
-      continue;
-
-    argv[k] = silc_calloc(x_len + 1, sizeof(unsigned char));
-    memcpy(argv[k], x, x_len);
-    argv_lens[k] = x_len;
-    argv_types[k] = x_type;
-    k++;
+  if (argc) {
+    argv = silc_calloc(argc, sizeof(unsigned char *));
+    argv_lens = silc_calloc(argc, sizeof(uint32));
+    argv_types = silc_calloc(argc, sizeof(uint32));
+
+    for (i = 0, k = 0; i < argc; i++) {
+      x_type = va_arg(ap, uint32);
+      x = va_arg(ap, unsigned char *);
+      x_len = va_arg(ap, uint32);
+      
+      if (!x_type || !x || !x_len)
+       continue;
+      
+      argv[k] = silc_calloc(x_len + 1, sizeof(unsigned char));
+      memcpy(argv[k], x, x_len);
+      argv_lens[k] = x_len;
+      argv_types[k] = x_type;
+      k++;
+    }
   }
 
   buffer = silc_command_payload_encode(cmd, k, argv, argv_lens, 
   }
 
   buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,