diff options
author | Elliott Sales de Andrade <qulogic@pidgin.im> | 2009-01-27 05:23:38 +0000 |
---|---|---|
committer | Elliott Sales de Andrade <qulogic@pidgin.im> | 2009-01-27 05:23:38 +0000 |
commit | 0c963f240081664099e9ea78371d8d4ecd439afa (patch) | |
tree | ecce2198e3e8f6ded3735a6ecadeae3234af4111 | |
parent | 03902898693d13f96fe4d46f440f9c0cecb57339 (diff) | |
parent | b51f78ae386bb24292b037ccd956d07993574321 (diff) | |
download | pidgin-0c963f240081664099e9ea78371d8d4ecd439afa.tar.gz |
merge of 'e67902dda5bd7dcff900f4bd6fb7a7722414b99f'
and 'd3a7fa8559928d78396928b5087bde580f1e6366'
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | libpurple/certificate.c | 24 | ||||
-rw-r--r-- | libpurple/core.c | 9 | ||||
-rw-r--r-- | libpurple/dbus-analyze-functions.py | 33 | ||||
-rw-r--r-- | libpurple/protocols/msn/cmdproc.c | 71 | ||||
-rw-r--r-- | libpurple/protocols/msn/cmdproc.h | 2 | ||||
-rw-r--r-- | libpurple/protocols/msn/msg.h | 2 |
7 files changed, 111 insertions, 31 deletions
@@ -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/certificate.c b/libpurple/certificate.c index 5f985fa492..b548e0468c 100644 --- a/libpurple/certificate.c +++ b/libpurple/certificate.c @@ -1546,31 +1546,11 @@ purple_certificate_init(void) void purple_certificate_uninit(void) { - GList *full_list, *l; - - /* Unregister all Schemes */ - full_list = g_list_copy(cert_schemes); /* Make a working copy */ - for (l = full_list; l; l = l->next) { - purple_certificate_unregister_scheme( - (PurpleCertificateScheme *) l->data ); - } - g_list_free(full_list); - /* Unregister all Verifiers */ - full_list = g_list_copy(cert_verifiers); /* Make a working copy */ - for (l = full_list; l; l = l->next) { - purple_certificate_unregister_verifier( - (PurpleCertificateVerifier *) l->data ); - } - g_list_free(full_list); + g_list_foreach(cert_verifiers, (GFunc)purple_certificate_unregister_verifier, NULL); /* Unregister all Pools */ - full_list = g_list_copy(cert_pools); /* Make a working copy */ - for (l = full_list; l; l = l->next) { - purple_certificate_unregister_pool( - (PurpleCertificatePool *) l->data ); - } - g_list_free(full_list); + g_list_foreach(cert_pools, (GFunc)purple_certificate_unregister_pool, NULL); } gpointer diff --git a/libpurple/core.c b/libpurple/core.c index 9a4ce973e6..7e4abd44fb 100644 --- a/libpurple/core.c +++ b/libpurple/core.c @@ -198,6 +198,14 @@ purple_core_quit(void) /* Transmission ends */ purple_connections_disconnect_all(); + /* + * Certificates must be destroyed before the SSL plugins, because + * PurpleCertificates contain pointers to PurpleCertificateSchemes, + * and the PurpleCertificateSchemes will be unregistered when the + * SSL plugin is uninit. + */ + purple_certificate_uninit(); + /* The SSL plugins must be uninit before they're unloaded */ purple_ssl_uninit(); @@ -220,7 +228,6 @@ purple_core_quit(void) purple_notify_uninit(); purple_conversations_uninit(); purple_connections_uninit(); - purple_certificate_uninit(); purple_buddy_icons_uninit(); purple_accounts_uninit(); purple_savedstatuses_uninit(); diff --git a/libpurple/dbus-analyze-functions.py b/libpurple/dbus-analyze-functions.py index 87c6ea6bd6..fe330cec97 100644 --- a/libpurple/dbus-analyze-functions.py +++ b/libpurple/dbus-analyze-functions.py @@ -117,7 +117,7 @@ class Binding: self.params.append(Parameter.fromtokens(paramtexts[i].split(), i)) self.call = "%s(%s)" % (self.function.name, - ", ".join([param.name for param in self.params])) + ", ".join(param.name for param in self.params)) def process(self): @@ -160,6 +160,10 @@ class Binding: elif type[0].startswith("Purple") or type[0] == "xmlnode": return self.inputpurplestructure(type, name) + # special case for *_get_data functions, be careful here... + elif (type[0] == "size_t") and (name == "len"): + return self.inputgetdata(type, name) + # unknown pointers are always replaced with NULL else: return self.inputpointer(type, name) @@ -196,6 +200,10 @@ class Binding: if type[0] in ["GList", "GSList"]: return self.outputlist(type, name) + # Special case for *_get_data functions + if type[0] == "gconstpointer": + return self.outputgetdata(type, name) + raise myexception @@ -309,7 +317,13 @@ class ClientBinding (Binding): self.returncode.append("return garray_int_to_%s(%s);" % (type[0].lower(), name)); - + # Special case for *_get_data functions, don't need client bindings, + # but do need the name so it doesn't crash + def inputgetdata(self, type, name): + raise myexception + def outputgetdata(self, type, name): + raise myexception + class ServerBinding (Binding): def __init__(self, functiontext, paramtexts): Binding.__init__(self, functiontext, paramtexts) @@ -475,6 +489,21 @@ class ServerBinding (Binding): % (name, name)) self.addouttype("ai", name) + # Special case for *_get_data functions + def inputgetdata(self, type, name): + self.cdecls.append("\tsize_t %s = 0;" % name) + return True + def outputgetdata(self, type, name): + # This is a total hack, but self.call is set up before the parameters + # are processed, so we can't tell it to pass a parameter by reference. + self.call = "%s(%s)" % (self.function.name, + ", ".join(param.name if param.name != "len" else "&len" for param in self.params)) + + self.cdecls.append("\tgconstpointer %s;" % name) + self.ccode.append("\t%s = %s;" % (name, self.call)) + self.cparamsout.append("DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &%s, %s" \ + % (name, "len")) + self.addouttype("ay", name) class BindingSet: regexp = r"^(\w[^()]*)\(([^()]*)\)\s*;\s*$"; 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; |