changeset 25002:c7e4ec5c30b1

merge of '6922052516b4de648838827a2c1806840619d49a' and 'a2f4d295f1d985858eacada121adb414f6cc924b'
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Tue, 27 Jan 2009 05:23:38 +0000
parents f648144bc93d (current diff) 0ffa511ac165 (diff)
children 86ba0d87c04b
files
diffstat 7 files changed, 111 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Jan 27 04:22:53 2009 +0000
+++ b/ChangeLog	Tue Jan 27 05:23:38 2009 +0000
@@ -5,6 +5,7 @@
 	* Fix transfer of buddy icons, custom smileys and files from the
 	latest WLM 9 official client. (Thomas Gibson-Robinson)
 	* Fix a crash when removing an account with an unknown protocol id.
+	* Large (multi-part) messages on MSN are now correctly re-combined.
 
 	Finch:
 	* Allow rebinding keys to change the focused widget (details in the
--- a/libpurple/certificate.c	Tue Jan 27 04:22:53 2009 +0000
+++ b/libpurple/certificate.c	Tue Jan 27 05:23:38 2009 +0000
@@ -1546,31 +1546,11 @@
 void
 purple_certificate_uninit(void)
 {
-	GList *full_list, *l;
-
-	/* Unregister all Schemes */
-	full_list = g_list_copy(cert_schemes); /* Make a working copy */
-	for (l = full_list; l; l = l->next) {
-		purple_certificate_unregister_scheme(
-			(PurpleCertificateScheme *) l->data );
-	}
-	g_list_free(full_list);
-
 	/* Unregister all Verifiers */
-	full_list = g_list_copy(cert_verifiers); /* Make a working copy */
-	for (l = full_list; l; l = l->next) {
-		purple_certificate_unregister_verifier(
-			(PurpleCertificateVerifier *) l->data );
-	}
-	g_list_free(full_list);
+	g_list_foreach(cert_verifiers, (GFunc)purple_certificate_unregister_verifier, NULL);
 
 	/* Unregister all Pools */
-	full_list = g_list_copy(cert_pools); /* Make a working copy */
-	for (l = full_list; l; l = l->next) {
-		purple_certificate_unregister_pool(
-			(PurpleCertificatePool *) l->data );
-	}
-	g_list_free(full_list);
+	g_list_foreach(cert_pools, (GFunc)purple_certificate_unregister_pool, NULL);
 }
 
 gpointer
--- a/libpurple/core.c	Tue Jan 27 04:22:53 2009 +0000
+++ b/libpurple/core.c	Tue Jan 27 05:23:38 2009 +0000
@@ -198,6 +198,14 @@
 	/* Transmission ends */
 	purple_connections_disconnect_all();
 
+	/*
+	 * Certificates must be destroyed before the SSL plugins, because
+	 * PurpleCertificates contain pointers to PurpleCertificateSchemes,
+	 * and the PurpleCertificateSchemes will be unregistered when the
+	 * SSL plugin is uninit.
+	 */
+	purple_certificate_uninit();
+
 	/* The SSL plugins must be uninit before they're unloaded */
 	purple_ssl_uninit();
 
@@ -220,7 +228,6 @@
 	purple_notify_uninit();
 	purple_conversations_uninit();
 	purple_connections_uninit();
-	purple_certificate_uninit();
 	purple_buddy_icons_uninit();
 	purple_accounts_uninit();
 	purple_savedstatuses_uninit();
--- a/libpurple/dbus-analyze-functions.py	Tue Jan 27 04:22:53 2009 +0000
+++ b/libpurple/dbus-analyze-functions.py	Tue Jan 27 05:23:38 2009 +0000
@@ -117,7 +117,7 @@
             self.params.append(Parameter.fromtokens(paramtexts[i].split(), i))
 
         self.call = "%s(%s)" % (self.function.name,
-                                ", ".join([param.name for param in self.params]))
+                                ", ".join(param.name for param in self.params))
         
     
     def process(self):
@@ -160,6 +160,10 @@
             elif type[0].startswith("Purple") or type[0] == "xmlnode":
                 return self.inputpurplestructure(type, name)
 
+            # special case for *_get_data functions, be careful here...
+            elif (type[0] == "size_t") and (name == "len"):
+                return self.inputgetdata(type, name)
+            
             # unknown pointers are always replaced with NULL
             else:
                 return self.inputpointer(type, name)
@@ -196,6 +200,10 @@
             if type[0] in ["GList", "GSList"]:
                 return self.outputlist(type, name)
 
+        # Special case for *_get_data functions
+        if type[0] == "gconstpointer":
+            return self.outputgetdata(type, name)
+
         raise myexception
     
 
@@ -309,7 +317,13 @@
         self.returncode.append("return garray_int_to_%s(%s);" %
                                (type[0].lower(), name));
 
- 
+    # Special case for *_get_data functions, don't need client bindings,
+    #  but do need the name so it doesn't crash
+    def inputgetdata(self, type, name):
+        raise myexception
+    def outputgetdata(self, type, name):
+        raise myexception
+
 class ServerBinding (Binding):
     def __init__(self, functiontext, paramtexts):
         Binding.__init__(self, functiontext, paramtexts)
@@ -475,6 +489,21 @@
                               % (name, name))
             self.addouttype("ai", name)
 
+    # Special case for *_get_data functions
+    def inputgetdata(self, type, name):
+        self.cdecls.append("\tsize_t %s = 0;" % name)
+        return True
+    def outputgetdata(self, type, name):
+        # This is a total hack, but self.call is set up before the parameters
+        #  are processed, so we can't tell it to pass a parameter by reference.
+        self.call = "%s(%s)" % (self.function.name,
+                                ", ".join(param.name if param.name != "len" else "&len" for param in self.params))
+
+        self.cdecls.append("\tgconstpointer %s;" % name)
+        self.ccode.append("\t%s = %s;" % (name, self.call))
+        self.cparamsout.append("DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &%s, %s" \
+                               % (name, "len"))
+        self.addouttype("ay", name)
 
 class BindingSet:
     regexp = r"^(\w[^()]*)\(([^()]*)\)\s*;\s*$";
--- a/libpurple/protocols/msn/cmdproc.c	Tue Jan 27 04:22:53 2009 +0000
+++ b/libpurple/protocols/msn/cmdproc.c	Tue Jan 27 05:23:38 2009 +0000
@@ -35,6 +35,9 @@
 	cmdproc->txqueue = g_queue_new();
 	cmdproc->history = msn_history_new();
 
+	cmdproc->multiparts = g_hash_table_new_full(g_str_hash, g_str_equal,
+	                                            NULL, (GDestroyNotify)msn_message_unref);
+
 	return cmdproc;
 }
 
@@ -53,6 +56,8 @@
 	if (cmdproc->last_cmd != NULL)
 		msn_command_destroy(cmdproc->last_cmd);
 
+	g_hash_table_destroy(cmdproc->multiparts);
+
 	g_free(cmdproc);
 }
 
@@ -235,6 +240,61 @@
 msn_cmdproc_process_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
 {
 	MsnMsgTypeCb cb;
+	const char *messageId = NULL;
+
+	/* Multi-part messages */
+	if ((messageId = msn_message_get_attr(msg, "Message-ID")) != NULL) {
+		const char *chunk_text = msn_message_get_attr(msg, "Chunks");
+		guint chunk;
+		if (chunk_text != NULL) {
+			chunk = strtol(chunk_text, NULL, 10);
+			/* 1024 chunks of ~1300 bytes is ~1MB, which seems OK to prevent 
+			   some random client causing pidgin to hog a ton of memory.
+			   Probably should figure out the maximum that the official client
+			   actually supports, though. */
+			if (chunk > 0 && chunk < 1024) {
+				msg->total_chunks = chunk;
+				msg->received_chunks = 1;
+				g_hash_table_insert(cmdproc->multiparts, (gpointer)messageId, msn_message_ref(msg));
+				purple_debug_info("msn", "Received chunked message, messageId: '%s', total chunks: %d\n",
+				                  messageId, chunk);
+			} else {
+				purple_debug_error("msn", "MessageId '%s' has too many chunks: %d\n", messageId, chunk);
+			}
+			return;
+		} else {
+			chunk_text = msn_message_get_attr(msg, "Chunk");
+			if (chunk_text != NULL) {
+				MsnMessage *first = g_hash_table_lookup(cmdproc->multiparts, messageId);
+				chunk = strtol(chunk_text, NULL, 10);
+				if (first == NULL) {
+					purple_debug_error("msn",
+					                   "Unable to find first chunk of messageId '%s' to correspond with chunk %d.\n",
+					                   messageId, chunk+1);
+				} else if (first->received_chunks == chunk) {
+					/* Chunk is from 1 to total-1 (doesn't count first one) */
+					purple_debug_info("msn", "Received chunk %d of %d, messageId: '%s'\n",
+					                  chunk+1, first->total_chunks, messageId);
+					first->body = g_realloc(first->body, first->body_len + msg->body_len);
+					memcpy(first->body + first->body_len, msg->body, msg->body_len);
+					first->body_len += msg->body_len;
+					first->received_chunks++;
+					if (first->received_chunks != first->total_chunks)
+						return;
+					else
+						/* We're done! Send it along... The caller takes care of
+						   freeing the old one. */
+						msg = first;
+				} else {
+					/* TODO: Can you legitimately receive chunks out of order? */
+					g_hash_table_remove(cmdproc->multiparts, messageId);
+					return;
+				}
+			} else {
+				purple_debug_error("msn", "Received MessageId '%s' with no chunk number!\n", messageId);
+			}
+		}
+	}
 
 	if (msn_message_get_content_type(msg) == NULL)
 	{
@@ -245,15 +305,14 @@
 	cb = g_hash_table_lookup(cmdproc->cbs_table->msgs,
 							 msn_message_get_content_type(msg));
 
-	if (cb == NULL)
-	{
+	if (cb != NULL)
+		cb(cmdproc, msg);
+	else
 		purple_debug_warning("msn", "Unhandled content-type '%s'\n",
 						   msn_message_get_content_type(msg));
 
-		return;
-	}
-
-	cb(cmdproc, msg);
+	if (messageId != NULL)
+		g_hash_table_remove(cmdproc->multiparts, messageId);
 }
 
 void
--- a/libpurple/protocols/msn/cmdproc.h	Tue Jan 27 04:22:53 2009 +0000
+++ b/libpurple/protocols/msn/cmdproc.h	Tue Jan 27 05:23:38 2009 +0000
@@ -46,6 +46,8 @@
 
 	MsnHistory *history;
 
+	GHashTable *multiparts; /**< Multi-part message ID's */
+
 	void *data; /**< Extra data, like the switchboard. */
 };
 
--- a/libpurple/protocols/msn/msg.h	Tue Jan 27 04:22:53 2009 +0000
+++ b/libpurple/protocols/msn/msg.h	Tue Jan 27 05:23:38 2009 +0000
@@ -109,6 +109,8 @@
 	char *charset;
 	char *body;
 	gsize body_len;
+	guint total_chunks;   /**< How many chunks in this multi-part message */
+	guint received_chunks; /**< How many chunks we've received so far */
 
 	MsnSlpHeader msnslp_header;
 	MsnSlpFooter msnslp_footer;