changeset 21044:6b02dba5bf41

Patch from Pekka Riikone to fix various SILC issues. Fixes: #3103
author Ethan Blanton <elb@pidgin.im>
date Mon, 29 Oct 2007 00:19:53 +0000
parents 6b9e304272e4
children daf98e539358
files libpurple/protocols/silc/chat.c libpurple/protocols/silc/ops.c libpurple/protocols/silc/pk.c libpurple/protocols/silc/silc.c libpurple/protocols/silc/silcpurple.h libpurple/protocols/silc/util.c libpurple/protocols/silc/wb.c
diffstat 7 files changed, 217 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/silc/chat.c	Mon Oct 29 00:09:18 2007 +0000
+++ b/libpurple/protocols/silc/chat.c	Mon Oct 29 00:19:53 2007 +0000
@@ -160,15 +160,17 @@
 		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 @@
 	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 @@
 	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 @@
 		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,
@@ -1320,7 +1305,7 @@
 				ret =
 			 	silc_client_send_channel_message(client, conn,
 								 channel, key,
-								 flags, NULL,
+								 flags, sg->sha1hash,
 								 buf->data,
 								 silc_buffer_len(buf));
 			silc_mime_partial_free(list);
@@ -1334,7 +1319,8 @@
 
 	/* Send channel message */
 	ret = silc_client_send_channel_message(client, conn, channel, key,
-					       flags, NULL, (unsigned char *)msg2,
+					       flags, sg->sha1hash,
+					       (unsigned char *)msg2,
 					       strlen(msg2));
 	if (ret) {
 		serv_got_chat_in(gc, id, purple_connection_get_display_name(gc), 0, msg,
--- a/libpurple/protocols/silc/ops.c	Mon Oct 29 00:09:18 2007 +0000
+++ b/libpurple/protocols/silc/ops.c	Mon Oct 29 00:19:53 2007 +0000
@@ -1274,13 +1274,15 @@
 				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 @@
 				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);
--- a/libpurple/protocols/silc/pk.c	Mon Oct 29 00:09:18 2007 +0000
+++ b/libpurple/protocols/silc/pk.c	Mon Oct 29 00:19:53 2007 +0000
@@ -158,6 +158,11 @@
 				    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) {
--- a/libpurple/protocols/silc/silc.c	Mon Oct 29 00:09:18 2007 +0000
+++ b/libpurple/protocols/silc/silc.c	Mon Oct 29 00:19:53 2007 +0000
@@ -128,6 +128,7 @@
 			 NULL, 0);
 }
 
+#if __SILC_TOOLKIT_VERSION < SILC_VERSION(1,1,1)
 static gboolean
 silcpurple_scheduler(gpointer *context)
 {
@@ -135,6 +136,105 @@
 	silc_client_run_one(client);
 	return TRUE;
 }
+#else
+typedef struct {
+  SilcPurple sg;
+  SilcUInt32 fd;
+  guint tag;
+} *SilcPurpleTask;
+
+/* A timeout occurred.  Call SILC scheduler. */
+
+static gboolean
+silcpurple_scheduler_timeout(gpointer context)
+{
+	SilcPurpleTask task = (SilcPurpleTask)context;
+	silc_client_run_one(task->sg->client);
+	silc_dlist_del(task->sg->tasks, task);
+	silc_free(task);
+	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;
+	SilcPurpleTask ptask = NULL;
+
+	if (added) {
+	  if (fd_task) {
+	    /* Add fd or change fd events */
+	    PurpleInputCondition e = 0;
+
+	    silc_dlist_start(sg->tasks);
+	    while ((ptask = silc_dlist_get(sg->tasks)))
+	      if (ptask->fd == fd) {
+		purple_input_remove(ptask->tag);
+		break;
+	      }
+
+	    if (event & SILC_TASK_READ)
+	      e |= PURPLE_INPUT_READ;
+	    if (event & SILC_TASK_WRITE)
+	      e |= PURPLE_INPUT_WRITE;
+
+	    if (e) {
+	      if (!ptask) {
+		ptask = silc_calloc(1, sizeof(*ptask));
+		ptask->fd = fd;
+		silc_dlist_add(sg->tasks, ptask);
+	      }
+	      ptask->tag = purple_input_add(fd, e, silcpurple_scheduler_fd,
+					    client);
+	    } else if (ptask) {
+	      silc_dlist_del(sg->tasks, ptask);
+	      silc_free(ptask);
+	    }
+	  } else {
+	    /* Add timeout */
+	    ptask = silc_calloc(1, sizeof(*ptask));
+	    ptask->sg = sg;
+	    ptask->tag = purple_timeout_add((seconds * 1000) +
+					    (useconds / 1000),
+					    silcpurple_scheduler_timeout,
+					    ptask);
+	    silc_dlist_add(sg->tasks, ptask);
+	  }
+	} else {
+	  if (fd_task) {
+	    /* Remove fd */
+	    silc_dlist_start(sg->tasks);
+	    while ((ptask = silc_dlist_get(sg->tasks)))
+	      if (ptask->fd == fd) {
+		purple_input_remove(ptask->tag);
+		silc_dlist_del(sg->tasks, ptask);
+		silc_free(ptask);
+		break;
+	      }
+	  }
+	}
+}
+#endif /* __SILC_TOOLKIT_VERSION */
 
 static void
 silcpurple_connect_cb(SilcClient client, SilcClientConnection conn,
@@ -316,6 +416,8 @@
 		return;
 	}
 
+	silc_hash_alloc("sha1", &sg->sha1hash);
+
 	/* Wrap socket to TCP stream */
 	silc_socket_tcp_stream_create(source, TRUE, FALSE,
 				      sg->client->schedule,
@@ -324,21 +426,11 @@
 
 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 +467,10 @@
 {
 	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 +523,21 @@
 			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,20 +545,32 @@
 	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->tasks = 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;
+
 	silc_client_stop(sg->client, NULL, NULL);
 	silc_client_free(sg->client);
+	if (sg->sha1hash)
+		silc_hash_free(sg->sha1hash);
 	if (sg->mimeass)
 		silc_mime_assembler_free(sg->mimeass);
 	silc_free(sg);
@@ -467,16 +581,33 @@
 silcpurple_close(PurpleConnection *gc)
 {
 	SilcPurple sg = gc->proto_data;
+#if __SILC_TOOLKIT_VERSION >= SILC_VERSION(1,1,1)
+	SilcPurpleTask task;
+#endif /* __SILC_TOOLKIT_VERSION */
 
 	g_return_if_fail(sg != NULL);
 
 	/* Send QUIT */
 	silc_client_command_call(sg->client, sg->conn, NULL,
-				 "QUIT", "Download Pidgin: " PURPLE_WEBSITE, NULL);
+				 "QUIT", "Download Pidgin: " PURPLE_WEBSITE,
+				 NULL);
 
 	if (sg->conn)
 		silc_client_close_connection(sg->client, sg->conn);
 
+#if __SILC_TOOLKIT_VERSION >= SILC_VERSION(1,1,1)
+	if (sg->conn)
+	  silc_client_run_one(sg->client);
+	silc_schedule_set_notify(sg->client->schedule, NULL, NULL);
+
+	silc_dlist_start(sg->tasks);
+	while ((task = silc_dlist_get(sg->tasks))) {
+	  purple_input_remove(task->tag);
+	  silc_free(task);
+	}
+	silc_dlist_uninit(sg->tasks);
+#endif /* __SILC_TOOLKIT_VERSION */
+
 	purple_timeout_remove(sg->scheduler);
 	purple_timeout_add(1, (GSourceFunc)silcpurple_close_final, sg);
 }
@@ -1155,7 +1286,7 @@
 			silc_dlist_start(list);
 			while ((buf = silc_dlist_get(list)) != SILC_LIST_END)
 				silc_client_send_private_message(client, conn,
-								 client_entry, im->flags, NULL,
+								 client_entry, im->flags, sg->sha1hash,
 								 buf->data,
 								 silc_buffer_len(buf));
 			silc_mime_partial_free(list);
@@ -1167,7 +1298,7 @@
 
 	/* Send the message */
 	silc_client_send_private_message(client, conn, client_entry, im->flags,
-					 NULL, (unsigned char *)im->message, im->message_len);
+					 sg->sha1hash, (unsigned char *)im->message, im->message_len);
 	purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname,
 			     im->message, 0, time(NULL));
 	goto out;
@@ -1259,7 +1390,7 @@
 			while ((buf = silc_dlist_get(list)) != SILC_LIST_END)
 				ret =
 			 	silc_client_send_private_message(client, conn,
-								 client_entry, mflags, NULL,
+								 client_entry, mflags, sg->sha1hash,
 								 buf->data,
 								 silc_buffer_len(buf));
 			silc_mime_partial_free(list);
@@ -1271,7 +1402,7 @@
 
 	/* Send private message directly */
 	ret = silc_client_send_private_message(client, conn, client_entry,
-					       mflags, NULL,
+					       mflags, sg->sha1hash,
 					       (unsigned char *)msg,
 					       strlen(msg));
 
--- a/libpurple/protocols/silc/silcpurple.h	Mon Oct 29 00:09:18 2007 +0000
+++ b/libpurple/protocols/silc/silcpurple.h	Mon Oct 29 00:19:53 2007 +0000
@@ -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"
@@ -68,7 +71,9 @@
 	SilcClientConnection conn;
 	SilcPublicKey public_key;
 	SilcPrivateKey private_key;
+	SilcHash sha1hash;
 
+	SilcDList tasks;
 	guint scheduler;
 	PurpleConnection *gc;
 	PurpleAccount *account;
--- a/libpurple/protocols/silc/util.c	Mon Oct 29 00:09:18 2007 +0000
+++ b/libpurple/protocols/silc/util.c	Mon Oct 29 00:19:53 2007 +0000
@@ -347,8 +347,12 @@
 	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)
--- a/libpurple/protocols/silc/wb.c	Mon Oct 29 00:09:18 2007 +0000
+++ b/libpurple/protocols/silc/wb.c	Mon Oct 29 00:19:53 2007 +0000
@@ -254,10 +254,10 @@
 
 static void
 silcpurple_wb_request(SilcClient client, const unsigned char *message,
-		    SilcUInt32 message_len, SilcClientEntry sender,
-		    SilcChannelEntry channel)
+		      SilcUInt32 message_len, SilcClientEntry sender,
+		      SilcChannelEntry channel)
 {
-	char tmp[128];
+	char tmp[256];
 	SilcPurpleWbRequest req;
 	PurpleConnection *gc;
 	SilcPurple sg;
@@ -274,20 +274,24 @@
 		else
 			wb = silcpurple_wb_init_ch(sg, channel);
 
-		silcpurple_wb_parse(wb->proto_data, wb, (unsigned char *)message,
-				  message_len);
+		silcpurple_wb_parse(wb->proto_data, wb,
+				    (unsigned char *)message,
+				    message_len);
 		return;
 	}
 
+	/* Close any previous unaccepted requests */
+	purple_request_close_with_handle(sender);
+
 	if (!channel) {
 		g_snprintf(tmp, sizeof(tmp),
-			_("%s sent message to whiteboard. Would you like "
-			  "to open the whiteboard?"), sender->nickname);
+			   _("%s sent message to whiteboard. Would you like "
+			     "to open the whiteboard?"), sender->nickname);
 	} else {
 		g_snprintf(tmp, sizeof(tmp),
-			_("%s sent message to whiteboard on %s channel. "
-			  "Would you like to open the whiteboard?"),
-			sender->nickname, channel->channel_name);
+			   _("%s sent message to whiteboard on %s channel. "
+			     "Would you like to open the whiteboard?"),
+			   sender->nickname, channel->channel_name);
 	}
 
 	req = silc_calloc(1, sizeof(*req));
@@ -299,10 +303,10 @@
 	req->channel = channel;
 	req->sg = sg;
 
-	purple_request_action(gc, _("Whiteboard"), tmp, NULL, 1,
-				sg->account, sender->nickname, NULL, req, 2,
-			    _("Yes"), G_CALLBACK(silcpurple_wb_request_cb),
-			    _("No"), G_CALLBACK(silcpurple_wb_request_cb));
+	purple_request_action(sender, _("Whiteboard"), tmp, NULL, 1,
+			      sg->account, sender->nickname, NULL, req, 2,
+			      _("Yes"), G_CALLBACK(silcpurple_wb_request_cb),
+			      _("No"), G_CALLBACK(silcpurple_wb_request_cb));
 }
 
 /* Process incoming whiteboard message */