Mercurial > pidgin
comparison 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 |
comparison
equal
deleted
inserted
replaced
25376:a1c4ae9a2fcc | 25377:0ffa511ac165 |
---|---|
33 | 33 |
34 cmdproc->session = session; | 34 cmdproc->session = session; |
35 cmdproc->txqueue = g_queue_new(); | 35 cmdproc->txqueue = g_queue_new(); |
36 cmdproc->history = msn_history_new(); | 36 cmdproc->history = msn_history_new(); |
37 | 37 |
38 cmdproc->multiparts = g_hash_table_new_full(g_str_hash, g_str_equal, | |
39 NULL, (GDestroyNotify)msn_message_unref); | |
40 | |
38 return cmdproc; | 41 return cmdproc; |
39 } | 42 } |
40 | 43 |
41 void | 44 void |
42 msn_cmdproc_destroy(MsnCmdProc *cmdproc) | 45 msn_cmdproc_destroy(MsnCmdProc *cmdproc) |
50 | 53 |
51 msn_history_destroy(cmdproc->history); | 54 msn_history_destroy(cmdproc->history); |
52 | 55 |
53 if (cmdproc->last_cmd != NULL) | 56 if (cmdproc->last_cmd != NULL) |
54 msn_command_destroy(cmdproc->last_cmd); | 57 msn_command_destroy(cmdproc->last_cmd); |
58 | |
59 g_hash_table_destroy(cmdproc->multiparts); | |
55 | 60 |
56 g_free(cmdproc); | 61 g_free(cmdproc); |
57 } | 62 } |
58 | 63 |
59 void | 64 void |
233 | 238 |
234 void | 239 void |
235 msn_cmdproc_process_msg(MsnCmdProc *cmdproc, MsnMessage *msg) | 240 msn_cmdproc_process_msg(MsnCmdProc *cmdproc, MsnMessage *msg) |
236 { | 241 { |
237 MsnMsgTypeCb cb; | 242 MsnMsgTypeCb cb; |
243 const char *messageId = NULL; | |
244 | |
245 /* Multi-part messages */ | |
246 if ((messageId = msn_message_get_attr(msg, "Message-ID")) != NULL) { | |
247 const char *chunk_text = msn_message_get_attr(msg, "Chunks"); | |
248 guint chunk; | |
249 if (chunk_text != NULL) { | |
250 chunk = strtol(chunk_text, NULL, 10); | |
251 /* 1024 chunks of ~1300 bytes is ~1MB, which seems OK to prevent | |
252 some random client causing pidgin to hog a ton of memory. | |
253 Probably should figure out the maximum that the official client | |
254 actually supports, though. */ | |
255 if (chunk > 0 && chunk < 1024) { | |
256 msg->total_chunks = chunk; | |
257 msg->received_chunks = 1; | |
258 g_hash_table_insert(cmdproc->multiparts, (gpointer)messageId, msn_message_ref(msg)); | |
259 purple_debug_info("msn", "Received chunked message, messageId: '%s', total chunks: %d\n", | |
260 messageId, chunk); | |
261 } else { | |
262 purple_debug_error("msn", "MessageId '%s' has too many chunks: %d\n", messageId, chunk); | |
263 } | |
264 return; | |
265 } else { | |
266 chunk_text = msn_message_get_attr(msg, "Chunk"); | |
267 if (chunk_text != NULL) { | |
268 MsnMessage *first = g_hash_table_lookup(cmdproc->multiparts, messageId); | |
269 chunk = strtol(chunk_text, NULL, 10); | |
270 if (first == NULL) { | |
271 purple_debug_error("msn", | |
272 "Unable to find first chunk of messageId '%s' to correspond with chunk %d.\n", | |
273 messageId, chunk+1); | |
274 } else if (first->received_chunks == chunk) { | |
275 /* Chunk is from 1 to total-1 (doesn't count first one) */ | |
276 purple_debug_info("msn", "Received chunk %d of %d, messageId: '%s'\n", | |
277 chunk+1, first->total_chunks, messageId); | |
278 first->body = g_realloc(first->body, first->body_len + msg->body_len); | |
279 memcpy(first->body + first->body_len, msg->body, msg->body_len); | |
280 first->body_len += msg->body_len; | |
281 first->received_chunks++; | |
282 if (first->received_chunks != first->total_chunks) | |
283 return; | |
284 else | |
285 /* We're done! Send it along... The caller takes care of | |
286 freeing the old one. */ | |
287 msg = first; | |
288 } else { | |
289 /* TODO: Can you legitimately receive chunks out of order? */ | |
290 g_hash_table_remove(cmdproc->multiparts, messageId); | |
291 return; | |
292 } | |
293 } else { | |
294 purple_debug_error("msn", "Received MessageId '%s' with no chunk number!\n", messageId); | |
295 } | |
296 } | |
297 } | |
238 | 298 |
239 if (msn_message_get_content_type(msg) == NULL) | 299 if (msn_message_get_content_type(msg) == NULL) |
240 { | 300 { |
241 purple_debug_misc("msn", "failed to find message content\n"); | 301 purple_debug_misc("msn", "failed to find message content\n"); |
242 return; | 302 return; |
243 } | 303 } |
244 | 304 |
245 cb = g_hash_table_lookup(cmdproc->cbs_table->msgs, | 305 cb = g_hash_table_lookup(cmdproc->cbs_table->msgs, |
246 msn_message_get_content_type(msg)); | 306 msn_message_get_content_type(msg)); |
247 | 307 |
248 if (cb == NULL) | 308 if (cb != NULL) |
249 { | 309 cb(cmdproc, msg); |
310 else | |
250 purple_debug_warning("msn", "Unhandled content-type '%s'\n", | 311 purple_debug_warning("msn", "Unhandled content-type '%s'\n", |
251 msn_message_get_content_type(msg)); | 312 msn_message_get_content_type(msg)); |
252 | 313 |
253 return; | 314 if (messageId != NULL) |
254 } | 315 g_hash_table_remove(cmdproc->multiparts, messageId); |
255 | |
256 cb(cmdproc, msg); | |
257 } | 316 } |
258 | 317 |
259 void | 318 void |
260 msn_cmdproc_process_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) | 319 msn_cmdproc_process_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) |
261 { | 320 { |