[PATCH] SILC prpl fixes

Pekka Riikonen priikone at iki.fi
Sat Jul 28 05:16:03 EDT 2007


Hello,

The enclosed patch fixes the following:

* Various crashes when SILC Toolkit fails to encode or decode a public key

* The laptop battery draining problem (bug in Red Hat bugzilla) because
   the SILC Toolkit is polled every few msecs.  Now it is truly event based
   and fixes the problem.  Old behavior is preserved for Toolkit's that
   doesn't support the feature.

 	Pekka
________________________________________________________________________
  Pekka Riikonen                                 priikone at silcnet.org
  Secure Internet Live Conferencing (SILC)       http://silcnet.org/
-------------- next part --------------
#
# old_revision [56ee47cf16ab80166a40a0a656778f158c6f1c59]
#
# patch "libpurple/protocols/silc/chat.c"
#  from [1ae8b183d4f656fe89a006ddd488d46043bc53c6]
#    to [469cc7777393ac90437b447a99baf65d5145401d]
# 
# patch "libpurple/protocols/silc/ops.c"
#  from [464ac0e6768a8f4badeb182e2bfef9b3ebc34e19]
#    to [9e7ac0c6b5e26d76032a4e514decd5c659b87678]
# 
# patch "libpurple/protocols/silc/pk.c"
#  from [a67b620a11231b9b218c27471db5765efed1a124]
#    to [d51e1c49b31e88f5a0d34afb6f4cc4b0170c9eb2]
# 
# patch "libpurple/protocols/silc/silc.c"
#  from [e6875f9a8cec199df09286d63dca544debb3d183]
#    to [148f5b3f738db98c9b95f8303c7f2714ad8abfcf]
# 
# patch "libpurple/protocols/silc/silcpurple.h"
#  from [83a974c5ca39f14d643ad5b512d67742e0ef7e75]
#    to [2740ea8368e4ace212817207c2acc3e3a61690d0]
# 
# patch "libpurple/protocols/silc/util.c"
#  from [dc180615f15f1f5b3128810202d21d5a06061a7b]
#    to [dd1c3ee1af03d94f6a285aed1a767a97acc5aee8]
#
============================================================
--- libpurple/protocols/silc/chat.c	1ae8b183d4f656fe89a006ddd488d46043bc53c6
+++ libpurple/protocols/silc/chat.c	469cc7777393ac90437b447a99baf65d5145401d
@@ -160,15 +160,17 @@ silcpurple_chat_getinfo(PurpleConnection
 		unsigned char *pk;
 		SilcUInt32 pk_len;
 		pk = silc_pkcs_public_key_encode(channel->founder_key, &pk_len);
-		fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
-		babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
+		if (pk) {
+			fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+			babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
 
-		g_string_append_printf(s, _("<br><b>Founder Key Fingerprint:</b><br>%s"), fingerprint);
-		g_string_append_printf(s, _("<br><b>Founder Key Babbleprint:</b><br>%s"), babbleprint);
+			g_string_append_printf(s, _("<br><b>Founder Key Fingerprint:</b><br>%s"), fingerprint);
+			g_string_append_printf(s, _("<br><b>Founder Key Babbleprint:</b><br>%s"), babbleprint);
 
-		silc_free(fingerprint);
-		silc_free(babbleprint);
-		silc_free(pk);
+			silc_free(fingerprint);
+			silc_free(babbleprint);
+			silc_free(pk);
+		}
 	}
 
 	buf = g_string_free(s, FALSE);
@@ -460,6 +462,8 @@ void silcpurple_chat_chauth_show(SilcPur
 	silc_dlist_start(channel_pubkeys);
 	while ((public_key = silc_dlist_get(channel_pubkeys))) {
 		pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+		if (!pk)
+			continue;
 		fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4);
 		babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4);
 
@@ -1013,9 +1017,6 @@ void silcpurple_chat_join(PurpleConnecti
 	SilcClient client = sg->client;
 	SilcClientConnection conn = sg->conn;
 	const char *channel, *passphrase, *parentch;
-#if 0
-	PurpleChat *chat;
-#endif
 
 	if (!conn)
 		return;
@@ -1071,22 +1072,6 @@ void silcpurple_chat_join(PurpleConnecti
 		return;
 	}
 
-#if 0
-	/* If the channel is not on buddy list, automatically add it there. */
-	chat = purple_blist_find_chat(sg->account, channel);
-	if (!chat) {
-		data = g_hash_table_new_full(g_str_hash, g_str_equal,
-					     g_free, g_free);
-		g_hash_table_replace(data, g_strdup("channel"),
-				     g_strdup(channel));
-		if (passphrase)
-		  g_hash_table_replace(data, g_strdup("passphrase"),
-				       g_strdup(passphrase));
-		chat = purple_chat_new(sg->account, NULL, data);
-		purple_blist_add_chat(chat, NULL, NULL);
-	}
-#endif
-
 	/* XXX We should have other properties here as well:
 	   1. whether to try to authenticate to the channel
 	     1a. with default key,
============================================================
--- libpurple/protocols/silc/ops.c	464ac0e6768a8f4badeb182e2bfef9b3ebc34e19
+++ libpurple/protocols/silc/ops.c	9e7ac0c6b5e26d76032a4e514decd5c659b87678
@@ -1274,13 +1274,15 @@ silc_command_reply(SilcClient client, Si
 				unsigned char *pk;
 				SilcUInt32 pk_len;
 				pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
-				fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
-				babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
-				purple_notify_user_info_add_pair(user_info, _("Public Key Fingerprint"), fingerprint);
-				purple_notify_user_info_add_pair(user_info, _("Public Key Babbleprint"), babbleprint);
-				silc_free(fingerprint);
-				silc_free(babbleprint);
-				silc_free(pk);
+				if (pk) {
+					fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+					babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
+					purple_notify_user_info_add_pair(user_info, _("Public Key Fingerprint"), fingerprint);
+					purple_notify_user_info_add_pair(user_info, _("Public Key Babbleprint"), babbleprint);
+					silc_free(fingerprint);
+					silc_free(babbleprint);
+					silc_free(pk);
+				}
 			}
 
 #if 0 /* XXX for now, let's not show attrs here */
@@ -1346,13 +1348,15 @@ silc_command_reply(SilcClient client, Si
 				unsigned char *pk;
 				SilcUInt32 pk_len;
 				pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
-				fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
-				babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
-				purple_notify_user_info_add_pair(user_info, _("Public Key Fingerprint"), fingerprint);
-				purple_notify_user_info_add_pair(user_info, _("Public Key Babbleprint"), babbleprint);
-				silc_free(fingerprint);
-				silc_free(babbleprint);
-				silc_free(pk);
+				if (pk) {
+					fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+					babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
+					purple_notify_user_info_add_pair(user_info, _("Public Key Fingerprint"), fingerprint);
+					purple_notify_user_info_add_pair(user_info, _("Public Key Babbleprint"), babbleprint);
+					silc_free(fingerprint);
+					silc_free(babbleprint);
+					silc_free(pk);
+				}
 			}
 
 			purple_notify_userinfo(gc, nickname, user_info, NULL, NULL);
============================================================
--- libpurple/protocols/silc/pk.c	a67b620a11231b9b218c27471db5765efed1a124
+++ libpurple/protocols/silc/pk.c	d51e1c49b31e88f5a0d34afb6f4cc4b0170c9eb2
@@ -158,6 +158,11 @@ void silcpurple_verify_public_key(SilcCl
 				    NULL, &hostname, &ip, &port);
 
 	pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+	if (!pk) {
+		if (completion)
+			completion(FALSE, context);
+		return;
+	}
 
 	if (conn_type == SILC_CONN_SERVER ||
 	    conn_type == SILC_CONN_ROUTER) {
============================================================
--- libpurple/protocols/silc/silc.c	e6875f9a8cec199df09286d63dca544debb3d183
+++ libpurple/protocols/silc/silc.c	148f5b3f738db98c9b95f8303c7f2714ad8abfcf
@@ -128,6 +128,7 @@ silcpurple_keepalive(PurpleConnection *g
 			 NULL, 0);
 }
 
+#if __SILC_TOOLKIT_VERSION < SILC_VERSION(1,1,1)
 static gboolean
 silcpurple_scheduler(gpointer *context)
 {
@@ -135,8 +136,99 @@ silcpurple_scheduler(gpointer *context)
 	silc_client_run_one(client);
 	return TRUE;
 }
+#else
+typedef struct {
+  guint tag;
+  SilcUInt32 fd;
+} *SilcPurpleFd;
 
+/* A timeout occurred.  Call SILC scheduler. */
+
+static gboolean
+silcpurple_scheduler_timeout(gpointer context)
+{
+	SilcClient client = (SilcClient)context;
+	silc_client_run_one(client);
+	return FALSE;
+}
+
+/* An fd task event occurred.  Call SILC scheduler. */
+
 static void
+silcpurple_scheduler_fd(gpointer data, gint fd, PurpleInputCondition cond)
+{
+	SilcClient client = (SilcClient)data;
+	silc_client_run_one(client);
+}
+
+/* SILC Scheduler notify callback.  This is called whenever task is added to
+   or deleted from SILC scheduler.  It's also called when fd task events
+   change.  Here we add same tasks to glib's main loop. */
+
+static void
+silcpurple_scheduler(SilcSchedule schedule,
+		     SilcBool added, SilcTask task,
+		     SilcBool fd_task, SilcUInt32 fd,
+		     SilcTaskEvent event,
+		     long seconds, long useconds,
+		     void *context)
+{
+	SilcClient client = (SilcClient)context;
+	PurpleConnection *gc = client->application;
+	SilcPurple sg = gc->proto_data;
+	SilcPurpleFd fdtask = NULL;
+
+	if (added) {
+	  if (fd_task) {
+	    /* Add fd or change fd events */
+	    PurpleInputCondition e = 0;
+
+	    silc_dlist_start(sg->fds);
+	    while ((fdtask = silc_dlist_get(sg->fds)))
+	      if (fdtask->fd == fd) {
+		purple_input_remove(fdtask->tag);
+		break;
+	      }
+
+	    if (event & SILC_TASK_READ)
+	      e |= PURPLE_INPUT_READ;
+	    if (event & SILC_TASK_WRITE)
+	      e |= PURPLE_INPUT_WRITE;
+
+	    if (e) {
+	      if (!fdtask) {
+		fdtask = silc_calloc(1, sizeof(*fdtask));
+		fdtask->fd = fd;
+		silc_dlist_add(sg->fds, fdtask);
+	      }
+	      fdtask->tag = purple_input_add(fd, e, silcpurple_scheduler_fd,
+					     client);
+	    } else if (fdtask) {
+	      silc_dlist_del(sg->fds, fdtask);
+	      silc_free(fdtask);
+	    }
+	  } else {
+	    /* Add timeout */
+	    purple_timeout_add((seconds * 1000) + (useconds / 1000),
+			       silcpurple_scheduler_timeout, client);
+	  }
+	} else {
+	  if (fd_task) {
+	    /* Remove fd */
+	    silc_dlist_start(sg->fds);
+	    while ((fdtask = silc_dlist_get(sg->fds)))
+	      if (fdtask->fd == fd) {
+		purple_input_remove(fdtask->tag);
+		silc_dlist_del(sg->fds, fdtask);
+		silc_free(fdtask);
+		break;
+	      }
+	  }
+	}
+}
+#endif /* __SILC_TOOLKIT_VERSION */
+
+static void
 silcpurple_connect_cb(SilcClient client, SilcClientConnection conn,
 		      SilcClientConnectionStatus status, SilcStatus error,
 		      const char *message, void *context)
@@ -324,21 +416,11 @@ static void silcpurple_running(SilcClien
 
 static void silcpurple_running(SilcClient client, void *context)
 {
-	PurpleAccount *account = context;
-	PurpleConnection *gc = account->gc;
-	SilcPurple sg;
+	SilcPurple sg = context;
+	PurpleConnection *gc = sg->gc;
+	PurpleAccount *account = purple_connection_get_account(gc);
 	char pkd[256], prd[256];
 
-	sg = silc_calloc(1, sizeof(*sg));
-	if (!sg)
-		return;
-	memset(sg, 0, sizeof(*sg));
-	sg->client = client;
-	sg->gc = gc;
-	sg->account = account;
-	sg->scheduler = SILC_PTR_TO_32(gc->proto_data);
-	gc->proto_data = sg;
-
 	/* Progress */
 	purple_connection_update_progress(gc, _("Connecting to SILC Server"), 1, 5);
 
@@ -375,10 +457,10 @@ silcpurple_login(PurpleAccount *account)
 {
 	SilcClient client;
 	PurpleConnection *gc;
+	SilcPurple sg;
 	SilcClientParams params;
 	const char *cipher, *hmac;
 	char *username, *hostname, *realname, **up;
-	guint scheduler;
 	int i;
 
 	gc = account->gc;
@@ -431,11 +513,21 @@ silcpurple_login(PurpleAccount *account)
 			break;
 		}
 
+	sg = silc_calloc(1, sizeof(*sg));
+	if (!sg)
+		return;
+	sg->client = client;
+	sg->gc = gc;
+	sg->account = account;
+	gc->proto_data = sg;
+
 	/* Init SILC client */
 	if (!silc_client_init(client, username, hostname, realname,
-			      silcpurple_running, account)) {
+			      silcpurple_running, sg)) {
 		gc->wants_to_die = TRUE;
 		purple_connection_error(gc, _("Cannot initialize SILC protocol"));
+		gc->proto_data = NULL;
+		silc_free(sg);
 		return;
 	}
 
@@ -443,18 +535,38 @@ silcpurple_login(PurpleAccount *account)
 	if (!silcpurple_check_silc_dir(gc)) {
 		gc->wants_to_die = TRUE;
 		purple_connection_error(gc, _("Error loading SILC key pair"));
+		gc->proto_data = NULL;
+		silc_free(sg);
 		return;
 	}
 
+#if __SILC_TOOLKIT_VERSION < SILC_VERSION(1,1,1)
 	/* Schedule SILC using Glib's event loop */
-	scheduler = purple_timeout_add(300, (GSourceFunc)silcpurple_scheduler, client);
-	gc->proto_data = SILC_32_TO_PTR(scheduler);
+	sg->scheduler = purple_timeout_add(300, (GSourceFunc)silcpurple_scheduler, client);
+#else
+	/* Run SILC scheduler */
+	sg->fds = silc_dlist_init();
+	silc_schedule_set_notify(client->schedule, silcpurple_scheduler,
+				 client);
+	silc_client_run_one(client);
+#endif /* __SILC_TOOLKIT_VERSION */
 }
 
 static int
 silcpurple_close_final(gpointer *context)
 {
 	SilcPurple sg = (SilcPurple)context;
+#if __SILC_TOOLKIT_VERSION >= SILC_VERSION(1,1,1)
+	SilcPurpleFd task;
+
+	silc_dlist_start(sg->fds);
+	while ((task = silc_dlist_get(sg->fds))) {
+	  g_source_remove_by_user_data(SILC_32_TO_PTR(task->fd));
+	  silc_free(task);
+	}
+	silc_dlist_uninit(sg->fds);
+#endif /* __SILC_TOOLKIT_VERSION */
+
 	silc_client_stop(sg->client, NULL, NULL);
 	silc_client_free(sg->client);
 	if (sg->mimeass)
============================================================
--- libpurple/protocols/silc/silcpurple.h	83a974c5ca39f14d643ad5b512d67742e0ef7e75
+++ libpurple/protocols/silc/silcpurple.h	2740ea8368e4ace212817207c2acc3e3a61690d0
@@ -35,6 +35,9 @@
 #include "server.h"
 #include "util.h"
 
+#undef SILC_VERSION
+#define SILC_VERSION(a, b, c) (((a) << 24) + ((b) << 16) + ((c) << 8))
+
 /* Default public and private key file names */
 #define SILCPURPLE_PUBLIC_KEY_NAME "public_key.pub"
 #define SILCPURPLE_PRIVATE_KEY_NAME "private_key.prv"
@@ -69,6 +72,7 @@ typedef struct SilcPurpleStruct {
 	SilcPublicKey public_key;
 	SilcPrivateKey private_key;
 
+	SilcDList fds;
 	guint scheduler;
 	PurpleConnection *gc;
 	PurpleAccount *account;
============================================================
--- libpurple/protocols/silc/util.c	dc180615f15f1f5b3128810202d21d5a06061a7b
+++ libpurple/protocols/silc/util.c	dd1c3ee1af03d94f6a285aed1a767a97acc5aee8
@@ -347,8 +347,12 @@ void silcpurple_show_public_key(SilcPurp
 	key_len = silc_pkcs_public_key_get_len(public_key);
 
 	pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+	if (!pk)
+	  return;
 	fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
 	babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
+	if (!fingerprint || !babbleprint)
+	  return;
 
 	s = g_string_new("");
 	if (ident->realname)


More information about the Devel mailing list