Mercurial > pidgin.yaz
diff libpurple/protocols/myspace/myspace.c @ 16410:1aa62f7368ca
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).
author | Jeffrey Connelly <jaconnel@calpoly.edu> |
---|---|
date | Mon, 30 Apr 2007 04:34:04 +0000 |
parents | bb649c52fc19 |
children | 3b5037a93807 |
line wrap: on
line diff
--- 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);