Merged silc_1_1_branch to trunk.
[silc.git] / apps / irssi / src / silc / core / client_ops.c
index 44c7b0a32b2c8e6cff34cbeb2c18ff35263f41cc..38e90d0844553855d9cc38cc2497756754e37975 100644 (file)
@@ -2,9 +2,9 @@
 
   client_ops.c
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2005 Pekka Riikonen
+  Copyright (C) 2001 - 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
@@ -46,9 +46,8 @@
 
 static void
 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
-                               const char *name, SilcSocketType conn_type,
-                               unsigned char *pk, SilcUInt32 pk_len,
-                               SilcSKEPKType pk_type,
+                               const char *name, SilcConnectionType conn_type,
+                               SilcPublicKey public_key,
                                SilcVerifyPublicKey completion, void *context);
 
 char *silc_get_session_filename(SILC_SERVER_REC *server)
@@ -164,49 +163,48 @@ silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
 
 static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
                                           SilcChannelEntry channel_entry,
-                                          SilcBuffer channel_pubkeys)
+                                          SilcDList channel_pubkeys)
 {
-  SilcUInt16 argc;
-  SilcArgumentPayload chpks;
-  unsigned char *pk;
+  SilcArgumentDecodedList e;
+  SilcPublicKey pubkey;
+  SilcSILCPublicKey silc_pubkey;
   SilcUInt32 pk_len, type;
-  int c = 1;
+  unsigned char *pk;
   char *fingerprint, *babbleprint;
-  SilcPublicKey pubkey;
-  SilcPublicKeyIdentifier ident;
+  int c = 1;
 
   printformat_module("fe-common/silc", server, NULL,
                     MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
                     channel_entry->channel_name);
 
-  SILC_GET16_MSB(argc, channel_pubkeys->data);
-  chpks = silc_argument_payload_parse(channel_pubkeys->data + 2,
-                                     channel_pubkeys->len - 2, argc);
-  if (!chpks)
-    return;
+  silc_dlist_start(channel_pubkeys);
+  while ((e = silc_dlist_get(channel_pubkeys))) {
+    pubkey = e->argument;
+    type = e->arg_type;
+
+    if (silc_pkcs_get_type(pubkey) != SILC_PKCS_SILC)
+      continue;
+
+    pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
+    if (!pk)
+      continue;
 
-  pk = silc_argument_get_first_arg(chpks, &type, &pk_len);
-  while (pk) {
-    fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4);
-    babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4);
-    silc_pkcs_public_key_payload_decode(pk, pk_len, &pubkey);
-    ident = silc_pkcs_decode_identifier(pubkey->identifier);
+    fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+    babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
+    silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, pubkey);
 
     printformat_module("fe-common/silc", server, NULL,
                       MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
                       c++, channel_entry->channel_name,
                       type == 0x00 ? "Added" : "Removed",
-                      ident->realname ? ident->realname : "",
+                      silc_pubkey->identifier.realname ?
+                      silc_pubkey->identifier.realname : "",
                       fingerprint, babbleprint);
 
     silc_free(fingerprint);
     silc_free(babbleprint);
-    silc_pkcs_public_key_free(pubkey);
-    silc_pkcs_free_identifier(ident);
-    pk = silc_argument_get_next_arg(chpks, &type, &pk_len);
+    silc_free(pk);
   }
-
-  silc_argument_payload_free(chpks);
 }
 
 void silc_say(SilcClient client, SilcClientConnection conn,
@@ -238,32 +236,29 @@ void silc_say_error(char *msg, ...)
   va_end(va);
 }
 
-/* try to verify a message using locally stored public key data */
+/* Try to verify a message using locally stored public key data */
+
 int verify_message_signature(SilcClientEntry sender,
-                            SilcMessageSignedPayload sig,
                             SilcMessagePayload message)
 {
   SilcPublicKey pk;
   char file[256], filename[256];
   char *fingerprint, *fingerprint2;
-  unsigned char *pk_data;
+  const unsigned char *pk_data;
   SilcUInt32 pk_datalen;
   struct stat st;
   int ret = SILC_MSG_SIGNED_VERIFIED, i;
 
-  if (sig == NULL)
-    return SILC_MSG_SIGNED_UNKNOWN;
-
   /* get public key from the signature payload and compare it with the
      one stored in the client entry */
-  pk = silc_message_signed_get_public_key(sig, &pk_data, &pk_datalen);
+  pk = silc_message_signed_get_public_key(message, &pk_data, &pk_datalen);
 
   if (pk != NULL) {
     fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
 
-    if (sender->fingerprint) {
+    if (sender->fingerprint[0]) {
       fingerprint2 = silc_fingerprint(sender->fingerprint,
-                                     sender->fingerprint_len);
+                                     sizeof(sender->fingerprint));
       if (strcmp(fingerprint, fingerprint2)) {
         /* since the public key differs from the senders public key, the
            verification _failed_ */
@@ -273,9 +268,9 @@ int verify_message_signature(SilcClientEntry sender,
       }
       silc_free(fingerprint2);
     }
-  } else if (sender->fingerprint)
+  } else if (sender->fingerprint[0])
     fingerprint = silc_fingerprint(sender->fingerprint,
-                                  sender->fingerprint_len);
+                                  sizeof(sender->fingerprint));
   else
     /* no idea, who or what signed that message ... */
     return SILC_MSG_SIGNED_UNKNOWN;
@@ -297,9 +292,7 @@ int verify_message_signature(SilcClientEntry sender,
     SilcPublicKey cached_pk=NULL;
 
     /* try to load the file */
-    if (!silc_pkcs_load_public_key(filename, &cached_pk, SILC_PKCS_FILE_PEM) &&
-       !silc_pkcs_load_public_key(filename, &cached_pk,
-                                  SILC_PKCS_FILE_BIN)) {
+    if (!silc_pkcs_load_public_key(filename, &cached_pk)) {
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
       if (pk == NULL)
@@ -316,8 +309,8 @@ int verify_message_signature(SilcClientEntry sender,
   }
 
   /* the public key is now in pk, our "level of trust" in ret */
-  if ((pk) && silc_message_signed_verify(sig, message, pk,
-                                        silc_client->sha1hash)!= SILC_AUTH_OK)
+  if ((pk) && silc_message_signed_verify(message, pk,
+                                        sha1hash) != SILC_AUTH_OK)
     ret = SILC_MSG_SIGNED_FAILED;
 
   if (pk)
@@ -326,74 +319,74 @@ int verify_message_signature(SilcClientEntry sender,
   return ret;
 }
 
-char * silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
+char *silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
 {
-    char *data, *ptr;
-    int i = 0, j = 0, len = strlen(escaped_data);
-
-    data = silc_calloc(len, sizeof(char));
-
-    while (i < len) {
-        ptr = memchr(escaped_data + i, 1, len - i);
-        if (ptr) {
-            int inc = (ptr - escaped_data) - i;
-            memcpy(data + j, escaped_data + i, inc);
-            j += inc;
-            i += inc + 2;
-            data[j++] = *(ptr + 1) - 1;
-        } else {
-            memcpy(data + j, escaped_data + i, len - i);
-            j += (len - i);
-            break;
-        }
+  char *data, *ptr;
+  int i = 0, j = 0, len = strlen(escaped_data);
+
+  data = silc_calloc(len, sizeof(char));
+
+  while (i < len) {
+    ptr = memchr(escaped_data + i, 1, len - i);
+    if (ptr) {
+      int inc = (ptr - escaped_data) - i;
+      memcpy(data + j, escaped_data + i, inc);
+      j += inc;
+      i += inc + 2;
+      data[j++] = *(ptr + 1) - 1;
+    } else {
+      memcpy(data + j, escaped_data + i, len - i);
+      j += (len - i);
+      break;
     }
+  }
 
-    *length = j;
-    return data;
+  *length = j;
+  return data;
 }
 
-char * silc_escape_data(const char *data, SilcUInt32 len)
+char *silc_escape_data(const char *data, SilcUInt32 len)
 {
-    char *escaped_data, *ptr, *ptr0, *ptr1;
-    int i = 0, j = 0;
-
-    escaped_data = silc_calloc(2 * len, sizeof(char));
-
-    while (i < len) {
-        ptr0 = memchr(data + i, 0, len - i);
-        ptr1 = memchr(data + i, 1, len - i);
-
-        ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
-
-        if (ptr) {
-            int inc = (ptr - data) - i;
-            if (inc)
-                memcpy(escaped_data + j, data + i, inc);
-            j += inc;
-            i += inc;
-            escaped_data[j++] = 1;
-            escaped_data[j++] = *(data + i++) + 1;
-        } else {
-            memcpy(escaped_data + j, data + i, len - i);
-            j += (len - i);
-            break;
-        }
+  char *escaped_data, *ptr, *ptr0, *ptr1;
+  int i = 0, j = 0;
+
+  escaped_data = silc_calloc(2 * len, sizeof(char));
+
+  while (i < len) {
+    ptr0 = memchr(data + i, 0, len - i);
+    ptr1 = memchr(data + i, 1, len - i);
+
+    ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
+
+    if (ptr) {
+      int inc = (ptr - data) - i;
+      if (inc)
+       memcpy(escaped_data + j, data + i, inc);
+      j += inc;
+      i += inc;
+      escaped_data[j++] = 1;
+      escaped_data[j++] = *(data + i++) + 1;
+    } else {
+      memcpy(escaped_data + j, data + i, len - i);
+      j += (len - i);
+      break;
     }
+  }
 
-    return escaped_data;
+  return escaped_data;
 }
 
 void silc_emit_mime_sig(SILC_SERVER_REC *server, WI_ITEM_REC *item,
-               const char *data, SilcUInt32 data_len, const char *nick,
-              int verified)
+                       const char *data, SilcUInt32 data_len,
+                       const char *nick, int verified)
 {
-   char *escaped_data;
+  char *escaped_data;
 
-   escaped_data = silc_escape_data(data, data_len);
+  escaped_data = silc_escape_data(data, data_len);
 
-   signal_emit("mime", 5, server, item, escaped_data, nick, verified);
+  signal_emit("mime", 5, server, item, escaped_data, nick, verified);
 
-   silc_free(escaped_data);
+  silc_free(escaped_data);
 }
 
 
@@ -428,13 +421,14 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
     SilcChannelUser chu = silc_client_on_channel(channel, sender);
     if (chu)
       nick = silc_nicklist_insert(chanrec, chu, FALSE);
+    if (!nick)
+      return;
   }
 
   /* If the messages is digitally signed, verify it, if possible. */
   if (flags & SILC_MESSAGE_FLAG_SIGNED) {
     if (!settings_get_bool("ignore_message_signatures")) {
-      SilcMessageSignedPayload sig = silc_message_get_signature(payload);
-      verified = verify_message_signature(sender, sig, payload);
+      verified = verify_message_signature(sender, payload);
     } else {
       flags &= ~SILC_MESSAGE_FLAG_SIGNED;
     }
@@ -442,8 +436,8 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
 
   if (flags & SILC_MESSAGE_FLAG_DATA) {
     silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
-               nick == NULL ? NULL : nick->nick,
-               flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
+                      nick == NULL ? NULL : nick->nick,
+                      flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
     message = NULL;
   }
 
@@ -559,15 +553,14 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
 
   server = conn == NULL ? NULL : conn->context;
   memset(userhost, 0, sizeof(userhost));
-  if (sender->username)
+  if (sender->username[0])
     snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
             sender->username, sender->hostname);
 
   /* If the messages is digitally signed, verify it, if possible. */
   if (flags & SILC_MESSAGE_FLAG_SIGNED) {
     if (!settings_get_bool("ignore_message_signatures")) {
-      SilcMessageSignedPayload sig = silc_message_get_signature(payload);
-      verified = verify_message_signature(sender, sig, payload);
+      verified = verify_message_signature(sender, payload);
     } else {
       flags &= ~SILC_MESSAGE_FLAG_SIGNED;
     }
@@ -575,11 +568,11 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
 
   if (flags & SILC_MESSAGE_FLAG_DATA) {
     silc_emit_mime_sig(server,
-               sender->nickname ?
+               sender->nickname[0] ?
                (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
                NULL,
                message, message_len,
-               sender->nickname ? sender->nickname : "[<unknown>]",
+               sender->nickname[0] ? sender->nickname : "[<unknown>]",
                flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
     message = NULL;
   }
@@ -600,24 +593,24 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
                        cp, message_len);
       if (flags & SILC_MESSAGE_FLAG_SIGNED)
         signal_emit("message silc signed_private_action", 6, server, cp,
-                   sender->nickname ? sender->nickname : "[<unknown>]",
-                   sender->username ? userhost : NULL,
+                   sender->nickname[0] ? sender->nickname : "[<unknown>]",
+                   sender->username[0] ? userhost : NULL,
                    NULL, verified);
       else
         signal_emit("message silc private_action", 5, server, cp,
-                   sender->nickname ? sender->nickname : "[<unknown>]",
-                   sender->username ? userhost : NULL, NULL);
+                   sender->nickname[0] ? sender->nickname : "[<unknown>]",
+                   sender->username[0] ? userhost : NULL, NULL);
       silc_free(dm);
     } else {
       if (flags & SILC_MESSAGE_FLAG_SIGNED)
         signal_emit("message silc signed_private_action", 6, server, message,
-                   sender->nickname ? sender->nickname : "[<unknown>]",
-                   sender->username ? userhost : NULL,
+                   sender->nickname[0] ? sender->nickname : "[<unknown>]",
+                   sender->username[0] ? userhost : NULL,
                    NULL, verified);
       else
         signal_emit("message silc private_action", 5, server, message,
-                   sender->nickname ? sender->nickname : "[<unknown>]",
-                   sender->username ? userhost : NULL, NULL);
+                   sender->nickname[0] ? sender->nickname : "[<unknown>]",
+                   sender->username[0] ? userhost : NULL, NULL);
     }
   else if (flags & SILC_MESSAGE_FLAG_NOTICE)
     if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
@@ -632,24 +625,24 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
                        cp, message_len);
       if (flags & SILC_MESSAGE_FLAG_SIGNED)
         signal_emit("message silc signed_private_notice", 6, server, cp,
-                   sender->nickname ? sender->nickname : "[<unknown>]",
-                   sender->username ? userhost : NULL,
+                   sender->nickname[0] ? sender->nickname : "[<unknown>]",
+                   sender->username[0] ? userhost : NULL,
                    NULL, verified);
       else
         signal_emit("message silc private_notice", 5, server, cp,
-                   sender->nickname ? sender->nickname : "[<unknown>]",
-                   sender->username ? userhost : NULL, NULL);
+                   sender->nickname[0] ? sender->nickname : "[<unknown>]",
+                   sender->username[0] ? userhost : NULL, NULL);
       silc_free(dm);
     } else {
       if (flags & SILC_MESSAGE_FLAG_SIGNED)
         signal_emit("message silc signed_private_notice", 6, server, message,
-                   sender->nickname ? sender->nickname : "[<unknown>]",
-                   sender->username ? userhost : NULL,
+                   sender->nickname[0] ? sender->nickname : "[<unknown>]",
+                   sender->username[0] ? userhost : NULL,
                    NULL, verified);
       else
         signal_emit("message silc private_notice", 5, server, message,
-                   sender->nickname ? sender->nickname : "[<unknown>]",
-                   sender->username ? userhost : NULL, NULL);
+                   sender->nickname[0] ? sender->nickname : "[<unknown>]",
+                   sender->username[0] ? userhost : NULL, NULL);
     }
   else {
     if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
@@ -666,24 +659,24 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
                     cp, message_len);
       if (flags & SILC_MESSAGE_FLAG_SIGNED)
         signal_emit("message signed_private", 5, server, cp,
-                 sender->nickname ? sender->nickname : "[<unknown>]",
-                 sender->username ? userhost : NULL, verified);
+                 sender->nickname[0] ? sender->nickname : "[<unknown>]",
+                 sender->username[0] ? userhost : NULL, verified);
       else
         signal_emit("message private", 4, server, cp,
-                 sender->nickname ? sender->nickname : "[<unknown>]",
-                 sender->username ? userhost : NULL);
+                 sender->nickname[0] ? sender->nickname : "[<unknown>]",
+                 sender->username[0] ? userhost : NULL);
       silc_free(dm);
       return;
     }
 
     if (flags & SILC_MESSAGE_FLAG_SIGNED)
       signal_emit("message signed_private", 5, server, message,
-              sender->nickname ? sender->nickname : "[<unknown>]",
-              sender->username ? userhost : NULL, verified);
+              sender->nickname[0] ? sender->nickname : "[<unknown>]",
+              sender->username[0] ? userhost : NULL, verified);
     else
       signal_emit("message private", 4, server, message,
-              sender->nickname ? sender->nickname : "[<unknown>]",
-              sender->username ? userhost : NULL);
+              sender->nickname[0] ? sender->nickname : "[<unknown>]",
+              sender->username[0] ? userhost : NULL);
   }
 }
 
@@ -709,9 +702,9 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
   void *entry;
   SilcUInt32 mode;
   char buf[512];
-  char *name, *tmp;
+  char *name, *tmp, *cipher, *hmac;
   GSList *list1, *list_tmp;
-  SilcBuffer buffer;
+  SilcDList chpks, clients;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -736,11 +729,10 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     name = va_arg(va, char *);
     client_entry = va_arg(va, SilcClientEntry);
 
-    memset(buf, 0, sizeof(buf));
-    snprintf(buf, sizeof(buf) - 1, "%s@%s",
-            client_entry->username, client_entry->hostname);
-    signal_emit("message invite", 4, server, channel ? channel->channel_name :
-               name, client_entry->nickname, buf);
+    silc_snprintf(buf, sizeof(buf) - 1, "%s@%s",
+                 client_entry->username, client_entry->hostname);
+    signal_emit("message invite", 4, server, name,
+               client_entry->nickname, buf);
     break;
 
   case SILC_NOTIFY_TYPE_JOIN:
@@ -756,7 +748,10 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     if (client_entry == server->conn->local_entry) {
       /* You joined to channel */
       chanrec = silc_channel_find(server, channel->channel_name);
-      if (chanrec != NULL && !chanrec->joined)
+      if (chanrec == NULL)
+       chanrec = silc_channel_create(server, channel->channel_name,
+                                       channel->channel_name, TRUE);
+      if (!chanrec->joined)
        chanrec->entry = channel;
     } else {
       chanrec = silc_channel_find_entry(server, channel);
@@ -768,12 +763,41 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     }
 
     memset(buf, 0, sizeof(buf));
-    if (client_entry->username)
-    snprintf(buf, sizeof(buf) - 1, "%s@%s",
-            client_entry->username, client_entry->hostname);
+    if (client_entry->username[0])
+      snprintf(buf, sizeof(buf) - 1, "%s@%s",
+              client_entry->username, client_entry->hostname);
     signal_emit("message join", 4, server, channel->channel_name,
                client_entry->nickname,
-               client_entry->username == NULL ? "" : buf);
+               !client_entry->username[0] ? "" : buf);
+
+    /* If there are multiple same nicknames on channel now, tell it to user. */
+    if (client_entry != server->conn->local_entry) {
+      char *nick, tmp[32];
+      int count = 0;
+
+      silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
+      clients = silc_client_get_clients_local(client, conn, nick, TRUE);
+      if (!clients || silc_dlist_count(clients) < 2) {
+       silc_free(nick);
+       silc_client_list_free(client, conn, clients);
+       break;
+      }
+      silc_dlist_start(clients);
+      while ((client_entry2 = silc_dlist_get(clients)))
+       if (silc_client_on_channel(channel, client_entry2))
+         count++;
+      if (count > 1) {
+       silc_snprintf(tmp, sizeof(tmp), "%d", silc_dlist_count(clients));
+       printformat_module("fe-common/silc", server, channel->channel_name,
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_MANY_NICKS,
+                          tmp, nick);
+       printformat_module("fe-common/silc", server, channel->channel_name,
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
+                          buf, client_entry->nickname);
+      }
+      silc_client_list_free(client, conn, clients);
+      silc_free(nick);
+    }
     break;
 
   case SILC_NOTIFY_TYPE_LEAVE:
@@ -791,7 +815,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
       snprintf(buf, sizeof(buf) - 1, "%s@%s",
               client_entry->username, client_entry->hostname);
     signal_emit("message part", 5, server, channel->channel_name,
-               client_entry->nickname,  client_entry->username ?
+               client_entry->nickname,  client_entry->username[0] ?
                buf : "", client_entry->nickname);
 
     chanrec = silc_channel_find_entry(server, channel);
@@ -800,6 +824,35 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
       if (nickrec != NULL)
        nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
     }
+
+    /* If there is only one client with this same nickname on channel now
+       change it to the base format if it is formatted nickname. */
+    if (channel) {
+      silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
+      clients = silc_client_get_clients_local(client, conn, name, TRUE);
+      if (!clients || silc_dlist_count(clients) != 2) {
+       silc_free(name);
+       silc_client_list_free(client, conn, clients);
+       break;
+      }
+      silc_dlist_start(clients);
+      client_entry2 = silc_dlist_get(clients);
+      if (client_entry2 == client_entry)
+        client_entry2 = silc_dlist_get(clients);
+      if (silc_client_on_channel(channel, client_entry2)) {
+       silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
+       silc_client_nickname_format(client, conn, client_entry2, TRUE);
+       if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
+         nicklist_rename_unique(SERVER(server), client_entry2, buf,
+                                client_entry2, client_entry2->nickname);
+         printformat_module("fe-common/silc", server, channel->channel_name,
+                            MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
+                            buf, client_entry2->nickname);
+       }
+      }
+      silc_client_list_free(client, conn, clients);
+      silc_free(name);
+    }
     break;
 
   case SILC_NOTIFY_TYPE_SIGNOFF:
@@ -811,21 +864,16 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
 
     client_entry = va_arg(va, SilcClientEntry);
     tmp = va_arg(va, char *);
+    channel = va_arg(va, SilcChannelEntry);
 
     silc_server_free_ftp(server, client_entry);
 
-    /* Print only if we have the nickname.  If this cliente has just quit
-       when we were only resolving it, it is possible we don't have the
-       nickname. */
-    if (client_entry->nickname) {
-      memset(buf, 0, sizeof(buf));
-      if (client_entry->username)
-        snprintf(buf, sizeof(buf) - 1, "%s@%s",
-                client_entry->username, client_entry->hostname);
-      signal_emit("message quit", 4, server, client_entry->nickname,
-                 client_entry->username ? buf : "",
-                 tmp ? tmp : "");
-    }
+    memset(buf, 0, sizeof(buf));
+    if (client_entry->username)
+      snprintf(buf, sizeof(buf) - 1, "%s@%s",
+              client_entry->username, client_entry->hostname);
+    signal_emit("message quit", 4, server, client_entry->nickname,
+               client_entry->username[0] ? buf : "", tmp ? tmp : "");
 
     list1 = nicklist_get_same_unique(SERVER(server), client_entry);
     for (list_tmp = list1; list_tmp != NULL; list_tmp =
@@ -835,6 +883,35 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
 
       nicklist_remove(channel, nickrec);
     }
+
+    /* If there is only one client with this same nickname on channel now
+       change it to the base format if it is formatted nickname. */
+    if (channel) {
+      silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
+      clients = silc_client_get_clients_local(client, conn, name, TRUE);
+      if (!clients || silc_dlist_count(clients) != 2) {
+       silc_free(name);
+       silc_client_list_free(client, conn, clients);
+       break;
+      }
+      silc_dlist_start(clients);
+      client_entry2 = silc_dlist_get(clients);
+      if (client_entry2 == client_entry)
+        client_entry2 = silc_dlist_get(clients);
+      if (silc_client_on_channel(channel, client_entry2)) {
+       silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
+       silc_client_nickname_format(client, conn, client_entry2, TRUE);
+       if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
+         nicklist_rename_unique(SERVER(server), client_entry2, buf,
+                                client_entry2, client_entry2->nickname);
+         printformat_module("fe-common/silc", server, channel->channel_name,
+                            MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
+                            buf, client_entry2->nickname);
+       }
+      }
+      silc_client_list_free(client, conn, clients);
+      silc_free(name);
+    }
     break;
 
   case SILC_NOTIFY_TYPE_TOPIC_SET:
@@ -900,19 +977,18 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
 
     client_entry = va_arg(va, SilcClientEntry);
-    client_entry2 = va_arg(va, SilcClientEntry);
+    name = va_arg(va, char *);                /* old nickname */
 
-    if (!strcmp(client_entry->nickname, client_entry2->nickname))
+    if (!strcmp(client_entry->nickname, name))
       break;
 
     memset(buf, 0, sizeof(buf));
     snprintf(buf, sizeof(buf) - 1, "%s@%s",
-            client_entry2->username, client_entry2->hostname);
+            client_entry->username, client_entry->hostname);
     nicklist_rename_unique(SERVER(server),
-                          client_entry, client_entry->nickname,
-                          client_entry2, client_entry2->nickname);
-    signal_emit("message nick", 4, server, client_entry2->nickname,
-               client_entry->nickname, buf);
+                          client_entry, name,
+                          client_entry, client_entry->nickname);
+    signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
     break;
 
   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
@@ -925,18 +1001,15 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     idtype = va_arg(va, int);
     entry = va_arg(va, void *);
     mode = va_arg(va, SilcUInt32);
-    (void)va_arg(va, char *);                 /* cipher */
-    (void)va_arg(va, char *);                 /* hmac */
+    cipher = va_arg(va, char *);               /* cipher */
+    hmac = va_arg(va, char *);                /* hmac */
     (void)va_arg(va, char *);                 /* passphrase */
     (void)va_arg(va, SilcPublicKey);          /* founder key */
-    buffer = va_arg(va, SilcBuffer);          /* channel public keys */
+    chpks = va_arg(va, SilcDList);            /* channel public keys */
     channel = va_arg(va, SilcChannelEntry);
 
-    tmp = silc_client_chmode(mode,
-                            channel->channel_key ?
-                            silc_cipher_get_name(channel->channel_key) : "",
-                            channel->hmac ?
-                            silc_hmac_get_name(channel->hmac) : "");
+    tmp = silc_client_chmode(mode, cipher ? cipher : "",
+                            hmac ? hmac : "");
 
     chanrec = silc_channel_find_entry(server, channel);
     if (chanrec != NULL) {
@@ -966,8 +1039,8 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     }
 
     /* Print the channel public key list */
-    if (buffer)
-      silc_parse_channel_public_keys(server, channel, buffer);
+    if (chpks)
+      silc_parse_channel_public_keys(server, channel, chpks);
 
     silc_free(tmp);
     break;
@@ -1160,34 +1233,32 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
       /*
        * Server has quit the network.
        */
-      int i;
-      SilcClientEntry *clients;
-      SilcUInt32 clients_count;
+      SilcDList clients;
 
-      SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+      SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
 
       (void)va_arg(va, void *);
-      clients = va_arg(va, SilcClientEntry *);
-      clients_count = va_arg(va, SilcUInt32);
+      clients = va_arg(va, SilcDList);
 
-      for (i = 0; i < clients_count; i++) {
+      silc_dlist_start(clients);
+      while ((client_entry = silc_dlist_get(clients))) {
        memset(buf, 0, sizeof(buf));
 
        /* Print only if we have the nickname.  If this client has just quit
           when we were only resolving it, it is possible we don't have the
           nickname. */
-       if (clients[i]->nickname) {
-         if (clients[i]->username)
+       if (client_entry->nickname[0]) {
+         if (client_entry->username[0])
            snprintf(buf, sizeof(buf) - 1, "%s@%s",
-                    clients[i]->username, clients[i]->hostname);
-         signal_emit("message quit", 4, server, clients[i]->nickname,
-                     clients[i]->username ? buf : "",
+                    client_entry->username, client_entry->hostname);
+         signal_emit("message quit", 4, server, client_entry->nickname,
+                     client_entry->username[0] ? buf : "",
                      "server signoff");
        }
 
-       silc_server_free_ftp(server, clients[i]);
+       silc_server_free_ftp(server, client_entry);
 
-       list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
+       list1 = nicklist_get_same_unique(SERVER(server), client_entry);
        for (list_tmp = list1; list_tmp != NULL; list_tmp =
               list_tmp->next->next) {
          CHANNEL_REC *channel = list_tmp->data;
@@ -1275,114 +1346,6 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
   va_end(va);
 }
 
-/* Called to indicate that connection was either successfully established
-   or connecting failed.  This is also the first time application receives
-   the SilcClientConnection object which it should save somewhere. */
-
-void silc_connect(SilcClient client, SilcClientConnection conn,
-                 SilcClientConnectionStatus status)
-{
-  SILC_SERVER_REC *server = conn->context;
-
-  if (!server || server->disconnected) {
-    silc_client_close_connection(client, conn);
-    return;
-  }
-
-  switch (status) {
-  case SILC_CLIENT_CONN_SUCCESS:
-    /* We have successfully connected to server */
-    if ((client->nickname != NULL) &&
-        (strcmp(client->nickname, client->username)))
-      silc_queue_enable(conn); /* enable queueing until we have our nick */
-    server->connected = TRUE;
-    signal_emit("event connected", 1, server);
-    break;
-
-  case SILC_CLIENT_CONN_SUCCESS_RESUME:
-    /* We have successfully resumed old detached session */
-    server->connected = TRUE;
-    signal_emit("event connected", 1, server);
-
-    /* If we resumed old session check whether we need to update
-       our nickname */
-    if (strcmp(server->nick, conn->local_entry->nickname)) {
-      char *old;
-      old = g_strdup(server->nick);
-      server_change_nick(SERVER(server), conn->local_entry->nickname);
-      nicklist_rename_unique(SERVER(server),
-                            conn->local_entry, server->nick,
-                            conn->local_entry, conn->local_entry->nickname);
-      signal_emit("message own_nick", 4, server, server->nick, old, "");
-      g_free(old);
-    }
-
-    /* remove the detach data now */
-    {
-      char *file;
-
-      file = silc_get_session_filename(server);
-
-      unlink(file);
-      silc_free(file);
-    }
-    break;
-
-  default:
-    {
-      char * file;
-
-      file = silc_get_session_filename(server);
-
-      if (silc_file_size(file) > 0)
-        printformat_module("fe-common/silc", server, NULL,
-                          MSGLEVEL_CRAP, SILCTXT_REATTACH_FAILED, file);
-
-      silc_free(file);
-
-      server->connection_lost = TRUE;
-      if (server->conn)
-        server->conn->context = NULL;
-      server_disconnect(SERVER(server));
-
-      break;
-    }
-  }
-}
-
-/* Called to indicate that connection was disconnected to the server. */
-
-void silc_disconnect(SilcClient client, SilcClientConnection conn,
-                    SilcStatus status, const char *message)
-{
-  SILC_SERVER_REC *server = conn->context;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (!server || server->connection_lost)
-    return;
-
-  if (server->conn && server->conn->local_entry) {
-    nicklist_rename_unique(SERVER(server),
-                          server->conn->local_entry, server->nick,
-                          server->conn->local_entry,
-                          silc_client->username);
-    silc_change_nick(server, silc_client->username);
-  }
-
-  if (message)
-    silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
-            "Server closed connection: %s (%d) %s",
-            silc_get_status_message(status), status,
-            message ? message : "");
-
-  if (server->conn)
-    server->conn->context = NULL;
-  server->conn = NULL;
-  server->connection_lost = TRUE;
-  server_disconnect(SERVER(server));
-}
-
 /* Command handler. This function is called always in the command function.
    If error occurs it will be called as well. `conn' is the associated
    client connection. `cmd_context' is the command context that was
@@ -1392,11 +1355,11 @@ void silc_disconnect(SilcClient client, SilcClientConnection conn,
    after application has called the command. Just to tell application
    that the command really was processed. */
 
-static bool cmode_list_chpks = FALSE;
+static SilcBool cmode_list_chpks = FALSE;
 
 void silc_command(SilcClient client, SilcClientConnection conn,
-                 SilcClientCommandContext cmd_context, bool success,
-                 SilcCommand command, SilcStatus status)
+                 SilcBool success, SilcCommand command, SilcStatus status,
+                 SilcUInt32 argc, unsigned char **argv)
 {
   SILC_SERVER_REC *server = conn->context;
 
@@ -1410,13 +1373,13 @@ void silc_command(SilcClient client, SilcClientConnection conn,
   switch (command) {
 
   case SILC_COMMAND_INVITE:
-    if (cmd_context->argc > 2)
+    if (argc > 2)
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
-                        cmd_context->argv[2],
-                        (cmd_context->argv[1][0] == '*' ?
+                        argv[2],
+                        (argv[1][0] == '*' ?
                          (char *)conn->current_channel->channel_name :
-                         (char *)cmd_context->argv[1]));
+                         (char *)argv[1]));
     break;
 
   case SILC_COMMAND_DETACH:
@@ -1424,8 +1387,7 @@ void silc_command(SilcClient client, SilcClientConnection conn,
     break;
 
   case SILC_COMMAND_CMODE:
-    if (cmd_context->argc == 3 &&
-       !strcmp(cmd_context->argv[2], "+C"))
+    if (argc == 3 && !strcmp(argv[2], "+C"))
       cmode_list_chpks = TRUE;
     else
       cmode_list_chpks = FALSE;
@@ -1436,85 +1398,11 @@ void silc_command(SilcClient client, SilcClientConnection conn,
   }
 }
 
-typedef struct {
-  SilcChannelEntry channel;
-  bool retry;
-} *SilcJoinResolve;
-
-/* Client info resolving callback when JOIN command reply is received.
-   This will cache all users on the channel. */
-
-static void silc_client_join_get_users(SilcClient client,
-                                      SilcClientConnection conn,
-                                      SilcClientEntry *clients,
-                                      SilcUInt32 clients_count,
-                                      void *context)
-{
-  SilcJoinResolve r = context;
-  SilcChannelEntry channel = r->channel;
-  SilcHashTableList htl;
-  SilcChannelUser chu;
-  SILC_SERVER_REC *server = conn->context;
-  SILC_CHANNEL_REC *chanrec;
-  SilcClientEntry founder = NULL;
-  NICK_REC *ownnick;
-
-  SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
-                 silc_hash_table_count(channel->user_list)));
-
-  if (!clients && r->retry < 1) {
-    /* Retry to resolve */
-    r->retry++;
-    silc_client_get_clients_by_channel(client, conn, channel,
-                                      silc_client_join_get_users, context);
-    return;
-  }
-
-  chanrec = silc_channel_find(server, channel->channel_name);
-  if (chanrec == NULL)
-    return;
-
-  silc_hash_table_list(channel->user_list, &htl);
-  while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
-    if (!chu->client->nickname)
-      continue;
-    if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
-      founder = chu->client;
-    silc_nicklist_insert(chanrec, chu, FALSE);
-  }
-  silc_hash_table_list_reset(&htl);
-
-  ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
-  nicklist_set_own(CHANNEL(chanrec), ownnick);
-  signal_emit("channel joined", 1, chanrec);
-  chanrec->entry = channel;
-
-  if (chanrec->topic)
-    printformat_module("fe-common/silc", server, channel->channel_name,
-                      MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
-                      channel->channel_name, chanrec->topic);
-
-  if (founder) {
-    if (founder == conn->local_entry) {
-      printformat_module("fe-common/silc",
-                        server, channel->channel_name, MSGLEVEL_CRAP,
-                        SILCTXT_CHANNEL_FOUNDER_YOU,
-                        channel->channel_name);
-      signal_emit("nick mode changed", 2, chanrec, ownnick);
-    } else
-      printformat_module("fe-common/silc",
-                        server, channel->channel_name, MSGLEVEL_CRAP,
-                        SILCTXT_CHANNEL_FOUNDER,
-                        channel->channel_name, founder->nickname);
-  }
-}
-
 typedef struct {
   SilcClient client;
   SilcClientConnection conn;
   void *entry;
   SilcIdType id_type;
-  char *fingerprint;
 } *GetkeyContext;
 
 void silc_getkey_cb(bool success, void *context)
@@ -1524,17 +1412,32 @@ void silc_getkey_cb(bool success, void *context)
   char *name = (getkey->id_type == SILC_ID_CLIENT ?
                ((SilcClientEntry)getkey->entry)->nickname :
                ((SilcServerEntry)getkey->entry)->server_name);
+  SilcPublicKey public_key = (getkey->id_type == SILC_ID_CLIENT ?
+                             ((SilcClientEntry)getkey->entry)->public_key :
+                             ((SilcServerEntry)getkey->entry)->public_key);
+  SilcSILCPublicKey silc_pubkey;
+
+  silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
 
   if (success) {
-    printformat_module("fe-common/silc", NULL, NULL,
-                      MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
+    if (getkey->id_type == SILC_ID_CLIENT)
+      printformat_module("fe-common/silc", NULL, NULL,
+                        MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED_CLIENT,
+                        name,
+                        silc_pubkey->identifier.realname ?
+                        silc_pubkey->identifier.realname : "",
+                        silc_pubkey->identifier.email ?
+                        silc_pubkey->identifier.email : "");
+    else
+      printformat_module("fe-common/silc", NULL, NULL,
+                        MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED,
+                        entity, name);
   } else {
     printformat_module("fe-common/silc", NULL, NULL,
                       MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
                       entity, name);
   }
 
-  silc_free(getkey->fingerprint);
   silc_free(getkey);
 }
 
@@ -1564,13 +1467,13 @@ void silc_parse_inviteban_list(SilcClient client,
                     MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
                     channel->channel_name, list_type);
 
-  /* parse the list */
+  /* Parse the list */
   tmp = silc_argument_get_first_arg(list, &type, &len);
   while (tmp) {
     switch (type) {
       case 1:
        {
-         /* an invite string */
+         /* An invite string */
          char **list;
          int i=0;
 
@@ -1590,7 +1493,7 @@ void silc_parse_inviteban_list(SilcClient client,
 
       case 2:
        {
-         /* a public key */
+         /* A public key */
          char *fingerprint, *babbleprint;
 
          /* tmp is Public Key Payload, take public key from it. */
@@ -1607,32 +1510,29 @@ void silc_parse_inviteban_list(SilcClient client,
 
       case 3:
        {
-         /* a client ID */
-         SilcClientID *client_id;
+         /* A Client ID */
          SilcClientEntry client_entry;
+         SilcID id;
 
-         client_id = silc_id_payload_parse_id(tmp, len, NULL);
-
-         if (client_id == NULL) {
+         if (!silc_id_payload_parse_id(tmp, len, &id)) {
            silc_say_error("Invalid data in %s list encountered", list_type);
            break;
          }
 
-         client_entry = silc_client_get_client_by_id(client, conn, client_id);
-
+         client_entry = silc_client_get_client_by_id(client, conn,
+                                                     &id.u.client_id);
          if (client_entry) {
            printformat_module("fe-common/silc", server,
                               (chanrec ? chanrec->visible_name : NULL),
                               MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
                               ++counter, channel->channel_name, list_type,
                               client_entry->nickname);
+           silc_client_unref_client(client, conn, client_entry);
          } else {
            resolving = TRUE;
-           silc_client_get_client_by_id_resolve(client, conn, client_id,
+           silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
                                                 NULL, NULL, NULL);
          }
-
-         silc_free(client_id);
        }
        break;
 
@@ -1640,6 +1540,7 @@ void silc_parse_inviteban_list(SilcClient client,
        /* "trash" */
        silc_say_error("Unkown type in %s list: %u (len %u)",
                       list_type, type, len);
+       break;
     }
     tmp = silc_argument_get_next_arg(list, &type, &len);
   }
@@ -1667,17 +1568,12 @@ void silc_parse_inviteban_list(SilcClient client,
    and each command defines the number and type of arguments it passes to the
    application (on error they are not sent). */
 
-void
-silc_command_reply(SilcClient client, SilcClientConnection conn,
-                  SilcCommandPayload cmd_payload, bool success,
-                  SilcCommand command, SilcStatus status, ...)
-
+void silc_command_reply(SilcClient client, SilcClientConnection conn,
+                       SilcCommand command, SilcStatus status,
+                       SilcStatus error, va_list vp)
 {
   SILC_SERVER_REC *server = conn->context;
   SILC_CHANNEL_REC *chanrec;
-  va_list vp;
-
-  va_start(vp, status);
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1686,41 +1582,30 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     {
       char buf[1024], *nickname, *username, *realname, *nick;
       unsigned char *fingerprint;
-      SilcUInt32 idle, mode;
-      SilcBuffer channels, user_modes;
+      SilcUInt32 idle, mode, *user_modes;
+      SilcDList channels;
       SilcClientEntry client_entry;
       SilcDList attrs;
 
       if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
        /* Print the unknown nick for user */
-       unsigned char *tmp =
-         silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
-                                    2, NULL);
+       char *tmp = va_arg(vp, char *);
        if (tmp)
-         silc_say_error("%s: %s", tmp,
-                        silc_get_status_message(status));
+         silc_say_error("%s: %s", tmp, silc_get_status_message(status));
        break;
       } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
        /* Try to find the entry for the unknown client ID, since we
           might have, and print the nickname of it for user. */
-       SilcUInt32 tmp_len;
-       unsigned char *tmp =
-         silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
-                                    2, &tmp_len);
-       if (tmp) {
-         SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
-                                                            NULL);
-         if (client_id) {
-           client_entry = silc_client_get_client_by_id(client, conn,
-                                                       client_id);
-           if (client_entry && client_entry->nickname)
-             silc_say_error("%s: %s", client_entry->nickname,
-                            silc_get_status_message(status));
-           silc_free(client_id);
-         }
+       SilcClientID *id = va_arg(vp, SilcClientID *);
+       if (id) {
+         client_entry = silc_client_get_client_by_id(client, conn, id);
+         if (client_entry && client_entry->nickname[0])
+           silc_say_error("%s: %s", client_entry->nickname,
+                          silc_get_status_message(status));
+         silc_client_unref_client(client, conn, client_entry);
        }
        break;
-      } else if (!success) {
+      } else if (SILC_STATUS_IS_ERROR(status)) {
        silc_say_error("WHOIS: %s", silc_get_status_message(status));
        return;
       }
@@ -1729,14 +1614,14 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       nickname = va_arg(vp, char *);
       username = va_arg(vp, char *);
       realname = va_arg(vp, char *);
-      channels = va_arg(vp, SilcBuffer);
+      channels = va_arg(vp, SilcDList);
       mode = va_arg(vp, SilcUInt32);
       idle = va_arg(vp, SilcUInt32);
       fingerprint = va_arg(vp, unsigned char *);
-      user_modes = va_arg(vp, SilcBuffer);
+      user_modes = va_arg(vp, SilcUInt32 *);
       attrs = va_arg(vp, SilcDList);
 
-      silc_parse_userfqdn(nickname, &nick, NULL);
+      silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
                         SILCTXT_WHOIS_USERINFO, nickname,
                         client_entry->username, client_entry->hostname,
@@ -1746,33 +1631,25 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       silc_free(nick);
 
       if (channels && user_modes) {
-       SilcUInt32 *umodes;
-       SilcDList list = silc_channel_payload_parse_list(channels->data,
-                                                        channels->len);
-       if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
-                                      &umodes)) {
-         SilcChannelPayload entry;
-         int i = 0;
+       SilcChannelPayload entry;
+       int i = 0;
 
-         memset(buf, 0, sizeof(buf));
-         silc_dlist_start(list);
-         while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
-           SilcUInt32 name_len;
-           char *m = silc_client_chumode_char(umodes[i++]);
-           char *name = silc_channel_get_name(entry, &name_len);
-
-           if (m)
-             silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
-           silc_strncat(buf, sizeof(buf) - 1, name, name_len);
-           silc_strncat(buf, sizeof(buf) - 1, " ", 1);
-           silc_free(m);
-         }
-
-         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
-                            SILCTXT_WHOIS_CHANNELS, buf);
-         silc_channel_payload_list_free(list);
-         silc_free(umodes);
+       memset(buf, 0, sizeof(buf));
+       silc_dlist_start(channels);
+       while ((entry = silc_dlist_get(channels))) {
+         SilcUInt32 name_len;
+         char *m = silc_client_chumode_char(user_modes[i++]);
+         char *name = silc_channel_get_name(entry, &name_len);
+
+         if (m)
+           silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
+         silc_strncat(buf, sizeof(buf) - 1, name, name_len);
+         silc_strncat(buf, sizeof(buf) - 1, " ", 1);
+         silc_free(m);
        }
+
+       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
+                          SILCTXT_WHOIS_CHANNELS, buf);
       }
 
       if (mode) {
@@ -1805,57 +1682,17 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     }
     break;
 
-  case SILC_COMMAND_IDENTIFY:
-    {
-      SilcClientEntry client_entry;
-
-      if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
-       /* Print the unknown nick for user */
-       unsigned char *tmp =
-         silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
-                                    2, NULL);
-       if (tmp)
-         silc_say_error("%s: %s", tmp,
-                        silc_get_status_message(status));
-       break;
-      } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
-       /* Try to find the entry for the unknown client ID, since we
-          might have, and print the nickname of it for user. */
-       SilcUInt32 tmp_len;
-       unsigned char *tmp =
-         silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
-                                    2, &tmp_len);
-       if (tmp) {
-         SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
-                                                            NULL);
-         if (client_id) {
-           client_entry = silc_client_get_client_by_id(client, conn,
-                                                       client_id);
-           if (client_entry && client_entry->nickname)
-             silc_say_error("%s: %s", client_entry->nickname,
-                            silc_get_status_message(status));
-           silc_free(client_id);
-         }
-       }
-       break;
-      }
-
-      break;
-    }
-
   case SILC_COMMAND_WHOWAS:
     {
       char *nickname, *username, *realname;
 
       if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
-       char *tmp =
-         silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
-                                    2, NULL);
+       char *tmp = va_arg(vp, char *);
        if (tmp)
          silc_say_error("%s: %s", tmp,
                         silc_get_status_message(status));
        break;
-      } else if (!success) {
+      } else if (SILC_STATUS_IS_ERROR(status)) {
        silc_say_error("WHOWAS: %s", silc_get_status_message(status));
        return;
       }
@@ -1874,51 +1711,56 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
   case SILC_COMMAND_INVITE:
     {
       SilcChannelEntry channel;
-      SilcBuffer payload;
       SilcArgumentPayload invite_list;
-      SilcUInt16 argc;
 
-      if (!success)
+      if (SILC_STATUS_IS_ERROR(status))
        return;
 
       channel = va_arg(vp, SilcChannelEntry);
-      payload = va_arg(vp, SilcBuffer);
-
-      if (payload) {
-       SILC_GET16_MSB(argc, payload->data);
-       invite_list = silc_argument_payload_parse(payload->data + 2,
-                                                 payload->len - 2, argc);
-       if (invite_list) {
-         silc_parse_inviteban_list(client, conn, server, channel,
-                                   "invite", invite_list);
-         silc_argument_payload_free(invite_list);
-       }
-      }
+      invite_list = va_arg(vp, SilcArgumentPayload);
+
+      if (invite_list)
+       silc_parse_inviteban_list(client, conn, server, channel,
+                                 "invite", invite_list);
     }
     break;
 
   case SILC_COMMAND_JOIN:
     {
-      char *channel, *mode, *topic;
+      char *channel, *mode, *topic, *cipher, *hmac;
       SilcUInt32 modei;
+      SilcHashTableList *user_list;
       SilcChannelEntry channel_entry;
-      SilcBuffer client_id_list;
-      SilcUInt32 list_count;
-
-      if (!success)
+      SilcChannelUser chu;
+      SilcClientEntry founder = NULL;
+      NICK_REC *ownnick;
+
+      if (SILC_STATUS_IS_ERROR(status)) {
+       if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
+         char *tmp = va_arg(vp, char *);
+         if (tmp)
+           silc_say_error("JOIN: %s: %s", tmp,
+                          silc_get_status_message(status));
+         return;
+       }
+       if (status == SILC_STATUS_ERR_NO_SUCH_CHANNEL) {
+         char *tmp = va_arg(vp, char *);
+         if (tmp)
+           silc_say_error("JOIN: %s: %s", tmp,
+                          silc_get_status_message(status));
+         return;
+       }
+       silc_say_error("JOIN: %s", silc_get_status_message(status));
        return;
+      }
 
       channel = va_arg(vp, char *);
       channel_entry = va_arg(vp, SilcChannelEntry);
       modei = va_arg(vp, SilcUInt32);
-      (void)va_arg(vp, SilcUInt32);
-      (void)va_arg(vp, unsigned char *);
-      (void)va_arg(vp, unsigned char *);
-      (void)va_arg(vp, unsigned char *);
+      user_list = va_arg(vp, SilcHashTableList *);
       topic = va_arg(vp, char *);
-      (void)va_arg(vp, unsigned char *);
-      list_count = va_arg(vp, SilcUInt32);
-      client_id_list = va_arg(vp, SilcBuffer);
+      cipher = va_arg(vp, char *);
+      hmac = va_arg(vp, char *);
 
       chanrec = silc_channel_find(server, channel);
       if (!chanrec)
@@ -1947,23 +1789,45 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        silc_free(dm);
       }
 
-      mode = silc_client_chmode(modei,
-                               channel_entry->channel_key ?
-                               silc_cipher_get_name(channel_entry->
-                                                    channel_key) : "",
-                               channel_entry->hmac ?
-                               silc_hmac_get_name(channel_entry->hmac) : "");
+      mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
       g_free_not_null(chanrec->mode);
       chanrec->mode = g_strdup(mode == NULL ? "" : mode);
       signal_emit("channel mode changed", 1, chanrec);
 
-      /* Resolve the client information */
-      {
-       SilcJoinResolve r = silc_calloc(1, sizeof(*r));
-       r->channel = channel_entry;
-       silc_client_get_clients_by_list(client, conn, list_count,
-                                       client_id_list,
-                                       silc_client_join_get_users, r);
+      /* Get user list */
+      while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
+       if (!chu->client->nickname[0])
+         continue;
+       if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
+         founder = chu->client;
+       silc_nicklist_insert(chanrec, chu, FALSE);
+      }
+
+      ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
+      if (!ownnick)
+       break;
+      nicklist_set_own(CHANNEL(chanrec), ownnick);
+      signal_emit("channel joined", 1, chanrec);
+      chanrec->entry = channel_entry;
+
+      if (chanrec->topic)
+       printformat_module("fe-common/silc", server,
+                          channel_entry->channel_name,
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
+                          channel_entry->channel_name, chanrec->topic);
+
+      if (founder) {
+       if (founder == conn->local_entry) {
+         printformat_module("fe-common/silc",
+                            server, channel_entry->channel_name,
+                            MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
+                            channel_entry->channel_name);
+         signal_emit("nick mode changed", 2, chanrec, ownnick);
+       } else
+         printformat_module("fe-common/silc",
+                            server, channel_entry->channel_name,
+                            MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
+                            channel_entry->channel_name, founder->nickname);
       }
 
       break;
@@ -1975,30 +1839,30 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
       GSList *nicks;
 
-      if (!success)
+      if (SILC_STATUS_IS_ERROR(status)) {
+       silc_say_error("NICK: %s", silc_get_status_message(status));
        return;
+      }
 
       nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
       if ((nicks != NULL) &&
-        (strcmp(SERVER(server)->nick, client_entry->nickname))) {
+         (strcmp(SERVER(server)->nick, client_entry->nickname))) {
        char buf[512];
        SilcClientEntry collider, old;
 
        old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
-       collider = silc_client_get_client_by_id(client, conn,
-                                               old->id);
-
+       collider = silc_client_get_client_by_id(client, conn, &old->id);
        if (collider != client_entry) {
-
-          memset(buf, 0, sizeof(buf));
-          snprintf(buf, sizeof(buf) - 1, "%s@%s",
-                  collider->username, collider->hostname);
+         memset(buf, 0, sizeof(buf));
+         snprintf(buf, sizeof(buf) - 1, "%s@%s",
+                  collider->username, collider->hostname);
          nicklist_rename_unique(SERVER(server),
-                                old, old->nickname,
-                                collider, collider->nickname);
+                                old, old->nickname,
+                                collider, collider->nickname);
          silc_print_nick_change(server, collider->nickname,
-                                client_entry->nickname, buf);
+                                client_entry->nickname, buf);
        }
+       silc_client_unref_client(client, conn, collider);
       }
 
       if (nicks != NULL)
@@ -2026,13 +1890,11 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       char users[20];
       char tmp[256], *cp, *dm = NULL;
 
-      if (!success)
+      if (SILC_STATUS_IS_ERROR(status))
        return;
 
       (void)va_arg(vp, SilcChannelEntry);
       name = va_arg(vp, char *);
-      if (!name)
-       return;
       topic = va_arg(vp, char *);
       usercount = va_arg(vp, int);
 
@@ -2071,7 +1933,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       SilcUInt32 mode;
       char *reason;
 
-      if (!success)
+      if (SILC_STATUS_IS_ERROR(status))
        return;
 
       mode = va_arg(vp, SilcUInt32);
@@ -2106,8 +1968,10 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     break;
 
   case SILC_COMMAND_OPER:
-    if (!success)
+    if (SILC_STATUS_IS_ERROR(status)) {
+      silc_say_error("OPER: %s", silc_get_status_message(status));
       return;
+    }
 
     server->umode |= SILC_UMODE_SERVER_OPERATOR;
     signal_emit("user mode changed", 2, server, NULL);
@@ -2117,8 +1981,10 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     break;
 
   case SILC_COMMAND_SILCOPER:
-    if (!success)
+    if (SILC_STATUS_IS_ERROR(status)) {
+      silc_say_error("SILCOPER: %s", silc_get_status_message(status));
       return;
+    }
 
     server->umode |= SILC_UMODE_ROUTER_OPERATOR;
     signal_emit("user mode changed", 2, server, NULL);
@@ -2133,8 +1999,10 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       SilcChannelEntry channel;
       SilcChannelUser chu;
 
-      if (!success)
+      if (SILC_STATUS_IS_ERROR(status)) {
+       silc_say_error("USERS: %s", silc_get_status_message(status));
        return;
+      }
 
       channel = va_arg(vp, SilcChannelEntry);
 
@@ -2147,7 +2015,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        SilcClientEntry e = chu->client;
        char stat[5], *mode;
 
-       if (!e->nickname)
+       if (!e->nickname[0])
          continue;
 
        memset(stat, 0, sizeof(stat));
@@ -2174,8 +2042,8 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        printformat_module("fe-common/silc", server, channel->channel_name,
                           MSGLEVEL_CRAP, SILCTXT_USERS,
                           e->nickname, stat,
-                          e->username ? e->username : "",
-                          e->hostname ? e->hostname : "",
+                          e->username[0] ? e->username : "",
+                          e->hostname[0] ? e->hostname : "",
                           e->realname ? e->realname : "");
        if (mode)
          silc_free(mode);
@@ -2187,26 +2055,17 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
   case SILC_COMMAND_BAN:
     {
       SilcChannelEntry channel;
-      SilcBuffer payload;
-      SilcArgumentPayload ban_list;
-      SilcUInt16 argc;
+      SilcArgumentPayload invite_list;
 
-      if (!success)
+      if (SILC_STATUS_IS_ERROR(status))
        return;
 
       channel = va_arg(vp, SilcChannelEntry);
-      payload = va_arg(vp, SilcBuffer);
-
-      if (payload) {
-       SILC_GET16_MSB(argc, payload->data);
-       ban_list = silc_argument_payload_parse(payload->data + 2,
-                                              payload->len - 2, argc);
-       if (ban_list) {
-         silc_parse_inviteban_list(client, conn, server, channel,
-                                   "ban", ban_list);
-         silc_argument_payload_free(ban_list);
-       }
-      }
+      invite_list = va_arg(vp, SilcArgumentPayload);
+
+      if (invite_list)
+       silc_parse_inviteban_list(client, conn, server, channel,
+                                 "ban", invite_list);
     }
     break;
 
@@ -2215,27 +2074,24 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       SilcIdType id_type;
       void *entry;
       SilcPublicKey public_key;
-      unsigned char *pk;
-      SilcUInt32 pk_len;
       GetkeyContext getkey;
       char *name;
 
-      if (!success)
+      if (SILC_STATUS_IS_ERROR(status)) {
+       silc_say_error("GETKEY: %s", silc_get_status_message(status));
        return;
+      }
 
       id_type = va_arg(vp, SilcUInt32);
       entry = va_arg(vp, void *);
       public_key = va_arg(vp, SilcPublicKey);
 
       if (public_key) {
-       pk = silc_pkcs_public_key_encode(public_key, &pk_len);
-
        getkey = silc_calloc(1, sizeof(*getkey));
        getkey->entry = entry;
        getkey->id_type = id_type;
        getkey->client = client;
        getkey->conn = conn;
-       getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
 
        name = (id_type == SILC_ID_CLIENT ?
                ((SilcClientEntry)entry)->nickname :
@@ -2243,11 +2099,9 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
 
        silc_verify_public_key_internal(client, conn, name,
                                        (id_type == SILC_ID_CLIENT ?
-                                        SILC_SOCKET_TYPE_CLIENT :
-                                        SILC_SOCKET_TYPE_SERVER),
-                                       pk, pk_len, SILC_SKE_PK_TYPE_SILC,
-                                       silc_getkey_cb, getkey);
-       silc_free(pk);
+                                        SILC_CONN_CLIENT :
+                                        SILC_CONN_SERVER),
+                                       public_key, silc_getkey_cb, getkey);
       } else {
        printformat_module("fe-common/silc", server, NULL,
                           MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
@@ -2261,7 +2115,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       char *server_name;
       char *server_info;
 
-      if (!success)
+      if (SILC_STATUS_IS_ERROR(status))
        return;
 
       server_entry = va_arg(vp, SilcServerEntry);
@@ -2282,7 +2136,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       char *topic;
       char tmp[256], *cp, *dm = NULL;
 
-      if (!success)
+      if (SILC_STATUS_IS_ERROR(status))
        return;
 
       channel = va_arg(vp, SilcChannelEntry);
@@ -2326,126 +2180,99 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
 
   case SILC_COMMAND_STATS:
     {
-      SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
-                my_router_ops, cell_clients, cell_channels, cell_servers,
-                clients, channels, servers, routers, server_ops, router_ops;
-      SilcUInt32 buf_len;
-      SilcBufferStruct buf;
-      unsigned char *tmp_buf;
+      SilcClientStats *cstats;
       char tmp[40];
       const char *tmptime;
       int days, hours, mins, secs;
 
-      if (!success)
+      if (SILC_STATUS_IS_ERROR(status))
        return;
 
-      tmp_buf = va_arg(vp, unsigned char *);
-      buf_len = va_arg(vp, SilcUInt32);
-
-      if (!tmp_buf || !buf_len) {
+      cstats = va_arg(vp, SilcClientStats *);
+      if (!cstats) {
        printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
        return;
       }
 
-      /* Get statistics structure */
-      silc_buffer_set(&buf, tmp_buf, buf_len);
-      silc_buffer_unformat(&buf,
-                          SILC_STR_UI_INT(&starttime),
-                          SILC_STR_UI_INT(&uptime),
-                          SILC_STR_UI_INT(&my_clients),
-                          SILC_STR_UI_INT(&my_channels),
-                          SILC_STR_UI_INT(&my_server_ops),
-                          SILC_STR_UI_INT(&my_router_ops),
-                          SILC_STR_UI_INT(&cell_clients),
-                          SILC_STR_UI_INT(&cell_channels),
-                          SILC_STR_UI_INT(&cell_servers),
-                          SILC_STR_UI_INT(&clients),
-                          SILC_STR_UI_INT(&channels),
-                          SILC_STR_UI_INT(&servers),
-                          SILC_STR_UI_INT(&routers),
-                          SILC_STR_UI_INT(&server_ops),
-                          SILC_STR_UI_INT(&router_ops),
-                          SILC_STR_END);
-
-      tmptime = silc_get_time(starttime);
+      tmptime = silc_time_string(cstats->starttime);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Local server start time", tmptime);
 
-      days = uptime / (24 * 60 * 60);
-      uptime -= days * (24 * 60 * 60);
-      hours = uptime / (60 * 60);
-      uptime -= hours * (60 * 60);
-      mins = uptime / 60;
-      uptime -= mins * 60;
-      secs = uptime;
+      days = cstats->uptime / (24 * 60 * 60);
+      cstats->uptime -= days * (24 * 60 * 60);
+      hours = cstats->uptime / (60 * 60);
+      cstats->uptime -= hours * (60 * 60);
+      mins = cstats->uptime / 60;
+      cstats->uptime -= mins * 60;
+      secs = cstats->uptime;
       snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
               days, hours, mins, secs);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Local server uptime", tmp);
 
-      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
+      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Local server clients", tmp);
 
-      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
+      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Local server channels", tmp);
 
-      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
+      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Local server operators", tmp);
 
-      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
+      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Local router operators", tmp);
 
-      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
+      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Local cell clients", tmp);
 
-      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
+      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Local cell channels", tmp);
 
-      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
+      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Local cell servers", tmp);
 
-      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
+      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Total clients", tmp);
 
-      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
+      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Total channels", tmp);
 
-      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
+      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Total servers", tmp);
 
-      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
+      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Total routers", tmp);
 
-      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
+      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                           "Total server operators", tmp);
 
-      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
+      snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_STATS,
                         "Total router operators", tmp);
@@ -2455,20 +2282,20 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
   case SILC_COMMAND_CMODE:
     {
       SilcChannelEntry channel_entry;
-      SilcBuffer channel_pubkeys;
+      SilcDList chpks;
 
       channel_entry = va_arg(vp, SilcChannelEntry);
       (void)va_arg(vp, SilcUInt32);
       (void)va_arg(vp, SilcPublicKey);
-      channel_pubkeys = va_arg(vp, SilcBuffer);
+      chpks = va_arg(vp, SilcDList);
 
-      if (!success || !cmode_list_chpks ||
+      if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
          !channel_entry || !channel_entry->channel_name)
        return;
 
       /* Print the channel public key list */
-      if (channel_pubkeys)
-        silc_parse_channel_public_keys(server, channel_entry, channel_pubkeys);
+      if (chpks)
+        silc_parse_channel_public_keys(server, channel_entry, chpks);
       else
         printformat_module("fe-common/silc", server, NULL,
                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
@@ -2479,14 +2306,53 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
 
   case SILC_COMMAND_LEAVE:
     {
-      /* we might be cycling, so disable queueing again */
+      if (SILC_STATUS_IS_ERROR(status))
+       return;
+
+      /* We might be cycling, so disable queueing again */
       silc_queue_disable(conn);
     }
     break;
 
-  }
+  case SILC_COMMAND_DETACH:
+    {
+      /* Save the detachment data to file. */
+      char *file;
+      SilcBuffer detach;
+
+      if (SILC_STATUS_IS_ERROR(status))
+       return;
 
-  va_end(vp);
+      detach = va_arg(vp, SilcBuffer);
+      file = silc_get_session_filename(server);
+      silc_file_writefile(file, silc_buffer_data(detach),
+                         silc_buffer_len(detach));
+      silc_free(file);
+    }
+    break;
+
+  case SILC_COMMAND_KILL:
+    {
+      SilcClientEntry client_entry;
+
+      if (SILC_STATUS_IS_ERROR(status)) {
+       silc_say_error("KILL: %s", silc_get_status_message(status));
+       return;
+      }
+
+      client_entry = va_arg(vp, SilcClientEntry);
+      if (!client_entry || !client_entry->nickname[0])
+       break;
+
+      /* Print this only if the killed client isn't joined on channels.
+        If it is, we receive KILLED notify and we'll print this there. */
+      if (!silc_hash_table_count(client_entry->channels))
+       printformat_module("fe-common/silc", server, NULL,
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
+                          client_entry->nickname,
+                          conn->local_entry->nickname, "");
+    }
+  }
 }
 
 typedef struct {
@@ -2495,9 +2361,7 @@ typedef struct {
   char *filename;
   char *entity;
   char *entity_name;
-  unsigned char *pk;
-  SilcUInt32 pk_len;
-  SilcSKEPKType pk_type;
+  SilcPublicKey public_key;
   SilcVerifyPublicKey completion;
   void *context;
 } *PublicKeyVerify;
@@ -2512,8 +2376,8 @@ static void verify_public_key_completion(const char *line, void *context)
       verify->completion(TRUE, verify->context);
 
     /* Save the key for future checking */
-    silc_pkcs_save_public_key_data(verify->filename, verify->pk,
-                                  verify->pk_len, SILC_PKCS_FILE_PEM);
+    silc_pkcs_save_public_key(verify->filename, verify->public_key,
+                             SILC_PKCS_FILE_BASE64);
   } else {
     /* Call the completion */
     if (verify->completion)
@@ -2528,7 +2392,6 @@ static void verify_public_key_completion(const char *line, void *context)
   silc_free(verify->filename);
   silc_free(verify->entity);
   silc_free(verify->entity_name);
-  silc_free(verify->pk);
   silc_free(verify);
 }
 
@@ -2539,34 +2402,51 @@ static void verify_public_key_completion(const char *line, void *context)
 
 static void
 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
-                               const char *name, SilcSocketType conn_type,
-                               unsigned char *pk, SilcUInt32 pk_len,
-                               SilcSKEPKType pk_type,
+                               const char *name,
+                               SilcConnectionType conn_type,
+                               SilcPublicKey public_key,
                                SilcVerifyPublicKey completion, void *context)
 {
-  int i;
+  PublicKeyVerify verify;
   char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
   char *fingerprint, *babbleprint, *format;
+  SilcPublicKey local_pubkey;
+  SilcSILCPublicKey silc_pubkey;
+  SilcUInt16 port;
+  const char *hostname, *ip;
+  unsigned char *pk;
+  SilcUInt32 pk_len;
   struct passwd *pw;
   struct stat st;
-  char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
-                  conn_type == SILC_SOCKET_TYPE_ROUTER) ?
+  char *entity = ((conn_type == SILC_CONN_SERVER ||
+                  conn_type == SILC_CONN_ROUTER) ?
                  "server" : "client");
-  PublicKeyVerify verify;
+  int i;
 
-  if (pk_type != SILC_SKE_PK_TYPE_SILC) {
+  if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
     printformat_module("fe-common/silc", NULL, NULL,
                       MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
-                      entity, pk_type);
+                      entity, silc_pkcs_get_type(public_key));
+    if (completion)
+      completion(FALSE, context);
+    return;
+  }
+
+  /* Encode public key */
+  pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+  if (!pk) {
     if (completion)
       completion(FALSE, context);
     return;
   }
 
+  silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
+
   pw = getpwuid(getuid());
   if (!pw) {
     if (completion)
       completion(FALSE, context);
+    silc_free(pk);
     return;
   }
 
@@ -2574,16 +2454,19 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   memset(filename2, 0, sizeof(filename2));
   memset(file, 0, sizeof(file));
 
-  if (conn_type == SILC_SOCKET_TYPE_SERVER ||
-      conn_type == SILC_SOCKET_TYPE_ROUTER) {
+  /* Get remote host information */
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
+                             NULL, &hostname, &ip, &port);
+
+  if (conn_type == SILC_CONN_SERVER ||
+      conn_type == SILC_CONN_ROUTER) {
     if (!name) {
-      snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
-              conn->sock->ip, conn->sock->port);
+      snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
       snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
               get_irssi_dir(), entity, file);
 
       snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
-              conn->sock->hostname, conn->sock->port);
+              hostname, port);
       snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
               get_irssi_dir(), entity, file);
 
@@ -2591,7 +2474,7 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
       hostf = filename2;
     } else {
       snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
-              name, conn->sock->port);
+              name, port);
       snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
               get_irssi_dir(), entity, file);
 
@@ -2621,12 +2504,10 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   verify->conn = conn;
   verify->filename = strdup(ipf);
   verify->entity = strdup(entity);
-  verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
-                        (name ? strdup(name) : strdup(conn->sock->hostname))
+  verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
+                        (name ? strdup(name) : strdup(hostname))
                         : NULL);
-  verify->pk = silc_memdup(pk, pk_len);
-  verify->pk_len = pk_len;
-  verify->pk_type = pk_type;
+  verify->public_key = public_key;
   verify->completion = completion;
   verify->context = context;
 
@@ -2637,6 +2518,13 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                       SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
                       verify->entity_name : entity);
+    if (conn_type == SILC_CONN_CLIENT && name &&
+       silc_pubkey->identifier.realname)
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+                        SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
+                        silc_pubkey->identifier.realname,
+                        silc_pubkey->identifier.email ?
+                        silc_pubkey->identifier.email : "");
     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                       SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
@@ -2647,25 +2535,27 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
                            format, 0, verify);
     g_free(format);
     silc_free(fingerprint);
+    silc_free(babbleprint);
+    silc_free(pk);
     return;
   } else {
     /* The key already exists, verify it. */
-    SilcPublicKey public_key;
     unsigned char *encpk;
     SilcUInt32 encpk_len;
 
     /* Load the key file, try for both IP filename and hostname filename */
-    if (!silc_pkcs_load_public_key(ipf, &public_key,
-                                  SILC_PKCS_FILE_PEM) &&
-       !silc_pkcs_load_public_key(ipf, &public_key,
-                                  SILC_PKCS_FILE_BIN) &&
-       (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
-                                              SILC_PKCS_FILE_PEM) &&
-                   !silc_pkcs_load_public_key(hostf, &public_key,
-                                              SILC_PKCS_FILE_BIN)))) {
+    if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
+       (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
                         verify->entity_name : entity);
+      if (conn_type == SILC_CONN_CLIENT && name &&
+         silc_pubkey->identifier.realname)
+       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+                          SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
+                          silc_pubkey->identifier.realname,
+                          silc_pubkey->identifier.email ?
+                          silc_pubkey->identifier.email : "");
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
@@ -2678,15 +2568,24 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
                              format, 0, verify);
       g_free(format);
       silc_free(fingerprint);
+      silc_free(babbleprint);
+      silc_free(pk);
       return;
     }
 
     /* Encode the key data */
-    encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
+    encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
     if (!encpk) {
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
                         verify->entity_name : entity);
+      if (conn_type == SILC_CONN_CLIENT && name &&
+         silc_pubkey->identifier.realname)
+       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+                          SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
+                          silc_pubkey->identifier.realname,
+                          silc_pubkey->identifier.email ?
+                          silc_pubkey->identifier.email : "");
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
@@ -2699,14 +2598,24 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
                              format, 0, verify);
       g_free(format);
       silc_free(fingerprint);
+      silc_free(babbleprint);
+      silc_free(pk);
       return;
     }
+    silc_pkcs_public_key_free(local_pubkey);
 
     /* Compare the keys */
     if (memcmp(encpk, pk, encpk_len)) {
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
                         verify->entity_name : entity);
+      if (conn_type == SILC_CONN_CLIENT && name &&
+         silc_pubkey->identifier.realname)
+       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+                          SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
+                          silc_pubkey->identifier.realname,
+                          silc_pubkey->identifier.email ?
+                          silc_pubkey->identifier.email : "");
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
@@ -2725,18 +2634,23 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
                              format, 0, verify);
       g_free(format);
       silc_free(fingerprint);
+      silc_free(babbleprint);
+      silc_free(encpk);
+      silc_free(pk);
       return;
     }
 
     /* Local copy matched */
     if (completion)
       completion(TRUE, context);
+    silc_free(encpk);
     silc_free(fingerprint);
+    silc_free(babbleprint);
     silc_free(verify->filename);
     silc_free(verify->entity);
     silc_free(verify->entity_name);
-    silc_free(verify->pk);
     silc_free(verify);
+    silc_free(pk);
   }
 }
 
@@ -2747,12 +2661,11 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
 
 void
 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
-                      SilcSocketType conn_type, unsigned char *pk,
-                      SilcUInt32 pk_len, SilcSKEPKType pk_type,
+                      SilcConnectionType conn_type,
+                      SilcPublicKey public_key,
                       SilcVerifyPublicKey completion, void *context)
 {
-  silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
-                                 pk_len, pk_type,
+  silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
                                  completion, context);
 }
 
@@ -2787,131 +2700,60 @@ void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
 typedef struct {
   SilcGetAuthMeth completion;
   void *context;
-} *InternalGetAuthMethod;
+} *GetAuthMethod;
 
-/* Callback called when we've received the authentication method information
-   from the server after we've requested it. This will get the authentication
-   data from the user if needed. */
-
-static void silc_get_auth_method_callback(SilcClient client,
-                                         SilcClientConnection conn,
-                                         SilcAuthMethod auth_meth,
-                                         void *context)
+static void silc_get_auth_ask_passphrase(const unsigned char *passphrase,
+                                        SilcUInt32 passphrase_len,
+                                        void *context)
 {
-  InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  switch (auth_meth) {
-  case SILC_AUTH_NONE:
-    /* No authentication required. */
-    (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
-    break;
-  case SILC_AUTH_PASSWORD:
-    {
-      /* Check whether we find the password for this server in our
-        configuration.  If not, then don't provide so library will ask
-        it from the user. */
-      SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
-                                                      conn->remote_port);
-      if (!setup || !setup->password) {
-       (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
-       break;
-      }
-
-      (*internal->completion)(TRUE, auth_meth, setup->password,
-                             strlen(setup->password), internal->context);
-    }
-    break;
-  case SILC_AUTH_PUBLIC_KEY:
-    /* Do not get the authentication data now, the library will generate
-       it using our default key, if we do not provide it here. */
-    /* XXX In the future when we support multiple local keys and multiple
-       local certificates we will need to ask from user which one to use. */
-    (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
-    break;
-  }
-
-  silc_free(internal);
+  GetAuthMethod a = context;
+  a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
+               passphrase, passphrase_len, a->context);
+  silc_free(a);
 }
 
-/* Find authentication method and authentication data by hostname and
-   port. The hostname may be IP address as well. The found authentication
-   method and authentication data is returned to `auth_meth', `auth_data'
-   and `auth_data_len'. The function returns TRUE if authentication method
-   is found and FALSE if not. `conn' may be NULL. */
+/* Find authentication data by hostname and port. The hostname may be IP
+   address as well.*/
 
 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
                          char *hostname, SilcUInt16 port,
+                         SilcAuthMethod auth_meth,
                          SilcGetAuthMeth completion, void *context)
 {
-  InternalGetAuthMethod internal;
+  SERVER_SETUP_REC *setup;
 
   SILC_LOG_DEBUG(("Start"));
 
-  /* If we do not have this connection configured by the user in a
-     configuration file then resolve the authentication method from the
-     server for this session. */
-  internal = silc_calloc(1, sizeof(*internal));
-  internal->completion = completion;
-  internal->context = context;
-
-  silc_client_request_authentication_method(client, conn,
-                                           silc_get_auth_method_callback,
-                                           internal);
-}
-
-/* Notifies application that failure packet was received.  This is called
-   if there is some protocol active in the client.  The `protocol' is the
-   protocol context.  The `failure' is opaque pointer to the failure
-   indication.  Note, that the `failure' is protocol dependant and application
-   must explicitly cast it to correct type.  Usually `failure' is 32 bit
-   failure type (see protocol specs for all protocol failure types). */
-
-void silc_failure(SilcClient client, SilcClientConnection conn,
-                 SilcProtocol protocol, void *failure)
-{
-  SILC_LOG_DEBUG(("Start"));
-
-  if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
-    SilcSKEStatus status = (SilcSKEStatus)failure;
-
-    if (status == SILC_SKE_STATUS_BAD_VERSION)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_KE_BAD_VERSION);
-    if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
-    if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_KE_UNKNOWN_GROUP);
-    if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_KE_UNKNOWN_CIPHER);
-    if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_KE_UNKNOWN_PKCS);
-    if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
-    if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_KE_UNKNOWN_HMAC);
-    if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_KE_INCORRECT_SIGNATURE);
-    if (status == SILC_SKE_STATUS_INVALID_COOKIE)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_KE_INVALID_COOKIE);
+  if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
+    /* Returning NULL will cause library to use our private key configured
+       for this connection */
+    completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
+    return;
   }
 
-  if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
-    SilcUInt32 err = (SilcUInt32)failure;
+  /* Check whether we find the password for this server in our
+     configuration.  If it's set, always send it server. */
+  setup = server_setup_find_port(hostname, port);
+  if (setup && setup->password) {
+    completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
+              context);
+    return;
+  }
 
-    if (err == SILC_AUTH_FAILED)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_AUTH_FAILED);
+  /* Didn't find password.  If server wants it, ask it from user. */
+  if (auth_meth == SILC_AUTH_PASSWORD) {
+    GetAuthMethod a;
+    a = silc_calloc(1, sizeof(*a));
+    if (a) {
+      a->completion = completion;
+      a->context = context;
+      silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
+      return;
+    }
   }
+
+  /* No authentication */
+  completion(SILC_AUTH_NONE, NULL, 0, context);
 }
 
 /* Asks whether the user would like to perform the key agreement protocol.
@@ -2921,20 +2763,22 @@ void silc_failure(SilcClient client, SilcClientConnection conn,
    desired (application may start it later by calling the function
    silc_client_perform_key_agreement). */
 
-bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
+void silc_key_agreement(SilcClient client, SilcClientConnection conn,
                        SilcClientEntry client_entry, const char *hostname,
-                       SilcUInt16 port, SilcKeyAgreementCallback *completion,
-                       void **context)
+                       SilcUInt16 protocol, SilcUInt16 port)
 {
-  char portstr[12];
+  char portstr[12], protostr[5];
 
   SILC_LOG_DEBUG(("Start"));
 
   /* We will just display the info on the screen and return FALSE and user
      will have to start the key agreement with a command. */
 
-  if (hostname)
+  if (hostname) {
     snprintf(portstr, sizeof(portstr) - 1, "%d", port);
+    snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
+            "TCP");
+  }
 
   if (!hostname)
     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
@@ -2942,12 +2786,7 @@ bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
   else
     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                       SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
-                      client_entry->nickname, hostname, portstr);
-
-  *completion = NULL;
-  *context = NULL;
-
-  return FALSE;
+                      client_entry->nickname, hostname, portstr, protostr);
 }
 
 /* Notifies application that file transfer protocol session is being
@@ -2999,38 +2838,6 @@ void silc_ftp(SilcClient client, SilcClientConnection conn,
                       client_entry->nickname, hostname, portstr);
 }
 
-/* Delivers SILC session detachment data indicated by `detach_data' to the
-   application.  If application has issued SILC_COMMAND_DETACH command
-   the client session in the SILC network is not quit.  The client remains
-   in the network but is detached.  The detachment data may be used later
-   to resume the session in the SILC Network.  The appliation is
-   responsible of saving the `detach_data', to for example in a file.
-
-   The detachment data can be given as argument to the functions
-   silc_client_connect_to_server, or silc_client_add_connection when
-   creating connection to remote server, inside SilcClientConnectionParams
-   structure.  If it is provided the client library will attempt to resume
-   the session in the network.  After the connection is created
-   successfully, the application is responsible of setting the user
-   interface for user into the same state it was before detaching (showing
-   same channels, channel modes, etc).  It can do this by fetching the
-   information (like joined channels) from the client library. */
-
-void
-silc_detach(SilcClient client, SilcClientConnection conn,
-            const unsigned char *detach_data, SilcUInt32 detach_data_len)
-{
-  SILC_SERVER_REC *server = conn->context;
-  char *file;
-
-  /* Save the detachment data to file. */
-
-  file = silc_get_session_filename(server);
-  silc_file_writefile(file, detach_data, detach_data_len);
-  silc_free(file);
-}
-
-
 /* SILC client operations */
 SilcClientOperations ops = {
   silc_say,
@@ -3039,13 +2846,9 @@ SilcClientOperations ops = {
   silc_notify,
   silc_command,
   silc_command_reply,
-  silc_connect,
-  silc_disconnect,
   silc_get_auth_method,
   silc_verify_public_key,
   silc_ask_passphrase,
-  silc_failure,
   silc_key_agreement,
   silc_ftp,
-  silc_detach,
 };