updates.
[silc.git] / apps / silcd / command.c
index d72636f44453ef5404c368b2eebcc8f3c4230ca6..48033266a4e0eb5f7ced7b97007340b52f18e0f3 100644 (file)
@@ -34,9 +34,9 @@ static void
 silc_server_command_send_status_data(SilcServerCommandContext cmd,
                                     SilcCommand command,
                                     SilcCommandStatus status,
-                                    unsigned int arg_type,
+                                    uint32 arg_type,
                                     unsigned char *arg,
-                                    unsigned int arg_len);
+                                    uint32 arg_len);
 SILC_TASK_CALLBACK(silc_server_command_process_timeout);
 
 /* Server command list. */
@@ -71,13 +71,14 @@ SilcServerCommand silc_command_list[] =
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
   SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG),
   SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(getkey, GETKEY, SILC_CF_LAG | SILC_CF_REG),
 
   { NULL, 0 },
 };
 
 #define SILC_SERVER_COMMAND_CHECK_ARGC(command, context, min, max)           \
 do {                                                                         \
-  unsigned int _argc = silc_argument_get_arg_num(cmd->args);                 \
+  uint32 _argc = silc_argument_get_arg_num(cmd->args);               \
                                                                              \
   SILC_LOG_DEBUG(("Start"));                                                 \
                                                                              \
@@ -248,7 +249,7 @@ void silc_server_command_free(SilcServerCommandContext ctx)
                  ctx->users));
   if (ctx->users < 1) {
     if (ctx->payload)
-      silc_command_free_payload(ctx->payload);
+      silc_command_payload_free(ctx->payload);
     if (ctx->packet)
       silc_packet_context_free(ctx->packet);
     if (ctx->sock)
@@ -277,7 +278,7 @@ silc_server_command_dup(SilcServerCommandContext ctx)
 
 void silc_server_command_pending(SilcServer server,
                                 SilcCommand reply_cmd,
-                                unsigned short ident,
+                                uint16 ident,
                                 SilcServerPendingDestructor destructor,
                                 SilcCommandCb callback,
                                 void *context)
@@ -297,7 +298,7 @@ void silc_server_command_pending(SilcServer server,
 
 void silc_server_command_pending_del(SilcServer server,
                                     SilcCommand reply_cmd,
-                                    unsigned short ident)
+                                    uint16 ident)
 {
   SilcServerCommandPending *r;
 
@@ -316,7 +317,7 @@ void silc_server_command_pending_del(SilcServer server,
 int silc_server_command_pending_check(SilcServer server,
                                      SilcServerCommandReplyContext ctx,
                                      SilcCommand command, 
-                                     unsigned short ident)
+                                     uint16 ident)
 {
   SilcServerCommandPending *r;
 
@@ -370,9 +371,9 @@ static void
 silc_server_command_send_status_data(SilcServerCommandContext cmd,
                                     SilcCommand command,
                                     SilcCommandStatus status,
-                                    unsigned int arg_type,
+                                    uint32 arg_type,
                                     unsigned char *arg,
-                                    unsigned int arg_len)
+                                    uint32 arg_len)
 {
   SilcBuffer buffer;
 
@@ -397,15 +398,15 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
 static int
 silc_server_command_whois_parse(SilcServerCommandContext cmd,
                                SilcClientID ***client_id,
-                               unsigned int *client_id_count,
+                               uint32 *client_id_count,
                                char **nickname,
                                char **server_name,
                                int *count,
                                SilcCommand command)
 {
   unsigned char *tmp;
-  unsigned int len;
-  unsigned int argc = silc_argument_get_arg_num(cmd->args);
+  uint32 len;
+  uint32 argc = silc_argument_get_arg_num(cmd->args);
   int i, k;
 
   /* If client ID is in the command it must be used instead of nickname */
@@ -477,7 +478,7 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
 static char
 silc_server_command_whois_check(SilcServerCommandContext cmd,
                                SilcClientEntry *clients,
-                               unsigned int clients_count)
+                               uint32 clients_count)
 {
   SilcServer server = cmd->server;
   int i;
@@ -491,7 +492,7 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
 
     if (!entry->nickname || !entry->username || !entry->userinfo) {
       SilcBuffer tmpbuf;
-      unsigned short old_ident;
+      uint16 old_ident;
 
       if (!entry->router)
        continue;
@@ -526,7 +527,7 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
 static void
 silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
                                     SilcClientEntry *clients,
-                                    unsigned int clients_count,
+                                    uint32 clients_count,
                                     int count)
 {
   SilcServer server = cmd->server;
@@ -535,8 +536,8 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
   SilcBuffer packet, idp, channels;
   SilcClientEntry entry;
   SilcCommandStatus status;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
-  char nh[128], uh[128];
+  uint16 ident = silc_command_get_ident(cmd->payload);
+  char nh[256], uh[256];
   unsigned char idle[4], mode[4];
   SilcSocketConnection hsock;
 
@@ -554,11 +555,18 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
 
     if (entry->data.registered == FALSE) {
       if (clients_count == 1) {
-       SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
-                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                            2, idp->data, idp->len);
-       silc_buffer_free(idp);
+       if (entry->nickname) {
+         silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+                                              SILC_STATUS_ERR_NO_SUCH_NICK,
+                                              3, entry->nickname, 
+                                              strlen(entry->nickname));
+       } else {
+         SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+         silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+                                    SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+                                              2, idp->data, idp->len);
+         silc_buffer_free(idp);
+       }
       }
       continue;
     }
@@ -591,10 +599,14 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
     strncat(nh, entry->nickname, strlen(entry->nickname));
     if (!strchr(entry->nickname, '@')) {
       strncat(nh, "@", 1);
-      len = entry->router ? strlen(entry->router->server_name) :
-       strlen(server->server_name);
-      strncat(nh, entry->router ? entry->router->server_name :
-             server->server_name, len);
+      if (entry->servername) {
+       strncat(nh, entry->servername, strlen(entry->servername));
+      } else {
+       len = entry->router ? strlen(entry->router->server_name) :
+         strlen(server->server_name);
+       strncat(nh, entry->router ? entry->router->server_name :
+               server->server_name, len);
+      }
     }
       
     strncat(uh, entry->username, strlen(entry->username));
@@ -653,10 +665,10 @@ silc_server_command_whois_from_client(SilcServerCommandContext cmd)
 {
   SilcServer server = cmd->server;
   char *nick = NULL, *server_name = NULL;
-  int count = 0, clients_count = 0;
+  int count = 0;
   SilcClientEntry *clients = NULL, entry;
   SilcClientID **client_id = NULL;
-  unsigned int client_id_count = 0;
+  uint32 client_id_count = 0, clients_count = 0;
   int i, ret = 0;
 
   /* Protocol dictates that we must always send the received WHOIS request
@@ -666,7 +678,7 @@ silc_server_command_whois_from_client(SilcServerCommandContext cmd)
   if (server->server_type == SILC_SERVER && !cmd->pending && 
       !server->standalone) {
     SilcBuffer tmpbuf;
-    unsigned short old_ident;
+    uint16 old_ident;
 
     old_ident = silc_command_get_ident(cmd->payload);
     silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
@@ -795,10 +807,10 @@ silc_server_command_whois_from_server(SilcServerCommandContext cmd)
 {
   SilcServer server = cmd->server;
   char *nick = NULL, *server_name = NULL;
-  int count = 0, clients_count = 0;
+  int count = 0;
   SilcClientEntry *clients = NULL, entry;
   SilcClientID **client_id = NULL;
-  unsigned int client_id_count = 0;
+  uint32 client_id_count = 0, clients_count = 0;
   int i, ret = 0;
 
   /* Parse the whois request */
@@ -932,7 +944,7 @@ silc_server_command_whowas_parse(SilcServerCommandContext cmd,
                                 int *count)
 {
   unsigned char *tmp;
-  unsigned int len;
+  uint32 len;
 
   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
   if (!tmp) {
@@ -964,7 +976,7 @@ silc_server_command_whowas_parse(SilcServerCommandContext cmd,
 static char
 silc_server_command_whowas_check(SilcServerCommandContext cmd,
                                 SilcClientEntry *clients,
-                                unsigned int clients_count)
+                                uint32 clients_count)
 {
   SilcServer server = cmd->server;
   int i;
@@ -975,7 +987,7 @@ silc_server_command_whowas_check(SilcServerCommandContext cmd,
 
     if (!entry->nickname || !entry->username) {
       SilcBuffer tmpbuf;
-      unsigned short old_ident;
+      uint16 old_ident;
 
       if (!entry->router)
        continue;
@@ -1010,7 +1022,7 @@ silc_server_command_whowas_check(SilcServerCommandContext cmd,
 static void
 silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
                                      SilcClientEntry *clients,
-                                     unsigned int clients_count)
+                                     uint32 clients_count)
 {
   SilcServer server = cmd->server;
   char *tmp;
@@ -1018,7 +1030,7 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
   SilcBuffer packet, idp;
   SilcClientEntry entry = NULL;
   SilcCommandStatus status;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint16 ident = silc_command_get_ident(cmd->payload);
   char found = FALSE;
   char nh[256], uh[256];
 
@@ -1063,10 +1075,14 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
     strncat(nh, entry->nickname, strlen(entry->nickname));
     if (!strchr(entry->nickname, '@')) {
       strncat(nh, "@", 1);
-      len = entry->router ? strlen(entry->router->server_name) :
-       strlen(server->server_name);
-      strncat(nh, entry->router ? entry->router->server_name :
-             server->server_name, len);
+      if (entry->servername) {
+       strncat(nh, entry->servername, strlen(entry->servername));
+      } else {
+       len = entry->router ? strlen(entry->router->server_name) :
+         strlen(server->server_name);
+       strncat(nh, entry->router ? entry->router->server_name :
+               server->server_name, len);
+      }
     }
       
     strncat(uh, entry->username, strlen(entry->username));
@@ -1111,8 +1127,9 @@ silc_server_command_whowas_from_client(SilcServerCommandContext cmd)
 {
   SilcServer server = cmd->server;
   char *nick = NULL, *server_name = NULL;
-  int count = 0, clients_count = 0;
+  int count = 0;
   SilcClientEntry *clients = NULL;
+  uint32 clients_count = 0;
   int ret = 0;
 
   /* Protocol dictates that we must always send the received WHOWAS request
@@ -1122,7 +1139,7 @@ silc_server_command_whowas_from_client(SilcServerCommandContext cmd)
   if (server->server_type == SILC_SERVER && 
       !cmd->pending && !server->standalone) {
     SilcBuffer tmpbuf;
-    unsigned short old_ident;
+    uint16 old_ident;
 
     old_ident = silc_command_get_ident(cmd->payload);
     silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
@@ -1196,8 +1213,9 @@ silc_server_command_whowas_from_server(SilcServerCommandContext cmd)
 {
   SilcServer server = cmd->server;
   char *nick = NULL, *server_name = NULL;
-  int count = 0, clients_count = 0;
+  int count = 0;
   SilcClientEntry *clients = NULL;
+  uint32 clients_count = 0;
   int ret = 0;
 
   /* Parse the whowas request */
@@ -1278,7 +1296,7 @@ SILC_SERVER_CMD_FUNC(whowas)
 static char
 silc_server_command_identify_check(SilcServerCommandContext cmd,
                                   SilcClientEntry *clients,
-                                  unsigned int clients_count)
+                                  uint32 clients_count)
 {
   SilcServer server = cmd->server;
   int i;
@@ -1292,7 +1310,7 @@ silc_server_command_identify_check(SilcServerCommandContext cmd,
 
     if (!entry->nickname) {
       SilcBuffer tmpbuf;
-      unsigned short old_ident;
+      uint16 old_ident;
       
       if (!entry->router)
        continue;
@@ -1332,7 +1350,7 @@ silc_server_command_identify_check(SilcServerCommandContext cmd,
 static void
 silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
                                        SilcClientEntry *clients,
-                                       unsigned int clients_count,
+                                       uint32 clients_count,
                                        int count)
 {
   SilcServer server = cmd->server;
@@ -1341,7 +1359,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
   SilcBuffer packet, idp;
   SilcClientEntry entry;
   SilcCommandStatus status;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint16 ident = silc_command_get_ident(cmd->payload);
   char nh[256], uh[256];
   SilcSocketConnection hsock;
 
@@ -1390,10 +1408,14 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
     strncat(nh, entry->nickname, strlen(entry->nickname));
     if (!strchr(entry->nickname, '@')) {
       strncat(nh, "@", 1);
-      len = entry->router ? strlen(entry->router->server_name) :
-       strlen(server->server_name);
-      strncat(nh, entry->router ? entry->router->server_name :
-             server->server_name, len);
+      if (entry->servername) {
+       strncat(nh, entry->servername, strlen(entry->servername));
+      } else {
+       len = entry->router ? strlen(entry->router->server_name) :
+         strlen(server->server_name);
+       strncat(nh, entry->router ? entry->router->server_name :
+               server->server_name, len);
+      }
     }
       
     if (!entry->username) {
@@ -1432,10 +1454,10 @@ silc_server_command_identify_from_client(SilcServerCommandContext cmd)
 {
   SilcServer server = cmd->server;
   char *nick = NULL, *server_name = NULL;
-  int count = 0, clients_count = 0; 
+  int count = 0;
   SilcClientEntry *clients = NULL, entry;
   SilcClientID **client_id = NULL;
-  unsigned int client_id_count = 0;
+  uint32 client_id_count = 0, clients_count = 0;
   int i, ret = 0;
 
   /* Protocol dictates that we must always send the received IDENTIFY request
@@ -1445,7 +1467,7 @@ silc_server_command_identify_from_client(SilcServerCommandContext cmd)
   if (server->server_type == SILC_SERVER && 
       !cmd->pending && !server->standalone) {
     SilcBuffer tmpbuf;
-    unsigned short old_ident;
+    uint16 old_ident;
 
     old_ident = silc_command_get_ident(cmd->payload);
     silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
@@ -1571,10 +1593,10 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd)
 {
   SilcServer server = cmd->server;
   char *nick = NULL, *server_name = NULL;
-  int count = 0, clients_count = 0;
+  int count = 0;
   SilcClientEntry *clients = NULL, entry;
   SilcClientID **client_id = NULL;
-  unsigned int client_id_count = 0;
+  uint32 client_id_count = 0, clients_count = 0;
   int i, ret = 0;
 
   /* Parse the IDENTIFY request */
@@ -1716,7 +1738,7 @@ SILC_SERVER_CMD_FUNC(nick)
   SilcBuffer packet, nidp, oidp;
   SilcClientID *new_id;
   char *nick;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint16 ident = silc_command_get_ident(cmd->payload);
 
   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
     goto out;
@@ -1746,19 +1768,16 @@ SILC_SERVER_CMD_FUNC(nick)
     silc_server_send_notify_nick_change(server, server->router->connection, 
                                        server->server_type == SILC_SERVER ? 
                                        FALSE : TRUE, client->id,
-                                       new_id, SILC_ID_CLIENT_LEN);
+                                       new_id);
 
   /* Remove old cache entry */
-  silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT, 
-                        client->id); 
+  silc_idcache_del_by_context(server->local_list->clients, client);
 
   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
   /* Free old ID */
-  if (client->id) {
-    memset(client->id, 0, SILC_ID_CLIENT_LEN);
+  if (client->id)
     silc_free(client->id);
-  }
 
   /* Save the nickname as this client is our local client */
   if (client->nickname)
@@ -1769,8 +1788,7 @@ SILC_SERVER_CMD_FUNC(nick)
 
   /* Update client cache */
   silc_idcache_add(server->local_list->clients, client->nickname, 
-                  strlen(client->nickname), SILC_ID_CLIENT, client->id, 
-                  (void *)client, TRUE, FALSE);
+                  client->id, (void *)client, FALSE);
 
   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
@@ -1800,18 +1818,18 @@ SILC_SERVER_CMD_FUNC(nick)
 static void
 silc_server_command_list_send_reply(SilcServerCommandContext cmd,
                                    SilcChannelEntry *lch, 
-                                   unsigned int lch_count,
+                                   uint32 lch_count,
                                    SilcChannelEntry *gch,
-                                   unsigned int gch_count)
+                                   uint32 gch_count)
 {
   int i;
   SilcBuffer packet, idp;
   SilcChannelEntry entry;
   SilcCommandStatus status;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint16 ident = silc_command_get_ident(cmd->payload);
   char *topic;
   unsigned char usercount[4];
-  unsigned int users;
+  uint32 users;
 
   for (i = 0; i < lch_count; i++)
     if (lch[i]->mode & SILC_CHANNEL_MODE_SECRET)
@@ -1846,7 +1864,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
       memset(usercount, 0, sizeof(usercount));
     } else {
       topic = entry->topic;
-      users = silc_list_count(entry->user_list);
+      users = silc_hash_table_count(entry->user_list);
       SILC_PUT32_MSB(users, usercount);
     }
 
@@ -1897,7 +1915,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
       memset(usercount, 0, sizeof(usercount));
     } else {
       topic = entry->topic;
-      users = silc_list_count(entry->user_list);
+      users = silc_hash_table_count(entry->user_list);
       SILC_PUT32_MSB(users, usercount);
     }
 
@@ -1936,9 +1954,9 @@ SILC_SERVER_CMD_FUNC(list)
   SilcServer server = cmd->server;
   SilcChannelID *channel_id = NULL;
   unsigned char *tmp;
-  unsigned int tmp_len;
+  uint32 tmp_len;
   SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
-  unsigned int lch_count = 0, gch_count = 0;
+  uint32 lch_count = 0, gch_count = 0;
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LIST, cmd, 0, 2);
 
@@ -1983,8 +2001,8 @@ SILC_SERVER_CMD_FUNC(topic)
   SilcChannelClientEntry chl;
   SilcBuffer packet, idp;
   unsigned char *tmp;
-  unsigned int argc, tmp_len;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint32 argc, tmp_len;
+  uint16 ident = silc_command_get_ident(cmd->payload);
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_TOPIC, cmd, 1, 2);
 
@@ -2032,11 +2050,13 @@ SILC_SERVER_CMD_FUNC(topic)
       goto out;
     }
 
-    /* See whether has rights to change topic */
-    silc_list_start(channel->user_list);
-    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
-      if (chl->client == client)
-       break;
+    /* See whether the client is on channel and has rights to change topic */
+    if (!silc_hash_table_find(channel->user_list, client, NULL, 
+                             (void *)&chl)) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
+      goto out;
+    }
 
     if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
       if (channel->mode & SILC_CHANNEL_MODE_TOPIC) {
@@ -2056,7 +2076,7 @@ SILC_SERVER_CMD_FUNC(topic)
       silc_server_send_notify_topic_set(server, server->router->connection,
                                        server->server_type == SILC_ROUTER ?
                                        TRUE : FALSE, channel, client->id,
-                                       SILC_ID_CLIENT_LEN, channel->topic);
+                                       channel->topic);
 
     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
@@ -2107,8 +2127,8 @@ SILC_SERVER_CMD_FUNC(invite)
   SilcIDListData idata;
   SilcBuffer idp, idp2, packet;
   unsigned char *tmp, *add, *del;
-  unsigned int len;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint32 len;
+  uint16 ident = silc_command_get_ident(cmd->payload);
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 4);
 
@@ -2150,16 +2170,12 @@ SILC_SERVER_CMD_FUNC(invite)
   /* Check whether the channel is invite-only channel. If yes then the
      sender of this command must be at least channel operator. */
   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
-    silc_list_start(channel->user_list);
-    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
-      if (chl->client == sender) {
-       if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
-         silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                       SILC_STATUS_ERR_NO_CHANNEL_PRIV);
-         goto out;
-       }
-       break;
-      }
+    silc_hash_table_find(channel->user_list, sender, NULL, (void *)&chl);
+    if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+      goto out;
+    }
   }
 
   /* Get destination client ID */
@@ -2205,6 +2221,11 @@ SILC_SERVER_CMD_FUNC(invite)
     
     /* Get route to the client */
     dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id, &idata);
+    if (!dest_sock) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+      goto out;
+    }
 
     memset(invite, 0, sizeof(invite));
     strncat(invite, dest->nickname, strlen(dest->nickname));
@@ -2287,18 +2308,24 @@ SILC_SERVER_CMD_FUNC(invite)
     silc_server_send_notify_invite(server, server->router->connection,
                                   server->server_type == SILC_ROUTER ?
                                   TRUE : FALSE, channel,
-                                  sender->id, SILC_ID_CLIENT_LEN,
-                                  add, del);
+                                  sender->id, add, del);
 
   /* Send command reply */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
-                                               SILC_STATUS_OK, ident, 2,
-                                               2, tmp, len,
-                                               3, channel->invite_list,
-                                               channel->invite_list ?
-                                               strlen(channel->invite_list) :
-                                               0);
+
+  if (add || del)
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
+                                          SILC_STATUS_OK, ident, 2,
+                                          2, tmp, len,
+                                          3, channel->invite_list,
+                                          channel->invite_list ?
+                                          strlen(channel->invite_list) : 0);
+  else
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
+                                          SILC_STATUS_OK, ident, 1,
+                                          2, tmp, len);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
@@ -2346,7 +2373,7 @@ SILC_SERVER_CMD_FUNC(quit)
   SilcSocketConnection sock = cmd->sock;
   QuitInternal q;
   unsigned char *tmp = NULL;
-  unsigned int len = 0;
+  uint32 len = 0;
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_QUIT, cmd, 0, 1);
 
@@ -2383,7 +2410,7 @@ SILC_SERVER_CMD_FUNC(kill)
   SilcClientEntry remote_client;
   SilcClientID *client_id;
   unsigned char *tmp, *comment;
-  unsigned int tmp_len, tmp_len2;
+  uint32 tmp_len, tmp_len2;
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_KILL, cmd, 1, 2);
 
@@ -2431,6 +2458,12 @@ SILC_SERVER_CMD_FUNC(kill)
     }
   }
 
+  if (remote_client->data.registered == FALSE) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+                                         SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+    goto out;
+  }
+
   /* Get comment */
   comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
   if (tmp_len2 > 128)
@@ -2456,15 +2489,13 @@ SILC_SERVER_CMD_FUNC(kill)
   /* Send KILLED notify to primary route */
   if (!server->standalone)
     silc_server_send_notify_killed(server, server->router->connection, TRUE,
-                                  remote_client->id, SILC_ID_CLIENT_LEN,
-                                  comment);
+                                  remote_client->id, comment);
 
   /* Send KILLED notify to the client directly */
   silc_server_send_notify_killed(server, remote_client->connection ? 
                                 remote_client->connection : 
                                 remote_client->router->connection, FALSE,
-                                remote_client->id, SILC_ID_CLIENT_LEN,
-                                comment);
+                                remote_client->id, comment);
 
   /* Remove the client from all channels. This generates new keys to the
      channels as well. */
@@ -2498,9 +2529,9 @@ SILC_SERVER_CMD_FUNC(info)
   SilcServer server = cmd->server;
   SilcBuffer packet, idp;
   unsigned char *tmp;
-  unsigned int tmp_len;
+  uint32 tmp_len;
   char *dest_server, *server_info = NULL, *server_name;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint16 ident = silc_command_get_ident(cmd->payload);
   SilcServerEntry entry = NULL;
   SilcServerID *server_id = NULL;
 
@@ -2566,7 +2597,7 @@ SILC_SERVER_CMD_FUNC(info)
        server->server_type == SILC_ROUTER && entry && !entry->server_info) {
       /* Send to the server */
       SilcBuffer tmpbuf;
-      unsigned short old_ident;
+      uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
@@ -2591,7 +2622,7 @@ SILC_SERVER_CMD_FUNC(info)
     if (!entry && !cmd->pending && !server->standalone) {
       /* Send to the primary router */
       SilcBuffer tmpbuf;
-      unsigned short old_ident;
+      uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
@@ -2629,13 +2660,20 @@ SILC_SERVER_CMD_FUNC(info)
   server_name = entry->server_name;
 
   /* Send the reply */
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
-                                               SILC_STATUS_OK, ident, 3,
-                                               2, idp->data, idp->len,
-                                               3, server_name, 
-                                               strlen(server_name),
-                                               4, server_info, 
-                                               strlen(server_info));
+  if (server_info)
+    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
+                                                 SILC_STATUS_OK, ident, 3,
+                                                 2, idp->data, idp->len,
+                                                 3, server_name, 
+                                                 strlen(server_name),
+                                                 4, server_info, 
+                                                 strlen(server_info));
+  else
+    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
+                                                 SILC_STATUS_OK, ident, 2,
+                                                 2, idp->data, idp->len,
+                                                 3, server_name, 
+                                                 strlen(server_name));
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
     
@@ -2653,7 +2691,7 @@ SILC_SERVER_CMD_FUNC(ping)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcServerID *id;
-  unsigned int len;
+  uint32 len;
   unsigned char *tmp;
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 2);
@@ -2669,7 +2707,7 @@ SILC_SERVER_CMD_FUNC(ping)
   if (!id)
     goto out;
 
-  if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
+  if (SILC_ID_SERVER_COMPARE(id, server->id)) {
     /* Send our reply */
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
                                          SILC_STATUS_OK);
@@ -2694,16 +2732,16 @@ static void silc_server_command_join_channel(SilcServer server,
                                             SilcChannelEntry channel,
                                             SilcClientID *client_id,
                                             int created,
-                                            unsigned int umode)
+                                            uint32 umode)
 {
   SilcSocketConnection sock = cmd->sock;
   unsigned char *tmp;
-  unsigned int tmp_len, user_count;
+  uint32 tmp_len, user_count;
   unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4];
   SilcClientEntry client;
   SilcChannelClientEntry chl;
   SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint16 ident = silc_command_get_ident(cmd->payload);
   char check[512];
 
   SILC_LOG_DEBUG(("Start"));
@@ -2785,7 +2823,7 @@ static void silc_server_command_join_channel(SilcServer server,
 
   /* Check user count limit if set. */
   if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
-    if (silc_list_count(channel->user_list) + 1 > 
+    if (silc_hash_table_count(channel->user_list) + 1 > 
        channel->user_limit) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                            SILC_STATUS_ERR_CHANNEL_IS_FULL);
@@ -2805,7 +2843,7 @@ static void silc_server_command_join_channel(SilcServer server,
   }
 
   /* Generate new channel key as protocol dictates */
-  if ((!created && silc_list_count(channel->user_list) > 0) || 
+  if ((!created && silc_hash_table_count(channel->user_list) > 0) || 
       !channel->channel_key)
     silc_server_create_channel_key(server, channel, 0);
 
@@ -2823,8 +2861,8 @@ static void silc_server_command_join_channel(SilcServer server,
   chl->mode = umode;
   chl->client = client;
   chl->channel = channel;
-  silc_list_add(channel->user_list, chl);
-  silc_list_add(client->channels, chl);
+  silc_hash_table_add(channel->user_list, client, chl);
+  silc_hash_table_add(client->channels, channel, chl);
 
   /* Get users on the channel */
   silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
@@ -2891,8 +2929,7 @@ static void silc_server_command_join_channel(SilcServer server,
     if (!server->standalone)
       silc_server_send_notify_join(server, server->router->connection,
                                   server->server_type == SILC_ROUTER ?
-                                  TRUE : FALSE, channel, client->id,
-                                  SILC_ID_CLIENT_LEN);
+                                  TRUE : FALSE, channel, client->id);
   }
 
   silc_buffer_free(reply);
@@ -2914,10 +2951,10 @@ SILC_SERVER_CMD_FUNC(join)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  int tmp_len;
+  uint32 tmp_len;
   char *tmp, *channel_name = NULL, *cipher, *hmac;
   SilcChannelEntry channel;
-  unsigned int umode = 0;
+  uint32 umode = 0;
   int created = FALSE;
   SilcClientID *client_id;
 
@@ -2969,7 +3006,7 @@ SILC_SERVER_CMD_FUNC(join)
        be same as the client's ID. */
     if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
       SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
-      if (SILC_ID_CLIENT_COMPARE(entry->id, client_id)) {
+      if (!SILC_ID_CLIENT_COMPARE(entry->id, client_id)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                        SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
        goto out;
@@ -3001,7 +3038,7 @@ SILC_SERVER_CMD_FUNC(join)
           or joins the client to it). */
        if (server->server_type == SILC_SERVER) {
          SilcBuffer tmpbuf;
-         unsigned short old_ident;
+         uint16 old_ident;
          
          old_ident = silc_command_get_ident(cmd->payload);
          silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
@@ -3076,7 +3113,7 @@ SILC_SERVER_CMD_FUNC(join)
   /* If the channel does not have global users and is also empty it means the
      channel was created globally (by our router) and the client will be the
      channel founder and operator. */
-  if (!channel->global_users && silc_list_count(channel->user_list) == 0) {
+  if (!channel->global_users && !silc_hash_table_count(channel->user_list)) {
     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
     created = TRUE;            /* Created globally by our router */
   }
@@ -3100,8 +3137,8 @@ SILC_SERVER_CMD_FUNC(motd)
   SilcServer server = cmd->server;
   SilcBuffer packet, idp;
   char *motd, *dest_server;
-  int motd_len;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint32 motd_len;
+  uint16 ident = silc_command_get_ident(cmd->payload);
   
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 1);
 
@@ -3157,7 +3194,7 @@ SILC_SERVER_CMD_FUNC(motd)
        entry && !entry->motd) {
       /* Send to the server */
       SilcBuffer tmpbuf;
-      unsigned short old_ident;
+      uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
@@ -3182,7 +3219,7 @@ SILC_SERVER_CMD_FUNC(motd)
     if (!entry && !cmd->pending && !server->standalone) {
       /* Send to the primary router */
       SilcBuffer tmpbuf;
-      unsigned short old_ident;
+      uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
@@ -3244,8 +3281,8 @@ SILC_SERVER_CMD_FUNC(umode)
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   SilcBuffer packet;
   unsigned char *tmp_mask;
-  unsigned int mask;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint32 mask;
+  uint16 ident = silc_command_get_ident(cmd->payload);
 
   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
     goto out;
@@ -3302,8 +3339,7 @@ SILC_SERVER_CMD_FUNC(umode)
   /* Send UMODE change to primary router */
   if (!server->standalone)
     silc_server_send_notify_umode(server, server->router->connection, TRUE,
-                                 client->id, SILC_ID_CLIENT_LEN,
-                                 client->mode);
+                                 client->id, client->mode);
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_UMODE,
@@ -3322,7 +3358,7 @@ SILC_SERVER_CMD_FUNC(umode)
 
 int silc_server_check_cmode_rights(SilcChannelEntry channel,
                                   SilcChannelClientEntry client,
-                                  unsigned int mode)
+                                  uint32 mode)
 {
   int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
   int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
@@ -3396,8 +3432,8 @@ SILC_SERVER_CMD_FUNC(cmode)
   SilcBuffer packet, cidp;
   unsigned char *tmp, *tmp_id, *tmp_mask;
   char *cipher = NULL, *hmac = NULL;
-  unsigned int mode_mask, tmp_len, tmp_len2;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint32 mode_mask, tmp_len, tmp_len2;
+  uint16 ident = silc_command_get_ident(cmd->payload);
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CMODE, cmd, 2, 7);
 
@@ -3445,10 +3481,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   }
 
   /* Get entry to the channel user list */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
-    if (chl->client == client)
-      break;
+  silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
 
   /* Check that client has rights to change any requested channel modes */
   if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
@@ -3488,7 +3521,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   
   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
     /* User limit is set on channel */
-    unsigned int user_limit;
+    uint32 user_limit;
       
     /* Get user limit */
     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
@@ -3712,7 +3745,6 @@ SILC_SERVER_CMD_FUNC(cmode)
                                  server->server_type == SILC_ROUTER ? 
                                  TRUE : FALSE, channel,
                                  mode_mask, client->id, SILC_ID_CLIENT,
-                                 SILC_ID_CLIENT_LEN,
                                  cipher, hmac);
 
   /* Send command reply to sender */
@@ -3745,9 +3777,9 @@ SILC_SERVER_CMD_FUNC(cumode)
   SilcChannelClientEntry chl;
   SilcBuffer packet, idp;
   unsigned char *tmp_id, *tmp_ch_id, *tmp_mask;
-  unsigned int target_mask, sender_mask = 0, tmp_len, tmp_ch_len;
+  uint32 target_mask, sender_mask = 0, tmp_len, tmp_ch_len;
   int notify = FALSE;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint16 ident = silc_command_get_ident(cmd->payload);
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 4);
 
@@ -3786,13 +3818,8 @@ SILC_SERVER_CMD_FUNC(cumode)
   }
 
   /* Check that client has rights to change other's rights */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-    if (chl->client == client) {
-      sender_mask = chl->mode;
-      break;
-    }
-  }
+  silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
+  sender_mask = chl->mode;
   
   /* Get the target client's channel mode mask */
   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
@@ -3842,10 +3869,8 @@ SILC_SERVER_CMD_FUNC(cumode)
     }
 
     /* Get entry to the channel user list */
-    silc_list_start(channel->user_list);
-    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
-      if (chl->client == target_client)
-       break;
+    silc_hash_table_find(channel->user_list, target_client, NULL, 
+                        (void *)&chl);
   }
 
   /* 
@@ -3863,7 +3888,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
     /* The client tries to claim the founder rights. */
     unsigned char *tmp_auth;
-    unsigned int tmp_auth_len, auth_len;
+    uint32 tmp_auth_len, auth_len;
     void *auth;
     
     if (target_client != client) {
@@ -3960,9 +3985,8 @@ SILC_SERVER_CMD_FUNC(cumode)
                                     server->server_type == SILC_ROUTER ? 
                                     TRUE : FALSE, channel,
                                     target_mask, client->id, 
-                                    SILC_ID_CLIENT_LEN,
-                                    target_client->id, 
-                                    SILC_ID_CLIENT_LEN);
+                                    SILC_ID_CLIENT,
+                                    target_client->id);
   }
 
   /* Send command reply to sender */
@@ -3995,7 +4019,7 @@ SILC_SERVER_CMD_FUNC(kick)
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcBuffer idp;
-  unsigned int tmp_len;
+  uint32 tmp_len;
   unsigned char *tmp, *comment;
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 3);
@@ -4035,16 +4059,11 @@ SILC_SERVER_CMD_FUNC(kick)
   }
 
   /* Check that the kicker is channel operator or channel founder */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-    if (chl->client == client) {
-      if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
-                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV);
-       goto out;
-      }
-      break;
-    }
+  silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
+  if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+    goto out;
   }
   
   /* Get target Client ID */
@@ -4071,16 +4090,11 @@ SILC_SERVER_CMD_FUNC(kick)
 
   /* Check that the target client is not channel founder. Channel founder
      cannot be kicked from the channel. */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-    if (chl->client == target_client) {
-      if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
-                                 SILC_STATUS_ERR_NO_CHANNEL_FOPRIV);
-       goto out;
-      }
-      break;
-    }
+  silc_hash_table_find(channel->user_list, target_client, NULL, (void *)&chl);
+  if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+                                         SILC_STATUS_ERR_NO_CHANNEL_FOPRIV);
+    goto out;
   }
   
   /* Check whether target client is on the channel */
@@ -4121,8 +4135,7 @@ SILC_SERVER_CMD_FUNC(kick)
     silc_server_send_notify_kicked(server, server->router->connection,
                                   server->server_type == SILC_ROUTER ?
                                   TRUE : FALSE, channel,
-                                  target_client->id, SILC_ID_CLIENT_LEN,
-                                  comment);
+                                  target_client->id, comment);
 
   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
     /* Re-generate channel key */
@@ -4148,7 +4161,7 @@ SILC_SERVER_CMD_FUNC(oper)
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   unsigned char *username, *auth;
-  unsigned int tmp_len;
+  uint32 tmp_len;
   SilcServerConfigSectionAdminConnection *admin;
   SilcIDListData idata = (SilcIDListData)client;
 
@@ -4201,8 +4214,7 @@ SILC_SERVER_CMD_FUNC(oper)
   /* Send UMODE change to primary router */
   if (!server->standalone)
     silc_server_send_notify_umode(server, server->router->connection, TRUE,
-                                 client->id, SILC_ID_CLIENT_LEN,
-                                 client->mode);
+                                 client->id, client->mode);
 
   /* Send reply to the sender */
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
@@ -4221,7 +4233,7 @@ SILC_SERVER_CMD_FUNC(silcoper)
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   unsigned char *username, *auth;
-  unsigned int tmp_len;
+  uint32 tmp_len;
   SilcServerConfigSectionAdminConnection *admin;
   SilcIDListData idata = (SilcIDListData)client;
 
@@ -4277,8 +4289,7 @@ SILC_SERVER_CMD_FUNC(silcoper)
   /* Send UMODE change to primary router */
   if (!server->standalone)
     silc_server_send_notify_umode(server, server->router->connection, TRUE,
-                                 client->id, SILC_ID_CLIENT_LEN,
-                                 client->mode);
+                                 client->id, client->mode);
 
   /* Send reply to the sender */
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
@@ -4297,8 +4308,8 @@ SILC_SERVER_CMD_FUNC(connect)
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   unsigned char *tmp, *host;
-  unsigned int tmp_len;
-  unsigned int port = SILC_PORT;
+  uint32 tmp_len;
+  uint32 port = SILC_PORT;
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CONNECT, cmd, 1, 2);
 
@@ -4356,8 +4367,8 @@ SILC_SERVER_CMD_FUNC(ban)
   SilcChannelClientEntry chl;
   SilcChannelID *channel_id = NULL;
   unsigned char *id, *add, *del;
-  unsigned int id_len, tmp_len;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint32 id_len, tmp_len;
+  uint16 ident = silc_command_get_ident(cmd->payload);
 
   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
     goto out;
@@ -4397,10 +4408,7 @@ SILC_SERVER_CMD_FUNC(ban)
   }
 
   /* Get entry to the channel user list */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
-    if (chl->client == client)
-      break;
+  silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
 
   /* The client must be at least channel operator. */
   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
@@ -4489,9 +4497,9 @@ SILC_SERVER_CMD_FUNC(close)
   SilcServerEntry server_entry;
   SilcSocketConnection sock;
   unsigned char *tmp;
-  unsigned int tmp_len;
+  uint32 tmp_len;
   unsigned char *name;
-  unsigned int port = SILC_PORT;
+  uint32 port = SILC_PORT;
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CLOSE, cmd, 1, 2);
 
@@ -4582,7 +4590,7 @@ SILC_SERVER_CMD_FUNC(leave)
   SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
   SilcChannelID *id = NULL;
   SilcChannelEntry channel;
-  unsigned int len;
+  uint32 len;
   unsigned char *tmp;
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 2);
@@ -4624,8 +4632,7 @@ SILC_SERVER_CMD_FUNC(leave)
   if (!server->standalone)
     silc_server_send_notify_leave(server, server->router->connection,
                                  server->server_type == SILC_ROUTER ?
-                                 TRUE : FALSE, channel, id_entry->id,
-                                 SILC_ID_CLIENT_LEN);
+                                 TRUE : FALSE, channel, id_entry->id);
 
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
                                        SILC_STATUS_OK);
@@ -4646,8 +4653,6 @@ SILC_SERVER_CMD_FUNC(leave)
                                 FALSE : !server->standalone);
   }
 
-  silc_free(id);
-
  out:
   if (id)
     silc_free(id);
@@ -4666,12 +4671,12 @@ SILC_SERVER_CMD_FUNC(users)
   SilcChannelID *id;
   SilcBuffer packet;
   unsigned char *channel_id;
-  unsigned int channel_id_len;
+  uint32 channel_id_len;
   SilcBuffer client_id_list;
   SilcBuffer client_mode_list;
   unsigned char lc[4];
-  unsigned int list_count = 0;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
+  uint32 list_count = 0;
+  uint16 ident = silc_command_get_ident(cmd->payload);
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 1);
 
@@ -4757,3 +4762,181 @@ SILC_SERVER_CMD_FUNC(users)
  out:
   silc_server_command_free(cmd);
 }
+
+/* Server side of command GETKEY. This fetches the client's public key
+   from the server where to the client is connected. */
+
+SILC_SERVER_CMD_FUNC(getkey)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcBuffer packet;
+  SilcClientEntry client;
+  SilcServerEntry server_entry;
+  SilcClientID *client_id = NULL;
+  SilcServerID *server_id = NULL;
+  SilcIDPayload idp = NULL;
+  uint16 ident = silc_command_get_ident(cmd->payload);
+  unsigned char *tmp;
+  uint32 tmp_len;
+  SilcBuffer pk;
+  SilcIdType id_type;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  idp = silc_id_payload_parse_data(tmp, tmp_len);
+  if (!idp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+
+  id_type = silc_id_payload_get_type(idp);
+  if (id_type == SILC_ID_CLIENT) {
+    client_id = silc_id_payload_get_id(idp);
+
+    /* If the client is not found from local list there is no chance it
+       would be locally connected client so send the command further. */
+    client = silc_idlist_find_client_by_id(server->local_list, 
+                                          client_id, NULL);
+    if (!client)
+      client = silc_idlist_find_client_by_id(server->global_list, 
+                                            client_id, NULL);
+    
+    if ((!client && !cmd->pending && !server->standalone) ||
+       (client && !client->connection && !cmd->pending && 
+        !server->standalone) ||
+       (client && !client->data.public_key && !cmd->pending &&
+        !server->standalone)) {
+      SilcBuffer tmpbuf;
+      uint16 old_ident;
+      SilcSocketConnection dest_sock;
+      
+      dest_sock = silc_server_get_client_route(server, NULL, 0, 
+                                              client_id, NULL);
+      if (!dest_sock)
+       goto out;
+      
+      old_ident = silc_command_get_ident(cmd->payload);
+      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+      
+      silc_server_packet_send(server, dest_sock,
+                             SILC_PACKET_COMMAND, cmd->packet->flags,
+                             tmpbuf->data, tmpbuf->len, TRUE);
+      
+      /* Reprocess this packet after received reply from router */
+      silc_server_command_pending(server, SILC_COMMAND_GETKEY, 
+                                 silc_command_get_ident(cmd->payload),
+                                 silc_server_command_destructor,
+                                 silc_server_command_getkey,
+                                 silc_server_command_dup(cmd));
+      cmd->pending = TRUE;
+      
+      silc_command_set_ident(cmd->payload, old_ident);
+      silc_buffer_free(tmpbuf);
+      return;
+    }
+
+    if (!client && cmd->pending) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
+                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+      goto out;
+    }
+
+    /* The client is locally connected, just get the public key and
+       send it back. */
+    tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len);
+    pk = silc_buffer_alloc(4 + tmp_len);
+    silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
+    silc_buffer_format(pk,
+                      SILC_STR_UI_SHORT(tmp_len),
+                      SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
+                      SILC_STR_UI_XNSTRING(tmp, tmp_len),
+                      SILC_STR_END);
+    silc_free(tmp);
+
+  } else if (id_type == SILC_ID_SERVER) {
+    server_id = silc_id_payload_get_id(idp);
+
+    /* If the server is not found from local list there is no chance it
+       would be locally connected server so send the command further. */
+    server_entry = silc_idlist_find_server_by_id(server->local_list, 
+                                                server_id, NULL);
+    if (!server_entry)
+      server_entry = silc_idlist_find_server_by_id(server->global_list, 
+                                                  server_id, NULL);
+    
+    if ((!server_entry && !cmd->pending && !server->standalone) ||
+       (server_entry && !server_entry->connection && !cmd->pending &&
+        !server->standalone) ||
+       (server_entry && !server_entry->data.public_key && !cmd->pending &&
+        !server->standalone)) {
+      SilcBuffer tmpbuf;
+      uint16 old_ident;
+      
+      old_ident = silc_command_get_ident(cmd->payload);
+      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+      
+      silc_server_packet_send(server, server->router->connection,
+                             SILC_PACKET_COMMAND, cmd->packet->flags,
+                             tmpbuf->data, tmpbuf->len, TRUE);
+      
+      /* Reprocess this packet after received reply from router */
+      silc_server_command_pending(server, SILC_COMMAND_GETKEY, 
+                                 silc_command_get_ident(cmd->payload),
+                                 silc_server_command_destructor,
+                                 silc_server_command_getkey,
+                                 silc_server_command_dup(cmd));
+      cmd->pending = TRUE;
+      
+      silc_command_set_ident(cmd->payload, old_ident);
+      silc_buffer_free(tmpbuf);
+      return;
+    }
+
+    if (!server_entry && cmd->pending) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
+                                           SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
+      goto out;
+    }
+
+    /* The client is locally connected, just get the public key and
+       send it back. */
+    tmp = silc_pkcs_public_key_encode(server_entry->data.public_key, &tmp_len);
+    pk = silc_buffer_alloc(4 + tmp_len);
+    silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
+    silc_buffer_format(pk,
+                      SILC_STR_UI_SHORT(tmp_len),
+                      SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
+                      SILC_STR_UI_XNSTRING(tmp, tmp_len),
+                      SILC_STR_END);
+    silc_free(tmp);
+  } else {
+    goto out;
+  }
+
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_GETKEY,
+                                               SILC_STATUS_OK, ident, 2,
+                                               2, tmp, tmp_len,
+                                               3, pk->data, pk->len);
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+                         packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
+  silc_buffer_free(pk);
+
+ out:
+  if (idp)
+    silc_id_payload_free(idp);
+  silc_free(client_id);
+  silc_free(server_id);
+  silc_server_command_free(cmd);
+}