changeset 17266:793301c04e3a

(Incomplete - plugin does not load) Begin migrating protocol message receiving to MsimMessage.
author Jeffrey Connelly <jaconnel@calpoly.edu>
date Thu, 31 May 2007 06:09:46 +0000
parents 253155592cd5
children 769ffb2ad44c 57bde8784308
files libpurple/protocols/myspace/message.c libpurple/protocols/myspace/message.h libpurple/protocols/myspace/myspace.c libpurple/protocols/myspace/myspace.h libpurple/protocols/myspace/session.h
diffstat 5 files changed, 406 insertions(+), 272 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/myspace/message.c	Thu May 31 03:06:46 2007 +0000
+++ b/libpurple/protocols/myspace/message.c	Thu May 31 06:09:46 2007 +0000
@@ -25,6 +25,7 @@
 static void msim_msg_free_element(gpointer data, gpointer user_data);
 static void msim_msg_debug_string_element(gpointer data, gpointer user_data);
 static gchar *msim_msg_pack_using(MsimMessage *msg, GFunc gf, gchar *sep, gchar *begin, gchar *end);
+static gchar *msim_msg_element_as_string(MsimMessageElement *elem);
 
 MsimMessage *msim_msg_new(void)
 {
@@ -137,6 +138,7 @@
 
 		type = va_arg(argp, int);
 
+		/* Interpret variadic arguments. */
 		switch (type)
 		{
 			case MSIM_TYPE_INTEGER: 
@@ -177,8 +179,6 @@
 }
 
 
-
-
 /** Append a new element to a message. 
  *
  * @param name Textual name of element (static string, neither copied nor freed).
@@ -197,7 +197,7 @@
  *
  * * MSIM_TYPE_STRING: gchar *. The data WILL BE FREED - use g_strdup() if needed.
  *
- * * MSIM_TYPE_BINARY: g_string_new_len(data, length). The data and GString will be freed.
+ * * MSIM_TYPE_BINARY: g_string_new_len(data, length). The data AND GString will be freed.
  *
  * * MSIM_TYPE_DICTIONARY: TODO
  *
@@ -321,47 +321,86 @@
 	return msim_msg_pack_using(msg, msim_msg_debug_string_element, "\n", "<MsimMessage: \n", ">");
 }
 
-/** Pack an element into its protocol representation.
+/** Return a message element data as a new string, converting from other types (integer, etc.) if necessary.
+ *
+ * @return gchar * The data as a string, or NULL. Caller must g_free().
+ */
+static gchar *msim_msg_element_as_string(MsimMessageElement *elem)
+{
+	switch (elem->type)
+	{
+		case MSIM_TYPE_INTEGER:
+			return g_strdup_printf("%d", GPOINTER_TO_UINT(elem->data));
+
+		case MSIM_TYPE_STRING:
+			/* Strings get escaped. msim_escape() creates a new string. */
+			return msim_escape((gchar *)elem->data);
+
+		case MSIM_TYPE_BINARY:
+			{
+				GString *gs;
+
+				gs = (GString *)elem->data;
+				/* Do not escape! */
+				return purple_base64_encode((guchar *)gs->str, gs->len);
+			}
+
+		case MSIM_TYPE_BOOLEAN:
+			/* These strings are not actually used by the wire protocol
+			 * -- see msim_msg_pack_element. */
+			return g_strdup(GPOINTER_TO_UINT(elem->data) ? "True" : "False");
+
+		case MSIM_TYPE_DICTIONARY:
+			/* TODO: pack using k=v\034k2=v2\034... */
+			return NULL;
+			
+		case MSIM_TYPE_LIST:
+			/* TODO: pack using a|b|c|d|... */
+			return NULL;
+
+		default:
+			purple_debug_info("msim", "field %s, unknown type %d\n", elem->name, elem->type);
+			return NULL;
+	}
+}
+
+/** Pack an element into its protocol representation. 
  *
  * @param data Pointer to an MsimMessageElement.
- * @param user_data 
+ * @param user_data Pointer to a gchar ** array of string items.
+ *
+ * Called by msim_msg_pack(). Will pack the MsimMessageElement into
+ * a part of the protocol string and append it to the array. Caller
+ * is responsible for creating array to correct dimensions, and
+ * freeing each string element of the array added by this function.
  */
 static void msim_msg_pack_element(gpointer data, gpointer user_data)
 {
 	MsimMessageElement *elem;
-	gchar *string;
+	gchar *string, *data_string;
 	gchar ***items;
-	gchar *binary;
-	gchar *escaped;
-	GString *gs;
 
 	elem = (MsimMessageElement *)data;
 	items = user_data;
 
+	data_string = msim_msg_element_as_string(elem);
+
 	switch (elem->type)
 	{
+		/* These types are represented by key name/value pairs. */
 		case MSIM_TYPE_INTEGER:
-			string = g_strdup_printf("%s\\%d", elem->name, GPOINTER_TO_UINT(elem->data));
+		case MSIM_TYPE_STRING:
+		case MSIM_TYPE_BINARY:
+		case MSIM_TYPE_DICTIONARY:
+		case MSIM_TYPE_LIST:
+			string = g_strconcat("%s", "\\", data_string, NULL);
 			break;
 
-		case MSIM_TYPE_STRING:
-			/* Strings get escaped. */
-			escaped = msim_escape((gchar *)elem->data);
-			string = g_strdup_printf("%s\\%s", elem->name, escaped);
-			g_free(escaped);
-			break;
-
-		case MSIM_TYPE_BINARY:
-			gs = (GString *)elem->data;
-			binary = purple_base64_encode((guchar*)gs->str, gs->len);
-			/* Do not escape! */
-			string = g_strdup_printf("%s\\%s", elem->name, binary);
-			g_free(binary);
-			break;
-
+		/* Boolean is represented by absence or presence of name. */
 		case MSIM_TYPE_BOOLEAN:
 			if (GPOINTER_TO_UINT(elem->data))
 			{
+				/* True - leave in, with blank value. */
 				string = g_strdup_printf("%s\\\\", elem->name);
 			} else {
 				/* False - leave out. */
@@ -369,21 +408,14 @@
 			}
 			break;
 
-		case MSIM_TYPE_DICTIONARY:
-			/* TODO: pack using k=v\034k2=v2\034... */
-			string = g_strdup_printf("%s\\TODO", elem->name);
-			break;
-			
-		case MSIM_TYPE_LIST:
-			/* TODO: pack using a|b|c|d|... */
-			string = g_strdup_printf("%s\\TODO", elem->name);
-			break;
-
 		default:
+			g_free(data_string);
 			g_return_if_fail(FALSE);
 			break;
 	}
 
+	g_free(data_string);
+
 	**items = string;
 	++(*items);
 }
@@ -400,3 +432,206 @@
 	return msim_msg_pack_using(msg, msim_msg_pack_element, "\\", "\\", "\\final\\");
 }
 
+/** 
+ * Parse a raw protocol message string into a MsimMessage *.
+ *
+ * @param raw The raw message string to parse, will be g_free()'d.
+ *
+ * @return MsimMessage *. Caller should msim_msg_free() when done.
+ */
+MsimMessage *msim_parse(gchar *raw)
+{
+	MsimMessage *msg;
+    gchar *token;
+    gchar **tokens;
+    gchar *key;
+    gchar *value;
+    int i;
+
+    g_return_val_if_fail(raw != NULL, NULL);
+
+    purple_debug_info("msim", "msim_parse: got <%s>\n", raw);
+
+    key = NULL;
+
+    /* All messages begin with a \. */
+    if (raw[0] != '\\' || raw[1] == 0)
+    {
+        purple_debug_info("msim", "msim_parse: incomplete/bad string, "
+                "missing initial backslash: <%s>\n", raw);
+        /* XXX: Should we try to recover, and read to first backslash? */
+
+        g_free(raw);
+        return NULL;
+    }
+
+    msg = msim_msg_new();
+
+    for (tokens = g_strsplit(raw + 1, "\\", 0), i = 0; 
+            (token = tokens[i]);
+            i++)
+    {
+#ifdef MSIM_DEBUG_PARSE
+        purple_debug_info("msim", "tok=<%s>, i%2=%d\n", token, i % 2);
+#endif
+        if (i % 2)
+        {
+			/* Odd-numbered ordinal is a value. */
+		
+			/* Note: returns a new string. */	
+            value = msim_unescape(token);
+
+			/* Always append strings, since protocol has no incoming
+			 * type information for each field. */
+			msim_msg_append(msg, key, MSIM_TYPE_STRING, value);
+#ifdef MSIM_DEBUG_PARSE
+			purple_debug_info("msim", "insert string: |%s|=|%s|\n", key, value);
+#endif
+        } else {
+			/* Even numbered indexes are key names. */
+            key = token;
+        }
+    }
+    g_strfreev(tokens);
+
+    /* Can free now since all data was copied to hash key/values */
+    g_free(raw);
+
+    return msg;
+}
+
+/**
+ * Parse a \x1c-separated "dictionary" of key=value pairs into a hash table.
+ *
+ * @param body_str The text of the dictionary to parse. Often the
+ *                  value for the 'body' field.
+ *
+ * @return Hash table of the keys and values. Must g_hash_table_destroy() when done.
+ */
+GHashTable *msim_parse_body(const gchar *body_str)
+{
+    GHashTable *table;
+    gchar *item;
+    gchar **items;
+    gchar **elements;
+    guint i;
+
+    g_return_val_if_fail(body_str != NULL, NULL);
+
+    table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ 
+    for (items = g_strsplit(body_str, "\x1c", 0), i = 0; 
+        (item = items[i]);
+        i++)
+    {
+        gchar *key, *value;
+
+        elements = g_strsplit(item, "=", 2);
+
+        key = elements[0];
+        if (!key)
+        {
+            purple_debug_info("msim", "msim_parse_body(%s): null key\n", 
+					body_str);
+            g_strfreev(elements);
+            break;
+        }
+
+        value = elements[1];
+        if (!value)
+        {
+            purple_debug_info("msim", "msim_parse_body(%s): null value\n", 
+					body_str);
+            g_strfreev(elements);
+            break;
+        }
+
+#ifdef MSIM_DEBUG_PARSE
+        purple_debug_info("msim", "-- %s: %s\n", key, value);
+#endif
+
+        /* XXX: This overwrites duplicates. */
+        /* TODO: make the GHashTable values be GList's, and append to the list if 
+         * there is already a value of the same key name. This is important for
+         * the WebChallenge message. */
+        g_hash_table_insert(table, g_strdup(key), g_strdup(value));
+        
+        g_strfreev(elements);
+    }
+
+    g_strfreev(items);
+
+    return table;
+}
+
+/** Return the first MsimMessageElement * with given name in the MsimMessage *. 
+ *
+ * @param name Name to search for.
+ *
+ * @return MsimMessageElement * matching name, or NULL.
+ *
+ * Note: useful fields of MsimMessageElement are 'data' and 'type'.
+ */
+MsimMessageElement *msim_msg_get_element(MsimMessage *msg, gchar *name)
+{
+	GList *i;
+
+	/* Linear search for the given name. O(n) but n is small. */
+	for (i = g_list_first(msg); i != NULL; i = g_list_next(msg))
+	{
+		MsimMessageElement *elem;
+
+		elem = i->data;
+		g_return_val_if_fail(elem != NULL, NULL);
+
+		if (strcmp(elem->name, name) == 0)
+			return elem;
+	}
+	return NULL;
+}
+
+/** Return the data of an element of a given name, as a string.
+ *
+ * @param name Name of element.
+ *
+ * @return gchar * The message string. Caller must g_free().
+ */
+gchar *msim_msg_get_string(MsimMessage *msg, gchar *name)
+{
+	MsimMessageElement *elem;
+
+	elem = msim_msg_get_element(msg, name);
+	if (!elem)
+		return NULL;
+
+	return msim_msg_element_as_string(elem);
+}
+
+/** Return the data of an element of a given name, as an integer.
+ *
+ * @param name Name of element.
+ *
+ * @return guint Numeric representation of data, or 0 if could not be converted.
+ *
+ * Useful to obtain an element's data if you know it should be an integer,
+ * even if it is not stored as an MSIM_TYPE_INTEGER. MSIM_TYPE_STRING will
+ * be converted handled correctly, for example.
+ */
+guint msim_msg_get_integer(MsimMessage *msg, gchar *name)
+{
+	MsimMessageElement *elem;
+
+	elem = msim_msg_get_element(msg, name);
+
+	switch (elem->type)
+	{
+		case MSIM_TYPE_INTEGER:
+			return GPOINTER_TO_UINT(elem->data);
+
+		case MSIM_TYPE_STRING:
+			return (guint)atoi((gchar *)elem->data);
+
+		default:
+			return 0;
+	}
+}
--- a/libpurple/protocols/myspace/message.h	Thu May 31 03:06:46 2007 +0000
+++ b/libpurple/protocols/myspace/message.h	Thu May 31 06:09:46 2007 +0000
@@ -22,7 +22,9 @@
 #ifndef _MYSPACE_MESSAGE_H
 #define _MYSPACE_MESSAGE_H
 
-#include "myspace.h"
+#include <glib.h>
+
+#include "session.h"
 
 /* Types */
 #define MsimMessage GList		/* #define instead of typedef to avoid casting */
@@ -48,6 +50,14 @@
 MsimMessage *msim_msg_append(MsimMessage *msg, gchar *name, MsimMessageType type, gpointer data);
 gchar *msim_msg_debug_string(MsimMessage *msg);
 gchar *msim_msg_pack(MsimMessage *msg);
+
 gboolean msim_msg_send(MsimSession *session, MsimMessage *msg);
 
+MsimMessage *msim_parse(gchar *raw);
+GHashTable *msim_parse_body(const gchar *body_str);
+
+MsimMessageElement *msim_msg_get_element(MsimMessage *msg, gchar *name);
+gchar *msim_msg_get_string(MsimMessage *msg, gchar *name);
+guint msim_msg_get_integer(MsimMessage *msg, gchar *name);
+
 #endif /* _MYSPACE_MESSAGE_H */
--- a/libpurple/protocols/myspace/myspace.c	Thu May 31 03:06:46 2007 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Thu May 31 06:09:46 2007 +0000
@@ -33,8 +33,8 @@
 
 #define PURPLE_PLUGIN
 
+#include "message.h"
 #include "myspace.h"
-#include "message.h"
 
 /** 
  * Load the plugin.
@@ -65,39 +65,33 @@
 GList *msim_status_types(PurpleAccount *acct)
 {
     GList *types;
-    PurpleStatusType *type;
+    PurpleStatusType *status;
 
-    purple_debug_info("myspace", "returning status types for %s: %s, %s, %s\n",
-                  acct->username,
-                  MSIM_STATUS_ONLINE, MSIM_STATUS_AWAY, MSIM_STATUS_OFFLINE, MSIM_STATUS_INVISIBLE);
-
+    purple_debug_info("myspace", "returning status types\n");
 
     types = NULL;
 
-	/* TODO: Clean up - I don't like all this repetition */
-    type = purple_status_type_new(PURPLE_STATUS_AVAILABLE, MSIM_STATUS_ONLINE,
-                              MSIM_STATUS_ONLINE, TRUE);
-    purple_status_type_add_attr(type, "message", _("Online"),
-                            purple_value_new(PURPLE_TYPE_STRING));
-    types = g_list_append(types, type);
+	/* TODO: Fix these:
+	 *
+	 * g_log: purple_presence_get_active_status: assertion `presence != NULL' failed
+	 * g_log: purple_status_get_name: assertion `status != NULL' failed
+	 * [...]
+	 *
+	 * and 
+	 * g_log: purple_presence_set_status_active: assertion `status != NULL' failed
+	 * [...]
+	 */
+    status = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, NULL, NULL, FALSE, TRUE, FALSE);
+    types = g_list_append(types, status);
 
-    type = purple_status_type_new(PURPLE_STATUS_AWAY, MSIM_STATUS_AWAY,
-                              MSIM_STATUS_AWAY, TRUE);
-    purple_status_type_add_attr(type, "message", _("Away"),
-                            purple_value_new(PURPLE_TYPE_STRING));
-    types = g_list_append(types, type);
+    status = purple_status_type_new_full(PURPLE_STATUS_AWAY, NULL, NULL, FALSE, TRUE, FALSE);
+    types = g_list_append(types, status);
 
-    type = purple_status_type_new(PURPLE_STATUS_OFFLINE, MSIM_STATUS_OFFLINE,
-                              MSIM_STATUS_OFFLINE, TRUE);
-    purple_status_type_add_attr(type, "message", _("Offline"),
-                            purple_value_new(PURPLE_TYPE_STRING));
-    types = g_list_append(types, type);
+    status = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, NULL, NULL, FALSE, TRUE, FALSE);
+    types = g_list_append(types, status);
 
-    type = purple_status_type_new(PURPLE_STATUS_INVISIBLE, MSIM_STATUS_INVISIBLE,
-                              MSIM_STATUS_INVISIBLE, TRUE);
-    purple_status_type_add_attr(type, "message", _("Invisible"),
-                            purple_value_new(PURPLE_TYPE_STRING));
-    types = g_list_append(types, type);
+    status = purple_status_type_new_full(PURPLE_STATUS_INVISIBLE, NULL, NULL, FALSE, TRUE, FALSE);
+    types = g_list_append(types, status);
 
     return types;
 }
@@ -177,154 +171,6 @@
 
 
 
-/** 
- * Parse a MySpaceIM protocol message into a hash table. 
- *
- * @param msg The message string to parse, will be g_free()'d.
- *
- * @return Hash table of message. Caller should destroy with
- *              g_hash_table_destroy() when done.
- */
-GHashTable *msim_parse(gchar *msg)
-{
-    GHashTable *table;
-    gchar *token;
-    gchar **tokens;
-    gchar *key;
-    gchar *value;
-    int i;
-
-    g_return_val_if_fail(msg != NULL, NULL);
-
-    purple_debug_info("msim", "msim_parse: got <%s>\n", msg);
-
-    key = NULL;
-
-    /* All messages begin with a \ */
-    if (msg[0] != '\\' || msg[1] == 0)
-    {
-        purple_debug_info("msim", "msim_parse: incomplete/bad msg, "
-                "missing initial backslash: <%s>\n", msg);
-        /* XXX: Should we try to recover, and read to first backslash? */
-
-        g_free(msg);
-        return NULL;
-    }
-
-    /* Create table of strings, set to call g_free on destroy. */
-    table = g_hash_table_new_full((GHashFunc)g_str_hash, 
-            (GEqualFunc)g_str_equal, g_free, g_free);
-
-    for (tokens = g_strsplit(msg + 1, "\\", 0), i = 0; 
-            (token = tokens[i]);
-            i++)
-    {
-#ifdef MSIM_DEBUG_PARSE
-        purple_debug_info("msim", "tok=<%s>, i%2=%d\n", token, i % 2);
-#endif
-        if (i % 2)
-        {
-			/* Odd-numbered ordinal is a value */
-		
-			/* Note: returns a new string */	
-            value = msim_unescape(token);
-
-            /* Check if key already exists */
-            if (g_hash_table_lookup(table, key) == NULL)
-            {
-#ifdef MSIM_DEBUG_PARSE
-                purple_debug_info("msim", "insert: |%s|=|%s|\n", key, value);
-#endif
-				/* Insert - strdup 'key' because it will be g_strfreev'd (as 'tokens'),
-				 * but do not strdup 'value' because it was newly allocated by
-				 * msim_unescape(). 
-				 */
-                g_hash_table_insert(table, g_strdup(key), value);
-            } else {
-                /* TODO: Some dictionaries have multiple values for the same
-                 * key. Should append to a GList to handle this case. */
-                purple_debug_info("msim", "msim_parse: key %s already exists, "
-                "not overwriting or replacing; ignoring new value %s\n", key,
-                value);
-            }
-        } else {
-			/* Even numbered index is a key name */
-            key = token;
-        }
-    }
-    g_strfreev(tokens);
-
-    /* Can free now since all data was copied to hash key/values */
-    g_free(msg);
-
-    return table;
-}
-
-/**
- * Parse a \x1c-separated "dictionary" of key=value pairs into a hash table.
- *
- * @param body_str The text of the dictionary to parse. Often the
- *                  value for the 'body' field.
- *
- * @return Hash table of the keys and values. Must g_hash_table_destroy() when done.
- */
-GHashTable *msim_parse_body(const gchar *body_str)
-{
-    GHashTable *table;
-    gchar *item;
-    gchar **items;
-    gchar **elements;
-    guint i;
-
-    g_return_val_if_fail(body_str != NULL, NULL);
-
-    table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
- 
-    for (items = g_strsplit(body_str, "\x1c", 0), i = 0; 
-        (item = items[i]);
-        i++)
-    {
-        gchar *key, *value;
-
-        elements = g_strsplit(item, "=", 2);
-
-        key = elements[0];
-        if (!key)
-        {
-            purple_debug_info("msim", "msim_parse_body(%s): null key\n", 
-					body_str);
-            g_strfreev(elements);
-            break;
-        }
-
-        value = elements[1];
-        if (!value)
-        {
-            purple_debug_info("msim", "msim_parse_body(%s): null value\n", 
-					body_str);
-            g_strfreev(elements);
-            break;
-        }
-
-#ifdef MSIM_DEBUG_PARSE
-        purple_debug_info("msim", "-- %s: %s\n", key, value);
-#endif
-
-        /* XXX: This overwrites duplicates. */
-        /* TODO: make the GHashTable values be GList's, and append to the list if 
-         * there is already a value of the same key name. This is important for
-         * the WebChallenge message. */
-        g_hash_table_insert(table, g_strdup(key), g_strdup(value));
-        
-        g_strfreev(elements);
-    }
-
-    g_strfreev(items);
-
-    return table;
-}
-
-
 
 #ifdef MSIM_DEBUG_MSG
 void print_hash_item(gpointer key, gpointer value, gpointer user_data)
@@ -923,21 +769,31 @@
  * @return The return value of the function used to process the message, or -1 if
  * called with invalid parameters.
  */
-int msim_process(PurpleConnection *gc, GHashTable *table)
+int msim_process(PurpleConnection *gc, MsimMessage *msg)
 {
     MsimSession *session;
 
     g_return_val_if_fail(gc != NULL, -1);
-    g_return_val_if_fail(table != NULL, -1);
+    g_return_val_if_fail(msg != NULL, -1);
 
     session = (MsimSession *)gc->proto_data;
 
 #ifdef MSIM_DEBUG_MSG
-    purple_debug_info("msim", "-------- message -------------\n");
-    g_hash_table_foreach(table, print_hash_item, NULL);
-    purple_debug_info("msim", "------------------------------\n");
+	{
+		gchar *debug_msg;
+
+		purple_debug_info("msim", "-------- message -------------\n");
+
+		debug_msg = msim_msg_debug_string(msg);
+		purple_debug_info("msim", debug_msg);
+		g_free(debug_msg);
+
+		purple_debug_info("msim", "------------------------------\n");
+	}
 #endif
 
+	/* TODO: convert to use MsimMessage. */
+#if 0	
     if (g_hash_table_lookup(table, "nc"))
     {
         return msim_login_challenge(session, table);
@@ -991,7 +847,11 @@
         purple_debug_info("msim", "msim_process: unhandled message\n");
         return 0;
     }
+#else
+	return 0;
+#endif
 }
+
 /**
  * Process a message reply from the server.
  *
@@ -1186,7 +1046,7 @@
      * TODO: make status reflect reality
      * TODO: show headline */
     presence = purple_presence_new_for_buddy(buddy);
-    purple_presence_set_status_active(presence, MSIM_STATUS_ONLINE, TRUE);
+    /* purple_presence_set_status_active(presence, PURPLE_STATUS_AVAILABLE, TRUE); */
 
     g_strfreev(status_array);
     g_list_free(list);
@@ -1263,8 +1123,8 @@
     account = purple_connection_get_account(gc);
     session = gc->proto_data;
 
+    g_return_if_fail(cond == PURPLE_INPUT_READ);
     g_return_if_fail(MSIM_SESSION_VALID(session));
-    g_return_if_fail(cond == PURPLE_INPUT_READ);
 
     /* Only can handle so much data at once... 
      * If this happens, try recompiling with a higher MSIM_READ_BUF_SIZE.
@@ -1333,14 +1193,14 @@
     /* Look for \\final\\ end markers. If found, process message. */
     while((end = strstr(session->rxbuf, MSIM_FINAL_STRING)))
     {
-        GHashTable *table;
+        MsimMessage *msg;
 
 #ifdef MSIM_DEBUG_RXBUF
         purple_debug_info("msim", "in loop: buf=<%s>\n", session->rxbuf);
 #endif
         *end = 0;
-        table = msim_parse(g_strdup(session->rxbuf));
-        if (!table)
+        msg = msim_parse(g_strdup(session->rxbuf));
+        if (!msg)
         {
             purple_debug_info("msim", "msim_input_cb: couldn't parse <%s>\n", 
 					session->rxbuf);
@@ -1349,8 +1209,8 @@
         else
         {
             /* Process message. Returns 0 to free */
-            if (msim_process(gc, table) == 0)
-                g_hash_table_destroy(table);
+            if (msim_process(gc, msg) == 0)
+				msim_msg_free(msg);
         }
 
         /* Move remaining part of buffer to beginning. */
@@ -1511,7 +1371,7 @@
     g_return_if_fail(user != NULL);
     g_return_if_fail(cb != NULL);
 
-    purple_debug_info("msim", "msim_lookup_userid", 
+    purple_debug_info("msim", "msim_lookup_userid: "
 			"asynchronously looking up <%s>\n", user);
 
     /* TODO: check if this user's info was cached and fresh; if so return immediately */
@@ -1754,18 +1614,23 @@
 void init_plugin(PurplePlugin *plugin) 
 {
 	PurpleAccountOption *option;
-#ifdef _TEST_MSIM_MSG
-	MsimMessage *msg = msim_msg_new();
-	msg = msim_msg_append(msg, "bx", MSIM_TYPE_BINARY, g_string_new_len(g_strdup("XXX"), 3));
-	msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v1"));
-	msg = msim_msg_append(msg, "k1", MSIM_TYPE_INTEGER, 42);
-	msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v43"));
-	msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v52/xxx\\yyy"));
-	msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v7"));
-	purple_debug_info("msim", "msg=%s\n", msim_msg_debug_string(msg));
-	purple_debug_info("msim", "msg=%s\n", msim_msg_pack(msg));
-	msim_msg_free(msg);
-	exit(0);
+#ifdef  _TEST_MSIM_MSG
+	{
+		MsimMessage *msg;
+
+		purple_debug_info("msim", "testing MsimMessage\n");
+		msg = msim_msg_new();
+		msg = msim_msg_append(msg, "bx", MSIM_TYPE_BINARY, g_string_new_len(g_strdup("XXX"), 3));
+		msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v1"));
+		msg = msim_msg_append(msg, "k1", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(42));
+		msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v43"));
+		msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v52/xxx\\yyy"));
+		msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v7"));
+		purple_debug_info("msim", "msg=%s\n", msim_msg_debug_string(msg));
+		purple_debug_info("msim", "msg=%s\n", msim_msg_pack(msg));
+		msim_msg_free(msg);
+		exit(0);
+	}
 #endif
 
 	/* TODO: default to automatically try different ports. Make the user be
--- a/libpurple/protocols/myspace/myspace.h	Thu May 31 03:06:46 2007 +0000
+++ b/libpurple/protocols/myspace/myspace.h	Thu May 31 06:09:46 2007 +0000
@@ -48,6 +48,10 @@
 #include "debug.h"      /* for purple_debug_info */
 
 
+/* MySpaceIM includes */
+#include "session.h"
+#include "message.h"
+
 /* Conditional compilation options */
 
 /* Debugging options */
@@ -68,12 +72,6 @@
 
 /* Constants */
 
-/* Statuses */
-#define MSIM_STATUS_ONLINE      "online"
-#define MSIM_STATUS_AWAY        "away"
-#define MSIM_STATUS_OFFLINE     "offline"
-#define MSIM_STATUS_INVISIBLE   "invisible"
-
 /* Build version of MySpaceIM to report to servers (1.0.xxx.0) */
 #define MSIM_CLIENT_VERSION     673
 
@@ -97,32 +95,6 @@
 /* Authentication algorithm for login2 */
 #define MSIM_AUTH_ALGORITHM	196610
 
-/* Random number in every MsimSession, to ensure it is valid. */
-#define MSIM_SESSION_STRUCT_MAGIC       0xe4a6752b
-
-/* Everything needed to keep track of a session. */
-typedef struct _MsimSession
-{
-    guint magic;                        /**< MSIM_SESSION_STRUCT_MAGIC */
-    PurpleAccount *account;
-    PurpleConnection *gc;
-    gchar *sesskey;                     /**< Session key text string from server */
-    gchar *userid;                      /**< This user's numeric user ID */
-    gint fd;                            /**< File descriptor to/from server */
-
-    GHashTable *user_lookup_cb;         /**< Username -> userid lookup callback */
-    GHashTable *user_lookup_cb_data;    /**< Username -> userid lookup callback data */
-    GHashTable *user_lookup_cache;      /**< Cached information on users */
-
-    gchar *rxbuf;                       /**< Receive buffer */
-    guint rxoff;                        /**< Receive buffer offset */
-	guint next_rid;						/**< Next request/response ID */
-} MsimSession;
-
-/* Check if an MsimSession is valid */
-#define MSIM_SESSION_VALID(s) (session != NULL && \
-		session->magic == MSIM_SESSION_STRUCT_MAGIC)
-
 /* Callback function pointer type for when a user's information is received, 
  * initiated from a user lookup. */
 typedef void (*MSIM_USER_LOOKUP_CB)(MsimSession *session, GHashTable *userinfo,
@@ -148,9 +120,6 @@
 gchar *msim_escape(const gchar *msg);
 gchar *str_replace(const gchar *str, const gchar *old, const gchar *new);
 
-GHashTable *msim_parse(gchar *msg);
-GHashTable *msim_parse_body(const gchar *body_str);
-
 void print_hash_item(gpointer key, gpointer value, gpointer user_data);
 gboolean msim_send_raw(MsimSession *session, const gchar *msg);
 gchar *msim_pack(GHashTable *table);
@@ -173,7 +142,7 @@
 int msim_incoming_im(MsimSession *session, GHashTable *table);
 
 int msim_process_reply(MsimSession *session, GHashTable *table);
-int msim_process(PurpleConnection *gc, GHashTable *table);
+int msim_process(PurpleConnection *gc, MsimMessage *msg);
 
 int msim_error(MsimSession *session, GHashTable *table);
 void msim_status_cb(MsimSession *session, GHashTable *userinfo, 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/myspace/session.h	Thu May 31 06:09:46 2007 +0000
@@ -0,0 +1,55 @@
+/* MySpaceIM Protocol Plugin, session header file
+ *
+ * \author Jeff Connelly
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@homing.pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _MYSPACE_SESSION_H
+#define _MYSPACE_SESSION_H
+
+#include <glib.h>
+
+#include "account.h"
+
+/* Random number in every MsimSession, to ensure it is valid. */
+#define MSIM_SESSION_STRUCT_MAGIC       0xe4a6752b
+
+/* Everything needed to keep track of a session. */
+typedef struct _MsimSession
+{
+    guint magic;                        /**< MSIM_SESSION_STRUCT_MAGIC */
+    PurpleAccount *account;
+    PurpleConnection *gc;
+    gchar *sesskey;                     /**< Session key text string from server */
+    gchar *userid;                      /**< This user's numeric user ID */
+    gint fd;                            /**< File descriptor to/from server */
+
+    GHashTable *user_lookup_cb;         /**< Username -> userid lookup callback */
+    GHashTable *user_lookup_cb_data;    /**< Username -> userid lookup callback data */
+    GHashTable *user_lookup_cache;      /**< Cached information on users */
+
+    gchar *rxbuf;                       /**< Receive buffer */
+    guint rxoff;                        /**< Receive buffer offset */
+	guint next_rid;						/**< Next request/response ID */
+} MsimSession;
+
+/* Check if an MsimSession is valid */
+#define MSIM_SESSION_VALID(s) (session != NULL && \
+		session->magic == MSIM_SESSION_STRUCT_MAGIC)
+
+#endif /* !_MYSPACE_SESSION_H */