# HG changeset patch # User Jeffrey Connelly # Date 1177907644 0 # Node ID 1aa62f7368ca6bcc00c889b8f9426d2a39f300f1 # Parent b138e81a0831e0c7a729021b46d0b17792f686fe Add escaping and unescaping functions (for /1 and /2). Unescape is used on all incoming protocol message values. Escaping is currently only used on outgoing instant message text, but it will be used on all outgoing protocol message values, once code is written to create a packed message based on a hash table (or varargs). diff -r b138e81a0831 -r 1aa62f7368ca libpurple/protocols/myspace/myspace.c --- a/libpurple/protocols/myspace/myspace.c Mon Apr 30 04:30:00 2007 +0000 +++ b/libpurple/protocols/myspace/myspace.c Mon Apr 30 04:34:04 2007 +0000 @@ -125,6 +125,75 @@ */ return "myspace"; } + +/** + * Unescape a protocol message. + * + * @param msg The message to unescape. + * + * @return The unescaped message. Caller must g_free(). + * + * Messages should be unescaped after being received, as part of + * the parsing process. + */ +static gchar *msim_unescape(const gchar *msg) +{ + /* TODO: make more elegant, refactor with msim_escape */ + gchar *tmp, *ret; + + tmp = str_replace(msg, "/1", "/"); + ret = str_replace(tmp, "/2", "\\"); + g_free(tmp); + return ret; +} + +/** + * Escape a protocol message. + * + * @param msg The message to escape. + * + * @return The escaped message. Caller must g_free(). + * + * Messages should be escaped before sending. + */ +static gchar *msim_escape(const gchar *msg) +{ + /* TODO: make more elegant, refactor with msim_unescape */ + gchar *tmp, *ret; + + tmp = str_replace(msg, "/", "/1"); + ret = str_replace(tmp, "\\", "/2"); + g_free(tmp); + + return ret; +} + +/** + * Replace 'old' with 'new' in 'str'. + * + * @param str The original string. + * @param old The substring of 'str' to replace. + * @param new The replacement for 'old' within 'str'. + * + * @return A _new_ string, based on 'str', with 'old' replaced + * by 'new'. Must be g_free()'d by caller. + * + * This string replace method is based on + * http://mail.gnome.org/archives/gtk-app-devel-list/2000-July/msg00201.html + * + */ +static gchar *str_replace(const gchar* str, const gchar *old, const gchar *new) +{ + char **items; + char *ret; + + items = g_strsplit(str, old, -1); + ret = g_strjoinv(new, items); + g_free(items); + return ret; +} + + /** * Parse a MySpaceIM protocol message into a hash table. * @@ -172,7 +241,10 @@ #endif if (i % 2) { - value = token; + /* 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) @@ -180,7 +252,11 @@ #if MSIM_DEBUG_PARSE purple_debug_info("msim", "insert: |%s|=|%s|\n", key, value); #endif - g_hash_table_insert(table, g_strdup(key), g_strdup(value)); + /* 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. */ @@ -189,6 +265,7 @@ value); } } else { + /* Even numbered index is a key name */ key = token; } } @@ -277,28 +354,41 @@ * Send an arbitrary protocol message. * * @param session - * @param msg The textual, encoded message to send. + * @param msg The textual, packed message to send. + * + * @return TRUE if succeeded, FALSE if not. * * Note: this does not send instant messages. For that, see msim_send_im. */ -static void msim_send(MsimSession *session, const gchar *msg) +static gboolean msim_send(MsimSession *session, const gchar *msg) { - int ret; + int total_bytes_sent, total_bytes; - g_return_if_fail(MSIM_SESSION_VALID(session)); - g_return_if_fail(msg != NULL); - + g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE); + g_return_val_if_fail(msg != NULL, FALSE); + purple_debug_info("msim", "msim_send: writing <%s>\n", msg); - ret = send(session->fd, msg, strlen(msg), 0); + /* Loop until all data is sent, or a failure occurs. */ + total_bytes_sent = 0; + total_bytes = strlen(msg); + do + { + int bytes_sent; + + bytes_sent = send(session->fd, msg + total_bytes_sent, + total_bytes - total_bytes_sent, 0); - if (ret != strlen(msg)) - { - purple_debug_info("msim", - "msim_send(%s): strlen=%d, but only wrote %s\n", - msg, strlen(msg), ret); - /* TODO: better error -or- TODO: send all, loop unless ret=-1 */ - } + if (bytes_sent < 0) + { + purple_debug_info("msim", "msim_send(%s): send() failed: %s\n", + msg, g_strerror(errno)); + return FALSE; + } + total_bytes_sent += bytes_sent; + + } while(total_bytes_sent < total_bytes); + return TRUE; } /** @@ -388,6 +478,8 @@ g_free(nc); /* Reply */ + /* TODO: escape values. A response_str with a / in it (\ is not in base64) will + * cause a login failure! / must be encoded as /1. */ buf = g_strdup_printf("\\login2\\%d\\username\\%s\\response\\%s\\clientver\\%d\\reconn\\%d\\status\\%d\\id\\1\\final\\", 196610, account->username, response_str, MSIM_CLIENT_VERSION, 0, 100); @@ -612,10 +704,17 @@ g_return_val_if_fail(msim_is_userid(userid) == TRUE, 0); g_return_val_if_fail(message != NULL, 0); + /* XXX: delete after escape each value */ + message = msim_escape(message); + /* TODO: constants for bm types */ + /* TODO: escape values */ msg_string = g_strdup_printf("\\bm\\121\\sesskey\\%s\\t\\%s\\cv\\%d\\msg\\%s\\final\\", session->sesskey, userid, MSIM_CLIENT_VERSION, message); + /* XXX: delete after escape each value */ + g_free(message); + purple_debug_info("msim", "going to write: %s\n", msg_string); msim_send(session, msg_string); @@ -1362,6 +1461,7 @@ lid = 7; } + /* TODO: escape values */ msg_string = g_strdup_printf("\\persist\\1\\sesskey\\%s\\cmd\\1\\dsn\\%d\\uid\\%s\\lid\\%d\\rid\\%d\\body\\%s=%s\\final\\", session->sesskey, dsn, session->userid, lid, rid, field_name, user); diff -r b138e81a0831 -r 1aa62f7368ca libpurple/protocols/myspace/myspace.h --- a/libpurple/protocols/myspace/myspace.h Mon Apr 30 04:30:00 2007 +0000 +++ b/libpurple/protocols/myspace/myspace.h Mon Apr 30 04:34:04 2007 +0000 @@ -98,11 +98,14 @@ static GList *msim_status_types(PurpleAccount *acct); static const gchar *msim_list_icon(PurpleAccount *acct, PurpleBuddy *buddy); +static gchar *msim_unescape(const gchar *msg); +static gchar *msim_escape(const gchar *msg); +static gchar *str_replace(const gchar* str, const gchar *old, const gchar *new); static GHashTable* msim_parse(gchar* msg); static GHashTable *msim_parse_body(const gchar *body_str); static void print_hash_item(gpointer key, gpointer value, gpointer user_data); -static void msim_send(MsimSession *session, const gchar *msg); +static gboolean msim_send(MsimSession *session, const gchar *msg); static void msim_login(PurpleAccount *acct); static int msim_login_challenge(MsimSession *session, GHashTable *table);