Mercurial > pidgin
diff libpurple/protocols/msn/cmdproc.c @ 25377:0ffa511ac165
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.
author | Elliott Sales de Andrade <qulogic@pidgin.im> |
---|---|
date | Tue, 27 Jan 2009 05:22:10 +0000 |
parents | e069c16db597 |
children | 1977e930ab03 |
line wrap: on
line diff
--- 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