Added SILC Thread Queue API
[crypto.git] / apps / irssi / src / silc / core / silc-channels.c
index 14f251ab58642eaa26f0216b23369677c0899f4c..4bd4e49ef556fb0d8a464fb930f8f014028eafa7 100644 (file)
@@ -1,7 +1,7 @@
 /*
   silc-channels.c : irssi
 
-  Copyright (C) 2000 - 2001, 2004, 2006 Timo Sirainen
+  Copyright (C) 2000 - 2001, 2004, 2006, 2007 Timo Sirainen
                 Pekka Riikonen <priikone@silcnet.org>
 
   This program is free software; you can redistribute it and/or modify
@@ -111,7 +111,10 @@ static void silc_channels_join(SILC_SERVER_REC *server,
                               const char *channels, int automatic)
 {
   char **list, **tmp;
+  char *channel, *key;
   SILC_CHANNEL_REC *chanrec;
+  CHANNEL_SETUP_REC *schannel;
+  GString *tmpstr;
 
   list = g_strsplit(channels, ",", -1);
   for (tmp = list; *tmp != NULL; tmp++) {
@@ -119,7 +122,25 @@ static void silc_channels_join(SILC_SERVER_REC *server,
     if (chanrec)
       continue;
 
-    silc_command_exec(server, "JOIN", *tmp);
+    channel = *tmp;
+    key = strchr(channel, ' ');
+    if (key != NULL) {
+      *key = '\0';
+      key++;
+    }
+    tmpstr = g_string_new(NULL);
+
+    schannel = channel_setup_find(channel, server->connrec->chatnet);
+    if (key && *key != '\0')
+      g_string_sprintfa(tmpstr, "%s %s", channel, key);
+    else if (schannel && schannel->password && schannel->password[0] != '\0')
+      g_string_sprintfa(tmpstr, "%s %s", channel, schannel->password);
+    else
+      g_string_sprintfa(tmpstr, "%s", channel);
+
+
+    silc_command_exec(server, "JOIN", tmpstr->str);
+    g_string_free(tmpstr, FALSE);
   }
 
   g_strfreev(list);
@@ -140,11 +161,6 @@ static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
     silc_command_exec(server, "QUIT", msg);
 }
 
-static void sig_gui_quit(SILC_SERVER_REC *server, const char *msg)
-{
-  silc_client_stop(silc_client);
-}
-
 /* Find Irssi channel entry by SILC channel entry */
 
 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
@@ -214,6 +230,7 @@ static void command_action(const char *data, SILC_SERVER_REC *server,
   char *message = NULL;
   int target_type;
   void *free_arg;
+  SilcBool sign = FALSE;
 
   CMD_SILC_SERVER(server);
   if (!IS_SILC_SERVER(server) || !server->connected)
@@ -256,21 +273,23 @@ static void command_action(const char *data, SILC_SERVER_REC *server,
 
   if (target != NULL) {
     if (target_type == SEND_TARGET_CHANNEL) {
+      sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
+             settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
       if (silc_send_channel(server, target, (message != NULL ? message : msg),
                            SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
-                           (g_hash_table_lookup(optlist, "sign") != NULL ?
-                            SILC_MESSAGE_FLAG_SIGNED : 0))) {
+                           (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
        if (g_hash_table_lookup(optlist, "sign"))
           signal_emit("message silc signed_own_action", 3, server, msg, target);
        else
           signal_emit("message silc own_action", 3, server, msg, target);
       }
     } else {
+      sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
+             settings_get_bool("sign_private_messages") ? TRUE : FALSE);
       if (silc_send_msg(server, target, (message != NULL ? message : msg),
                        (message != NULL ? strlen(message) : strlen(msg)),
                        SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
-                       (g_hash_table_lookup(optlist, "sign") != NULL ?
-                        SILC_MESSAGE_FLAG_SIGNED : 0))) {
+                       (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
        if (g_hash_table_lookup(optlist, "sign"))
          signal_emit("message silc signed_own_private_action", 3,
                          server, msg, target);
@@ -318,6 +337,7 @@ static void command_notice(const char *data, SILC_SERVER_REC *server,
   char *message = NULL;
   int target_type;
   void *free_arg;
+  SilcBool sign;
 
   CMD_SILC_SERVER(server);
   if (!IS_SILC_SERVER(server) || !server->connected)
@@ -360,21 +380,23 @@ static void command_notice(const char *data, SILC_SERVER_REC *server,
 
   if (target != NULL) {
     if (target_type == SEND_TARGET_CHANNEL) {
+      sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
+             settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
       if (silc_send_channel(server, target, (message != NULL ? message : msg),
                            SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
-                           (g_hash_table_lookup(optlist, "sign") != NULL ?
-                            SILC_MESSAGE_FLAG_SIGNED : 0))) {
+                           (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
        if (g_hash_table_lookup(optlist, "sign"))
           signal_emit("message silc signed_own_notice", 3, server, msg, target);
        else
           signal_emit("message silc own_notice", 3, server, msg, target);
       }
     } else {
+      sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
+             settings_get_bool("sign_private_messages") ? TRUE : FALSE);
       if (silc_send_msg(server, target, (message != NULL ? message : msg),
                        (message != NULL ? strlen(message) : strlen(msg)),
                        SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
-                       (g_hash_table_lookup(optlist, "sign") != NULL ?
-                        SILC_MESSAGE_FLAG_SIGNED : 0))) {
+                       (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
        if (g_hash_table_lookup(optlist, "sign"))
          signal_emit("message silc signed_own_private_notice", 3,
                          server, msg, target);
@@ -442,9 +464,9 @@ static void command_away(const char *data, SILC_SERVER_REC *server,
 }
 
 typedef struct {
-  int type;                    /* 1 = msg, 2 = channel */
-  bool responder;
   SILC_SERVER_REC *server;
+  int type;                    /* 1 = msg, 2 = channel */
+  SilcBool responder;
 } *KeyInternal;
 
 /* Key agreement callback that is called after the key agreement protocol
@@ -459,7 +481,7 @@ static void keyagr_completion(SilcClient client,
                              SilcClientConnection conn,
                              SilcClientEntry client_entry,
                              SilcKeyAgreementStatus status,
-                             SilcSKEKeyMaterial *key,
+                             SilcSKEKeyMaterial key,
                              void *context)
 {
   KeyInternal i = (KeyInternal)context;
@@ -473,7 +495,7 @@ static void keyagr_completion(SilcClient client,
       /* Set the private key for this client */
       silc_client_del_private_message_key(client, conn, client_entry);
       silc_client_add_private_message_key_ske(client, conn, client_entry,
-                                             NULL, NULL, key, i->responder);
+                                             NULL, NULL, key);
       printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
                         SILCTXT_KEY_AGREEMENT_PRIVMSG,
                         client_entry->nickname);
@@ -483,6 +505,7 @@ static void keyagr_completion(SilcClient client,
     break;
 
   case SILC_KEY_AGREEMENT_ERROR:
+  case SILC_KEY_AGREEMENT_NO_MEMORY:
     printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
                       SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
     break;
@@ -521,7 +544,6 @@ static void keyagr_completion(SilcClient client,
     silc_free(i);
 }
 
-#if 0
 /* Local command KEY. This command is used to set and unset private
    keys for channels, set and unset private keys for private messages
    with remote clients and to send key agreement requests and
@@ -542,8 +564,8 @@ typedef struct {
 
 static void silc_client_command_key_get_clients(SilcClient client,
                                                SilcClientConnection conn,
-                                               SilcClientEntry *clients,
-                                               SilcUInt32 clients_count,
+                                               SilcStatus status,
+                                               SilcDList clients,
                                                void *context)
 {
   KeyGetClients internal = (KeyGetClients)context;
@@ -569,8 +591,8 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
                        WI_ITEM_REC *item)
 {
   SilcClientConnection conn;
-  SilcClientEntry *entrys, client_entry = NULL;
-  SilcUInt32 entry_count;
+  SilcClientEntry client_entry = NULL;
+  SilcDList clients;
   SILC_CHANNEL_REC *chanrec = NULL;
   SilcChannelEntry channel_entry = NULL;
   char *nickname = NULL, *tmp;
@@ -581,6 +603,10 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
   unsigned char **argv;
   SilcUInt32 *argv_lens, *argv_types;
   char *bindhost = NULL;
+  SilcChannelPrivateKey ch = NULL;
+  SilcDList ckeys;
+  SilcBool udp = FALSE;
+  int i;
 
   CMD_SILC_SERVER(server);
 
@@ -611,27 +637,26 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
       nickname = strdup("*");
     } else {
       /* Parse the typed nickname. */
-      if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
-       printformat_module("fe-common/silc", server, NULL,
-                          MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
-       return;
-      }
+      silc_client_nickname_parse(silc_client, conn, argv[2], &nickname);
+      if (!nickname)
+       nickname = strdup(argv[2]);
 
       /* Find client entry */
-      entrys = silc_client_get_clients_local(silc_client, conn, nickname,
-                                            argv[2], &entry_count);
-      if (!entrys) {
+      clients = silc_client_get_clients_local(silc_client, conn, argv[2],
+                                             FALSE);
+      if (!clients) {
        KeyGetClients inter = silc_calloc(1, sizeof(*inter));
        inter->server = server;
        inter->data = strdup(data);
        inter->nick = strdup(nickname);
        inter->item = item;
-       silc_client_get_clients(silc_client, conn, nickname, argv[2],
+       silc_client_get_clients(silc_client, conn, nickname, NULL,
                                silc_client_command_key_get_clients, inter);
        goto out;
       }
-      client_entry = entrys[0];
-      silc_free(entrys);
+
+      client_entry = silc_dlist_get(clients);
+      silc_client_list_free(silc_client, conn, clients);
     }
   }
 
@@ -640,20 +665,16 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
     char *name;
 
     if (argv[2][0] == '*') {
-      if (!conn->current_channel) {
-       silc_free(nickname);
+      if (!conn->current_channel)
        cmd_return_error(CMDERR_NOT_JOINED);
-      }
       name = conn->current_channel->channel_name;
     } else {
       name = argv[2];
     }
 
     chanrec = silc_channel_find(server, name);
-    if (chanrec == NULL) {
-      silc_free(nickname);
+    if (chanrec == NULL)
       cmd_return_error(CMDERR_CHAN_NOT_FOUND);
-    }
     channel_entry = chanrec->entry;
   }
 
@@ -664,42 +685,17 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
     if (argc >= 5) {
       char *cipher = NULL, *hmac = NULL;
 
+      if (argc >= 6)
+       cipher = argv[5];
+      if (argc >= 7)
+       hmac = argv[6];
+
       if (type == 1 && client_entry) {
        /* Set private message key */
-       bool responder = FALSE;
-
        silc_client_del_private_message_key(silc_client, conn, client_entry);
-
-       if (argc >= 6) {
-         if (!strcasecmp(argv[5], "-responder"))
-           responder = TRUE;
-         else
-           cipher = argv[5];
-       }
-       if (argc >= 7) {
-         if (!strcasecmp(argv[6], "-responder"))
-           responder = TRUE;
-         else
-           hmac = argv[6];
-       }
-       if (argc >= 8) {
-         if (!strcasecmp(argv[7], "-responder"))
-           responder = TRUE;
-       }
-
        silc_client_add_private_message_key(silc_client, conn, client_entry,
                                            cipher, hmac,
-                                           argv[4], argv_lens[4],
-                                           (argv[4][0] == '*' ?
-                                            TRUE : FALSE), responder);
-
-       /* Send the key to the remote client so that it starts using it
-          too. */
-       /* XXX for now we don't do this.  This feature is pretty stupid
-          and should perhaps be removed altogether from SILC.
-       silc_client_send_private_message_key(silc_client, conn,
-                                            client_entry, TRUE);
-       */
+                                           argv[4], argv_lens[4]);
       } else if (type == 2) {
        /* Set private channel key */
        if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
@@ -709,11 +705,6 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
          goto out;
        }
 
-       if (argc >= 6)
-         cipher = argv[5];
-       if (argc >= 7)
-         hmac = argv[6];
-
        if (!silc_client_add_channel_private_key(silc_client, conn,
                                                 channel_entry, NULL,
                                                 cipher, hmac,
@@ -743,8 +734,6 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
       silc_client_del_private_message_key(silc_client, conn, client_entry);
     } else if (type == 2) {
       /* Unset channel key(s) */
-      SilcChannelPrivateKey *keys;
-      SilcUInt32 keys_count;
       int number;
 
       if (argc == 4)
@@ -753,20 +742,25 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
 
       if (argc > 4) {
        number = atoi(argv[4]);
-       keys = silc_client_list_channel_private_keys(silc_client, conn,
-                                                    channel_entry,
-                                                    &keys_count);
-       if (!keys)
+       ckeys = silc_client_list_channel_private_keys(silc_client, conn,
+                                                     channel_entry);
+       if (!ckeys)
          goto out;
 
-       if (!number || number > keys_count) {
-         silc_client_free_channel_private_keys(keys, keys_count);
+       silc_dlist_start(ckeys);
+       if (!number || number > silc_dlist_count(ckeys)) {
+         silc_dlist_uninit(ckeys);
          goto out;
        }
 
+       for (i = 0; i < number; i++)
+         ch = silc_dlist_get(ckeys);
+       if (!ch)
+         goto out;
+
        silc_client_del_channel_private_key(silc_client, conn, channel_entry,
-                                           keys[number - 1]);
-       silc_client_free_channel_private_keys(keys, keys_count);
+                                           ch);
+       silc_dlist_uninit(ckeys);
       }
 
       goto out;
@@ -852,36 +846,34 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
       silc_client_free_private_message_keys(keys, keys_count);
 
     } else if (type == 2) {
-      SilcChannelPrivateKey *keys;
-      SilcUInt32 keys_count;
-      int k, i, len;
+      int len;
       char buf[1024];
 
-      keys = silc_client_list_channel_private_keys(silc_client, conn,
-                                                  channel_entry,
-                                                  &keys_count);
+      ckeys = silc_client_list_channel_private_keys(silc_client, conn,
+                                                   channel_entry);
 
       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
                         SILCTXT_CH_PRIVATE_KEY_LIST,
                         channel_entry->channel_name);
 
-      if (!keys)
+      if (!ckeys)
        goto out;
 
-      for (k = 0; k < keys_count; k++) {
+      silc_dlist_start(ckeys);
+      while ((ch = silc_dlist_get(ckeys))) {
        memset(buf, 0, sizeof(buf));
        strncat(buf, "  ", 2);
 
-       len = strlen(silc_cipher_get_name(keys[k]->cipher));
-       strncat(buf, silc_cipher_get_name(keys[k]->cipher),
+       len = strlen(silc_cipher_get_name(ch->send_key));
+       strncat(buf, silc_cipher_get_name(ch->send_key),
                len > 16 ? 16 : len);
        if (len < 16)
          for (i = 0; i < 16 - len; i++)
            strcat(buf, " ");
        strcat(buf, " ");
 
-       len = strlen(silc_hmac_get_name(keys[k]->hmac));
-       strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
+       len = strlen(silc_hmac_get_name(ch->hmac));
+       strncat(buf, silc_hmac_get_name(ch->hmac), len > 16 ? 16 : len);
        if (len < 16)
          for (i = 0; i < 16 - len; i++)
            strcat(buf, " ");
@@ -892,7 +884,7 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
        silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
       }
 
-      silc_client_free_channel_private_keys(keys, keys_count);
+      silc_dlist_uninit(ckeys);
     }
 
     goto out;
@@ -904,8 +896,14 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
 
     if (argc >= 5)
       hostname = argv[4];
-    if (argc >= 6)
-      port = atoi(argv[5]);
+    if (argc >= 6) {
+      if (!strcasecmp(argv[5], "UDP"))
+       udp = TRUE;
+      else
+       port = atoi(argv[5]);
+    }
+    if (argc >= 7)
+      udp = TRUE;
 
     internal = silc_calloc(1, sizeof(*internal));
     internal->type = type;
@@ -913,7 +911,6 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
 
     if (!hostname) {
       if (settings_get_bool("use_auto_addr")) {
-
         hostname = (char *)settings_get_str("auto_public_ip");
 
        /* If the hostname isn't set, treat this case as if auto_public_ip
@@ -940,8 +937,14 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
 
     if (argc >= 5)
       hostname = argv[4];
-    if (argc >= 6)
-      port = atoi(argv[5]);
+    if (argc >= 6) {
+      if (!strcasecmp(argv[5], "UDP"))
+       udp = TRUE;
+      else
+       port = atoi(argv[5]);
+    }
+    if (argc >= 7)
+      udp = TRUE;
 
     internal = silc_calloc(1, sizeof(*internal));
     internal->type = type;
@@ -953,39 +956,41 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
     command = 6;
     if (type == 2) {
       /* Unset channel key(s) */
-      SilcChannelPrivateKey *keys;
-      SilcUInt32 keys_count;
       int number;
 
-      keys = silc_client_list_channel_private_keys(silc_client, conn,
-                                                  channel_entry,
-                                                  &keys_count);
-      if (!keys)
+      ckeys = silc_client_list_channel_private_keys(silc_client, conn,
+                                                   channel_entry);
+      if (!ckeys)
        goto out;
 
+      silc_dlist_start(ckeys);
       if (argc == 4) {
        chanrec->cur_key++;
-       if (chanrec->cur_key >= keys_count)
+       if (chanrec->cur_key >= silc_dlist_count(ckeys))
          chanrec->cur_key = 0;
       }
 
       if (argc > 4) {
        number = atoi(argv[4]);
-       if (!number || number > keys_count)
+       if (!number || number > silc_dlist_count(ckeys))
          chanrec->cur_key = 0;
        else
          chanrec->cur_key = number - 1;
       }
 
+      for (i = 0; i < chanrec->cur_key; i++)
+       ch = silc_dlist_get(ckeys);
+      if (!ch)
+       goto out;
+
       /* Set the current channel private key */
       silc_client_current_channel_private_key(silc_client, conn,
-                                             channel_entry,
-                                             keys[chanrec->cur_key]);
+                                             channel_entry, ch);
       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
+                        SILCTXT_CH_PRIVATE_KEY_CHANGE, i + 1,
                         channel_entry->channel_name);
 
-      silc_client_free_channel_private_keys(keys, keys_count);
+      silc_dlist_uninit(ckeys);
       goto out;
     }
   }
@@ -998,13 +1003,22 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
   }
 
   if (command == 4 && client_entry) {
+    SilcClientConnectionParams params;
+
     printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
                       SILCTXT_KEY_AGREEMENT, argv[2]);
     internal->responder = TRUE;
+
+    memset(&params, 0, sizeof(params));
+    params.local_ip = hostname;
+    params.bind_ip = bindhost;
+    params.local_port = port;
+    params.udp = udp;
+    params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
+
     silc_client_send_key_agreement(
-                          silc_client, conn, client_entry, hostname,
-                          bindhost, port,
-                          settings_get_int("key_exchange_timeout_secs"),
+                          silc_client, conn, client_entry, &params,
+                          irssi_pubkey, irssi_privkey,
                           keyagr_completion, internal);
     if (!hostname)
       silc_free(internal);
@@ -1012,10 +1026,33 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
   }
 
   if (command == 5 && client_entry && hostname) {
+    SilcClientConnectionParams params;
+
     printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
                       SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
     internal->responder = FALSE;
-    silc_client_perform_key_agreement(silc_client, conn, client_entry,
+
+    memset(&params, 0, sizeof(params));
+    if (udp) {
+      if (settings_get_bool("use_auto_addr")) {
+       params.local_ip = (char *)settings_get_str("auto_public_ip");
+       if ((params.local_ip) && (*params.local_ip == '\0')) {
+         params.local_ip = silc_net_localip();
+       } else {
+         params.bind_ip = (char *)settings_get_str("auto_bind_ip");
+         if ((params.bind_ip) && (*params.bind_ip == '\0'))
+           params.bind_ip = NULL;
+         params.local_port = settings_get_int("auto_bind_port");
+       }
+      }
+      if (!params.local_ip)
+       params.local_ip = silc_net_localip();
+    }
+    params.udp = udp;
+    params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
+
+    silc_client_perform_key_agreement(silc_client, conn, client_entry, &params,
+                                     irssi_pubkey, irssi_privkey,
                                      hostname, port, keyagr_completion,
                                      internal);
     goto out;
@@ -1023,39 +1060,45 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
 
  out:
   silc_free(nickname);
+  return;
 }
 
 void silc_list_key(const char *pub_filename, int verbose)
 {
   SilcPublicKey public_key;
   SilcPublicKeyIdentifier ident;
+  SilcSILCPublicKey silc_pubkey;
   char *fingerprint, *babbleprint;
   unsigned char *pk;
   SilcUInt32 pk_len;
-  SilcPKCS pkcs;
   SilcUInt32 key_len = 0;
   int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
 
-  if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
-                                SILC_PKCS_FILE_PEM) == FALSE)
-    if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
-                                  SILC_PKCS_FILE_BIN) == FALSE) {
-      printformat_module("fe-common/silc", NULL, NULL,
-                         MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
-                         pub_filename);
-      return;
-    }
+  if (!silc_pkcs_load_public_key((char *)pub_filename, SILC_PKCS_ANY,
+                                &public_key)) {
+    printformat_module("fe-common/silc", NULL, NULL,
+                      MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
+                      pub_filename);
+    return;
+  }
 
-  ident = silc_pkcs_decode_identifier(public_key->identifier);
+  /* Print only SILC public keys */
+  if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
+    printformat_module("fe-common/silc", NULL, NULL,
+                      MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
+                      pub_filename);
+    return;
+  }
 
-  pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+  silc_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SILC, public_key);
+  ident = &silc_pubkey->identifier;
+
+  pk = silc_pkcs_public_key_encode(NULL, public_key, &pk_len);
+  if (!pk)
+    return;
   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
   babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
-
-  if (silc_pkcs_alloc(public_key->name, &pkcs)) {
-    key_len = silc_pkcs_public_key_set(pkcs, public_key);
-    silc_pkcs_free(pkcs);
-  }
+  key_len = silc_pkcs_public_key_get_len(public_key);
 
   printformat_module("fe-common/silc", NULL, NULL,
                      MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
@@ -1064,11 +1107,15 @@ void silc_list_key(const char *pub_filename, int verbose)
   if (verbose)
     printformat_module("fe-common/silc", NULL, NULL,
                        MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
-                       public_key->name);
+                      silc_pkcs_get_name(public_key));
   if (key_len && verbose)
     printformat_module("fe-common/silc", NULL, NULL,
                         MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
                         (unsigned int)key_len);
+  if (ident->version && verbose)
+    printformat_module("fe-common/silc", NULL, NULL,
+                        MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_VER,
+                        ident->version);
   if (ident->realname && (!is_server_key || verbose))
     printformat_module("fe-common/silc", NULL, NULL,
                        MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
@@ -1107,8 +1154,6 @@ void silc_list_key(const char *pub_filename, int verbose)
   silc_free(babbleprint);
   silc_free(pk);
   silc_pkcs_public_key_free(public_key);
-  silc_pkcs_free_identifier(ident);
-
 }
 
 void silc_list_keys_in_dir(const char *dirname, const char *where)
@@ -1119,7 +1164,7 @@ void silc_list_keys_in_dir(const char *dirname, const char *where)
   dir = opendir(dirname);
 
   if (dir == NULL)
-         cmd_return_error(CMDERR_ERRNO);
+    cmd_return_error(CMDERR_ERRNO);
 
   printformat_module("fe-common/silc", NULL, NULL,
                      MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
@@ -1169,9 +1214,7 @@ void silc_list_file(const char *filename)
 list_key:
 
   silc_list_key(path, TRUE);
-
 }
-#endif /* 0 */
 
 /* Lists locally saved client and server public keys. */
 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
@@ -1218,7 +1261,6 @@ void silc_channels_init(void)
   signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
   signal_add("server connected", (SIGNAL_FUNC) sig_connected);
   signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
-  signal_add("gui exit", (SIGNAL_FUNC) sig_gui_quit);
   signal_add("mime", (SIGNAL_FUNC) sig_mime);
 
   command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
@@ -1226,10 +1268,10 @@ void silc_channels_init(void)
   command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
   command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
   command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
-  //  command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
-  //  command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
+  command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
+  command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
 
-  //command_set_options("listkeys", "clients servers");
+  command_set_options("listkeys", "clients servers");
   command_set_options("action", "sign channel");
   command_set_options("notice", "sign channel");
 
@@ -1241,7 +1283,6 @@ void silc_channels_deinit(void)
   signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
   signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
   signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
-  signal_remove("gui exit", (SIGNAL_FUNC) sig_gui_quit);
   signal_remove("mime", (SIGNAL_FUNC) sig_mime);
 
   command_unbind("part", (SIGNAL_FUNC) command_part);
@@ -1249,8 +1290,8 @@ void silc_channels_deinit(void)
   command_unbind("action", (SIGNAL_FUNC) command_action);
   command_unbind("notice", (SIGNAL_FUNC) command_notice);
   command_unbind("away", (SIGNAL_FUNC) command_away);
-  //  command_unbind("key", (SIGNAL_FUNC) command_key);
-  //  command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
+  command_unbind("key", (SIGNAL_FUNC) command_key);
+  command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
 
   silc_nicklist_deinit();
 }