summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliott Sales de Andrade <qulogic@pidgin.im>2009-01-27 05:23:38 +0000
committerElliott Sales de Andrade <qulogic@pidgin.im>2009-01-27 05:23:38 +0000
commit0c963f240081664099e9ea78371d8d4ecd439afa (patch)
treeecce2198e3e8f6ded3735a6ecadeae3234af4111
parent03902898693d13f96fe4d46f440f9c0cecb57339 (diff)
parentb51f78ae386bb24292b037ccd956d07993574321 (diff)
downloadpidgin-0c963f240081664099e9ea78371d8d4ecd439afa.tar.gz
merge of 'e67902dda5bd7dcff900f4bd6fb7a7722414b99f'
and 'd3a7fa8559928d78396928b5087bde580f1e6366'
-rw-r--r--ChangeLog1
-rw-r--r--libpurple/certificate.c24
-rw-r--r--libpurple/core.c9
-rw-r--r--libpurple/dbus-analyze-functions.py33
-rw-r--r--libpurple/protocols/msn/cmdproc.c71
-rw-r--r--libpurple/protocols/msn/cmdproc.h2
-rw-r--r--libpurple/protocols/msn/msg.h2
7 files changed, 111 insertions, 31 deletions
diff --git a/ChangeLog b/ChangeLog
index d6f5ecbd8e..27e41e8105 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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;