pidgin: a2f4d295: Re-combine large (multi-part) messages o...

qulogic at pidgin.im qulogic at pidgin.im
Tue Jan 27 00:25:44 EST 2009


-----------------------------------------------------------------
Revision: a2f4d295f1d985858eacada121adb414f6cc924b
Ancestor: 33bcab783c3ff4bedbd9ffdfdb29f232a0d6e8b9
Author: qulogic at pidgin.im
Date: 2009-01-27T05:22:10
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/a2f4d295f1d985858eacada121adb414f6cc924b

Modified files:
        ChangeLog libpurple/protocols/msn/cmdproc.c
        libpurple/protocols/msn/cmdproc.h
        libpurple/protocols/msn/msg.h

ChangeLog: 

Re-combine large (multi-part) messages on MSN since we seem to say that we
do support receiving chunked messages.

References #393, though not the same as the patch in the ticket.

-------------- next part --------------
============================================================
--- ChangeLog	9061088e68eb10d8d6d7243f0598ba91b0e3aa49
+++ ChangeLog	256e2933978e764565acd28e12b5947db99bc811
@@ -5,6 +5,7 @@ version 2.5.5 (??/??/????):
 	* 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
============================================================
--- libpurple/protocols/msn/cmdproc.c	af0cf762cdce653bb98d968b8159bc8ff0f3ead8
+++ libpurple/protocols/msn/cmdproc.c	26f32ef7f803692995d9028c0655440151d22168
@@ -35,6 +35,9 @@ msn_cmdproc_new(MsnSession *session)
 	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 @@ msn_cmdproc_destroy(MsnCmdProc *cmdproc)
 	if (cmdproc->last_cmd != NULL)
 		msn_command_destroy(cmdproc->last_cmd);
 
+	g_hash_table_destroy(cmdproc->multiparts);
+
 	g_free(cmdproc);
 }
 
@@ -235,7 +240,62 @@ msn_cmdproc_process_msg(MsnCmdProc *cmdp
 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)
 	{
 		purple_debug_misc("msn", "failed to find message content\n");
@@ -245,15 +305,14 @@ msn_cmdproc_process_msg(MsnCmdProc *cmdp
 	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
============================================================
--- libpurple/protocols/msn/cmdproc.h	14484cdc00317352590dcc0dd06a0cbb9999caf2
+++ libpurple/protocols/msn/cmdproc.h	44bca181258d427bd44cf3a430fac597a58bef58
@@ -46,6 +46,8 @@ struct _MsnCmdProc
 
 	MsnHistory *history;
 
+	GHashTable *multiparts; /**< Multi-part message ID's */
+
 	void *data; /**< Extra data, like the switchboard. */
 };
 
============================================================
--- libpurple/protocols/msn/msg.h	80aaa015f0a2fc7191b4f67b7232841ea326be6a
+++ libpurple/protocols/msn/msg.h	532196ca4e57132ff397d5b529b6b7299eba3c1f
@@ -109,6 +109,8 @@ struct _MsnMessage
 	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;


More information about the Commits mailing list