# HG changeset patch # User Jeffrey Connelly # Date 1186249417 0 # Node ID acff371d79085a3074ccf09cd6c7e2f79e531021 # Parent 8f49acac9d1c5af3feba3289c3dd588636a14760 Fix crash when deleting buddies on Windows. This was done by correctly printing null strings in MsimMessage debug messages, since _uid_before had a NULL value when being sent to postprocessing. Closes #2400. diff -r 8f49acac9d1c -r acff371d7908 libpurple/protocols/myspace/message.c --- a/libpurple/protocols/myspace/message.c Tue Jul 31 02:56:58 2007 +0000 +++ b/libpurple/protocols/myspace/message.c Sat Aug 04 17:43:37 2007 +0000 @@ -118,8 +118,6 @@ { gchar *key, *value; MsimMessageType type; - GString *gs; - GList *gl; MsimMessage *msg; /* Begin with an empty message. */ @@ -153,20 +151,41 @@ break; case MSIM_TYPE_BINARY: - gs = va_arg(argp, GString *); + { + GString *gs; - g_return_val_if_fail(gs != NULL, FALSE); + gs = va_arg(argp, GString *); - /* msim_msg_free() will free this GString the caller created. */ - msg = msim_msg_append(msg, key, type, gs); - break; + g_return_val_if_fail(gs != NULL, FALSE); + + /* msim_msg_free() will free this GString the caller created. */ + msg = msim_msg_append(msg, key, type, gs); + break; + } case MSIM_TYPE_LIST: - gl = va_arg(argp, GList *); + { + GList *gl; + + gl = va_arg(argp, GList *); + + g_return_val_if_fail(gl != NULL, FALSE); + + msg = msim_msg_append(msg, key, type, gl); + break; + } - g_return_val_if_fail(gl != NULL, FALSE); + case MSIM_TYPE_DICTIONARY: + { + MsimMessage *dict; + + dict = va_arg(argp, MsimMessage *); - msg = msim_msg_append(msg, key, type, gl); + g_return_val_if_fail(dict != NULL, FALSE); + + msg = msim_msg_append(msg, key, type, dict); + break; + } default: purple_debug_info("msim", "msim_send: unknown type %d\n", type); @@ -268,7 +287,16 @@ new_data = g_string_new_len(gs->str, gs->len); } break; - /* TODO: other types */ + case MSIM_TYPE_DICTIONARY: + { + MsimMessage *dict; + + dict = (MsimMessage *)elem->data; + + new_data = msim_msg_clone(dict); + } + break; + default: purple_debug_info("msim", "msim_msg_clone_element: unknown type %d\n", elem->type); g_return_if_fail(NULL); @@ -330,7 +358,7 @@ break; case MSIM_TYPE_DICTIONARY: - /* TODO: free dictionary */ + msim_msg_free((MsimMessage *)elem->data); break; case MSIM_TYPE_LIST: @@ -452,7 +480,7 @@ * * * MSIM_TYPE_BINARY: g_string_new_len(data, length). The data AND GString will be freed. * - * * MSIM_TYPE_DICTIONARY: TODO + * * MSIM_TYPE_DICTIONARY: An MsimMessage *. Freed when message is destroyed. * * * MSIM_TYPE_LIST: GList * of gchar *. Again, everything will be freed. * @@ -540,15 +568,18 @@ switch (elem->type) { case MSIM_TYPE_INTEGER: - string = g_strdup_printf("%s(integer): %d", elem->name, GPOINTER_TO_UINT(elem->data)); + string = g_strdup_printf("%s(integer): %d", elem->name, + GPOINTER_TO_UINT(elem->data)); break; case MSIM_TYPE_RAW: - string = g_strdup_printf("%s(raw): %s", elem->name, (gchar *)elem->data); + string = g_strdup_printf("%s(raw): %s", elem->name, + elem->data ? (gchar *)elem->data : "(NULL)"); break; case MSIM_TYPE_STRING: - string = g_strdup_printf("%s(string): %s", elem->name, (gchar *)elem->data); + string = g_strdup_printf("%s(string): %s", elem->name, + elem->data ? (gchar *)elem->data : "(NULL)"); break; case MSIM_TYPE_BINARY: @@ -560,12 +591,25 @@ case MSIM_TYPE_BOOLEAN: string = g_strdup_printf("%s(boolean): %s", elem->name, - GPOINTER_TO_UINT(elem->data) ? "TRUE" : "FALSE"); + elem->data ? "TRUE" : "FALSE"); break; case MSIM_TYPE_DICTIONARY: - /* TODO: provide human-readable output of dictionary. */ - string = g_strdup_printf("%s(dict): TODO", elem->name); + { + gchar *s; + + if (!elem->data) + s = g_strdup("(NULL)"); + else + s = msim_msg_dump_to_str((MsimMessage *)elem->data); + + if (!s) + s = g_strdup("(NULL, couldn't msim_msg_dump_to_str)"); + + string = g_strdup_printf("%s(dict): %s", elem->name, s); + + g_free(s); + } break; case MSIM_TYPE_LIST: @@ -589,7 +633,8 @@ break; default: - string = g_strdup_printf("%s(unknown type %d", elem->name, elem->type); + string = g_strdup_printf("%s(unknown type %d", + elem->name ? elem->name : "(NULL)", elem->type); break; } @@ -604,6 +649,29 @@ void msim_msg_dump(const gchar *fmt_string, MsimMessage *msg) { + gchar *debug_str; + + g_return_if_fail(fmt_string != NULL); + + debug_str = msim_msg_dump_to_str(msg); + + g_return_if_fail(debug_str != NULL); + + purple_debug_info("msim_msg_dump", "debug_str=%s\n", debug_str); + + + purple_debug_info("msim", fmt_string, debug_str); + + g_free(debug_str); +} + +/** Return a human-readable string of the message. + * + * @return A new gchar *, must be g_free()'d. + */ +gchar * +msim_msg_dump_to_str(MsimMessage *msg) +{ gchar *debug_str; if (!msg) @@ -614,11 +682,7 @@ "\n", ""); } - g_return_if_fail(debug_str != NULL); - - purple_debug_info("msim", fmt_string, debug_str); - - g_free(debug_str); + return debug_str; } /** Return a message element data as a new string for a raw protocol message, converting from other types (integer, etc.) if necessary. @@ -643,7 +707,9 @@ case MSIM_TYPE_STRING: /* Strings get escaped. msim_escape() creates a new string. */ - return msim_escape((gchar *)elem->data); + g_return_val_if_fail(elem->data != NULL, NULL); + return elem->data ? msim_escape((gchar *)elem->data) : + g_strdup("(NULL)"); case MSIM_TYPE_BINARY: { @@ -655,12 +721,13 @@ } case MSIM_TYPE_BOOLEAN: - /* Not used by the wire protocol * -- see msim_msg_pack_element. */ - return NULL; + /* Not used by messages in the wire protocol * -- see msim_msg_pack_element. + * Only used by dictionaries, see msim_msg_pack_element_dict. */ + return elem->data ? g_strdup("On") : g_strdup("Off"); case MSIM_TYPE_DICTIONARY: /* TODO: pack using k=v\034k2=v2\034... */ - return NULL; + return msim_msg_pack_dict((MsimMessage *)elem->data); case MSIM_TYPE_LIST: /* Pack using a|b|c|d|... */ @@ -684,6 +751,54 @@ } } +/** Pack an element into its protcol representation inside a dictionary. + * + * See msim_msg_pack_element(). + */ +static void +msim_msg_pack_element_dict(gpointer data, gpointer user_data) +{ + MsimMessageElement *elem; + gchar *string, *data_string, ***items; + + elem = (MsimMessageElement *)data; + items = (gchar ***)user_data; + + /* Exclude elements beginning with '_' from packed protocol messages. */ + if (elem->name[0] == '_') + { + return; + } + + data_string = msim_msg_pack_element_data(elem); + + g_return_if_fail(data_string != NULL); + + switch (elem->type) + { + /* These types are represented by key name/value pairs (converted above). */ + case MSIM_TYPE_INTEGER: + case MSIM_TYPE_RAW: + case MSIM_TYPE_STRING: + case MSIM_TYPE_BINARY: + case MSIM_TYPE_DICTIONARY: + case MSIM_TYPE_LIST: + case MSIM_TYPE_BOOLEAN: /* Boolean is On or Off */ + string = g_strconcat(elem->name, "\\", data_string, NULL); + break; + + default: + g_free(data_string); + g_return_if_fail(FALSE); + break; + } + + g_free(data_string); + + **items = string; + ++(*items); +} + /** Pack an element into its protocol representation. * * @param data Pointer to an MsimMessageElement. @@ -702,7 +817,7 @@ gchar ***items; elem = (MsimMessageElement *)data; - items = user_data; + items = (gchar ***)user_data; /* Exclude elements beginning with '_' from packed protocol messages. */ if (elem->name[0] == '_') @@ -749,7 +864,7 @@ } -/** Return a packed string suitable for sending over the wire. +/** Return a packed string of a message suitable for sending over the wire. * * @return A string. Caller must g_free(). */ @@ -761,6 +876,18 @@ return msim_msg_pack_using(msg, msim_msg_pack_element, "\\", "\\", "\\final\\"); } +/** Return a packed string of a dictionary, suitable for embedding in MSIM_TYPE_DICTIONARY. + * + * @return A string; caller must g_free(). + */ +gchar * +msim_msg_pack_dict(MsimMessage *msg) +{ + g_return_val_if_fail(msg != NULL, NULL); + + return msim_msg_pack_using(msg, msim_msg_pack_element_dict, "\034", "", ""); +} + /** * Parse a raw protocol message string into a MsimMessage *. * @@ -1005,10 +1132,10 @@ switch (elem->type) { case MSIM_TYPE_LIST: - return msim_msg_list_copy((GList *)(elem->data)); + return msim_msg_list_copy((GList *)elem->data); case MSIM_TYPE_RAW: - return msim_msg_list_parse((gchar *)(elem->data)); + return msim_msg_list_parse((gchar *)elem->data); default: purple_debug_info("msim_msg_get_list", "type %d unknown, name %s\n", @@ -1017,6 +1144,39 @@ } } +/** Parse a \034-deliminated and =-separated string into a dictionary. TODO */ +MsimMessage * +msim_msg_dictionary_parse(gchar *raw) +{ + /* TODO - get code from msim_parse_body, but parse into MsimMessage */ + return NULL; +} + +/** Return an element as a new dictionary. Caller frees with msim_msg_free(). */ +MsimMessage * +msim_msg_get_dictionary(MsimMessage *msg, const gchar *name) +{ + MsimMessageElement *elem; + + elem = msim_msg_get(msg, name); + if (!elem) + return NULL; + + switch (elem->type) + { + case MSIM_TYPE_DICTIONARY: + return msim_msg_clone((MsimMessage *)elem->data); + + case MSIM_TYPE_RAW: + return msim_msg_dictionary_parse((gchar *)elem->data); + + default: + purple_debug_info("msim_msg_get_dictionary", "type %d unknown, name %s\n", + elem->type, name); + return NULL; + } +} + /** Return the data of an element of a given name, as an integer. * * @param name Name of element. diff -r 8f49acac9d1c -r acff371d7908 libpurple/protocols/myspace/message.h --- a/libpurple/protocols/myspace/message.h Tue Jul 31 02:56:58 2007 +0000 +++ b/libpurple/protocols/myspace/message.h Sat Aug 04 17:43:37 2007 +0000 @@ -54,8 +54,10 @@ void msim_msg_free(MsimMessage *msg); MsimMessage *msim_msg_append(MsimMessage *msg, const gchar *name, MsimMessageType type, gpointer data); MsimMessage *msim_msg_insert_before(MsimMessage *msg, const gchar *name_before, const gchar *name, MsimMessageType type, gpointer data); +gchar *msim_msg_dump_to_str(MsimMessage *msg); void msim_msg_dump(const char *fmt_string, MsimMessage *msg); gchar *msim_msg_pack(MsimMessage *msg); +gchar *msim_msg_pack_dict(MsimMessage *msg); GList *msim_msg_list_copy(GList *old); void msim_msg_list_free(GList *l); @@ -90,10 +92,12 @@ MsimMessage *msim_parse(gchar *raw); GHashTable *msim_parse_body(const gchar *body_str); +MsimMessage *msim_msg_dictionary_parse(gchar *raw); MsimMessageElement *msim_msg_get(MsimMessage *msg, const gchar *name); gchar *msim_msg_get_string(MsimMessage *msg, const gchar *name); GList *msim_msg_get_list(MsimMessage *msg, const gchar *name); +MsimMessage *msim_msg_get_dictionary(MsimMessage *msg, const gchar *name); guint msim_msg_get_integer(MsimMessage *msg, const gchar *name); gboolean msim_msg_get_binary(MsimMessage *msg, const gchar *name, gchar **binary_data, gsize *binary_length); diff -r 8f49acac9d1c -r acff371d7908 libpurple/protocols/myspace/myspace.c --- a/libpurple/protocols/myspace/myspace.c Tue Jul 31 02:56:58 2007 +0000 +++ b/libpurple/protocols/myspace/myspace.c Sat Aug 04 17:43:37 2007 +0000 @@ -2284,8 +2284,12 @@ "msim_check_inbox_cb: notifying of %d\n", n); /* TODO: free strings with callback _if_ change to dynamic (w/ token) */ - purple_notify_emails(session->account, - n, TRUE, subjects, froms, tos, urls, NULL, NULL); + purple_notify_emails(session->gc, /* handle */ + n, /* count */ + TRUE, /* detailed */ + subjects, froms, tos, urls, + NULL, /* PurpleNotifyCloseCallback cb */ + NULL); /* gpointer user_data */ } @@ -2889,8 +2893,6 @@ msim_do_postprocessing(MsimMessage *msg, const gchar *uid_before, const gchar *uid_field_name, guint uid) { - purple_debug_info("msim", "msim_do_postprocessing called with ufn=%s, ub=%s, uid=%d\n", - uid_field_name, uid_before, uid); msim_msg_dump("msim_do_postprocessing msg: %s\n", msg); /* First, check - if the field already exists, treat it as a format string. */ @@ -2991,7 +2993,7 @@ * @param uid_field_name Name of new field to add, containing uid of username. Static string. * @param uid_before Name of existing field to insert username field before. Static string. * - * @return Postprocessed message. + * @return TRUE if successful. */ gboolean msim_postprocess_outgoing(MsimSession *session, MsimMessage *msg, @@ -3002,9 +3004,9 @@ guint uid; gboolean rc; + g_return_val_if_fail(msg != NULL, FALSE); + /* Store information for msim_postprocess_outgoing_cb(). */ - purple_debug_info("msim", "msim_postprocess_outgoing(u=%s,ufn=%s,ub=%s)\n", - username, uid_field_name, uid_before); msim_msg_dump("msim_postprocess_outgoing: msg before=%s\n", msg); msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, g_strdup(username)); msg = msim_msg_append(msg, "_uid_field_name", MSIM_TYPE_STRING, g_strdup(uid_field_name)); @@ -3067,12 +3069,14 @@ "sesskey", MSIM_TYPE_INTEGER, session->sesskey, /* 'delprofileid' with uid will be inserted here. */ NULL); - /* TODO: free msg */ + if (!msim_postprocess_outgoing(session, delbuddy_msg, buddy->name, "delprofileid", NULL)) { purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("'delbuddy' command failed")); + msim_msg_free(delbuddy_msg); return; } + msim_msg_free(delbuddy_msg); persist_msg = msim_msg_new(TRUE, "persist", MSIM_TYPE_INTEGER, 1, @@ -3086,12 +3090,13 @@ "body", MSIM_TYPE_STRING, g_strdup("ContactID="), NULL); - /* TODO: free msg */ if (!msim_postprocess_outgoing(session, persist_msg, buddy->name, "body", NULL)) { purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("persist command failed")); + msim_msg_free(persist_msg); return; } + msim_msg_free(persist_msg); blocklist_msg = msim_msg_new(TRUE, "blocklist", MSIM_TYPE_BOOLEAN, TRUE, @@ -3103,8 +3108,10 @@ if (!msim_postprocess_outgoing(session, blocklist_msg, buddy->name, "idlist", NULL)) { purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("blocklist command failed")); + msim_msg_free(blocklist_msg); return; } + msim_msg_free(blocklist_msg); } /** Return whether the buddy can be messaged while offline. @@ -3194,6 +3201,7 @@ { purple_debug_info("msim_input_cb", "received %d bytes, pushing rxoff to %d, over buffer size of %d\n", n, n + session->rxoff, MSIM_READ_BUF_SIZE); + /* TODO: g_realloc like msn, yahoo, irc, jabber? */ purple_connection_error(gc, _("Read buffer full")); }