diff libpurple/protocols/silc/buddy.c @ 17806:980a104267da

Patch from Pekka Riikonen to update the SILC protocol plugin to work with SILC Toolkit 1.1 I added the fallback to SILC Toolkit 1.0 support (silc10 protocol directory) and configure.ac adjustments, any problems with this are 100% my fault.
author Stu Tomlinson <stu@nosnilmot.com>
date Sat, 09 Jun 2007 17:31:28 +0000
parents db39246fdf6d
children 9a96d8711303
line wrap: on
line diff
--- a/libpurple/protocols/silc/buddy.c	Sat Jun 09 16:39:00 2007 +0000
+++ b/libpurple/protocols/silc/buddy.c	Sat Jun 09 17:31:28 2007 +0000
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2004 Pekka Riikonen
+  Copyright (C) 2004 - 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
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "silcpurple.h"
 #include "wb.h"
@@ -29,7 +29,7 @@
 
 static void
 silcpurple_buddy_keyagr_do(PurpleConnection *gc, const char *name,
-			 			 gboolean force_local);
+			   gboolean force_local);
 
 typedef struct {
 	char *nick;
@@ -38,10 +38,10 @@
 
 static void
 silcpurple_buddy_keyagr_resolved(SilcClient client,
-			       SilcClientConnection conn,
-			       SilcClientEntry *clients,
-			       SilcUInt32 clients_count,
-			       void *context)
+				 SilcClientConnection conn,
+				 SilcStatus status,
+				 SilcDList clients,
+				 void *context)
 {
 	PurpleConnection *gc = client->application;
 	SilcPurpleResolve r = context;
@@ -62,21 +62,16 @@
 	silc_free(r);
 }
 
-typedef struct {
-	gboolean responder;
-} *SilcPurpleKeyAgr;
-
 static void
 silcpurple_buddy_keyagr_cb(SilcClient client,
-			 SilcClientConnection conn,
-			 SilcClientEntry client_entry,
-			 SilcKeyAgreementStatus status,
-			 SilcSKEKeyMaterial *key,
-			 void *context)
+			   SilcClientConnection conn,
+			   SilcClientEntry client_entry,
+			   SilcKeyAgreementStatus status,
+			   SilcSKEKeyMaterial key,
+			   void *context)
 {
 	PurpleConnection *gc = client->application;
 	SilcPurple sg = gc->proto_data;
-	SilcPurpleKeyAgr a = context;
 
 	if (!sg->conn)
 		return;
@@ -90,13 +85,13 @@
 			/* 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, a->responder);
+								NULL, NULL, key);
 			silc_ske_free_key_material(key);
 
-			
+
 			/* Open IM window */
 			convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
-									client_entry->nickname, sg->account);
+								      client_entry->nickname, sg->account);
 			if (convo) {
 				/* we don't have windows in the core anymore...but we may want to
 				 * provide some method for asking the UI to show the window
@@ -104,7 +99,7 @@
 				 */
 			} else {
 				convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, sg->account,
-							      client_entry->nickname);
+								client_entry->nickname);
 			}
 			g_snprintf(tmp, sizeof(tmp), "%s [private key]", client_entry->nickname);
 			purple_conversation_set_title(convo, tmp);
@@ -113,7 +108,7 @@
 
 	case SILC_KEY_AGREEMENT_ERROR:
 		purple_notify_error(gc, _("Key Agreement"),
-				  _("Error occurred during key agreement"), NULL);
+				    _("Error occurred during key agreement"), NULL);
 		break;
 
 	case SILC_KEY_AGREEMENT_FAILURE:
@@ -122,53 +117,48 @@
 
 	case SILC_KEY_AGREEMENT_TIMEOUT:
 		purple_notify_error(gc, _("Key Agreement"),
-				  _("Timeout during key agreement"), NULL);
+				    _("Timeout during key agreement"), NULL);
 		break;
 
 	case SILC_KEY_AGREEMENT_ABORTED:
 		purple_notify_error(gc, _("Key Agreement"),
-				  _("Key agreement was aborted"), NULL);
+				    _("Key agreement was aborted"), NULL);
 		break;
 
 	case SILC_KEY_AGREEMENT_ALREADY_STARTED:
 		purple_notify_error(gc, _("Key Agreement"),
-				  _("Key agreement is already started"), NULL);
+				    _("Key agreement is already started"), NULL);
 		break;
 
 	case SILC_KEY_AGREEMENT_SELF_DENIED:
 		purple_notify_error(gc, _("Key Agreement"),
-				  _("Key agreement cannot be started with yourself"),
-				  NULL);
+				    _("Key agreement cannot be started with yourself"),
+				    NULL);
 		break;
 
 	default:
 		break;
 	}
-
-	silc_free(a);
 }
 
 static void
 silcpurple_buddy_keyagr_do(PurpleConnection *gc, const char *name,
-			 gboolean force_local)
+			   gboolean force_local)
 {
 	SilcPurple sg = gc->proto_data;
-	SilcClientEntry *clients;
-	SilcUInt32 clients_count;
+	SilcDList clients;
+	SilcClientEntry client_entry;
+	SilcClientConnectionParams params;
 	char *local_ip = NULL, *remote_ip = NULL;
 	gboolean local = TRUE;
-	char *nickname;
-	SilcPurpleKeyAgr a;
+	SilcSocket sock;
 
 	if (!sg->conn || !name)
 		return;
 
-	if (!silc_parse_userfqdn(name, &nickname, NULL))
-		return;
-
 	/* Find client entry */
-	clients = silc_client_get_clients_local(sg->client, sg->conn, nickname, name,
-						&clients_count);
+	clients = silc_client_get_clients_local(sg->client, sg->conn, name,
+						FALSE);
 	if (!clients) {
 		/* Resolve unknown user */
 		SilcPurpleResolve r = silc_calloc(1, sizeof(*r));
@@ -176,12 +166,14 @@
 			return;
 		r->nick = g_strdup(name);
 		r->gc = gc;
-		silc_client_get_clients(sg->client, sg->conn, nickname, NULL,
+		silc_client_get_clients(sg->client, sg->conn, name, NULL,
 					silcpurple_buddy_keyagr_resolved, r);
-		silc_free(nickname);
 		return;
 	}
 
+	silc_socket_stream_get_info(silc_packet_stream_get_stream(sg->conn->stream),
+				    &sock, NULL, NULL, NULL);
+
 	/* Resolve the local IP from the outgoing socket connection.  We resolve
 	   it to check whether we have a private range IP address or public IP
 	   address.  If we have public then we will assume that we are not behind
@@ -196,14 +188,14 @@
 
 	   Naturally this algorithm does not always get things right. */
 
-	if (silc_net_check_local_by_sock(sg->conn->sock->sock, NULL, &local_ip)) {
+	if (silc_net_check_local_by_sock(sock, NULL, &local_ip)) {
 		/* Check if the IP is private */
 		if (!force_local && silcpurple_ip_is_private(local_ip)) {
 			local = FALSE;
 
 			/* Local IP is private, resolve the remote server IP to see whether
 			   we are talking to Internet or just on LAN. */
-			if (silc_net_check_host_by_sock(sg->conn->sock->sock, NULL,
+			if (silc_net_check_host_by_sock(sock, NULL,
 							&remote_ip))
 				if (silcpurple_ip_is_private(remote_ip))
 					/* We assume we are in LAN.  Let's provide
@@ -218,19 +210,24 @@
 	if (local && !local_ip)
 		local_ip = silc_net_localip();
 
-	a = silc_calloc(1, sizeof(*a));
-	if (!a)
-		return;
-	a->responder = local;
+	silc_dlist_start(clients);
+	client_entry = silc_dlist_get(clients);
+
+	memset(&params, 0, sizeof(params));
+	params.timeout_secs = 60;
+	if (local)
+	  /* Provide connection point */
+	  params.local_ip = local_ip;
 
 	/* Send the key agreement request */
-	silc_client_send_key_agreement(sg->client, sg->conn, clients[0],
-				       local ? local_ip : NULL, NULL, 0, 60,
-				       silcpurple_buddy_keyagr_cb, a);
+	silc_client_send_key_agreement(sg->client, sg->conn, client_entry,
+				       &params, sg->public_key,
+				       sg->private_key,
+				       silcpurple_buddy_keyagr_cb, NULL);
 
 	silc_free(local_ip);
 	silc_free(remote_ip);
-	silc_free(clients);
+	silc_client_list_free(sg->client, sg->conn, clients);
 }
 
 typedef struct {
@@ -244,8 +241,8 @@
 static void
 silcpurple_buddy_keyagr_request_cb(SilcPurpleKeyAgrAsk a, gint id)
 {
-	SilcPurpleKeyAgr ai;
 	SilcClientEntry client_entry;
+	SilcClientConnectionParams params;
 
 	if (id != 1)
 		goto out;
@@ -255,26 +252,27 @@
 						    &a->client_id);
 	if (!client_entry) {
 		purple_notify_error(a->client->application, _("Key Agreement"),
-				  _("The remote user is not present in the network any more"),
-				  NULL);
+				    _("The remote user is not present in the network any more"),
+				    NULL);
 		goto out;
 	}
 
 	/* If the hostname was provided by the requestor perform the key agreement
 	   now.  Otherwise, we will send him a request to connect to us. */
 	if (a->hostname) {
-		ai = silc_calloc(1, sizeof(*ai));
-		if (!ai)
-			goto out;
-		ai->responder = FALSE;
-		silc_client_perform_key_agreement(a->client, a->conn, client_entry,
+		memset(&params, 0, sizeof(params));
+		params.timeout_secs = 60;
+		silc_client_perform_key_agreement(a->client, a->conn,
+						  client_entry, &params,
+						  a->conn->public_key,
+						  a->conn->private_key,
 						  a->hostname, a->port,
-						  silcpurple_buddy_keyagr_cb, ai);
+						  silcpurple_buddy_keyagr_cb, NULL);
 	} else {
 		/* Send request.  Force us as the point of connection since requestor
 		   did not provide the point of connection. */
 		silcpurple_buddy_keyagr_do(a->client->application,
-					 client_entry->nickname, TRUE);
+					   client_entry->nickname, TRUE);
 	}
 
  out:
@@ -283,14 +281,19 @@
 }
 
 void silcpurple_buddy_keyagr_request(SilcClient client,
-				   SilcClientConnection conn,
-				   SilcClientEntry client_entry,
-				   const char *hostname, SilcUInt16 port)
+				     SilcClientConnection conn,
+				     SilcClientEntry client_entry,
+				     const char *hostname, SilcUInt16 port,
+				     SilcUInt16 protocol)
 {
 	char tmp[128], tmp2[128];
 	SilcPurpleKeyAgrAsk a;
 	PurpleConnection *gc = client->application;
 
+	/* For now Pidgin don't support UDP key agreement */
+	if (protocol == 1)
+	  return;
+
 	g_snprintf(tmp, sizeof(tmp),
 		   _("Key agreement request received from %s. Would you like to "
 		     "perform the key agreement?"), client_entry->nickname);
@@ -304,15 +307,15 @@
 		return;
 	a->client = client;
 	a->conn = conn;
-	a->client_id = *client_entry->id;
+	a->client_id = client_entry->id;
 	if (hostname)
 		a->hostname = strdup(hostname);
 	a->port = port;
 
 	purple_request_action(client->application, _("Key Agreement Request"), tmp,
-			    hostname ? tmp2 : NULL, 1, gc->account, client_entry->nickname,
-				NULL, a, 2, _("Yes"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb),
-			    _("No"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb));
+			      hostname ? tmp2 : NULL, 1, gc->account, client_entry->nickname,
+			      NULL, a, 2, _("Yes"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb),
+			      _("No"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb));
 }
 
 static void
@@ -333,9 +336,7 @@
 	PurpleBuddy *b;
 	PurpleConnection *gc;
         SilcPurple sg;
-	char *nickname;
-	SilcClientEntry *clients;
-	SilcUInt32 clients_count;
+	SilcDList clients;
 
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
@@ -343,23 +344,16 @@
 	gc = purple_account_get_connection(b->account);
 	sg = gc->proto_data;
 
-	if (!silc_parse_userfqdn(b->name, &nickname, NULL))
-		return;
-
 	/* Find client entry */
 	clients = silc_client_get_clients_local(sg->client, sg->conn,
-						nickname, b->name,
-						&clients_count);
-	if (!clients) {
-		silc_free(nickname);
+						b->name, FALSE);
+	if (!clients)
 		return;
-	}
 
-	clients[0]->prv_resp = FALSE;
+	silc_dlist_start(clients);
 	silc_client_del_private_message_key(sg->client, sg->conn,
-					    clients[0]);
-	silc_free(clients);
-	silc_free(nickname);
+					    silc_dlist_get(clients));
+	silc_client_list_free(sg->client, sg->conn, clients);
 }
 
 typedef struct {
@@ -386,8 +380,8 @@
 						    &p->client_id);
 	if (!client_entry) {
 		purple_notify_error(p->client->application, _("IM With Password"),
-				  _("The remote user is not present in the network any more"),
-				  NULL);
+				    _("The remote user is not present in the network any more"),
+				    NULL);
 		silc_free(p);
 		return;
 	}
@@ -398,21 +392,16 @@
 	silc_client_add_private_message_key(p->client, p->conn,
 					    client_entry, NULL, NULL,
 					    (unsigned char *)passphrase,
-					    strlen(passphrase), FALSE,
-					    client_entry->prv_resp);
-	if (!client_entry->prv_resp)
-		silc_client_send_private_message_key_request(p->client,
-							     p->conn,
-							     client_entry);
+					    strlen(passphrase));
         silc_free(p);
 }
 
 static void
 silcpurple_buddy_privkey_resolved(SilcClient client,
-				SilcClientConnection conn,
-				SilcClientEntry *clients,
-				SilcUInt32 clients_count,
-				void *context)
+				  SilcClientConnection conn,
+				  SilcStatus status,
+				  SilcDList clients,
+				  void *context)
 {
 	char tmp[256];
 
@@ -434,42 +423,39 @@
 silcpurple_buddy_privkey(PurpleConnection *gc, const char *name)
 {
 	SilcPurple sg = gc->proto_data;
-	char *nickname;
 	SilcPurplePrivkey p;
-	SilcClientEntry *clients;
-	SilcUInt32 clients_count;
+	SilcDList clients;
+	SilcClientEntry client_entry;
 
 	if (!name)
 		return;
-	if (!silc_parse_userfqdn(name, &nickname, NULL))
-		return;
 
 	/* Find client entry */
 	clients = silc_client_get_clients_local(sg->client, sg->conn,
-						nickname, name,
-						&clients_count);
+						name, FALSE);
 	if (!clients) {
-		silc_client_get_clients(sg->client, sg->conn, nickname, NULL,
+		silc_client_get_clients(sg->client, sg->conn, name, NULL,
 					silcpurple_buddy_privkey_resolved,
 					g_strdup(name));
-		silc_free(nickname);
 		return;
 	}
 
+	silc_dlist_start(clients);
+	client_entry = silc_dlist_get(clients);
+
 	p = silc_calloc(1, sizeof(*p));
 	if (!p)
 		return;
 	p->client = sg->client;
 	p->conn = sg->conn;
-	p->client_id = *clients[0]->id;
+	p->client_id = client_entry->id;
 	purple_request_input(gc, _("IM With Password"), NULL,
 	                     _("Set IM Password"), NULL, FALSE, TRUE, NULL,
 	                     _("OK"), G_CALLBACK(silcpurple_buddy_privkey_cb),
 	                     _("Cancel"), G_CALLBACK(silcpurple_buddy_privkey_cb),
 	                     gc->account, NULL, NULL, p);
 
-	silc_free(clients);
-	silc_free(nickname);
+	silc_client_list_free(sg->client, sg->conn, clients);
 }
 
 static void
@@ -498,13 +484,21 @@
 static void
 silcpurple_buddy_getkey(PurpleConnection *gc, const char *name);
 
-static void
-silcpurple_buddy_getkey_cb(SilcPurpleBuddyGetkey g,
-			 SilcClientCommandReplyContext cmd)
+static SilcBool
+silcpurple_buddy_getkey_cb(SilcClient client, SilcClientConnection conn,
+			   SilcCommand command, SilcStatus status,
+			   SilcStatus error, void *context, va_list ap)
 {
 	SilcClientEntry client_entry;
-	unsigned char *pk;
-	SilcUInt32 pk_len;
+	SilcPurpleBuddyGetkey g = context;
+
+	if (status != SILC_STATUS_OK) {
+		purple_notify_error(g->client->application, _("Get Public Key"),
+				  _("The remote user is not present in the network any more"),
+				  NULL);
+		silc_free(g);
+		return FALSE;
+	}
 
 	/* Get the client entry. */
 	client_entry = silc_client_get_client_by_id(g->client, g->conn,
@@ -514,30 +508,28 @@
 				  _("The remote user is not present in the network any more"),
 				  NULL);
 		silc_free(g);
-		return;
+		return FALSE;
 	}
 
 	if (!client_entry->public_key) {
 		silc_free(g);
-		return;
+		return FALSE;
 	}
 
 	/* Now verify the public key */
-	pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
 	silcpurple_verify_public_key(g->client, g->conn, client_entry->nickname,
-				   SILC_SOCKET_TYPE_CLIENT,
-				   pk, pk_len, SILC_SKE_PK_TYPE_SILC,
-				   NULL, NULL);
-	silc_free(pk);
+				     SILC_CONN_CLIENT, client_entry->public_key,
+				     NULL, NULL);
 	silc_free(g);
+	return TRUE;
 }
 
 static void
 silcpurple_buddy_getkey_resolved(SilcClient client,
-			       SilcClientConnection conn,
-			       SilcClientEntry *clients,
-			       SilcUInt32 clients_count,
-			       void *context)
+				 SilcClientConnection conn,
+				 SilcStatus status,
+				 SilcDList clients,
+				 void *context)
 {
 	char tmp[256];
 
@@ -546,7 +538,7 @@
 			   _("User %s is not present in the network"),
 			   (const char *)context);
 		purple_notify_error(client->application, _("Get Public Key"),
-				  _("Cannot fetch the public key"), tmp);
+				    _("Cannot fetch the public key"), tmp);
 		g_free(context);
 		return;
 	}
@@ -561,42 +553,38 @@
 	SilcPurple sg = gc->proto_data;
 	SilcClient client = sg->client;
 	SilcClientConnection conn = sg->conn;
-	SilcClientEntry *clients;
-	SilcUInt32 clients_count;
+	SilcClientEntry client_entry;
+	SilcDList clients;
 	SilcPurpleBuddyGetkey g;
-	char *nickname;
+	SilcUInt16 cmd_ident;
 
 	if (!name)
 		return;
 
-	if (!silc_parse_userfqdn(name, &nickname, NULL))
-		return;
-
 	/* Find client entry */
-	clients = silc_client_get_clients_local(client, conn, nickname, name,
-						&clients_count);
+	clients = silc_client_get_clients_local(client, conn, name, FALSE);
 	if (!clients) {
-		silc_client_get_clients(client, conn, nickname, NULL,
+		silc_client_get_clients(client, conn, name, NULL,
 					silcpurple_buddy_getkey_resolved,
 					g_strdup(name));
-		silc_free(nickname);
 		return;
 	}
 
+	silc_dlist_start(clients);
+	client_entry = silc_dlist_get(clients);
+
 	/* Call GETKEY */
 	g = silc_calloc(1, sizeof(*g));
 	if (!g)
 		return;
 	g->client = client;
 	g->conn = conn;
-	g->client_id = *clients[0]->id;
-	silc_client_command_call(client, conn, NULL, "GETKEY",
-				 clients[0]->nickname, NULL);
-	silc_client_command_pending(conn, SILC_COMMAND_GETKEY,
-				    conn->cmd_ident,
-				    (SilcCommandCb)silcpurple_buddy_getkey_cb, g);
-	silc_free(clients);
-	silc_free(nickname);
+	g->client_id = client_entry->id;
+	cmd_ident = silc_client_command_call(client, conn, NULL, "GETKEY",
+					     client_entry->nickname, NULL);
+	silc_client_command_pending(conn, SILC_COMMAND_GETKEY, cmd_ident,
+				    silcpurple_buddy_getkey_cb, g);
+	silc_client_list_free(client, conn, clients);
 }
 
 static void
@@ -629,8 +617,7 @@
 	sg = gc->proto_data;
 
 	pkfile = purple_blist_node_get_string(node, "public-key");
-	if (!silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_PEM) &&
-	    !silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_BIN)) {
+	if (!silc_pkcs_load_public_key(pkfile, &public_key)) {
 		purple_notify_error(gc,
 				  _("Show Public Key"),
 				  _("Could not load public key"), NULL);
@@ -661,6 +648,7 @@
 	PurpleBuddy *b;
 	unsigned char *offline_pk;
 	SilcUInt32 offline_pk_len;
+	SilcPublicKey public_key;
 	unsigned int offline        : 1;
 	unsigned int pubkey_search  : 1;
 	unsigned int init           : 1;
@@ -670,10 +658,10 @@
 silcpurple_add_buddy_ask_pk_cb(SilcPurpleBuddyRes r, gint id);
 static void
 silcpurple_add_buddy_resolved(SilcClient client,
-			    SilcClientConnection conn,
-			    SilcClientEntry *clients,
-			    SilcUInt32 clients_count,
-			    void *context);
+			      SilcClientConnection conn,
+			      SilcStatus status,
+			      SilcDList clients,
+			      void *context);
 
 void silcpurple_get_info(PurpleConnection *gc, const char *who)
 {
@@ -735,35 +723,38 @@
 	g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not trusted"),
 		   r->b->name);
 	purple_notify_error(r->client->application, _("Add Buddy"), tmp,
-			  _("You cannot receive buddy notifications until you "
-			    "import his/her public key.  You can use the Get Public Key "
-			    "command to get the public key."));
+			    _("You cannot receive buddy notifications until you "
+			      "import his/her public key.  You can use the Get Public Key "
+			      "command to get the public key."));
 	purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_OFFLINE, NULL);
 }
 
 static void
-silcpurple_add_buddy_save(bool success, void *context)
+silcpurple_add_buddy_save(SilcBool success, void *context)
 {
 	SilcPurpleBuddyRes r = context;
 	PurpleBuddy *b = r->b;
-	SilcClient client = r->client;
 	SilcClientEntry client_entry;
 	SilcAttributePayload attr;
 	SilcAttribute attribute;
 	SilcVCardStruct vcard;
-	SilcAttributeObjMime message, extension;
+	SilcMime message = NULL, extension = NULL;
 #ifdef SILC_ATTRIBUTE_USER_ICON
-	SilcAttributeObjMime usericon;
+	SilcMime usericon = NULL;
 #endif
 	SilcAttributeObjPk serverpk, usersign, serversign;
 	gboolean usign_success = TRUE, ssign_success = TRUE;
 	char filename[512], filename2[512], *fingerprint = NULL, *tmp;
 	SilcUInt32 len;
+	SilcHash hash;
 	int i;
 
 	if (!success) {
 		/* The user did not trust the public key. */
 		silcpurple_add_buddy_pk_no(r);
+		silc_free(r->offline_pk);
+		if (r->public_key)
+		  silc_pkcs_public_key_free(r->public_key);
 		silc_free(r);
 		return;
 	}
@@ -783,6 +774,8 @@
 		purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_OFFLINE, NULL);
 		silc_free(fingerprint);
 		silc_free(r->offline_pk);
+		if (r->public_key)
+		  silc_pkcs_public_key_free(r->public_key);
 		silc_free(r);
 		return;
 	}
@@ -791,16 +784,15 @@
 	client_entry = silc_client_get_client_by_id(r->client, r->conn,
 						    &r->client_id);
 	if (!client_entry) {
+		silc_free(r->offline_pk);
+		silc_pkcs_public_key_free(r->public_key);
+		if (r->public_key)
+		  silc_pkcs_public_key_free(r->public_key);
 		silc_free(r);
 		return;
 	}
 
 	memset(&vcard, 0, sizeof(vcard));
-	memset(&message, 0, sizeof(message));
-	memset(&extension, 0, sizeof(extension));
-#ifdef SILC_ATTRIBUTE_USER_ICON
-	memset(&usericon, 0, sizeof(usericon));
-#endif
 	memset(&serverpk, 0, sizeof(serverpk));
 	memset(&usersign, 0, sizeof(usersign));
 	memset(&serversign, 0, sizeof(serversign));
@@ -822,21 +814,24 @@
 				break;
 
 			case SILC_ATTRIBUTE_STATUS_MESSAGE:
-				if (!silc_attribute_get_object(attr, (void *)&message,
-							       sizeof(message)))
+				message = silc_mime_alloc();
+				if (!silc_attribute_get_object(attr, (void *)message,
+							       sizeof(*message)))
 					continue;
 				break;
 
 			case SILC_ATTRIBUTE_EXTENSION:
-				if (!silc_attribute_get_object(attr, (void *)&extension,
-							       sizeof(extension)))
+				extension = silc_mime_alloc();
+				if (!silc_attribute_get_object(attr, (void *)extension,
+							       sizeof(*extension)))
 					continue;
 				break;
 
 #ifdef SILC_ATTRIBUTE_USER_ICON
 			case SILC_ATTRIBUTE_USER_ICON:
-				if (!silc_attribute_get_object(attr, (void *)&usericon,
-							       sizeof(usericon)))
+				usericon = silc_mime_alloc();
+				if (!silc_attribute_get_object(attr, (void *)usericon,
+							       sizeof(*usericon)))
 					continue;
 				break;
 #endif
@@ -872,50 +867,54 @@
 	}
 
 	/* Verify the attribute signatures */
+	silc_hash_alloc((const unsigned char *)"sha1", &hash);
 
 	if (usersign.data) {
-		SilcPKCS pkcs;
 		unsigned char *verifyd;
 		SilcUInt32 verify_len;
 
-		silc_pkcs_alloc((unsigned char*)"rsa", &pkcs);
 		verifyd = silc_attribute_get_verify_data(client_entry->attrs,
 							 FALSE, &verify_len);
-		if (verifyd && silc_pkcs_public_key_set(pkcs, client_entry->public_key)){
-			if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash,
-							usersign.data,
-							usersign.data_len,
-							verifyd, verify_len))
-				usign_success = FALSE;
-		}
+		if (verifyd && !silc_pkcs_verify(client_entry->public_key,
+						 usersign.data,
+						 usersign.data_len,
+						 verifyd, verify_len, hash))
+			usign_success = FALSE;
 		silc_free(verifyd);
 	}
 
-	if (serversign.data && !strcmp(serverpk.type, "silc-rsa")) {
+	if (serversign.data) {
 		SilcPublicKey public_key;
-		SilcPKCS pkcs;
+		SilcPKCSType type = 0;
 		unsigned char *verifyd;
 		SilcUInt32 verify_len;
 
-		if (silc_pkcs_public_key_decode(serverpk.data, serverpk.data_len,
-						&public_key)) {
-			silc_pkcs_alloc((unsigned char *)"rsa", &pkcs);
+		if (!strcmp(serverpk.type, "silc-rsa"))
+		  type = SILC_PKCS_SILC;
+		else if (!strcmp(serverpk.type, "ssh-rsa"))
+		  type = SILC_PKCS_SSH2;
+		else if (!strcmp(serverpk.type, "x509v3-sign-rsa"))
+		  type = SILC_PKCS_X509V3;
+		else if (!strcmp(serverpk.type, "pgp-sign-rsa"))
+		  type = SILC_PKCS_OPENPGP;
+
+		if (silc_pkcs_public_key_alloc(type, serverpk.data,
+					       serverpk.data_len,
+					       &public_key)) {
 			verifyd = silc_attribute_get_verify_data(client_entry->attrs,
 								 TRUE, &verify_len);
-			if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)) {
-				if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash,
-							       serversign.data,
-							       serversign.data_len,
-							       verifyd, verify_len))
-					ssign_success = FALSE;
-			}
+			if (verifyd && !silc_pkcs_verify(public_key,
+							 serversign.data,
+							 serversign.data_len,
+							 verifyd, verify_len,
+							 hash))
+				ssign_success = FALSE;
 			silc_pkcs_public_key_free(public_key);
 			silc_free(verifyd);
 		}
 	}
 
-	fingerprint = silc_fingerprint(client_entry->fingerprint,
-				       client_entry->fingerprint_len);
+	fingerprint = silc_fingerprint(client_entry->fingerprint, 20);
 	for (i = 0; i < strlen(fingerprint); i++)
 		if (fingerprint[i] == ' ')
 			fingerprint[i] = '_';
@@ -954,46 +953,45 @@
 		}
 
 		/* Save status message */
-		if (message.mime) {
+		if (message) {
 			memset(filename2, 0, sizeof(filename2));
 			g_snprintf(filename2, sizeof(filename2) - 1,
 				   "%s" G_DIR_SEPARATOR_S "status_message.mime",
 				   filename);
-			silc_file_writefile(filename2, (char *)message.mime,
-					    message.mime_len);
+			tmp = (char *)silc_mime_get_data(message, &len);
+			silc_file_writefile(filename2, tmp, len);
+			silc_mime_free(message);
 		}
 
 		/* Save extension data */
-		if (extension.mime) {
+		if (extension) {
 			memset(filename2, 0, sizeof(filename2));
 			g_snprintf(filename2, sizeof(filename2) - 1,
 				   "%s" G_DIR_SEPARATOR_S "extension.mime",
 				   filename);
-			silc_file_writefile(filename2, (char *)extension.mime,
-					    extension.mime_len);
+			tmp = (char *)silc_mime_get_data(extension, &len);
+			silc_file_writefile(filename2, tmp, len);
+			silc_mime_free(extension);
 		}
 
 #ifdef SILC_ATTRIBUTE_USER_ICON
 		/* Save user icon */
-		if (usericon.mime) {
-			SilcMime m = silc_mime_decode(usericon.mime,
-						      usericon.mime_len);
-			if (m) {
-				const char *type = silc_mime_get_field(m, "Content-Type");
-				if (!strcmp(type, "image/jpeg") ||
-				    !strcmp(type, "image/gif") ||
-				    !strcmp(type, "image/bmp") ||
-				    !strcmp(type, "image/png")) {
-					const unsigned char *data;
-					SilcUInt32 data_len;
-					data = silc_mime_get_data(m, &data_len);
-					if (data) {
-						/* TODO: Check if SILC gives us something to use as the checksum instead */
-						purple_buddy_icons_set_for_user(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), g_memdup(data, data_len), data_len, NULL);
-					}
+		if (usericon) {
+			const char *type = silc_mime_get_field(usericon, "Content-Type");
+			if (type &&
+			    (!strcmp(type, "image/jpeg") ||
+			     !strcmp(type, "image/gif") ||
+			     !strcmp(type, "image/bmp") ||
+			     !strcmp(type, "image/png"))) {
+				const unsigned char *data;
+				SilcUInt32 data_len;
+				data = silc_mime_get_data(usericon, &data_len);
+				if (data) {
+					/* TODO: Check if SILC gives us something to use as the checksum instead */
+					purple_buddy_icons_set_for_user(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), g_memdup(data, data_len), data_len, NULL);
 				}
-				silc_mime_free(m);
 			}
+			silc_mime_free(usericon);
 		}
 #endif
 	}
@@ -1015,7 +1013,11 @@
 	silc_client_command_call(r->client, r->conn, NULL, "WATCH", "-pubkey",
 				 filename2, NULL);
 
+	silc_hash_free(hash);
 	silc_free(fingerprint);
+	silc_free(r->offline_pk);
+	if (r->public_key)
+	  silc_pkcs_public_key_free(r->public_key);
 	silc_free(r);
 }
 
@@ -1023,11 +1025,9 @@
 silcpurple_add_buddy_ask_import(void *user_data, const char *name)
 {
 	SilcPurpleBuddyRes r = (SilcPurpleBuddyRes)user_data;
-	SilcPublicKey public_key;
 
 	/* Load the public key */
-	if (!silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_PEM) &&
-	    !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) {
+	if (!silc_pkcs_load_public_key(name, &r->public_key)) {
 		silcpurple_add_buddy_ask_pk_cb(r, 0);
 		purple_notify_error(r->client->application,
 				  _("Add Buddy"), _("Could not load public key"), NULL);
@@ -1035,12 +1035,10 @@
 	}
 
 	/* Now verify the public key */
-	r->offline_pk = silc_pkcs_public_key_encode(public_key, &r->offline_pk_len);
+	r->offline_pk = silc_pkcs_public_key_encode(r->public_key, &r->offline_pk_len);
 	silcpurple_verify_public_key(r->client, r->conn, r->b->name,
-				   SILC_SOCKET_TYPE_CLIENT,
-				   r->offline_pk, r->offline_pk_len,
-				   SILC_SKE_PK_TYPE_SILC,
-				   silcpurple_add_buddy_save, r);
+				     SILC_CONN_CLIENT, r->public_key,
+				     silcpurple_add_buddy_save, r);
 }
 
 static void
@@ -1065,9 +1063,9 @@
 
 	/* Open file selector to select the public key. */
 	purple_request_file(r->client->application, _("Open..."), NULL, FALSE,
-			  G_CALLBACK(silcpurple_add_buddy_ask_import),
-			  G_CALLBACK(silcpurple_add_buddy_ask_pk_cancel),
-			  purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r);
+			    G_CALLBACK(silcpurple_add_buddy_ask_import),
+			    G_CALLBACK(silcpurple_add_buddy_ask_pk_cancel),
+			    purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r);
 
 }
 
@@ -1078,20 +1076,29 @@
 	g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not present in the network"),
 		   r->b->name);
 	purple_request_action(r->client->application, _("Add Buddy"), tmp,
-			    _("To add the buddy you must import his/her public key. "
-			      "Press Import to import a public key."), 0,
-				  purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r, 2,
-			    _("Cancel"), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb),
-			    _("_Import..."), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb));
+			      _("To add the buddy you must import his/her public key. "
+				"Press Import to import a public key."), 0,
+			      purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r, 2,
+			      _("Cancel"), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb),
+			      _("_Import..."), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb));
 }
 
-static void
-silcpurple_add_buddy_getkey_cb(SilcPurpleBuddyRes r,
-			     SilcClientCommandReplyContext cmd)
+static SilcBool
+silcpurple_add_buddy_getkey_cb(SilcClient client, SilcClientConnection conn,
+			       SilcCommand command, SilcStatus status,
+			       SilcStatus error, void *context, va_list ap)
 {
+	SilcPurpleBuddyRes r = context;
 	SilcClientEntry client_entry;
-	unsigned char *pk;
-	SilcUInt32 pk_len;
+
+	if (status != SILC_STATUS_OK) {
+		/* The buddy is offline/nonexistent. We will require user
+		   to associate a public key with the buddy or the buddy
+		   cannot be added. */
+		r->offline = TRUE;
+		silcpurple_add_buddy_ask_pk(r);
+		return FALSE;
+	}
 
 	/* Get the client entry. */
 	client_entry = silc_client_get_client_by_id(r->client, r->conn,
@@ -1102,16 +1109,14 @@
 		   cannot be added. */
 		r->offline = TRUE;
 		silcpurple_add_buddy_ask_pk(r);
-		return;
+		return FALSE;
 	}
 
 	/* Now verify the public key */
-	pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
 	silcpurple_verify_public_key(r->client, r->conn, client_entry->nickname,
-				   SILC_SOCKET_TYPE_CLIENT,
-				   pk, pk_len, SILC_SKE_PK_TYPE_SILC,
-				   silcpurple_add_buddy_save, r);
-	silc_free(pk);
+				     SILC_CONN_CLIENT, client_entry->public_key,
+				     silcpurple_add_buddy_save, r);
+	return TRUE;
 }
 
 static void
@@ -1120,6 +1125,7 @@
 	PurpleRequestField *f;
 	const GList *list;
 	SilcClientEntry client_entry;
+	SilcDList clients;
 
 	f = purple_request_fields_get_field(fields, "list");
 	list = purple_request_field_list_get_selected(f);
@@ -1131,7 +1137,11 @@
 	}
 
 	client_entry = purple_request_field_list_get_data(f, list->data);
-	silcpurple_add_buddy_resolved(r->client, r->conn, &client_entry, 1, r);
+	clients = silc_dlist_init();
+	silc_dlist_add(clients, client_entry);
+	silcpurple_add_buddy_resolved(r->client, r->conn, SILC_STATUS_OK,
+				      clients, r);
+	silc_dlist_uninit(clients);
 }
 
 static void
@@ -1143,16 +1153,14 @@
 }
 
 static void
-silcpurple_add_buddy_select(SilcPurpleBuddyRes r,
-			  SilcClientEntry *clients,
-			  SilcUInt32 clients_count)
+silcpurple_add_buddy_select(SilcPurpleBuddyRes r, SilcDList clients)
 {
 	PurpleRequestFields *fields;
 	PurpleRequestFieldGroup *g;
 	PurpleRequestField *f;
 	char tmp[512], tmp2[128];
-	int i;
 	char *fingerprint;
+	SilcClientEntry client_entry;
 
 	fields = purple_request_fields_new();
 	g = purple_request_field_group_new(NULL);
@@ -1161,56 +1169,56 @@
 	purple_request_field_list_set_multi_select(f, FALSE);
 	purple_request_fields_add_group(fields, g);
 
-	for (i = 0; i < clients_count; i++) {
+	silc_dlist_start(clients);
+	while ((client_entry = silc_dlist_get(clients))) {
 		fingerprint = NULL;
-		if (clients[i]->fingerprint) {
-			fingerprint = silc_fingerprint(clients[i]->fingerprint,
-						       clients[i]->fingerprint_len);
+		if (*client_entry->fingerprint) {
+			fingerprint = silc_fingerprint(client_entry->fingerprint, 20);
 			g_snprintf(tmp2, sizeof(tmp2), "\n%s", fingerprint);
 		}
 		g_snprintf(tmp, sizeof(tmp), "%s - %s (%s@%s)%s",
-			   clients[i]->realname, clients[i]->nickname,
-			   clients[i]->username, clients[i]->hostname ?
-			   clients[i]->hostname : "",
+			   client_entry->realname, client_entry->nickname,
+			   client_entry->username, *client_entry->hostname ?
+			   client_entry->hostname : "",
 			   fingerprint ? tmp2 : "");
-		purple_request_field_list_add(f, tmp, clients[i]);
+		purple_request_field_list_add(f, tmp, client_entry);
 		silc_free(fingerprint);
 	}
 
 	purple_request_fields(r->client->application, _("Add Buddy"),
-				_("Select correct user"),
-				r->pubkey_search
-					? _("More than one user was found with the same public key. Select "
-						"the correct user from the list to add to the buddy list.")
-					: _("More than one user was found with the same name. Select "
-						"the correct user from the list to add to the buddy list."),
-				fields,
-				_("OK"), G_CALLBACK(silcpurple_add_buddy_select_cb),
-				_("Cancel"), G_CALLBACK(silcpurple_add_buddy_select_cancel),
-				purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r);
+			      _("Select correct user"),
+			      r->pubkey_search
+			      ? _("More than one user was found with the same public key. Select "
+				  "the correct user from the list to add to the buddy list.")
+			      : _("More than one user was found with the same name. Select "
+				  "the correct user from the list to add to the buddy list."),
+			      fields,
+			      _("OK"), G_CALLBACK(silcpurple_add_buddy_select_cb),
+			      _("Cancel"), G_CALLBACK(silcpurple_add_buddy_select_cancel),
+			      purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r);
 }
 
 static void
 silcpurple_add_buddy_resolved(SilcClient client,
-			    SilcClientConnection conn,
-			    SilcClientEntry *clients,
-			    SilcUInt32 clients_count,
-			    void *context)
+			      SilcClientConnection conn,
+			      SilcStatus status,
+			      SilcDList clients,
+			      void *context)
 {
 	SilcPurpleBuddyRes r = context;
 	PurpleBuddy *b = r->b;
 	SilcAttributePayload pub;
 	SilcAttributeObjPk userpk;
-	unsigned char *pk;
-	SilcUInt32 pk_len;
 	const char *filename;
+	SilcClientEntry client_entry = NULL;
+	SilcUInt16 cmd_ident;
 
 	filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key");
 
 	/* If the buddy is offline/nonexistent, we will require user
 	   to associate a public key with the buddy or the buddy
 	   cannot be added. */
-	if (!clients_count) {
+	if (!clients) {
 		if (r->init) {
 			silc_free(r);
 			return;
@@ -1228,33 +1236,37 @@
 
 	/* If more than one client was found with nickname, we need to verify
 	   from user which one is the correct. */
-	if (clients_count > 1 && !r->pubkey_search) {
+	if (silc_dlist_count(clients) > 1 && !r->pubkey_search) {
 		if (r->init) {
 			silc_free(r);
 			return;
 		}
 
-		silcpurple_add_buddy_select(r, clients, clients_count);
+		silcpurple_add_buddy_select(r, clients);
 		return;
 	}
 
+	silc_dlist_start(clients);
+	client_entry = silc_dlist_get(clients);
+
 	/* If we searched using public keys and more than one entry was found
 	   the same person is logged on multiple times. */
-	if (clients_count > 1 && r->pubkey_search && b->name) {
+	if (silc_dlist_count(clients) > 1 && r->pubkey_search && b->name) {
 		if (r->init) {
 			/* Find the entry that closest matches to the
 			   buddy nickname. */
-			int i;
-			for (i = 0; i < clients_count; i++) {
-				if (!strncasecmp(b->name, clients[i]->nickname,
+			SilcClientEntry entry;
+			silc_dlist_start(clients);
+			while ((entry = silc_dlist_get(clients))) {
+				if (!strncasecmp(b->name, entry->nickname,
 						 strlen(b->name))) {
-					clients[0] = clients[i];
+					client_entry = entry;
 					break;
 				}
 			}
 		} else {
 			/* Verify from user which one is correct */
-			silcpurple_add_buddy_select(r, clients, clients_count);
+			silcpurple_add_buddy_select(r, clients);
 			return;
 		}
 	}
@@ -1262,61 +1274,60 @@
 	/* The client was found.  Now get its public key and verify
 	   that before adding the buddy. */
 	memset(&userpk, 0, sizeof(userpk));
-	b->proto_data = silc_memdup(clients[0]->id, sizeof(*clients[0]->id));
-	r->client_id = *clients[0]->id;
+	b->proto_data = silc_memdup(&client_entry->id, sizeof(client_entry->id));
+	r->client_id = client_entry->id;
 
 	/* Get the public key from attributes, if not present then
 	   resolve it with GETKEY unless we have it cached already. */
-	if (clients[0]->attrs && !clients[0]->public_key) {
-		pub = silcpurple_get_attr(clients[0]->attrs,
-					SILC_ATTRIBUTE_USER_PUBLIC_KEY);
+	if (client_entry->attrs && !client_entry->public_key) {
+		pub = silcpurple_get_attr(client_entry->attrs,
+					  SILC_ATTRIBUTE_USER_PUBLIC_KEY);
 		if (!pub || !silc_attribute_get_object(pub, (void *)&userpk,
 						       sizeof(userpk))) {
 			/* Get public key with GETKEY */
-			silc_client_command_call(client, conn, NULL,
-						 "GETKEY", clients[0]->nickname, NULL);
+			cmd_ident =
+			  silc_client_command_call(client, conn, NULL,
+						   "GETKEY", client_entry->nickname, NULL);
 			silc_client_command_pending(conn, SILC_COMMAND_GETKEY,
-						    conn->cmd_ident,
-						    (SilcCommandCb)silcpurple_add_buddy_getkey_cb,
+						    cmd_ident,
+						    silcpurple_add_buddy_getkey_cb,
 						    r);
 			return;
 		}
-		if (!silc_pkcs_public_key_decode(userpk.data, userpk.data_len,
-						 &clients[0]->public_key))
+		if (!silc_pkcs_public_key_alloc(SILC_PKCS_SILC,
+						userpk.data, userpk.data_len,
+						&client_entry->public_key))
 			return;
 		silc_free(userpk.data);
-	} else if (filename && !clients[0]->public_key) {
-		if (!silc_pkcs_load_public_key(filename, &clients[0]->public_key,
-					       SILC_PKCS_FILE_PEM) &&
-		    !silc_pkcs_load_public_key(filename, &clients[0]->public_key,
-					       SILC_PKCS_FILE_BIN)) {
+	} else if (filename && !client_entry->public_key) {
+		if (!silc_pkcs_load_public_key(filename, &client_entry->public_key)) {
 			/* Get public key with GETKEY */
-			silc_client_command_call(client, conn, NULL,
-						 "GETKEY", clients[0]->nickname, NULL);
+			cmd_ident =
+			  silc_client_command_call(client, conn, NULL,
+						   "GETKEY", client_entry->nickname, NULL);
 			silc_client_command_pending(conn, SILC_COMMAND_GETKEY,
-						    conn->cmd_ident,
-						    (SilcCommandCb)silcpurple_add_buddy_getkey_cb,
+						    cmd_ident,
+						    silcpurple_add_buddy_getkey_cb,
 						    r);
 			return;
 		}
-	} else if (!clients[0]->public_key) {
+	} else if (!client_entry->public_key) {
 		/* Get public key with GETKEY */
-		silc_client_command_call(client, conn, NULL,
-					 "GETKEY", clients[0]->nickname, NULL);
+		cmd_ident =
+		  silc_client_command_call(client, conn, NULL,
+					   "GETKEY", client_entry->nickname, NULL);
 		silc_client_command_pending(conn, SILC_COMMAND_GETKEY,
-					    conn->cmd_ident,
-					    (SilcCommandCb)silcpurple_add_buddy_getkey_cb,
+					    cmd_ident,
+					    silcpurple_add_buddy_getkey_cb,
 					    r);
 		return;
 	}
 
 	/* We have the public key, verify it. */
-	pk = silc_pkcs_public_key_encode(clients[0]->public_key, &pk_len);
-	silcpurple_verify_public_key(client, conn, clients[0]->nickname,
-				   SILC_SOCKET_TYPE_CLIENT,
-				   pk, pk_len, SILC_SKE_PK_TYPE_SILC,
-				   silcpurple_add_buddy_save, r);
-	silc_free(pk);
+	silcpurple_verify_public_key(client, conn, client_entry->nickname,
+				     SILC_CONN_CLIENT,
+				     client_entry->public_key,
+				     silcpurple_add_buddy_save, r);
 }
 
 static void
@@ -1344,10 +1355,7 @@
 		SilcPublicKey public_key;
 		SilcAttributeObjPk userpk;
 
-		if (!silc_pkcs_load_public_key(filename, &public_key,
-					       SILC_PKCS_FILE_PEM) &&
-		    !silc_pkcs_load_public_key(filename, &public_key,
-					       SILC_PKCS_FILE_BIN))
+		if (!silc_pkcs_load_public_key(filename, &public_key))
 			return;
 
 		/* Get all attributes, and use the public key to search user */
@@ -1632,12 +1640,13 @@
 						    sg->conn,
 						    buddy->proto_data);
 
-	if (client_entry && client_entry->send_key) {
+	if (client_entry &&
+	    silc_client_private_message_key_is_set(sg->client,
+						   sg->conn, client_entry)) {
 		act = purple_menu_action_new(_("Reset IM Key"),
 		                           PURPLE_CALLBACK(silcpurple_buddy_resetkey),
 		                           NULL, NULL);
 		m = g_list_append(m, act);
-
 	} else {
 		act = purple_menu_action_new(_("IM with Key Exchange"),
 		                           PURPLE_CALLBACK(silcpurple_buddy_keyagr),
@@ -1690,9 +1699,7 @@
 	SilcClientConnection conn = sg->conn;
 	SilcMime mime;
 	char type[32];
-	unsigned char *icon;
 	const char *t;
-	SilcAttributeObjMime obj;
 
 	/* Remove */
 	if (!img) {
@@ -1717,12 +1724,9 @@
 	silc_mime_add_field(mime, "Content-Type", type);
 	silc_mime_add_data(mime, purple_imgstore_get_data(img), purple_imgstore_get_size(img));
 
-	obj.mime = icon = silc_mime_encode(mime, &obj.mime_len);
-	if (obj.mime)
-		silc_client_attribute_add(client, conn, 
-					  SILC_ATTRIBUTE_USER_ICON, &obj, sizeof(obj));
+	silc_client_attribute_add(client, conn,
+				  SILC_ATTRIBUTE_USER_ICON, mime, sizeof(*mime));
 
-	silc_free(icon);
 	silc_mime_free(mime);
 }
 #endif