# HG changeset patch # User Elliott Sales de Andrade # Date 1233033730 0 # Node ID 0ffa511ac1654d66dfc2f66b63641d24a211c526 # Parent a1c4ae9a2fcc61024167d4f93ce8eefe5b8d4b1f 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. diff -r a1c4ae9a2fcc -r 0ffa511ac165 ChangeLog --- a/ChangeLog Tue Jan 27 04:54:13 2009 +0000 +++ b/ChangeLog Tue Jan 27 05:22:10 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 diff -r a1c4ae9a2fcc -r 0ffa511ac165 libpurple/protocols/msn/cmdproc.c --- a/libpurple/protocols/msn/cmdproc.c Tue Jan 27 04:54:13 2009 +0000 +++ b/libpurple/protocols/msn/cmdproc.c Tue Jan 27 05:22:10 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 diff -r a1c4ae9a2fcc -r 0ffa511ac165 libpurple/protocols/msn/cmdproc.h --- a/libpurple/protocols/msn/cmdproc.h Tue Jan 27 04:54:13 2009 +0000 +++ b/libpurple/protocols/msn/cmdproc.h Tue Jan 27 05:22:10 2009 +0000 @@ -46,6 +46,8 @@ MsnHistory *history; + GHashTable *multiparts; /**< Multi-part message ID's */ + void *data; /**< Extra data, like the switchboard. */ }; diff -r a1c4ae9a2fcc -r 0ffa511ac165 libpurple/protocols/msn/msg.h --- a/libpurple/protocols/msn/msg.h Tue Jan 27 04:54:13 2009 +0000 +++ b/libpurple/protocols/msn/msg.h Tue Jan 27 05:22:10 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;