changeset 17973:acff371d7908

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.
author Jeffrey Connelly <jaconnel@calpoly.edu>
date Sat, 04 Aug 2007 17:43:37 +0000
parents 8f49acac9d1c
children 3d400b022acc
files libpurple/protocols/myspace/message.c libpurple/protocols/myspace/message.h libpurple/protocols/myspace/myspace.c
diffstat 3 files changed, 214 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- 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", "<MsimMessage: \n", "\n/MsimMessage>");
 	}
 
-    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.
--- 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);
 
--- 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=<uid>"),
 			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"));
     }