Mon Jan 12 13:01:10 CET 2004 Jochen Eisinger <jochen@penguin-breeder.org>
[silc.git] / apps / irssi / src / silc / core / client_ops.c
index c86fe00fcaa46434f23730a9d5653171bbacbd07..3b5ca0ccb1a4726993b75b70149d68c5c3bd94f8 100644 (file)
@@ -34,6 +34,7 @@
 #include "levels.h"
 #include "settings.h"
 #include "ignore.h"
+#include "special-vars.h"
 #include "fe-common/core/printtext.h"
 #include "fe-common/core/fe-channels.h"
 #include "fe-common/core/keyboard.h"
@@ -49,6 +50,20 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
                                SilcSKEPKType pk_type,
                                SilcVerifyPublicKey completion, void *context);
 
+char *silc_get_session_filename(SILC_SERVER_REC *server)
+{
+  char *file, *expanded;
+
+  expanded = parse_special_string(settings_get_str("session_filename"),
+                               SERVER(server), NULL, "", NULL, 0);
+
+  file = silc_calloc(1, strlen(expanded) + 255);
+  snprintf(file, strlen(expanded) + 255, "%s/%s", get_irssi_dir(), expanded);
+  free(expanded);
+
+  return file;
+}
+
 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
                                  SilcUInt32 buf_size)
 {
@@ -124,6 +139,53 @@ silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
   g_slist_free(windows);
 }
 
+static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
+                                          SilcChannelEntry channel_entry,
+                                          SilcBuffer channel_pubkeys)
+{
+  SilcUInt16 argc;
+  SilcArgumentPayload chpks;
+  unsigned char *pk;
+  SilcUInt32 pk_len, type;
+  int c = 1;
+  char *fingerprint, *babbleprint;
+  SilcPublicKey pubkey;
+  SilcPublicKeyIdentifier ident;
+
+  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;
+
+  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);
+
+    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 : "",
+                      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_argument_payload_free(chpks);
+}
+
 void silc_say(SilcClient client, SilcClientConnection conn,
              SilcClientMessageType type, char *msg, ...)
 {
@@ -241,6 +303,77 @@ int verify_message_signature(SilcClientEntry sender,
   return ret;
 }
 
+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;
+        }
+    }
+
+    *length = j;
+    return data;
+}
+
+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;
+        }
+    }
+
+    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)
+{
+   char *escaped_data;
+
+   escaped_data = silc_escape_data(data, data_len);
+
+   signal_emit("mime", 5, server, item, escaped_data, nick, verified);
+
+   silc_free(escaped_data);
+}
+
+
 /* Message for a channel. The `sender' is the nickname of the sender
    received in the packet. The `channel_name' is the name of the channel. */
 
@@ -284,43 +417,67 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
   }
 
   if (flags & SILC_MESSAGE_FLAG_DATA) {
-    /* MIME object received, try to display it as well as we can */
-    char type[128], enc[128];
-    unsigned char *data;
-    SilcUInt32 data_len;
-
-    memset(type, 0, sizeof(type));
-    memset(enc, 0, sizeof(enc));
-    if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
-                        enc, sizeof(enc) - 1, &data, &data_len))
-      return;
-
-    /* Then figure out what we can display */
-    if (strstr(type, "text/") && !strstr(type, "text/t140") &&
-       !strstr(type, "text/vnd")) {
-      /* It is something textual, display it */
-      message = (const unsigned char *)data;
-    } else {
-      printformat_module("fe-common/silc", server, channel->channel_name,
-                        MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
-                        nick == NULL ? "[<unknown>]" : nick->nick, type);
-      message = NULL;
-    }
+    silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
+               nick == NULL ? NULL : nick->nick,
+               flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
+    message = NULL;
   }
 
   if (!message)
     return;
 
-  /* FIXME: replace those printformat calls with signals and add signature
-            information to them (if present) */
   if (flags & SILC_MESSAGE_FLAG_ACTION)
-    printformat_module("fe-common/silc", server, channel->channel_name,
-                      MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
-                       nick == NULL ? "[<unknown>]" : nick->nick, message);
+    if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
+      char tmp[256], *cp, *dm = NULL;
+      memset(tmp, 0, sizeof(tmp));
+      cp = tmp;
+      if(message_len > sizeof(tmp) - 1) {
+        dm = silc_calloc(message_len + 1, sizeof(*dm));
+        cp = dm;
+      }
+      silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
+                       cp, message_len);
+      if (flags & SILC_MESSAGE_FLAG_SIGNED)
+        signal_emit("message silc signed_action", 6, server, cp, nick->nick,
+                   nick->host, channel->channel_name, verified);
+      else
+        signal_emit("message silc action", 5, server, cp, nick->nick,
+                   nick->host, channel->channel_name);
+      silc_free(dm);
+    } else {
+      if (flags & SILC_MESSAGE_FLAG_SIGNED)
+        signal_emit("message silc signed_action", 6, server, message,
+                   nick->nick, nick->host, channel->channel_name, verified);
+      else
+        signal_emit("message silc action", 5, server, message,
+                   nick->nick, nick->host, channel->channel_name);
+    }
   else if (flags & SILC_MESSAGE_FLAG_NOTICE)
-    printformat_module("fe-common/silc", server, channel->channel_name,
-                      MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
-                       nick == NULL ? "[<unknown>]" : nick->nick, message);
+    if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
+      char tmp[256], *cp, *dm = NULL;
+      memset(tmp, 0, sizeof(tmp));
+      cp = tmp;
+      if(message_len > sizeof(tmp) - 1) {
+        dm = silc_calloc(message_len + 1, sizeof(*dm));
+        cp = dm;
+      }
+      silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
+                       cp, message_len);
+      if (flags & SILC_MESSAGE_FLAG_SIGNED)
+       signal_emit("message silc signed_notice", 6, server, cp, nick->nick,
+               nick->host, channel->channel_name, verified);
+      else
+       signal_emit("message silc notice", 5, server, cp, nick->nick,
+               nick->host, channel->channel_name);
+      silc_free(dm);
+    } else {
+      if (flags & SILC_MESSAGE_FLAG_SIGNED)
+       signal_emit("message silc signed_notice", 6, server, message,
+               nick->nick, nick->host, channel->channel_name, verified);
+      else
+       signal_emit("message silc notice", 5, server, message,
+               nick->nick, nick->host, channel->channel_name);
+    }
   else {
     if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
       char tmp[256], *cp, *dm = NULL;
@@ -393,66 +550,117 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
   }
 
   if (flags & SILC_MESSAGE_FLAG_DATA) {
-    /* MIME object received, try to display it as well as we can */
-    char type[128], enc[128];
-    unsigned char *data;
-    SilcUInt32 data_len;
-
-    memset(type, 0, sizeof(type));
-    memset(enc, 0, sizeof(enc));
-    if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
-                        enc, sizeof(enc) - 1, &data, &data_len))
-      return;
-
-    /* Then figure out what we can display */
-    if (strstr(type, "text/") && !strstr(type, "text/t140") &&
-       !strstr(type, "text/vnd")) {
-      /* It is something textual, display it */
-      message = (const unsigned char *)data;
-    } else {
-      printformat_module("fe-common/silc", server, NULL,
-                        MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
-                        sender->nickname ? sender->nickname : "[<unknown>]",
-                        type);
-      message = NULL;
-    }
+    silc_emit_mime_sig(server,
+               sender->nickname ?
+               (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
+               NULL,
+               message, message_len,
+               sender->nickname ? sender->nickname : "[<unknown>]",
+               flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
+    message = NULL;
   }
 
   if (!message)
     return;
 
-  if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
-    char tmp[256], *cp, *dm = NULL;
-
-    memset(tmp, 0, sizeof(tmp));
-    cp = tmp;
-    if (message_len > sizeof(tmp) - 1) {
-      dm = silc_calloc(message_len + 1, sizeof(*dm));
-      cp = dm;
+  if (flags & SILC_MESSAGE_FLAG_ACTION)
+    if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
+      char tmp[256], *cp, *dm = NULL;
+      memset(tmp, 0, sizeof(tmp));
+      cp = tmp;
+      if(message_len > sizeof(tmp) - 1) {
+        dm = silc_calloc(message_len + 1, sizeof(*dm));
+        cp = dm;
+      }
+      silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
+                       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, 
+                   NULL, verified);
+      else
+        signal_emit("message silc private_action", 5, server, cp, 
+                   sender->nickname ? sender->nickname : "[<unknown>]",
+                   sender->username ? 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, 
+                   NULL, verified);
+      else
+        signal_emit("message silc private_action", 5, server, message, 
+                   sender->nickname ? sender->nickname : "[<unknown>]",
+                   sender->username ? userhost : NULL, NULL);
+    }
+  else if (flags & SILC_MESSAGE_FLAG_NOTICE)
+    if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
+      char tmp[256], *cp, *dm = NULL;
+      memset(tmp, 0, sizeof(tmp));
+      cp = tmp;
+      if(message_len > sizeof(tmp) - 1) {
+        dm = silc_calloc(message_len + 1, sizeof(*dm));
+        cp = dm;
+      }
+      silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
+                       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, 
+                   NULL, verified);
+      else
+        signal_emit("message silc private_notice", 5, server, cp, 
+                   sender->nickname ? sender->nickname : "[<unknown>]",
+                   sender->username ? 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, 
+                   NULL, verified);
+      else
+        signal_emit("message silc private_notice", 5, server, message, 
+                   sender->nickname ? sender->nickname : "[<unknown>]",
+                   sender->username ? userhost : NULL, NULL);
     }
+  else {
+    if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
+      char tmp[256], *cp, *dm = NULL;
+
+      memset(tmp, 0, sizeof(tmp));
+      cp = tmp;
+      if (message_len > sizeof(tmp) - 1) {
+        dm = silc_calloc(message_len + 1, sizeof(*dm));
+        cp = dm;
+      }
+
+      silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
+                    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);
+      else
+        signal_emit("message private", 4, server, cp,
+                 sender->nickname ? sender->nickname : "[<unknown>]",
+                 sender->username ? userhost : NULL);
+      silc_free(dm);
+      return;
+    } 
 
-    silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
-                    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);
+      signal_emit("message signed_private", 5, server, message,
+              sender->nickname ? sender->nickname : "[<unknown>]",
+              sender->username ? userhost : NULL, verified);
     else
-      signal_emit("message private", 4, server, cp,
-                 sender->nickname ? sender->nickname : "[<unknown>]",
-                 sender->username ? 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);
-  else
-    signal_emit("message private", 4, server, message,
-               sender->nickname ? sender->nickname : "[<unknown>]",
-               sender->username ? userhost : NULL);
+      signal_emit("message private", 4, server, message,
+              sender->nickname ? sender->nickname : "[<unknown>]",
+              sender->username ? userhost : NULL);
+  } 
 }
 
 /* Notify message to the client. The notify arguments are sent in the
@@ -479,6 +687,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
   char buf[512];
   char *name, *tmp;
   GSList *list1, *list_tmp;
+  SilcBuffer buffer;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -692,8 +901,11 @@ 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 *);
-    (void)va_arg(va, char *);
+    (void)va_arg(va, char *);                 /* cipher */
+    (void)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 */
     channel = va_arg(va, SilcChannelEntry);
 
     tmp = silc_client_chmode(mode,
@@ -729,6 +941,10 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
                         channel2->channel_name);
     }
 
+    /* Print the channel public key list */
+    if (buffer)
+      silc_parse_channel_public_keys(server, channel, buffer);
+
     silc_free(tmp);
     break;
 
@@ -1073,14 +1289,37 @@ void silc_connect(SilcClient client, SilcClientConnection conn,
       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:
-    server->connection_lost = TRUE;
-    if (server->conn)
-      server->conn->context = NULL;
-    server_disconnect(SERVER(server));
-    break;
+    {
+      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;
+    }
   }
 }
 
@@ -1126,6 +1365,8 @@ 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;
+
 void silc_command(SilcClient client, SilcClientConnection conn,
                  SilcClientCommandContext cmd_context, bool success,
                  SilcCommand command, SilcStatus status)
@@ -1155,6 +1396,14 @@ void silc_command(SilcClient client, SilcClientConnection conn,
     server->no_reconnect = TRUE;
     break;
 
+  case SILC_COMMAND_CMODE:
+    if (cmd_context->argc == 3 &&
+       !strcmp(cmd_context->argv[2], "+C"))
+      cmode_list_chpks = TRUE;
+    else
+      cmode_list_chpks = FALSE;
+    break;
+
   default:
     break;
   }
@@ -1188,9 +1437,9 @@ static void silc_client_join_get_users(SilcClient client,
 
   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);
-    r->retry++;
     return;
   }
 
@@ -1263,12 +1512,12 @@ void silc_getkey_cb(bool success, void *context)
 }
 
 /* Parse an invite or ban list */
-void  silc_parse_inviteban_list(SilcClient client,
-                               SilcClientConnection conn,
-                               SILC_SERVER_REC *server,
-                               SilcChannelEntry channel,
-                               const char *list_type,
-                               SilcArgumentPayload list)
+void silc_parse_inviteban_list(SilcClient client,
+                              SilcClientConnection conn,
+                              SILC_SERVER_REC *server,
+                              SilcChannelEntry channel,
+                              const char *list_type,
+                              SilcArgumentPayload list)
 {
   unsigned char *tmp;
   SilcUInt32 type, len;
@@ -1419,7 +1668,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        /* Print the unknown nick for user */
        unsigned char *tmp =
          silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
-                                    3, NULL);
+                                    2, NULL);
        if (tmp)
          silc_say_error("%s: %s", tmp,
                         silc_get_status_message(status));
@@ -1537,7 +1786,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        /* Print the unknown nick for user */
        unsigned char *tmp =
          silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
-                                    3, NULL);
+                                    2, NULL);
        if (tmp)
          silc_say_error("%s: %s", tmp,
                         silc_get_status_message(status));
@@ -1571,11 +1820,10 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     {
       char *nickname, *username, *realname;
 
-      if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
-         status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
-       char *tmp;
-       tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
-                                        3, NULL);
+      if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+       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));
@@ -1601,7 +1849,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       SilcChannelEntry channel;
       SilcBuffer payload;
       SilcArgumentPayload invite_list;
-      SilcUInt32 argc;
+      SilcUInt16 argc;
 
       if (!success)
        return;
@@ -1683,10 +1931,13 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       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);
+      {
+       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);
+      }
 
       break;
     }
@@ -1710,17 +1961,22 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        collider = silc_client_get_client_by_id(client, conn,
                                                old->id);
 
-        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);
-       silc_print_nick_change(server, collider->nickname,
-                              client_entry->nickname, buf);
-       g_slist_free(nicks);
+       if (collider != client_entry) {
+
+          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);
+         silc_print_nick_change(server, collider->nickname,
+                                client_entry->nickname, buf);
+       }
       }
 
+      if (nicks != NULL)
+       g_slist_free(nicks);
+
       old = g_strdup(server->nick);
       server_change_nick(SERVER(server), client_entry->nickname);
       nicklist_rename_unique(SERVER(server),
@@ -1899,7 +2155,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       SilcChannelEntry channel;
       SilcBuffer payload;
       SilcArgumentPayload ban_list;
-      SilcUInt32 argc;
+      SilcUInt16 argc;
 
       if (!success)
        return;
@@ -2162,6 +2418,30 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     }
     break;
 
+  case SILC_COMMAND_CMODE:
+    {
+      SilcChannelEntry channel_entry;
+      SilcBuffer channel_pubkeys;
+
+      channel_entry = va_arg(vp, SilcChannelEntry);
+      (void)va_arg(vp, SilcUInt32);
+      (void)va_arg(vp, SilcPublicKey);
+      channel_pubkeys = va_arg(vp, SilcBuffer);
+
+      if (!success || !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);
+      else
+       printformat_module("fe-common/silc", server, NULL,
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
+                          channel_entry->channel_name);
+    }
+    break;
+
   }
 
   va_end(vp);
@@ -2698,13 +2978,14 @@ void
 silc_detach(SilcClient client, SilcClientConnection conn,
             const unsigned char *detach_data, SilcUInt32 detach_data_len)
 {
-  char file[256];
+  SILC_SERVER_REC *server = conn->context;
+  char *file;
 
   /* Save the detachment data to file. */
 
-  memset(file, 0, sizeof(file));
-  snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
+  file = silc_get_session_filename(server);
   silc_file_writefile(file, detach_data, detach_data_len);
+  silc_free(file);
 }