diff libpurple/protocols/myspace/user.c @ 25005:401f548e3544

propagate from branch 'im.pidgin.pidgin' (head df6eba32e5b6b34d7483cbfb7e9f2e4c836ac35f) to branch 'org.darkrain42.pidgin.buddy-add' (head 6831808999a270f8c1a128c7430a73d3dc0bfae2)
author Paul Aurich <paul@darkrain42.org>
date Sun, 21 Dec 2008 18:32:37 +0000
parents 125cac3e24ee 22fd7467f0cc
children ae544623840b
line wrap: on
line diff
--- a/libpurple/protocols/myspace/user.c	Sat Nov 29 18:46:49 2008 +0000
+++ b/libpurple/protocols/myspace/user.c	Sun Dec 21 18:32:37 2008 +0000
@@ -19,21 +19,13 @@
 
 #include "myspace.h"
 
-static void msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user);
-static gchar *msim_format_now_playing(const gchar *band, const gchar *song);
-static void msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text,
-		gsize len, const gchar *error_message);
+static void msim_check_username_availability_cb(PurpleConnection *gc, const char *username_to_check);
 
-/* Callbacks for setting the username bit */
-static void msim_check_username_availability_cb(PurpleConnection *gc, const char *value);
-static void msim_username_is_available_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
-static void msim_set_username_confirmed_cb(PurpleConnection *gc);
-static void msim_username_is_set_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
-static void msim_set_username(MsimSession *session, const gchar *username,
-		MSIM_USER_LOOKUP_CB cb, gpointer data);
 static char *msim_username_to_set;
 
-/** Format the "now playing" indicator, showing the artist and song.
+/**
+ * Format the "now playing" indicator, showing the artist and song.
+ *
  * @return Return a new string (must be g_free()'d), or NULL.
  */
 static gchar *
@@ -48,13 +40,17 @@
 	}
 }
 
-/** Get the MsimUser from a PurpleBuddy, optionally creating it if needed. */
+/**
+ * Get the MsimUser from a PurpleBuddy, optionally creating it if needed.
+ */
 MsimUser *
 msim_get_user_from_buddy(PurpleBuddy *buddy, gboolean create)
 {
 	MsimUser *user;
 
-	g_return_val_if_fail(buddy != NULL, NULL);
+	if (!buddy) {
+		return NULL;
+	}
 
 	if (create && !buddy->proto_data) {
 		/* No MsimUser for this buddy; make one. */
@@ -62,6 +58,7 @@
 		/* TODO: where is this freed? */
 		user = g_new0(MsimUser, 1);
 		user->buddy = buddy;
+		user->id = purple_blist_node_get_int(&buddy->node, "UserID");
 		buddy->proto_data = (gpointer)user;
 	} else {
 		user = (MsimUser *)(buddy->proto_data);
@@ -70,7 +67,9 @@
 	return user;
 }
 
-/** Find and return an MsimUser * representing a user on the buddy list, or NULL. */
+/**
+ * Find and return an MsimUser * representing a user on the buddy list, or NULL.
+ */
 MsimUser *
 msim_find_user(MsimSession *session, const gchar *username)
 {
@@ -87,7 +86,8 @@
 	return user;
 }
 
-/** Append user information to a PurpleNotifyUserInfo, given an MsimUser. 
+/**
+ * Append user information to a PurpleNotifyUserInfo, given an MsimUser.
  * Used by msim_tooltip_text() and msim_get_info_cb() to show a user's profile.
  */
 void
@@ -95,28 +95,14 @@
 {
 	PurplePresence *presence;
 	gchar *str;
-	guint uid;
 	guint cv;
 
-	/* Useful to identify the account the tooltip refers to. 
+	/* Useful to identify the account the tooltip refers to.
 	 *  Other prpls show this. */
 	if (user->username) {
 		purple_notify_user_info_add_pair(user_info, _("User"), user->username);
 	}
 
-	uid = purple_blist_node_get_int(&user->buddy->node, "UserID");
-
-	if (full) {
-		/* TODO: link to username, if available */
-		if (uid) {
-			char *profile = g_strdup_printf("<a href=\"http://myspace.com/%d\">http://myspace.com/%d</a>",
-											uid, uid);
-			purple_notify_user_info_add_pair(user_info, _("Profile"), profile);
-			g_free(profile);
-		}
-	}
-
-
 	/* a/s/l...the vitals */
 	if (user->age) {
 		char age[16];
@@ -137,21 +123,23 @@
 		purple_notify_user_info_add_pair(user_info, _("Headline"), user->headline);
 	}
 
-	presence = purple_buddy_get_presence(user->buddy);
+	if (user->buddy != NULL) {
+		presence = purple_buddy_get_presence(user->buddy);
+
+		if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
+			PurpleStatus *status;
+			const char *artist, *title;
 
-	if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
-		PurpleStatus *status;
-		const char *artist, *title;
-		
-		status = purple_presence_get_status(presence, "tune");
-		title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
-		artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
+			status = purple_presence_get_status(presence, "tune");
+			title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
+			artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
 
-		str = msim_format_now_playing(artist, title);
-		if (str && *str) {
-			purple_notify_user_info_add_pair(user_info, _("Song"), str);
+			str = msim_format_now_playing(artist, title);
+			if (str && *str) {
+				purple_notify_user_info_add_pair(user_info, _("Song"), str);
+			}
+			g_free(str);
 		}
-		g_free(str);
 	}
 
 	/* Note: total friends only available if looked up by uid, not username. */
@@ -179,9 +167,55 @@
 			purple_notify_user_info_add_pair(user_info, _("Client Version"), client);
 		g_free(client);
 	}
+
+	if (full && user->id) {
+		/* TODO: link to username, if available */
+		char *profile;
+		purple_notify_user_info_add_section_break(user_info);
+		if (user->buddy != NULL)
+			profile = g_strdup_printf("<a href=\"http://myspace.com/%s\">%s</a>",
+					purple_buddy_get_name(user->buddy), _("View web profile"));
+		else
+			profile = g_strdup_printf("<a href=\"http://myspace.com/%d\">%s</a>",
+					user->id, _("View web profile"));
+		purple_notify_user_info_add_pair(user_info, NULL, profile);
+		g_free(profile);
+	}
 }
 
-/** Set the currently playing song artist and or title.
+/**
+ * Callback for when a buddy icon finished being downloaded.
+ */
+static void
+msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data,
+		gpointer user_data,
+		const gchar *url_text,
+		gsize len,
+		const gchar *error_message)
+{
+	MsimUser *user;
+
+	user = (MsimUser *)user_data;
+
+	purple_debug_info("msim_downloaded_buddy_icon",
+			"Downloaded %" G_GSIZE_FORMAT " bytes\n", len);
+
+	if (!url_text) {
+		purple_debug_info("msim_downloaded_buddy_icon",
+				"failed to download icon for %s",
+				user->buddy->name);
+		return;
+	}
+
+	purple_buddy_icons_set_for_user(user->buddy->account,
+			user->buddy->name,
+			g_memdup((gchar *)url_text, len), len,
+			/* Use URL itself as buddy icon "checksum" (TODO: ETag) */
+			user->image_url);		/* checksum */
+}
+
+/**
+ * Set the currently playing song artist and or title.
  *
  * @param user User associated with the now playing information.
  *
@@ -199,12 +233,16 @@
 	PurplePresence *presence;
 	const char *prev_artist, *prev_title;
 
+	if (user->buddy == NULL)
+		/* User not on buddy list so nothing to do */
+		return;
+
 	prev_artist = NULL;
 	prev_title = NULL;
 
-	if (new_artist && !strlen(new_artist))
+	if (new_artist && !*new_artist)
 		new_artist = NULL;
-	if (new_title && !strlen(new_title))
+	if (new_title && !*new_title)
 		new_title = NULL;
 
 	if (!new_artist && !new_title) {
@@ -216,15 +254,15 @@
 
 	if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
 		PurpleStatus *status;
-		
+
 		status = purple_presence_get_status(presence, "tune");
 		prev_title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
 		prev_artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
-	} 
+	}
 
 	if (!new_artist)
 		new_artist = prev_artist;
-	
+
 	if (!new_title)
 		new_title = prev_title;
 
@@ -234,22 +272,25 @@
 			NULL);
 }
 
-/** Store a field of information about a buddy. 
+/**
+ * Store a field of information about a buddy.
  *
  * @param key_str Key to store.
  * @param value_str Value string, either user takes ownership of this string
  *                  or it is freed if MsimUser doesn't store the string.
  * @param user User to store data in. Existing data will be replaced.
- * */
-void 
+ */
+static void
 msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user)
 {
 	if (g_str_equal(key_str, "UserID") || g_str_equal(key_str, "ContactID")) {
 		/* Save to buddy list, if it exists, for quick cached uid lookup with msim_uid2username_from_blist(). */
+		user->id = atol(value_str);
+		g_free(value_str);
 		if (user->buddy)
 		{
 			purple_debug_info("msim", "associating uid %s with username %s\n", key_str, user->buddy->name);
-			purple_blist_node_set_int(&user->buddy->node, "UserID", atol(value_str));
+			purple_blist_node_set_int(&user->buddy->node, "UserID", user->id);
 		}
 		/* Need to store in MsimUser, too? What if not on blist? */
 	} else if (g_str_equal(key_str, "Age")) {
@@ -263,13 +304,16 @@
 		user->location = value_str;
 	} else if (g_str_equal(key_str, "TotalFriends")) {
 		user->total_friends = atol(value_str);
+		g_free(value_str);
 	} else if (g_str_equal(key_str, "DisplayName")) {
 		g_free(user->display_name);
 		user->display_name = value_str;
 	} else if (g_str_equal(key_str, "BandName")) {
 		msim_set_artist_or_title(user, value_str, NULL);
+		g_free(value_str);
 	} else if (g_str_equal(key_str, "SongName")) {
 		msim_set_artist_or_title(user, NULL, value_str);
+		g_free(value_str);
 	} else if (g_str_equal(key_str, "UserName") || g_str_equal(key_str, "IMName") || g_str_equal(key_str, "NickName")) {
 		/* Ignore because PurpleBuddy knows this already */
 		g_free(value_str);
@@ -277,7 +321,7 @@
 		const gchar *previous_url;
 
 		if (user->temporary_user) {
-			/* This user will be destroyed soon; don't try to look up its image or avatar, 
+			/* This user will be destroyed soon; don't try to look up its image or avatar,
 			 * since that won't return immediately and we will end up accessing freed data.
 			 */
 			g_free(value_str);
@@ -285,7 +329,7 @@
 		}
 
 		if (user->temporary_user) {
-			/* This user will be destroyed soon; don't try to look up its image or avatar, 
+			/* This user will be destroyed soon; don't try to look up its image or avatar,
 			 * since that won't return immediately and we will end up accessing freed data.
 			 */
 			g_free(value_str);
@@ -333,7 +377,8 @@
 	}
 }
 
-/** Save buddy information to the buddy list from a user info reply message.
+/**
+ * Save buddy information to the buddy list from a user info reply message.
  *
  * @param session
  * @param msg The user information reply, with any amount of information.
@@ -345,10 +390,9 @@
  *
  * If the function has no buddy information, this function
  * is a no-op (and returns FALSE).
- *
  */
-gboolean 
-msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user)
+gboolean
+msim_store_user_info(MsimSession *session, const MsimMessage *msg, MsimUser *user)
 {
 	gchar *username;
 	MsimMessage *body, *body_node;
@@ -361,16 +405,49 @@
 		return FALSE;
 	}
 
+	if (msim_msg_get_integer(msg, "dsn") == MG_OWN_IM_INFO_DSN &&
+		msim_msg_get_integer(msg, "lid") == MG_OWN_IM_INFO_LID) {
+		/*
+		 * Some of this info will be available on the buddy list if the
+		 * has themselves as their own buddy.
+		 *
+		 * Much of the info is already available in MsimSession,
+		 * stored in msim_we_are_logged_on().
+		 */
+		gchar *tmpstr;
+
+		tmpstr = msim_msg_get_string(body, "ShowOnlyToList");
+		if (tmpstr != NULL) {
+			session->show_only_to_list = g_str_equal(tmpstr, "True");
+			g_free(tmpstr);
+		}
+
+		session->privacy_mode = msim_msg_get_integer(body, "PrivacyMode");
+		session->offline_message_mode = msim_msg_get_integer(body, "OfflineMessageMode");
+
+		msim_send(session,
+				"blocklist", MSIM_TYPE_BOOLEAN, TRUE,
+				"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+				"idlist", MSIM_TYPE_STRING,
+						g_strdup_printf("w%d|c%d",
+								session->show_only_to_list ? 1 : 0,
+								session->privacy_mode),
+				NULL);
+	} else if (msim_msg_get_integer(msg, "dsn") == MG_OWN_MYSPACE_INFO_DSN &&
+			msim_msg_get_integer(msg, "lid") == MG_OWN_MYSPACE_INFO_LID) {
+		/* TODO: same as above, but for MySpace info. */
+	}
+
 	username = msim_msg_get_string(body, "UserName");
 
 	if (!username) {
-		purple_debug_info("msim", 
+		purple_debug_info("msim",
 			"msim_process_reply: not caching body, no UserName\n");
 		msim_msg_free(body);
 		g_free(username);
 		return FALSE;
 	}
-	
+
 	/* Null user = find and store in PurpleBuddy's proto_data */
 	if (!user) {
 		user = msim_find_user(session, username);
@@ -382,8 +459,8 @@
 	}
 
 	/* TODO: make looping over MsimMessage's easier. */
-	for (body_node = body; 
-		body_node != NULL; 
+	for (body_node = body;
+		body_node != NULL;
 		body_node = msim_msg_get_next_element_node(body_node))
 	{
 		const gchar *key_str;
@@ -397,25 +474,64 @@
 		msim_store_user_info_each(key_str, value_str, user);
 	}
 
-	if (msim_msg_get_integer(msg, "dsn") == MG_OWN_IM_INFO_DSN &&
-		msim_msg_get_integer(msg, "lid") == MG_OWN_IM_INFO_LID) {
-		/* TODO: do something with our own IM info, if we need it for some
-		 * specific purpose. Otherwise it is available on the buddy list,
-		 * if the user has themselves as their own buddy. 
-		 *
-		 * However, much of the info is already available in MsimSession,
-		 * stored in msim_we_are_logged_on(). */
-	} else if (msim_msg_get_integer(msg, "dsn") == MG_OWN_MYSPACE_INFO_DSN &&
-			msim_msg_get_integer(msg, "lid") == MG_OWN_MYSPACE_INFO_LID) {
-		/* TODO: same as above, but for MySpace info. */
-	}
-
 	msim_msg_free(body);
 	g_free(username);
 
 	return TRUE;
 }
 
+#if 0
+/**
+ * Return whether a given username is syntactically valid.
+ * Note: does not actually check that the user exists.
+ */
+static gboolean
+msim_is_valid_username(const gchar *user)
+{
+	return !msim_is_userid(user) &&  /* Not all numeric */
+		strlen(user) <= MSIM_MAX_USERNAME_LENGTH
+		&& strspn(user, "0123456789"
+			"abcdefghijklmnopqrstuvwxyz"
+			"_"
+			"ABCDEFGHIJKLMNOPQRSTUVWXYZ") == strlen(user);
+}
+#endif
+
+/**
+ * Check if a string is a userid (all numeric).
+ *
+ * @param user The user id, email, or name.
+ *
+ * @return TRUE if is userid, FALSE if not.
+ */
+gboolean
+msim_is_userid(const gchar *user)
+{
+	g_return_val_if_fail(user != NULL, FALSE);
+
+	return strspn(user, "0123456789") == strlen(user);
+}
+
+/**
+ * Check if a string is an email address (contains an @).
+ *
+ * @param user The user id, email, or name.
+ *
+ * @return TRUE if is an email, FALSE if not.
+ *
+ * This function is not intended to be used as a generic
+ * means of validating email addresses, but to distinguish
+ * between a user represented by an email address from
+ * other forms of identification.
+ */
+static gboolean
+msim_is_email(const gchar *user)
+{
+	g_return_val_if_fail(user != NULL, FALSE);
+
+	return strchr(user, '@') != NULL;
+}
+
 /**
  * Asynchronously lookup user information, calling callback when receive result.
  *
@@ -425,7 +541,7 @@
  * @param data An arbitray data pointer passed to the callback.
  */
 /* TODO: change to not use callbacks */
-void 
+void
 msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data)
 {
 	MsimMessage *body;
@@ -440,8 +556,6 @@
 	purple_debug_info("msim", "msim_lookup_userid: "
 			"asynchronously looking up <%s>\n", user);
 
-	msim_msg_dump("msim_lookup_user: data=%s\n", (MsimMessage *)data);
-
 	/* Setup callback. Response will be associated with request using 'rid'. */
 	rid = msim_new_reply_callback(session, cb, data);
 
@@ -451,8 +565,8 @@
 
 	if (msim_is_userid(user)) {
 		field_name = "UserID";
-		dsn = MG_MYSPACE_INFO_BY_ID_DSN; 
-		lid = MG_MYSPACE_INFO_BY_ID_LID; 
+		dsn = MG_MYSPACE_INFO_BY_ID_DSN;
+		lid = MG_MYSPACE_INFO_BY_ID_LID;
 	} else if (msim_is_email(user)) {
 		field_name = "Email";
 		dsn = MG_MYSPACE_INFO_BY_STRING_DSN;
@@ -477,233 +591,90 @@
 			"rid", MSIM_TYPE_INTEGER, rid,
 			"body", MSIM_TYPE_DICTIONARY, body,
 			NULL));
-} 
-
-
-/**
- * Check if a string is a userid (all numeric).
- *
- * @param user The user id, email, or name.
- *
- * @return TRUE if is userid, FALSE if not.
- */
-gboolean 
-msim_is_userid(const gchar *user)
-{
-	g_return_val_if_fail(user != NULL, FALSE);
-
-	return strspn(user, "0123456789") == strlen(user);
-}
-
-/** Return whether a given username is syntactically valid. 
- * Note: does not actually check that the user exists. */
-gboolean
-msim_is_valid_username(const gchar *user)
-{
-	return !msim_is_userid(user) &&  /* Not all numeric */
-		strlen(user) <= MSIM_MAX_USERNAME_LENGTH
-		&& strspn(user, "0123456789"
-			"abcdefghijklmnopqrstuvwxyz"
-			"_"
-			"ABCDEFGHIJKLMNOPQRSTUVWXYZ") == strlen(user);
 }
 
 /**
- * Check if a string is an email address (contains an @).
- *
- * @param user The user id, email, or name.
- *
- * @return TRUE if is an email, FALSE if not.
- *
- * This function is not intended to be used as a generic
- * means of validating email addresses, but to distinguish
- * between a user represented by an email address from
- * other forms of identification.
- */ 
-gboolean 
-msim_is_email(const gchar *user)
+ * Called after username is set.
+ */
+static void msim_username_is_set_cb(MsimSession *session, const MsimMessage *userinfo, gpointer data)
 {
-	g_return_val_if_fail(user != NULL, FALSE);
-
-	return strchr(user, '@') != NULL;
-}
-
-
-/** Callback for when a buddy icon finished being downloaded. */
-static void
-msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data,
-		gpointer user_data,
-		const gchar *url_text,
-		gsize len,
-		const gchar *error_message)
-{
-	MsimUser *user;
-
-	user = (MsimUser *)user_data;
-
-	purple_debug_info("msim_downloaded_buddy_icon",
-			"Downloaded %" G_GSIZE_FORMAT " bytes\n", len);
-
-	if (!url_text) {
-		purple_debug_info("msim_downloaded_buddy_icon",
-				"failed to download icon for %s",
-				user->buddy->name);
-		return;
-	}
+	gchar *username;
+	const gchar *errmsg;
+	MsimMessage *body;
 
-	purple_buddy_icons_set_for_user(user->buddy->account,
-			user->buddy->name,
-			g_memdup((gchar *)url_text, len), len, 
-			/* Use URL itself as buddy icon "checksum" (TODO: ETag) */
-			user->image_url);		/* checksum */
-}
-
-/*** 
- * If they hit cancel or no at any point in the Setting Username process, we come here.              *
- * Currently.. We're safe letting them get by without setting it.. Unless we hear otherwise..        *
- * So for now, give them a menu.. If this becomes an issue with the Official client.. boot them here */
-void msim_do_not_set_username_cb(PurpleConnection *gc) {
-	purple_debug_info("msim", "Don't set username");
+	guint rid;
+	gint cmd,dsn,uid,lid,code;
+	/* \persistr\\cmd\258\dsn\9\uid\204084363\lid\14\rid\369\body\UserName=TheAlbinoRhino1.Code=0\final\ */
 
-	/* Protocol won't log in now without a username set.. Disconnect */
-	purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("No username set"));
-}
- 
-/** They've decided to set a username! Yay! */
-void msim_set_username_cb(PurpleConnection *gc) {
-	g_return_if_fail(gc != NULL);
-	purple_debug_info("msim","Set username\n");
-	purple_request_input(gc, _("MySpaceIM - Please Set a Username"),
-			_("Please enter a username to check its availability:"),
-			NULL,
-			"", FALSE, FALSE, NULL,
-			_("OK"), G_CALLBACK(msim_check_username_availability_cb),
-			_("Cancel"), G_CALLBACK(msim_do_not_set_username_cb),
-			purple_connection_get_account(gc),
-			NULL,
-			NULL,
-			gc);
-}
-
-/** Once they've submitted their desired new username, 
- * check if it is available here. */
-static void msim_check_username_availability_cb(PurpleConnection *gc, const char *username_to_check) 
-{
-	MsimMessage *user_msg;
-	MsimSession *session;
-
-	g_return_if_fail(gc != NULL);
-
-	session = (MsimSession *)gc->proto_data;
+	purple_debug_info("msim","username_is_set made\n");
 
 	g_return_if_fail(MSIM_SESSION_VALID(session));
 
-	purple_debug_info("msim_check_username_availability_cb", "Checking username: %s\n", username_to_check);
-	
-	user_msg = msim_msg_new(
-			"user", MSIM_TYPE_STRING, g_strdup(username_to_check),
-			NULL);
-
-	/* 25 characters: letters, numbers, underscores */
-	/* TODO: VERIFY ABOVE */
-
-	/* \persist\1\sesskey\288500516\cmd\1\dsn\5\uid\204084363\lid\7\rid\367\body\UserName=Jaywalker\final\ */
-	/* Official client uses a standard lookup... So do we! */
-	msim_lookup_user(session, username_to_check, msim_username_is_available_cb, user_msg);
-}
-
-/** This is where we do a bit more than merely prompt the user. 
- * Now we have some real data to tell us the state of their requested username 
- * \persistr\\cmd\257\dsn\5\uid\204084363\lid\7\rid\367\body\UserName=TheAlbinoRhino1\final\ */
-static void msim_username_is_available_cb(MsimSession *session, MsimMessage *userinfo, gpointer data) 
-{
-	MsimMessage *msg;
-	gchar *username;
-	MsimMessage *body;
-	gint userid;
-
-	purple_debug_info("msim_username_is_available_cb", "Look up username callback made\n");
-	
-	msg = (MsimMessage *)data;
-	g_return_if_fail(MSIM_SESSION_VALID(session));
-	g_return_if_fail(msg != NULL);
-	
-	username = msim_msg_get_string(msg, "user");
+	cmd = msim_msg_get_integer(userinfo, "cmd");
+	dsn = msim_msg_get_integer(userinfo, "dsn");
+	uid = msim_msg_get_integer(userinfo, "uid");
+	lid = msim_msg_get_integer(userinfo, "lid");
 	body = msim_msg_get_dictionary(userinfo, "body");
+	/* XXX: Mark for translation */
+	errmsg = ("An error occurred while trying to set the username.\n"
+			"Please try again, or visit http://editprofile.myspace.com/index.cfm?"
+			"fuseaction=profile.username to set your username.");
 
 	if (!body) {
-		purple_debug_info("msim_username_is_available_cb", "No body for %s?!\n", username);
-		purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, 
-				"An error occurred while trying to set the username.\n"
-				"Please try again, or visit http://editprofile.myspace.com/index.cfm?"
-				"fuseaction=profile.username to set your username.");
-		return;
+		purple_debug_info("msim_username_is_set_cb", "No body");
+		/* Error: No body! */
+		purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
 	}
-
-	userid = msim_msg_get_integer(body, "UserID");
+	username = msim_msg_get_string(body, "UserName");
+	code = msim_msg_get_integer(body,"Code");
 
-	purple_debug_info("msim_username_is_available_cb", "Returned username is %s and userid is %d\n", username, userid);
 	msim_msg_free(body);
-	msim_msg_free(msg);
+
+	purple_debug_info("msim_username_is_set_cb",
+			"cmd = %d, dsn = %d, lid = %d, code = %d, username = %s\n",
+			cmd, dsn, lid, code, username);
 
-	/* The response for a free username will ONLY have the UserName in it.. 
-	 * thus making UserID return 0 when we msg_get_integer it */
-	if (userid == 0) {
-		/* This username is currently unused */
-		purple_debug_info("msim_username_is_available_cb", "Username available. Prompting to Confirm.\n");
-		msim_username_to_set = g_strdup(username);
-		g_free(username);
-		purple_request_yes_no(session->gc,
-			_("MySpaceIM - Username Available"),
-			_("This username is available. Would you like to set it?"),
-			_("ONCE SET, THIS CANNOT BE CHANGED!"),
-			0,
-			session->account,
-			NULL,
-			NULL,
-			session->gc, 
-			G_CALLBACK(msim_set_username_confirmed_cb), 
-			G_CALLBACK(msim_do_not_set_username_cb));
+	if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_PUT)
+			&& dsn == MC_SET_USERNAME_DSN
+			&& lid == MC_SET_USERNAME_LID)
+	{
+		purple_debug_info("msim_username_is_set_cb", "Proper cmd,dsn,lid for username_is_set!\n");
+		purple_debug_info("msim_username_is_set_cb", "Username Set with return code %d\n",code);
+		if (code == 0) {
+			/* Good! */
+			session->username = username;
+			msim_we_are_logged_on(session);
+		} else {
+			purple_debug_info("msim_username_is_set", "code is %d",code);
+			/* TODO: what to do here? */
+		}
+	} else if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_GET)
+			&& dsn == MG_MYSPACE_INFO_BY_STRING_DSN
+			&& lid == MG_MYSPACE_INFO_BY_STRING_LID) {
+		/* Not quite done... ONE MORE STEP :) */
+		rid = msim_new_reply_callback(session, msim_username_is_set_cb, data);
+		body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username), NULL);
+		if (!msim_send(session, "persist", MSIM_TYPE_INTEGER, 1,
+					"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+					"cmd", MSIM_TYPE_INTEGER, MSIM_CMD_PUT,
+					"dsn", MSIM_TYPE_INTEGER, MC_SET_USERNAME_DSN,
+					"uid", MSIM_TYPE_INTEGER, session->userid,
+					"lid", MSIM_TYPE_INTEGER, MC_SET_USERNAME_LID,
+					"rid", MSIM_TYPE_INTEGER, rid,
+					"body", MSIM_TYPE_DICTIONARY, body,
+					NULL)) {
+			/* Error! */
+			/* Can't set... Disconnect */
+			purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
+		}
+
 	} else {
-		/* Looks like its in use or we have an invalid response */
-		purple_debug_info("msim_username_is_available_cb", "Username unavaiable. Prompting for new entry.\n");
-		purple_request_input(session->gc, _("MySpaceIM - Please Set a Username"),
-			_("This username is unavailable."),
-				_("Please try another username:"),
-				"", FALSE, FALSE, NULL,
-				_("OK"), G_CALLBACK(msim_check_username_availability_cb),
-				_("Cancel"), G_CALLBACK(msim_do_not_set_username_cb),
-				session->account,
-				NULL,
-				NULL,
-				session->gc);
+		/* Error! */
+		purple_debug_info("msim","username_is_set Error: Invalid cmd/dsn/lid combination");
+		purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
 	}
 }
 
-/* They've confirmed that username that was available, Lets make the call to set it */
-static void msim_set_username_confirmed_cb(PurpleConnection *gc) 
-{
-	MsimMessage *user_msg;
-	MsimSession *session;
-
-	g_return_if_fail(gc != NULL);
-
-	session = (MsimSession *)gc->proto_data;
-
-	g_return_if_fail(MSIM_SESSION_VALID(session));
-
-
-	user_msg = msim_msg_new(
-			"user", MSIM_TYPE_STRING, g_strdup(msim_username_to_set),
-			NULL);
-
-	purple_debug_info("msim_set_username_confirmed_cb", "Setting username to %s\n", msim_username_to_set);
-	
-	/* Sets our username... keep your fingers crossed :) */
-	msim_set_username(session, msim_username_to_set, msim_username_is_set_cb, user_msg);
-	g_free(msim_username_to_set);
-}
-
 /**
  * Asynchronously set new username, calling callback when receive result.
  *
@@ -712,7 +683,7 @@
  * @param cb Callback, called with user information when available.
  * @param data An arbitray data pointer passed to the callback.
  */
-static void 
+static void
 msim_set_username(MsimSession *session, const gchar *username,
 		MSIM_USER_LOOKUP_CB cb, gpointer data)
 {
@@ -726,8 +697,6 @@
 	purple_debug_info("msim", "msim_set_username: "
 			"Setting username %s\n", username);
 
-	msim_msg_dump("msim_set_username: data=%s\n", (MsimMessage *)data);
-
 	/* Setup callback. Response will be associated with request using 'rid'. */
 	rid = msim_new_reply_callback(session, cb, data);
 
@@ -756,82 +725,160 @@
 			 NULL));
 }
 
-/** Called after username is set. */
-static void msim_username_is_set_cb(MsimSession *session, MsimMessage *userinfo, gpointer data) 
+/**
+ * They've confirmed that username that was available, Lets make the call to set it
+ */
+static void msim_set_username_confirmed_cb(PurpleConnection *gc)
 {
-	gchar *username, *errmsg;
-	MsimMessage *body;
+	MsimMessage *user_msg;
+	MsimSession *session;
 
-	guint rid;
-	gint cmd,dsn,uid,lid,code;
-	/* \persistr\\cmd\258\dsn\9\uid\204084363\lid\14\rid\369\body\UserName=TheAlbinoRhino1.Code=0\final\ */
+	g_return_if_fail(gc != NULL);
 
-	purple_debug_info("msim","username_is_set made\n");
-	
+	session = (MsimSession *)gc->proto_data;
+
 	g_return_if_fail(MSIM_SESSION_VALID(session));
 
 
-	msim_msg_dump("username_is_set message is: %s\n", userinfo);
-	cmd = msim_msg_get_integer(userinfo, "cmd");
-	dsn = msim_msg_get_integer(userinfo, "dsn");
-	uid = msim_msg_get_integer(userinfo, "uid");
-	lid = msim_msg_get_integer(userinfo, "lid");
+	user_msg = msim_msg_new(
+			"user", MSIM_TYPE_STRING, g_strdup(msim_username_to_set),
+			NULL);
+
+	purple_debug_info("msim_set_username_confirmed_cb", "Setting username to %s\n", msim_username_to_set);
+
+	/* Sets our username... keep your fingers crossed :) */
+	msim_set_username(session, msim_username_to_set, msim_username_is_set_cb, user_msg);
+	g_free(msim_username_to_set);
+}
+
+/**
+ * This is where we do a bit more than merely prompt the user.
+ * Now we have some real data to tell us the state of their requested username
+ * \persistr\\cmd\257\dsn\5\uid\204084363\lid\7\rid\367\body\UserName=TheAlbinoRhino1\final\
+ */
+static void msim_username_is_available_cb(MsimSession *session, const MsimMessage *userinfo, gpointer data)
+{
+	MsimMessage *msg;
+	gchar *username;
+	MsimMessage *body;
+	gint userid;
+
+	purple_debug_info("msim_username_is_available_cb", "Look up username callback made\n");
+
+	msg = (MsimMessage *)data;
+	g_return_if_fail(MSIM_SESSION_VALID(session));
+	g_return_if_fail(msg != NULL);
+
+	username = msim_msg_get_string(msg, "user");
 	body = msim_msg_get_dictionary(userinfo, "body");
-	errmsg = g_strdup("An error occurred while trying to set the username.\n"
-			"Please try again, or visit http://editprofile.myspace.com/index.cfm?"
-			"fuseaction=profile.username to set your username.");
-	
+
 	if (!body) {
-		purple_debug_info("msim_username_is_set_cb", "No body");
-		/* Error: No body! */
-		purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
+		purple_debug_info("msim_username_is_available_cb", "No body for %s?!\n", username);
+		purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
+				"An error occurred while trying to set the username.\n"
+				"Please try again, or visit http://editprofile.myspace.com/index.cfm?"
+				"fuseaction=profile.username to set your username.");
+		return;
 	}
-	username = msim_msg_get_string(body, "UserName");
-	code = msim_msg_get_integer(body,"Code");
 
+	userid = msim_msg_get_integer(body, "UserID");
+
+	purple_debug_info("msim_username_is_available_cb", "Returned username is %s and userid is %d\n", username, userid);
 	msim_msg_free(body);
-
-	purple_debug_info("msim_username_is_set_cb", 
-			"cmd = %d, dsn = %d, lid = %d, code = %d, username = %s\n", 
-			cmd, dsn, lid, code, username);
+	msim_msg_free(msg);
 
-	if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_PUT) 
-			&& dsn == MC_SET_USERNAME_DSN 
-			&& lid == MC_SET_USERNAME_LID) {
-		purple_debug_info("msim_username_is_set_cb", "Proper cmd,dsn,lid for username_is_set!\n");
-		purple_debug_info("msim_username_is_set_cb", "Username Set with return code %d\n",code);
-		if (code == 0) {
-			/* Good! */
-			session->username = username;
-			msim_we_are_logged_on(session);
-		} else {
-			purple_debug_info("msim_username_is_set", "code is %d",code);
-			/* TODO: what to do here? */
-		}
-	} else if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_GET) 
-			&& dsn == MG_MYSPACE_INFO_BY_STRING_DSN 
-			&& lid == MG_MYSPACE_INFO_BY_STRING_LID) {
-		/* Not quite done... ONE MORE STEP :) */
-		rid = msim_new_reply_callback(session, msim_username_is_set_cb, data);
-		body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username), NULL);
-		if (!msim_send(session, "persist", MSIM_TYPE_INTEGER, 1, 
-					"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
-					"cmd", MSIM_TYPE_INTEGER, MSIM_CMD_PUT, 
-					"dsn", MSIM_TYPE_INTEGER, MC_SET_USERNAME_DSN, 
-					"uid", MSIM_TYPE_INTEGER, session->userid,
-					"lid", MSIM_TYPE_INTEGER, MC_SET_USERNAME_LID, 
-					"rid", MSIM_TYPE_INTEGER, rid, 
-					"body", MSIM_TYPE_DICTIONARY, body, 
-					NULL)) {
-			/* Error! */
-			/* Can't set... Disconnect */
-			purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
-		}
-			
+	/* The response for a free username will ONLY have the UserName in it..
+	 * thus making UserID return 0 when we msg_get_integer it */
+	if (userid == 0) {
+		/* This username is currently unused */
+		purple_debug_info("msim_username_is_available_cb", "Username available. Prompting to Confirm.\n");
+		msim_username_to_set = g_strdup(username);
+		g_free(username);
+		purple_request_yes_no(session->gc,
+			_("MySpaceIM - Username Available"),
+			_("This username is available. Would you like to set it?"),
+			_("ONCE SET, THIS CANNOT BE CHANGED!"),
+			0,
+			session->account,
+			NULL,
+			NULL,
+			session->gc,
+			G_CALLBACK(msim_set_username_confirmed_cb),
+			G_CALLBACK(msim_do_not_set_username_cb));
 	} else {
-		/* Error! */
-		purple_debug_info("msim","username_is_set Error: Invalid cmd/dsn/lid combination");
-		purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
+		/* Looks like its in use or we have an invalid response */
+		purple_debug_info("msim_username_is_available_cb", "Username unavaiable. Prompting for new entry.\n");
+		purple_request_input(session->gc, _("MySpaceIM - Please Set a Username"),
+			_("This username is unavailable."),
+				_("Please try another username:"),
+				"", FALSE, FALSE, NULL,
+				_("OK"), G_CALLBACK(msim_check_username_availability_cb),
+				_("Cancel"), G_CALLBACK(msim_do_not_set_username_cb),
+				session->account,
+				NULL,
+				NULL,
+				session->gc);
 	}
-	g_free(errmsg);
+}
+
+/**
+ * Once they've submitted their desired new username,
+ * check if it is available here.
+ */
+static void msim_check_username_availability_cb(PurpleConnection *gc, const char *username_to_check)
+{
+	MsimMessage *user_msg;
+	MsimSession *session;
+
+	g_return_if_fail(gc != NULL);
+
+	session = (MsimSession *)gc->proto_data;
+
+	g_return_if_fail(MSIM_SESSION_VALID(session));
+
+	purple_debug_info("msim_check_username_availability_cb", "Checking username: %s\n", username_to_check);
+
+	user_msg = msim_msg_new(
+			"user", MSIM_TYPE_STRING, g_strdup(username_to_check),
+			NULL);
+
+	/* 25 characters: letters, numbers, underscores */
+	/* TODO: VERIFY ABOVE */
+
+	/* \persist\1\sesskey\288500516\cmd\1\dsn\5\uid\204084363\lid\7\rid\367\body\UserName=Jaywalker\final\ */
+	/* Official client uses a standard lookup... So do we! */
+	msim_lookup_user(session, username_to_check, msim_username_is_available_cb, user_msg);
 }
+
+/***
+ * If they hit cancel or no at any point in the Setting Username process,
+ * we come here.  Currently we're safe letting them get by without
+ * setting it, unless we hear otherwise.  So for now give them a menu.
+ * If this becomes an issue with the official client then boot them here.
+ */
+void msim_do_not_set_username_cb(PurpleConnection *gc)
+{
+	purple_debug_info("msim", "Don't set username");
+
+	/* Protocol won't log in now without a username set.. Disconnect */
+	purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("No username set"));
+}
+
+/**
+ * They've decided to set a username! Yay!
+ */
+void msim_set_username_cb(PurpleConnection *gc)
+{
+	g_return_if_fail(gc != NULL);
+	purple_debug_info("msim","Set username\n");
+	purple_request_input(gc, _("MySpaceIM - Please Set a Username"),
+			_("Please enter a username to check its availability:"),
+			NULL,
+			"", FALSE, FALSE, NULL,
+			_("OK"), G_CALLBACK(msim_check_username_availability_cb),
+			_("Cancel"), G_CALLBACK(msim_do_not_set_username_cb),
+			purple_connection_get_account(gc),
+			NULL,
+			NULL,
+			gc);
+}