Merged silc_1_1_branch to trunk.
[silc.git] / apps / silcd / command_reply.c
index 198b7167ef56e7c994c10b8c0a274ed0ab6c5083..97aedf0e8e37455267c4818136418a9c24510b9f 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -60,9 +60,10 @@ SilcServerCommandReply silc_command_reply_list[] =
 /* Process received command reply. */
 
 void silc_server_command_reply_process(SilcServer server,
 /* Process received command reply. */
 
 void silc_server_command_reply_process(SilcServer server,
-                                      SilcSocketConnection sock,
+                                      SilcPacketStream sock,
                                       SilcBuffer buffer)
 {
                                       SilcBuffer buffer)
 {
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcServerCommandReply *cmd;
   SilcServerCommandReplyContext ctx;
   SilcCommandPayload payload;
   SilcServerCommandReply *cmd;
   SilcServerCommandReplyContext ctx;
   SilcCommandPayload payload;
@@ -71,7 +72,7 @@ void silc_server_command_reply_process(SilcServer server,
   SILC_LOG_DEBUG(("Start"));
 
   /* Get command reply payload from packet */
   SILC_LOG_DEBUG(("Start"));
 
   /* Get command reply payload from packet */
-  payload = silc_command_payload_parse(buffer->data, buffer->len);
+  payload = silc_command_payload_parse(buffer->data, silc_buffer_len(buffer));
   if (!payload) {
     /* Silently ignore bad reply packet */
     SILC_LOG_DEBUG(("Bad command reply packet"));
   if (!payload) {
     /* Silently ignore bad reply packet */
     SILC_LOG_DEBUG(("Bad command reply packet"));
@@ -82,14 +83,15 @@ void silc_server_command_reply_process(SilcServer server,
      command reply routine receiving it. */
   ctx = silc_calloc(1, sizeof(*ctx));
   ctx->server = server;
      command reply routine receiving it. */
   ctx = silc_calloc(1, sizeof(*ctx));
   ctx->server = server;
-  ctx->sock = silc_socket_dup(sock);
+  ctx->sock = sock;
   ctx->payload = payload;
   ctx->args = silc_command_get_args(ctx->payload);
   ctx->ident = silc_command_get_ident(ctx->payload);
   command = silc_command_get(ctx->payload);
   ctx->payload = payload;
   ctx->args = silc_command_get_args(ctx->payload);
   ctx->ident = silc_command_get_ident(ctx->payload);
   command = silc_command_get(ctx->payload);
+  silc_packet_stream_ref(sock);
 
   /* Client is not allowed to send reply to all commands */
 
   /* Client is not allowed to send reply to all commands */
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT &&
+  if (idata->conn_type == SILC_CONN_CLIENT &&
       command != SILC_COMMAND_WHOIS) {
     silc_server_command_reply_free(ctx);
     return;
       command != SILC_COMMAND_WHOIS) {
     silc_server_command_reply_free(ctx);
     return;
@@ -120,7 +122,7 @@ void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
   if (cmd) {
     silc_command_payload_free(cmd->payload);
     if (cmd->sock)
   if (cmd) {
     silc_command_payload_free(cmd->payload);
     if (cmd->sock)
-      silc_socket_free(cmd->sock); /* Decrease the reference counter */
+      silc_packet_stream_unref(cmd->sock);
     silc_free(cmd->callbacks);
     silc_free(cmd);
   }
     silc_free(cmd->callbacks);
     silc_free(cmd);
   }
@@ -131,35 +133,27 @@ silc_server_command_process_error(SilcServerCommandReplyContext cmd,
                                  SilcStatus error)
 {
   SilcServer server = cmd->server;
                                  SilcStatus error)
 {
   SilcServer server = cmd->server;
+  SilcIDListData idata = silc_packet_get_context(cmd->sock);
 
   /* If we received notify for invalid ID we'll remove the ID if we
      have it cached. */
   if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
 
   /* If we received notify for invalid ID we'll remove the ID if we
      have it cached. */
   if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
-      cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
+      idata->conn_type == SILC_CONN_ROUTER) {
     SilcClientEntry client;
     SilcClientEntry client;
-    SilcUInt32 tmp_len;
-    unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-    if (tmp) {
-      SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-      if (client_id) {
-       SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
-                       "the entry from cache"));
-       client = silc_idlist_find_client_by_id(server->global_list,
-                                              client_id, FALSE, NULL);
-       if (client) {
-
-         if (client->data.public_key)
-           silc_hash_table_del_by_context(server->pk_hash,
-                                           client->data.public_key,
-                                           client);
-
-         silc_server_remove_from_channels(server, NULL, client, TRUE,
-                                          NULL, TRUE, FALSE);
-         silc_idlist_del_data(client);
-         silc_idlist_del_client(server->global_list, client);
-       }
-       silc_free(client_id);
-      }
+    SilcID id;
+    if (silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id,
+                                 NULL)) {
+      SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
+                     "the entry from cache"));
+      client = silc_idlist_find_client_by_id(server->global_list,
+                                            SILC_ID_GET_ID(id), FALSE, NULL);
+      if (!client)
+       return;
+
+      silc_server_remove_from_channels(server, NULL, client, TRUE,
+                                      NULL, TRUE, FALSE);
+      silc_idlist_del_data(client);
+      silc_idlist_del_client(server->global_list, client);
     }
   }
 }
     }
   }
 }
@@ -171,14 +165,17 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
 {
   SilcServer server = cmd->server;
   unsigned char *id_data, *umodes;
 {
   SilcServer server = cmd->server;
   unsigned char *id_data, *umodes;
-  char *nickname, *username, *realname, *tmp, *servername = NULL;
+  char *nickname, *username, *realname, *tmp;
   unsigned char *fingerprint;
   unsigned char *fingerprint;
-  SilcClientID *client_id;
+  SilcID id;
   SilcClientEntry client;
   SilcClientEntry client;
-  SilcIDCacheEntry cache = NULL;
   char global = FALSE;
   char global = FALSE;
-  char *nick = NULL;
+  char nick[128 + 1], servername[256 + 1], uname[128 + 1];
   SilcUInt32 mode = 0, len, len2, id_len, flen;
   SilcUInt32 mode = 0, len, len2, id_len, flen;
+  const char *hostname, *ip;
+
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock),
+                             NULL, &hostname, &ip, NULL);
 
   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
 
   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
@@ -191,18 +188,19 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
   if (tmp)
     SILC_GET32_MSB(mode, tmp);
 
   if (tmp)
     SILC_GET32_MSB(mode, tmp);
 
-  client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
-  if (!client_id)
+  if (!silc_id_payload_parse_id(id_data, id_len, &id))
     return FALSE;
 
   fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);
 
   /* Check if we have this client cached already. */
 
     return FALSE;
 
   fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);
 
   /* Check if we have this client cached already. */
 
-  client = silc_idlist_find_client_by_id(server->local_list, client_id,
+  client = silc_idlist_find_client_by_id(server->local_list,
+                                        SILC_ID_GET_ID(id),
                                         FALSE, NULL);
   if (!client) {
                                         FALSE, NULL);
   if (!client) {
-    client = silc_idlist_find_client_by_id(server->global_list, client_id,
+    client = silc_idlist_find_client_by_id(server->global_list,
+                                          SILC_ID_GET_ID(id),
                                           FALSE, NULL);
     global = TRUE;
   }
                                           FALSE, NULL);
     global = TRUE;
   }
@@ -214,18 +212,21 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
       return FALSE;
 
     /* Take hostname out of nick string if it includes it. */
       return FALSE;
 
     /* Take hostname out of nick string if it includes it. */
-    silc_parse_userfqdn(nickname, &nick, &servername);
+    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
+                       sizeof(servername));
 
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be
        global. This will check for valid nickname and username strings. */
 
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be
        global. This will check for valid nickname and username strings. */
-    client = silc_idlist_add_client(server->global_list, nick, username,
-                                   strdup(realname), client_id,
-                                   cmd->sock->user_data, NULL, 0);
+    client = silc_idlist_add_client(server->global_list,
+                                   strdup(nick), username,
+                                   strdup(realname),
+                                   silc_id_dup(SILC_ID_GET_ID(id),
+                                               SILC_ID_CLIENT),
+                                   silc_packet_get_context(cmd->sock),
+                                   NULL);
     if (!client) {
       SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
     if (!client) {
       SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
-      silc_free(nick);
-      silc_free(servername);
       return FALSE;
     }
 
       return FALSE;
     }
 
@@ -233,60 +234,50 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
       (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
     client->mode = mode;
       (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
     client->mode = mode;
-    client->servername = servername;
+    client->servername = servername[0] ? strdup(servername) : NULL;
   } else {
     /* We have the client already, update the data */
 
     SILC_LOG_DEBUG(("Updating client data"));
 
     /* Check nickname */
   } else {
     /* We have the client already, update the data */
 
     SILC_LOG_DEBUG(("Updating client data"));
 
     /* Check nickname */
-    silc_parse_userfqdn(nickname, &nick, &servername);
+    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
+                       sizeof(servername));
     nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
                                     128, NULL);
     if (!nickname) {
       SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOIS reply "
                      "from %s",
     nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
                                     128, NULL);
     if (!nickname) {
       SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOIS reply "
                      "from %s",
-                     cmd->sock->hostname ? cmd->sock->hostname : "", nick));
-      silc_free(nick);
-      silc_free(servername);
+                     hostname ? hostname : "", nick));
       return FALSE;
     }
 
     /* Check username */
       return FALSE;
     }
 
     /* Check username */
-    silc_parse_userfqdn(username, &tmp, NULL);
-    if (!silc_identifier_verify(tmp, strlen(tmp), SILC_STRING_UTF8, 128)) {
-      silc_free(tmp);
-      silc_free(nick);
-      silc_free(servername);
+    silc_parse_userfqdn(username, uname, sizeof(uname), NULL, 0);
+    if (!silc_identifier_verify(uname, strlen(uname), SILC_STRING_UTF8, 128)) {
       SILC_LOG_ERROR(("Malformed username '%s' received in WHOIS reply "
                      "from %s",
       SILC_LOG_ERROR(("Malformed username '%s' received in WHOIS reply "
                      "from %s",
-                     cmd->sock->hostname ? cmd->sock->hostname : "", tmp));
+                     hostname ? hostname : "", tmp));
       return FALSE;
     }
       return FALSE;
     }
-    silc_free(tmp);
 
 
-    /* Remove the old cache entry  */
-    silc_idcache_del_by_context(global ? server->global_list->clients :
-                               server->local_list->clients, client);
+    /* Update entry */
+    silc_idcache_update_by_context(global ? server->global_list->clients :
+                                  server->local_list->clients, client, NULL,
+                                  nickname, TRUE);
 
     silc_free(client->nickname);
     silc_free(client->username);
     silc_free(client->userinfo);
     silc_free(client->servername);
 
 
     silc_free(client->nickname);
     silc_free(client->username);
     silc_free(client->userinfo);
     silc_free(client->servername);
 
-    client->nickname = nick;
+    client->nickname = strdup(nick);
     client->username = strdup(username);
     client->userinfo = strdup(realname);
     client->username = strdup(username);
     client->userinfo = strdup(realname);
-    client->servername = servername;
+    client->servername = servername[0] ? strdup(servername) : NULL;
     client->mode = mode;
     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
     client->mode = mode;
     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
-
-    /* Create new cache entry */
-    silc_idcache_add(global ? server->global_list->clients :
-                    server->local_list->clients, nickname, client->id,
-                    client, 0, NULL);
-    silc_free(client_id);
   }
 
   /* Save channel list if it was sent to us */
   }
 
   /* Save channel list if it was sent to us */
@@ -302,17 +293,6 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
     } else {
       silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL);
     }
     } else {
       silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL);
     }
-
-    /* If client is global and is not on any channel then add that we'll
-       expire the entry after a while. */
-    if (global) {
-      silc_idlist_find_client_by_id(server->global_list, client->id,
-                                   FALSE, &cache);
-      if (!silc_hash_table_count(client->channels))
-       cache->expire = time(NULL) + 300;
-      else
-       cache->expire = 0;
-    }
   }
 
   if (fingerprint && flen == sizeof(client->data.fingerprint))
   }
 
   if (fingerprint && flen == sizeof(client->data.fingerprint))
@@ -331,7 +311,7 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
     if (server->server_type != SILC_ROUTER && !client->data.public_key) {
       SilcAttributePayload attr;
       SilcAttributeObjPk pk;
     if (server->server_type != SILC_ROUTER && !client->data.public_key) {
       SilcAttributePayload attr;
       SilcAttributeObjPk pk;
-      unsigned char f[20];
+      unsigned char f[SILC_HASH_MAXLEN];
       SilcDList attrs = silc_attribute_payload_parse(tmp, len);
 
       SILC_LOG_DEBUG(("Take client public key from attributes"));
       SilcDList attrs = silc_attribute_payload_parse(tmp, len);
 
       SILC_LOG_DEBUG(("Take client public key from attributes"));
@@ -361,8 +341,9 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
            }
 
            /* Save the public key. */
            }
 
            /* Save the public key. */
-           if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
-                                            &client->data.public_key)) {
+           if (!silc_pkcs_public_key_alloc(SILC_PKCS_SILC,
+                                           pk.data, pk.data_len,
+                                           &client->data.public_key)) {
              silc_free(pk.type);
              silc_free(pk.data);
              continue;
              silc_free(pk.type);
              silc_free(pk.data);
              continue;
@@ -370,12 +351,12 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
 
            SILC_LOG_DEBUG(("Saved client public key from attributes"));
 
 
            SILC_LOG_DEBUG(("Saved client public key from attributes"));
 
-           /* Add to public key hash table */
-           if (!silc_hash_table_find_by_context(server->pk_hash,
-                                                client->data.public_key,
-                                                client, NULL))
-             silc_hash_table_add(server->pk_hash,
-                                 client->data.public_key, client);
+           /* Add client's public key to repository */
+           if (!silc_server_get_public_key_by_client(server, client, NULL))
+             silc_skr_add_public_key_simple(server->repository,
+                                            client->data.public_key,
+                                            SILC_SKR_USAGE_IDENTIFICATION,
+                                            client, NULL);
 
            silc_free(pk.type);
            silc_free(pk.data);
 
            silc_free(pk.type);
            silc_free(pk.data);
@@ -398,7 +379,7 @@ silc_server_command_reply_whois_save_client(SilcServerCommandReplyContext cmd)
 {
   unsigned char *tmp;
   SilcUInt32 len;
 {
   unsigned char *tmp;
   SilcUInt32 len;
-  SilcClientEntry client = cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
 
   /* Take Requested Attributes if set. */
   tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
 
   /* Take Requested Attributes if set. */
   tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
@@ -422,11 +403,12 @@ silc_server_command_reply_whois_save_client(SilcServerCommandReplyContext cmd)
 SILC_SERVER_CMD_REPLY_FUNC(whois)
 {
   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
 SILC_SERVER_CMD_REPLY_FUNC(whois)
 {
   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+  SilcIDListData idata = silc_packet_get_context(cmd->sock);
   SilcStatus status, error;
 
   COMMAND_CHECK_STATUS;
 
   SilcStatus status, error;
 
   COMMAND_CHECK_STATUS;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) {
+  if (idata->conn_type != SILC_CONN_CLIENT) {
     if (!silc_server_command_reply_whois_save(cmd))
       goto out;
   } else {
     if (!silc_server_command_reply_whois_save(cmd))
       goto out;
   } else {
@@ -460,12 +442,16 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
   SilcServer server = cmd->server;
   SilcUInt32 len, id_len;
   unsigned char *id_data;
   SilcServer server = cmd->server;
   SilcUInt32 len, id_len;
   unsigned char *id_data;
-  char *nickname, *username, *realname, *servername = NULL, *tmp;
-  SilcClientID *client_id;
+  char *nickname, *username, *realname;
+  SilcID id;
   SilcClientEntry client;
   SilcIDCacheEntry cache = NULL;
   SilcClientEntry client;
   SilcIDCacheEntry cache = NULL;
-  char *nick = NULL;
+  char nick[128 + 1], servername[256 + 1], uname[128 + 1];
   int global = FALSE;
   int global = FALSE;
+  const char *hostname, *ip;
+
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock),
+                             NULL, &hostname, &ip, NULL);
 
   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
 
   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
@@ -475,17 +461,18 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
 
   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
 
 
   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
 
-  client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
-  if (!client_id)
+  if (!silc_id_payload_parse_id(id_data, id_len, &id))
     return FALSE;
 
   /* Check if we have this client cached already. */
 
     return FALSE;
 
   /* Check if we have this client cached already. */
 
-  client = silc_idlist_find_client_by_id(server->local_list, client_id,
+  client = silc_idlist_find_client_by_id(server->local_list,
+                                        SILC_ID_GET_ID(id),
                                         FALSE, &cache);
   if (!client) {
     client = silc_idlist_find_client_by_id(server->global_list,
                                         FALSE, &cache);
   if (!client) {
     client = silc_idlist_find_client_by_id(server->global_list,
-                                          client_id, FALSE, &cache);
+                                          SILC_ID_GET_ID(id),
+                                          FALSE, &cache);
     global = TRUE;
   }
 
     global = TRUE;
   }
 
@@ -496,72 +483,63 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
       return FALSE;
 
     /* Take hostname out of nick string if it includes it. */
       return FALSE;
 
     /* Take hostname out of nick string if it includes it. */
-    silc_parse_userfqdn(nickname, &nick, &servername);
+    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
+                       sizeof(servername));
 
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be
        global. */
 
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be
        global. */
-    client = silc_idlist_add_client(server->global_list, nick, username,
+    client = silc_idlist_add_client(server->global_list,
+                                   strdup(nick), username,
                                    strdup(realname),
                                    strdup(realname),
-                                   silc_id_dup(client_id, SILC_ID_CLIENT),
-                                   cmd->sock->user_data, NULL,
-                                   SILC_ID_CACHE_EXPIRE_DEF);
+                                   silc_id_dup(SILC_ID_GET_ID(id),
+                                               SILC_ID_CLIENT),
+                                   silc_packet_get_context(cmd->sock), NULL);
     if (!client) {
       SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
     if (!client) {
       SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
-      silc_free(nick);
-      silc_free(servername);
       return FALSE;
     }
 
     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
       return FALSE;
     }
 
     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
-    client->servername = servername;
+    client->servername = servername[0] ? strdup(servername) : NULL;
   } else {
     /* We have the client already, update the data */
 
     /* Check nickname */
   } else {
     /* We have the client already, update the data */
 
     /* Check nickname */
-    silc_parse_userfqdn(nickname, &nick, &servername);
+    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
+                       sizeof(servername));
     nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
                                     128, NULL);
     if (!nickname) {
       SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOWAS reply "
                      "from %s",
     nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
                                     128, NULL);
     if (!nickname) {
       SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOWAS reply "
                      "from %s",
-                     cmd->sock->hostname ? cmd->sock->hostname : "", nick));
-      silc_free(nick);
-      silc_free(servername);
+                     hostname ? hostname : "", nick));
       return FALSE;
     }
 
     /* Check username */
       return FALSE;
     }
 
     /* Check username */
-    silc_parse_userfqdn(username, &tmp, NULL);
-    if (!silc_identifier_verify(tmp, strlen(tmp), SILC_STRING_UTF8, 128)) {
-      silc_free(tmp);
-      silc_free(nick);
-      silc_free(servername);
-      SILC_LOG_ERROR(("Malformed username '%s' received in WHOWAS reply "
-                     "from %s",
-                     cmd->sock->hostname ? cmd->sock->hostname : "", tmp));
+    silc_parse_userfqdn(username, uname, sizeof(uname), NULL, 0);
+    if (!silc_identifier_verify(uname, strlen(uname), SILC_STRING_UTF8, 128))
       return FALSE;
       return FALSE;
-    }
-    silc_free(tmp);
 
     silc_free(client->nickname);
     silc_free(client->username);
     silc_free(client->servername);
 
 
     silc_free(client->nickname);
     silc_free(client->username);
     silc_free(client->servername);
 
-    client->nickname = nick;
+    client->nickname = strdup(nick);
     client->username = strdup(username);
     client->username = strdup(username);
-    client->servername = servername;
+    client->servername = servername[0] ? strdup(servername) : NULL;
     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
 
     /* Remove the old cache entry and create a new one */
     silc_idcache_del_by_context(global ? server->global_list->clients :
     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
 
     /* Remove the old cache entry and create a new one */
     silc_idcache_del_by_context(global ? server->global_list->clients :
-                               server->local_list->clients, client);
+                               server->local_list->clients, client, NULL);
     silc_idcache_add(global ? server->global_list->clients :
                     server->local_list->clients, nickname, client->id,
     silc_idcache_add(global ? server->global_list->clients :
                     server->local_list->clients, nickname, client->id,
-                    client, 0, NULL);
+                    client);
   }
 
   /* If client is global and is not on any channel then add that we'll
   }
 
   /* If client is global and is not on any channel then add that we'll
@@ -570,13 +548,9 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
     silc_idlist_find_client_by_id(server->global_list, client->id,
                                  FALSE, &cache);
     if (!silc_hash_table_count(client->channels))
     silc_idlist_find_client_by_id(server->global_list, client->id,
                                  FALSE, &cache);
     if (!silc_hash_table_count(client->channels))
-      cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
-    else
-      cache->expire = 0;
+      silc_dlist_add(server->expired_clients, client);
   }
 
   }
 
-  silc_free(client_id);
-
   return TRUE;
 }
 
   return TRUE;
 }
 
@@ -620,17 +594,16 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
   SilcUInt32 len, id_len;
   unsigned char *id_data;
   char *name, *info;
   SilcUInt32 len, id_len;
   unsigned char *id_data;
   char *name, *info;
-  SilcClientID *client_id = NULL;
-  SilcServerID *server_id = NULL;
-  SilcChannelID *channel_id = NULL;
+  SilcClientID client_id;
+  SilcServerID server_id;
+  SilcChannelID*channel_id;
   SilcClientEntry client;
   SilcServerEntry server_entry;
   SilcChannelEntry channel;
   char global = FALSE;
   SilcClientEntry client;
   SilcServerEntry server_entry;
   SilcChannelEntry channel;
   char global = FALSE;
-  char *nick = NULL;
+  char nick[128 + 1];
   SilcIDPayload idp = NULL;
   SilcIdType id_type;
   SilcIDPayload idp = NULL;
   SilcIdType id_type;
-  int expire = 0;
 
   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
   if (!id_data)
 
   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
   if (!id_data)
@@ -646,16 +619,15 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
   switch (id_type) {
   case SILC_ID_CLIENT:
 
   switch (id_type) {
   case SILC_ID_CLIENT:
-    client_id = silc_id_payload_get_id(idp);
-    if (!client_id)
+    if (!silc_id_payload_get_id(idp, &client_id, sizeof(client_id)))
       goto error;
 
     SILC_LOG_DEBUG(("Received client information"));
 
     client = silc_idlist_find_client_by_id(server->local_list,
       goto error;
 
     SILC_LOG_DEBUG(("Received client information"));
 
     client = silc_idlist_find_client_by_id(server->local_list,
-                                          client_id, FALSE, NULL);
+                                          &client_id, FALSE, NULL);
     if (!client) {
     if (!client) {
-      client = silc_idlist_find_client_by_id(server->global_list, client_id,
+      client = silc_idlist_find_client_by_id(server->global_list, &client_id,
                                             FALSE, NULL);
       global = TRUE;
     }
                                             FALSE, NULL);
       global = TRUE;
     }
@@ -667,17 +639,18 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
       /* Take nickname */
       if (name)
 
       /* Take nickname */
       if (name)
-       silc_parse_userfqdn(name, &nick, NULL);
+       silc_parse_userfqdn(name, nick, sizeof(nick), NULL, 0);
 
       /* We don't have that client anywhere, add it. The client is added
         to global list since server didn't have it in the lists so it must be
         global. */
 
       /* We don't have that client anywhere, add it. The client is added
         to global list since server didn't have it in the lists so it must be
         global. */
-      client = silc_idlist_add_client(server->global_list, nick, info, NULL,
-                                     client_id, cmd->sock->user_data,
-                                     NULL, time(NULL) + 300);
+      client = silc_idlist_add_client(server->global_list,
+                                     nick[0] ? nick : NULL, info, NULL,
+                                     silc_id_dup(&client_id, SILC_ID_CLIENT),
+                                     silc_packet_get_context(cmd->sock),
+                                     NULL);
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
-       silc_free(nick);
        goto error;
       }
 
        goto error;
       }
 
@@ -691,30 +664,28 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
       /* Take nickname */
       if (name) {
 
       /* Take nickname */
       if (name) {
-       silc_parse_userfqdn(name, &nick, NULL);
+       silc_parse_userfqdn(name, nick, sizeof(nick), NULL, 0);
 
        /* Check nickname */
        name = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
                                     128, NULL);
        if (!name) {
 
        /* Check nickname */
        name = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
                                     128, NULL);
        if (!name) {
-         SILC_LOG_ERROR(("Malformed nickname '%s' received in IDENTIFY reply "
-                         "from %s",
-                         cmd->sock->hostname ?
-                         cmd->sock->hostname : "", nick));
+         SILC_LOG_ERROR(("Malformed nickname '%s' received in IDENTIFY "
+                         "reply ", nick));
          return FALSE;
        }
 
        /* Remove the old cache entry */
        silc_idcache_del_by_context(global ? server->global_list->clients :
          return FALSE;
        }
 
        /* Remove the old cache entry */
        silc_idcache_del_by_context(global ? server->global_list->clients :
-                                   server->local_list->clients, client);
+                                   server->local_list->clients, client, NULL);
 
        silc_free(client->nickname);
 
        silc_free(client->nickname);
-       client->nickname = nick;
+       client->nickname = strdup(nick);
 
        /* Add new cache entry */
        silc_idcache_add(global ? server->global_list->clients :
                         server->local_list->clients, name, client->id,
 
        /* Add new cache entry */
        silc_idcache_add(global ? server->global_list->clients :
                         server->local_list->clients, name, client->id,
-                        client, expire, NULL);
+                        client);
       }
 
       if (info) {
       }
 
       if (info) {
@@ -724,20 +695,6 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
       client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
 
       client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
-
-      /* If client is global and is not on any channel then add that we'll
-         expire the entry after a while. */
-      if (global && server->server_type == SILC_SERVER) {
-       SilcIDCacheEntry cache = NULL;
-        silc_idlist_find_client_by_id(server->global_list, client->id,
-                                     FALSE, &cache);
-        if (!silc_hash_table_count(client->channels))
-         cache->expire = time(NULL) + 300;
-        else
-         cache->expire = 0;
-      }
-
-      silc_free(client_id);
     }
 
     break;
     }
 
     break;
@@ -746,17 +703,16 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
     if (!name)
       goto error;
 
     if (!name)
       goto error;
 
-    server_id = silc_id_payload_get_id(idp);
-    if (!server_id)
+    if (!silc_id_payload_get_id(idp, &server_id, sizeof(server_id)))
       goto error;
 
     SILC_LOG_DEBUG(("Received server information"));
 
     server_entry = silc_idlist_find_server_by_id(server->local_list,
       goto error;
 
     SILC_LOG_DEBUG(("Received server information"));
 
     server_entry = silc_idlist_find_server_by_id(server->local_list,
-                                                server_id, FALSE, NULL);
+                                                &server_id, FALSE, NULL);
     if (!server_entry)
       server_entry = silc_idlist_find_server_by_id(server->global_list,
     if (!server_entry)
       server_entry = silc_idlist_find_server_by_id(server->global_list,
-                                                  server_id, FALSE, NULL);
+                                                  &server_id, FALSE, NULL);
     if (!server_entry) {
       /* If router did not find such Server ID in its lists then this must
         be bogus server or some router in the net is buggy. */
     if (!server_entry) {
       /* If router did not find such Server ID in its lists then this must
         be bogus server or some router in the net is buggy. */
@@ -766,27 +722,25 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
       /* We don't have that server anywhere, add it. */
       server_entry = silc_idlist_add_server(server->global_list,
                                            strdup(name), 0,
       /* We don't have that server anywhere, add it. */
       server_entry = silc_idlist_add_server(server->global_list,
                                            strdup(name), 0,
-                                           server_id, server->router,
+                                           silc_id_dup(&server_id,
+                                                       SILC_ID_SERVER),
+                                           server->router,
                                            SILC_PRIMARY_ROUTE(server));
                                            SILC_PRIMARY_ROUTE(server));
-      if (!server_entry) {
-       silc_free(server_id);
+      if (!server_entry)
        goto error;
        goto error;
-      }
+
       server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
       server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
       server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
       server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
       server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
       server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
-      server_id = NULL;
     }
 
     }
 
-    silc_free(server_id);
     break;
 
   case SILC_ID_CHANNEL:
     if (!name)
       goto error;
 
     break;
 
   case SILC_ID_CHANNEL:
     if (!name)
       goto error;
 
-    channel_id = silc_id_payload_get_id(idp);
-    if (!channel_id)
+    if (!silc_id_payload_get_id(idp, &channel_id, sizeof(channel_id)))
       goto error;
 
     SILC_LOG_DEBUG(("Received channel information"));
       goto error;
 
     SILC_LOG_DEBUG(("Received channel information"));
@@ -812,18 +766,17 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
       /* We don't have that channel anywhere, add it. */
       channel = silc_idlist_add_channel(server->global_list, strdup(name),
 
       /* We don't have that channel anywhere, add it. */
       channel = silc_idlist_add_channel(server->global_list, strdup(name),
-                                       SILC_CHANNEL_MODE_NONE, channel_id,
+                                       SILC_CHANNEL_MODE_NONE,
+                                       silc_id_dup(&channel_id,
+                                                   SILC_ID_CHANNEL),
                                        server->router, NULL, NULL, 0);
       if (!channel) {
                                        server->router, NULL, NULL, 0);
       if (!channel) {
-       silc_free(channel_id);
        silc_free(info);
        goto error;
       }
       silc_free(info);
        silc_free(info);
        goto error;
       }
       silc_free(info);
-      channel_id = NULL;
     }
 
     }
 
-    silc_free(channel_id);
     break;
   }
 
     break;
   }
 
@@ -876,18 +829,14 @@ SILC_SERVER_CMD_REPLY_FUNC(info)
   SilcServer server = cmd->server;
   SilcStatus status, error;
   SilcServerEntry entry;
   SilcServer server = cmd->server;
   SilcStatus status, error;
   SilcServerEntry entry;
-  SilcServerID *server_id;
+  SilcID id;
   SilcUInt32 tmp_len;
   unsigned char *tmp, *name;
 
   COMMAND_CHECK_STATUS;
 
   /* Get Server ID */
   SilcUInt32 tmp_len;
   unsigned char *tmp, *name;
 
   COMMAND_CHECK_STATUS;
 
   /* Get Server ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (!tmp)
-    goto out;
-  server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!server_id)
+  if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
 
   /* Get the name */
     goto out;
 
   /* Get the name */
@@ -895,21 +844,23 @@ SILC_SERVER_CMD_REPLY_FUNC(info)
   if (!name)
     goto out;
 
   if (!name)
     goto out;
 
-  entry = silc_idlist_find_server_by_id(server->local_list, server_id,
+  entry = silc_idlist_find_server_by_id(server->local_list,
+                                       SILC_ID_GET_ID(id),
                                        FALSE, NULL);
   if (!entry) {
                                        FALSE, NULL);
   if (!entry) {
-    entry = silc_idlist_find_server_by_id(server->global_list, server_id,
+    entry = silc_idlist_find_server_by_id(server->global_list,
+                                         SILC_ID_GET_ID(id),
                                          FALSE, NULL);
     if (!entry) {
       /* Add the server to global list */
                                          FALSE, NULL);
     if (!entry) {
       /* Add the server to global list */
-      server_id = silc_id_dup(server_id, SILC_ID_SERVER);
       entry = silc_idlist_add_server(server->global_list, strdup(name), 0,
       entry = silc_idlist_add_server(server->global_list, strdup(name), 0,
-                                    server_id, cmd->sock->user_data,
+                                    silc_id_dup(SILC_ID_GET_ID(id),
+                                                SILC_ID_SERVER),
+                                    silc_packet_get_context(cmd->sock),
                                     cmd->sock);
                                     cmd->sock);
-      if (!entry) {
-       silc_free(server_id);
+      if (!entry)
        goto out;
        goto out;
-      }
+
       entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     }
   }
       entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     }
   }
@@ -935,24 +886,22 @@ SILC_SERVER_CMD_REPLY_FUNC(motd)
   SilcServer server = cmd->server;
   SilcStatus status, error;
   SilcServerEntry entry = NULL;
   SilcServer server = cmd->server;
   SilcStatus status, error;
   SilcServerEntry entry = NULL;
-  SilcServerID *server_id;
+  SilcID id;
   SilcUInt32 tmp_len;
   unsigned char *tmp;
 
   COMMAND_CHECK_STATUS;
 
   /* Get Server ID */
   SilcUInt32 tmp_len;
   unsigned char *tmp;
 
   COMMAND_CHECK_STATUS;
 
   /* Get Server ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (!tmp)
-    goto out;
-  server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!server_id)
+  if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
 
     goto out;
 
-  entry = silc_idlist_find_server_by_id(server->local_list, server_id,
+  entry = silc_idlist_find_server_by_id(server->local_list,
+                                       SILC_ID_GET_ID(id),
                                        TRUE, NULL);
   if (!entry) {
                                        TRUE, NULL);
   if (!entry) {
-    entry = silc_idlist_find_server_by_id(server->global_list, server_id,
+    entry = silc_idlist_find_server_by_id(server->global_list,
+                                         SILC_ID_GET_ID(id),
                                          TRUE, NULL);
     if (!entry) {
       SilcBuffer buffer;
                                          TRUE, NULL);
     if (!entry) {
       SilcBuffer buffer;
@@ -968,6 +917,7 @@ SILC_SERVER_CMD_REPLY_FUNC(motd)
       /* entry isn't known so we IDENTIFY it. otherwise the
          silc_server_command_motd won't know about it and tell
          the client that there is no such server */
       /* entry isn't known so we IDENTIFY it. otherwise the
          silc_server_command_motd won't know about it and tell
          the client that there is no such server */
+      tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
       buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
                                              ++server->cmd_ident, 5,
                                              1, NULL, 0, 2, NULL, 0,
       buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
                                              ++server->cmd_ident, 5,
                                              1, NULL, 0, 2, NULL, 0,
@@ -975,7 +925,7 @@ SILC_SERVER_CMD_REPLY_FUNC(motd)
                                              5, tmp, tmp_len);
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, 0, buffer->data,
                                              5, tmp, tmp_len);
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, 0, buffer->data,
-                             buffer->len, TRUE);
+                             silc_buffer_len(buffer));
       silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
                                  server->cmd_ident,
                                  silc_server_command_reply_motd,
       silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
                                  server->cmd_ident,
                                  silc_server_command_reply_motd,
@@ -1011,12 +961,10 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   SilcServer server = cmd->server;
   SilcIDCacheEntry cache = NULL;
   SilcStatus status, error;
   SilcServer server = cmd->server;
   SilcIDCacheEntry cache = NULL;
   SilcStatus status, error;
-  SilcChannelID *id;
-  SilcClientID *client_id = NULL;
+  SilcID id, id2;
   SilcChannelEntry entry;
   SilcHmac hmac = NULL;
   SilcChannelEntry entry;
   SilcHmac hmac = NULL;
-  SilcUInt32 id_len, len, list_count;
-  unsigned char *id_string;
+  SilcUInt32 len, list_count;
   char *channel_name, *channel_namec = NULL, *tmp;
   SilcUInt32 mode, created;
   SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
   char *channel_name, *channel_namec = NULL, *tmp;
   SilcUInt32 mode, created;
   SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
@@ -1030,16 +978,11 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
     goto out;
 
   /* Get channel ID */
     goto out;
 
   /* Get channel ID */
-  id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
-  if (!id_string)
+  if (!silc_argument_get_decoded(cmd->args, 3, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
 
   /* Get client ID */
     goto out;
 
   /* Get client ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
-  if (!tmp)
-    goto out;
-  client_id = silc_id_payload_parse_id(tmp, len, NULL);
-  if (!client_id)
+  if (!silc_argument_get_decoded(cmd->args, 4, SILC_ARGUMENT_ID, &id2, NULL))
     goto out;
 
   /* Get mode mask */
     goto out;
 
   /* Get mode mask */
@@ -1060,15 +1003,10 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
   if (tmp) {
     keyp = silc_buffer_alloc(len);
   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
   if (tmp) {
     keyp = silc_buffer_alloc(len);
-    silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
+    silc_buffer_pull_tail(keyp, silc_buffer_truelen(keyp));
     silc_buffer_put(keyp, tmp, len);
   }
 
     silc_buffer_put(keyp, tmp, len);
   }
 
-  /* Parse the Channel ID */
-  id = silc_id_payload_parse_id(id_string, id_len, NULL);
-  if (!id)
-    goto out;
-
   /* Get hmac */
   tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
   if (tmp) {
   /* Get hmac */
   tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
   if (tmp) {
@@ -1103,7 +1041,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   /* Get founder key */
   tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
   if (tmp)
   /* Get founder key */
   tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
   if (tmp)
-    silc_pkcs_public_key_payload_decode(tmp, len, &founder_key);
+    silc_public_key_payload_decode(tmp, len, &founder_key);
 
   /* See whether we already have the channel. */
   channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
 
   /* See whether we already have the channel. */
   channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
@@ -1117,7 +1055,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
 
     SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
                    (created == 0 ? "existing" : "created"), channel_name,
 
     SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
                    (created == 0 ? "existing" : "created"), channel_name,
-                   silc_id_render(id, SILC_ID_CHANNEL)));
+                   silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL)));
 
     /* If the channel is found from global list we must move it to the
        local list. */
 
     /* If the channel is found from global list we must move it to the
        local list. */
@@ -1128,12 +1066,13 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
 
     /* Add the channel to our local list. */
     entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
 
     /* Add the channel to our local list. */
     entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
-                                   SILC_CHANNEL_MODE_NONE, id,
-                                   server->router, NULL, hmac, 0);
-    if (!entry) {
-      silc_free(id);
+                                   SILC_CHANNEL_MODE_NONE,
+                                   silc_id_dup(SILC_ID_GET_ID(id),
+                                               SILC_ID_CHANNEL),
+                                   server->router, NULL, NULL, hmac);
+    if (!entry)
       goto out;
       goto out;
-    }
+
     hmac = NULL;
     server->stat.my_channels++;
     server->stat.channels++;
     hmac = NULL;
     server->stat.my_channels++;
     server->stat.channels++;
@@ -1141,8 +1080,9 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
     /* The entry exists. */
 
     /* If ID has changed, then update it to the cache too. */
     /* The entry exists. */
 
     /* If ID has changed, then update it to the cache too. */
-    if (!SILC_ID_CHANNEL_COMPARE(entry->id, id))
-      silc_idlist_replace_channel_id(server->local_list, entry->id, id);
+    if (!SILC_ID_CHANNEL_COMPARE(entry->id, SILC_ID_GET_ID(id)))
+      silc_idlist_replace_channel_id(server->local_list, entry->id,
+                                    SILC_ID_GET_ID(id));
 
     entry->disabled = FALSE;
 
 
     entry->disabled = FALSE;
 
@@ -1219,7 +1159,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
 
   /* Get channel public key list */
   tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
 
   /* Get channel public key list */
   tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
-  if (tmp && server->server_type == SILC_SERVER)
+  if (tmp && server->server_type != SILC_ROUTER)
     silc_server_set_channel_pk_list(server, NULL, entry, tmp, len);
 
   /* The the user limit */
     silc_server_set_channel_pk_list(server, NULL, entry, tmp, len);
 
   /* The the user limit */
@@ -1232,11 +1172,8 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   entry->global_users = (created == 0 ? TRUE : FALSE);
 
   /* If channel was just created the mask must be zero */
   entry->global_users = (created == 0 ? TRUE : FALSE);
 
   /* If channel was just created the mask must be zero */
-  if (!entry->global_users && mode) {
-    SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
-                   "new channel, forcing it to zero", cmd->sock->hostname));
+  if (!entry->global_users && mode)
     mode = 0;
     mode = 0;
-  }
 
   /* Save channel mode */
   entry->mode = mode;
 
   /* Save channel mode */
   entry->mode = mode;
@@ -1250,7 +1187,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
 
   /* Save the users to the channel */
   silc_server_save_users_on_channel(server, cmd->sock, entry,
 
   /* Save the users to the channel */
   silc_server_save_users_on_channel(server, cmd->sock, entry,
-                                   client_id, client_id_list,
+                                   SILC_ID_GET_ID(id2), client_id_list,
                                    client_mode_list, list_count);
   entry->users_resolved = TRUE;
 
                                    client_mode_list, list_count);
   entry->users_resolved = TRUE;
 
@@ -1260,10 +1197,10 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   silc_free(channel_namec);
   if (hmac)
     silc_hmac_free(hmac);
   silc_free(channel_namec);
   if (hmac)
     silc_hmac_free(hmac);
-  silc_free(client_id);
   silc_server_command_reply_free(cmd);
 
   silc_server_command_reply_free(cmd);
 
-  silc_pkcs_public_key_free(founder_key);
+  if (founder_key)
+    silc_pkcs_public_key_free(founder_key);
   if (client_id_list)
     silc_buffer_free(client_id_list);
   if (client_mode_list)
   if (client_id_list)
     silc_buffer_free(client_id_list);
   if (client_mode_list)
@@ -1318,7 +1255,7 @@ SILC_SERVER_CMD_REPLY_FUNC(users)
   SilcServer server = cmd->server;
   SilcStatus status, error;
   SilcChannelEntry channel;
   SilcServer server = cmd->server;
   SilcStatus status, error;
   SilcChannelEntry channel;
-  SilcChannelID *channel_id = NULL;
+  SilcID id;
   SilcBuffer client_id_list;
   SilcBuffer client_mode_list;
   unsigned char *tmp;
   SilcBuffer client_id_list;
   SilcBuffer client_mode_list;
   unsigned char *tmp;
@@ -1328,29 +1265,25 @@ SILC_SERVER_CMD_REPLY_FUNC(users)
   COMMAND_CHECK_STATUS;
 
   /* Get channel ID */
   COMMAND_CHECK_STATUS;
 
   /* Get channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (!tmp)
-    goto out;
-  channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!channel_id)
+  if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
 
   /* Get channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list,
     goto out;
 
   /* Get channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list,
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
       SilcBuffer idp;
 
       if (server->server_type != SILC_SERVER)
        goto out;
 
     if (!channel) {
       SilcBuffer idp;
 
       if (server->server_type != SILC_SERVER)
        goto out;
 
-      idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+      idp = silc_id_payload_encode(SILC_ID_GET_ID(id), SILC_ID_CHANNEL);
       silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
                               SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
       silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
                               SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
-                              1, 5, idp->data, idp->len);
+                              1, 5, idp->data, silc_buffer_len(idp));
       silc_buffer_free(idp);
 
       /* Register pending command callback. After we've received the channel
       silc_buffer_free(idp);
 
       /* Register pending command callback. After we've received the channel
@@ -1400,7 +1333,6 @@ SILC_SERVER_CMD_REPLY_FUNC(users)
 
  out:
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
 
  out:
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
-  silc_free(channel_id);
  err:
   silc_server_command_reply_free(cmd);
 }
  err:
   silc_server_command_reply_free(cmd);
 }
@@ -1412,8 +1344,8 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey)
   SilcStatus status, error;
   SilcClientEntry client = NULL;
   SilcServerEntry server_entry = NULL;
   SilcStatus status, error;
   SilcClientEntry client = NULL;
   SilcServerEntry server_entry = NULL;
-  SilcClientID *client_id = NULL;
-  SilcServerID *server_id = NULL;
+  SilcClientID client_id;
+  SilcServerID server_id;
   unsigned char *tmp;
   SilcUInt32 len;
   SilcIDPayload idp = NULL;
   unsigned char *tmp;
   SilcUInt32 len;
   SilcIDPayload idp = NULL;
@@ -1435,38 +1367,40 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey)
     goto out;
 
   /* Decode the public key payload */
     goto out;
 
   /* Decode the public key payload */
-  if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
+  if (!silc_public_key_payload_decode(tmp, len, &public_key))
     goto out;
 
   id_type = silc_id_payload_get_type(idp);
   if (id_type == SILC_ID_CLIENT) {
     goto out;
 
   id_type = silc_id_payload_get_type(idp);
   if (id_type == SILC_ID_CLIENT) {
-    client_id = silc_id_payload_get_id(idp);
+    silc_id_payload_get_id(idp, &client_id, sizeof(client_id));
 
 
-    client = silc_idlist_find_client_by_id(server->local_list, client_id,
+    client = silc_idlist_find_client_by_id(server->local_list, &client_id,
                                           TRUE, NULL);
     if (!client) {
       client = silc_idlist_find_client_by_id(server->global_list,
                                           TRUE, NULL);
     if (!client) {
       client = silc_idlist_find_client_by_id(server->global_list,
-                                            client_id, TRUE, NULL);
+                                            &client_id, TRUE, NULL);
       if (!client)
        goto out;
     }
 
     if (!client->data.public_key) {
       if (!client)
        goto out;
     }
 
     if (!client->data.public_key) {
-      if (!silc_hash_table_find_by_context(server->pk_hash, public_key,
-                                          client, NULL))
-       silc_hash_table_add(server->pk_hash, public_key, client);
-
+      /* Add client's public key to repository */
+      if (!silc_server_get_public_key_by_client(server, client, NULL))
+       silc_skr_add_public_key_simple(server->repository,
+                                      public_key,
+                                      SILC_SKR_USAGE_IDENTIFICATION,
+                                      client, NULL);
       client->data.public_key = public_key;
       public_key = NULL;
     }
   } else if (id_type == SILC_ID_SERVER) {
       client->data.public_key = public_key;
       public_key = NULL;
     }
   } else if (id_type == SILC_ID_SERVER) {
-    server_id = silc_id_payload_get_id(idp);
+    silc_id_payload_get_id(idp, &server_id, sizeof(server_id));
 
 
-    server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
-                                                TRUE, NULL);
+    server_entry = silc_idlist_find_server_by_id(server->local_list,
+                                                &server_id, TRUE, NULL);
     if (!server_entry) {
       server_entry = silc_idlist_find_server_by_id(server->global_list,
     if (!server_entry) {
       server_entry = silc_idlist_find_server_by_id(server->global_list,
-                                                  server_id, TRUE, NULL);
+                                                  &server_id, TRUE, NULL);
       if (!server_entry)
        goto out;
     }
       if (!server_entry)
        goto out;
     }
@@ -1481,8 +1415,6 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey)
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
   if (idp)
     silc_id_payload_free(idp);
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
   if (idp)
     silc_id_payload_free(idp);
-  silc_free(client_id);
-  silc_free(server_id);
   if (public_key)
     silc_pkcs_public_key_free(public_key);
  err:
   if (public_key)
     silc_pkcs_public_key_free(public_key);
  err:
@@ -1494,21 +1426,16 @@ SILC_SERVER_CMD_REPLY_FUNC(list)
   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
   SilcServer server = cmd->server;
   SilcStatus status, error;
   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
   SilcServer server = cmd->server;
   SilcStatus status, error;
-  SilcChannelID *channel_id = NULL;
+  SilcID id;
   SilcChannelEntry channel;
   SilcIDCacheEntry cache;
   SilcChannelEntry channel;
   SilcIDCacheEntry cache;
-  SilcUInt32 len;
   unsigned char *tmp, *name, *namec = NULL, *topic;
   SilcUInt32 usercount = 0;
   unsigned char *tmp, *name, *namec = NULL, *topic;
   SilcUInt32 usercount = 0;
-  bool global_list = FALSE;
+  SilcBool global_list = FALSE;
 
   COMMAND_CHECK_STATUS;
 
 
   COMMAND_CHECK_STATUS;
 
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
-  if (!tmp)
-    goto out;
-  channel_id = silc_id_payload_parse_id(tmp, len, NULL);
-  if (!channel_id)
+  if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
 
   name = silc_argument_get_arg_type(cmd->args, 3, NULL);
     goto out;
 
   name = silc_argument_get_arg_type(cmd->args, 3, NULL);
@@ -1537,16 +1464,12 @@ SILC_SERVER_CMD_REPLY_FUNC(list)
       goto out;
 
     channel = silc_idlist_add_channel(server->global_list, strdup(name),
       goto out;
 
     channel = silc_idlist_add_channel(server->global_list, strdup(name),
-                                     SILC_CHANNEL_MODE_NONE, channel_id,
-                                     server->router, NULL, NULL,
-                                     time(NULL) + 60);
+                                     SILC_CHANNEL_MODE_NONE,
+                                     silc_id_dup(SILC_ID_GET_ID(id),
+                                                 SILC_ID_CHANNEL),
+                                     server->router, NULL, NULL, NULL);
     if (!channel)
       goto out;
     if (!channel)
       goto out;
-    channel_id = NULL;
-  } else {
-    /* Found, update expiry */
-    if (global_list && server->server_type == SILC_SERVER)
-      cache->expire = time(NULL) + 60;
   }
 
   channel->user_count = usercount;
   }
 
   channel->user_count = usercount;
@@ -1563,13 +1486,8 @@ SILC_SERVER_CMD_REPLY_FUNC(list)
     return;
   }
 
     return;
   }
 
-  /* Now purge all old entries from the global list, otherwise we'll might
-     have non-existent entries for long periods of time in the cache. */
-  silc_idcache_purge(server->global_list->channels);
-
  out:
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
  out:
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
-  silc_free(channel_id);
  err:
   silc_free(namec);
   silc_server_command_reply_free(cmd);
  err:
   silc_free(namec);
   silc_server_command_reply_free(cmd);