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 {