summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliott Sales de Andrade <qulogic@pidgin.im>2009-01-27 05:22:10 +0000
committerElliott Sales de Andrade <qulogic@pidgin.im>2009-01-27 05:22:10 +0000
commitb51f78ae386bb24292b037ccd956d07993574321 (patch)
treee3f880f0bd7a602169a539c16aff4c139f8180ac
parent14ac030847703a34a9cae06dde9b2de83f65ff2e (diff)
downloadpidgin-b51f78ae386bb24292b037ccd956d07993574321.tar.gz
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.
-rw-r--r--ChangeLog1
-rw-r--r--libpurple/protocols/msn/cmdproc.c71
-rw-r--r--libpurple/protocols/msn/cmdproc.h2
-rw-r--r--libpurple/protocols/msn/msg.h2
4 files changed, 70 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index d6f5ecbd8e..27e41e8105 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/libpurple/protocols/msn/cmdproc.c b/libpurple/protocols/msn/cmdproc.c
index 5cb8b9eaf1..e487c77a66 100644
--- a/libpurple/protocols/msn/cmdproc.c
+++ b/libpurple/protocols/msn/cmdproc.c
@@ -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,6 +240,61 @@ void
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 @@ msn_cmdproc_process_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
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
diff --git a/libpurple/protocols/msn/cmdproc.h b/libpurple/protocols/msn/cmdproc.h
index 3302603188..11a71eed99 100644
--- a/libpurple/protocols/msn/cmdproc.h
+++ b/libpurple/protocols/msn/cmdproc.h
@@ -46,6 +46,8 @@ struct _MsnCmdProc
MsnHistory *history;
+ GHashTable *multiparts; /**< Multi-part message ID's */
+
void *data; /**< Extra data, like the switchboard. */
};
diff --git a/libpurple/protocols/msn/msg.h b/libpurple/protocols/msn/msg.h
index 1123183d08..e24cf1b16d 100644
--- a/libpurple/protocols/msn/msg.h
+++ b/libpurple/protocols/msn/msg.h
@@ -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;