changeset 25758:b535b9ffb929

propagate from branch 'im.pidgin.pidgin' (head 6b951d62be418d5bfc437a1ab747c6ba900d7979) to branch 'im.pidgin.cpw.malu.xmpp.ibb_ft' (head 95e1ae61eda292e6ca5f636d5fc76bac8262940b)
author Marcus Lundblad <ml@update.uu.se>
date Tue, 16 Dec 2008 19:18:41 +0000
parents 476466aca5e0 (diff) 4b51394fd834 (current diff)
children 69cf692c09f5
files
diffstat 16 files changed, 3989 insertions(+), 4495 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Dec 16 19:17:44 2008 +0000
+++ b/ChangeLog	Tue Dec 16 19:18:41 2008 +0000
@@ -4,26 +4,29 @@
 	libpurple:
 	* Corrected maximum message lengths for Yahoo!
 	* The Buddy State Notification plugin no longer prints duplicate
-	  notifications when the same buddy is in multiple groups (Florian Quèze)
-	* The Buddy State Notification plugin no longer turns JID's, MSN Passport
-	  ID's, etc. into links (Florian Quèze)
-	* purple-remote now has a "getstatusmessage" command to retrieve the text
-	  of the current status message.
+	  notifications when the same buddy is in multiple groups (Florian
+	  Quèze)
+	* The Buddy State Notification plugin no longer turns JID's, MSN
+	  Passport ID's, etc. into links (Florian Quèze)
+	* purple-remote now has a "getstatusmessage" command to retrieve
+	  the text of the current status message.
 	* Various fixes to the nullprpl (Paul Aurich)
 	* Fix a crash when accessing the roomlist for an account that's not
 	  connected (Paul Aurich)
-	* Fix a crash in purple_accounts_delete that happens when this function is
-	  called before the buddy list is initialized (Florian Quèze)
-	* Fix use of av_len in perl bindings to fix some off-by-one bugs (Paul
-	  Aurich)
-	* On ICQ, advertise the ICQ 6 typing capability.  This should fix the
-	  reports of typing notifications not working with third-party clients
-	  (Jaromír Karmazín)
+	* Fix a crash in purple_accounts_delete that happens when this
+	  function is called before the buddy list is initialized
+	  (Florian Quèze)
+	* Fix use of av_len in perl bindings to fix some off-by-one bugs
+	  (Paul Aurich)
+	* On ICQ, advertise the ICQ 6 typing capability.  This should fix
+	  the reports of typing notifications not working with third-party
+	  clients (Jaromír Karmazín)
 	* Many QQ fixes and improvements, including the ability to connect
 	  using QQ2008 protocol and sending/receiving of long messages.
 	* Fix a crash with DNS SRV lookups (Florian Quèze)
-	* Fix insanely long idle times for Sametime 7.5 buddies by assuming 0 idle
-	  time if the idle timestamp is in the future (Laurent Montaron)
+	* Fix insanely long idle times for Sametime 7.5 buddies by assuming
+	  0 idle time if the idle timestamp is in the future (Laurent
+	  Montaron)
 
 	Gadu-Gadu:
 	* Fix some problems with Gadu-Gadu buddy icons (Adam Strzelecki)
@@ -32,46 +35,47 @@
 	  Strzelecki)
 
 	MSN:
-	* Fix an error with offline messages by shipping the *new* "Microsoft
-	  Secure Server Authority" and the "Microsoft Internet Authority"
-	  certificates. These are now always installed even when using
-	  --with-system-ssl-certs because most systems don't ship those
-	  intermediate certificates.
-	* The Games and Office media can now be set and displayed (in addition
-	  to the previous Music media). The Media status text now shows the
-	  album, if possible.
+	* Fix an error with offline messages by shipping the *new*
+	  "Microsoft Secure Server Authority" and the "Microsoft Internet
+	  Authority" certificates. These are now always installed even when
+	  using --with-system-ssl-certs because most systems don't ship
+	  those intermediate certificates.
+	* The Games and Office media can now be set and displayed (in
+	  addition to the previous Music media). The Media status text now
+	  shows the album, if possible.
 	* Messages sent from a mobile device while you were offline are now
 	  correctly received.
-	* Server transfers after you've been connected for a long time should 
-	  now be handled correctly.
+	* Server transfers after you've been connected for a long time
+	  should now be handled correctly.
 	* Many other fixes and code cleanup.
 
 	SIMPLE:
 	* Fix a crash when a malformed message is received.
-	* Don't allow connecting accounts if no server name has been specified
-	  (Florian Quèze)
+	* Don't allow connecting accounts if no server name has been
+	  specified (Florian Quèze)
 
 	XMPP:
-	* Fix the namespace URL we look for in PEP reply stanzas to match the URL
-	  used in the 'get' requests (Paul Aurich)
+	* Fix the namespace URL we look for in PEP reply stanzas to match
+	  the URL used in the 'get' requests (Paul Aurich)
 	* Resources can be set to the local machine's hostname by using
 	  __HOSTNAME__ as the resource string (Jonathan Sailor)
 	* Resources can now be left blank, causing the server to generate a
 	  resource for us where supported (Jonathan Sailor)
 	* Resources now default to no value
 	* Quit trying to get user info for MUC's (Paul Aurich)
-	* Send "client-accepts-full-bind-result" attribute during SASL login.
-	  This will fix Google Talk login failures if the user configures the
-	  wrong domain for his/her account.
-	* Support new <metadata/> element to indicate no XEP-0084 User Avatar
-	  (Paul Aurich)
-	* Fix SHA1 avatar checksum errors that occur when one of the bytes in a
-	  checksum begins with 0 (Paul Aurich)
-	
+	* Send "client-accepts-full-bind-result" attribute during SASL
+	  login. This will fix Google Talk login failures if the user
+	  configures the wrong domain for his/her account.
+	* Support new <metadata/> element to indicate no XEP-0084 User
+	  Avatar (Paul Aurich)
+	* Fix SHA1 avatar checksum errors that occur when one of the bytes
+	  in a checksum begins with 0 (Paul Aurich)
+
 	Zephyr:
 	* Enable auto-reply, to emulate 'zaway' (Toby Schaffer)
-	* Fix a crash when an account is configured to use tzc but tzc is not
-	  installed or the configured tzc command is invalid (Michael Terry)
+	* Fix a crash when an account is configured to use tzc but tzc is
+	  not installed or the configured tzc command is invalid (Michael
+	  Terry)
 	* Fix a 10 second delay waiting on tzc if it is not installed or the
 	  configured command is invalid (Michael Terry)
 
@@ -81,13 +85,18 @@
 	  previously changed that pref, add a line like this to
 	  ~/.purple/gtkrc-2.0 (where 500 is the timeout (in ms) you want):
 	      gtk-tooltip-timeout = 500
-	  To completely disable tooltips (e.g. if you had an old tooltip_delay
-	  of zero), add this to ~/.purple/gtkrc-2.0:
+	  To completely disable tooltips (e.g. if you had an old
+	  tooltip_delay of zero), add this to ~/.purple/gtkrc-2.0:
 	      gtk-enable-tooltips = 0
 	* Moved the release notification dialog to a mini-dialog in the
 	  buddylist.  (Thanks to Casey Ho)
-	* Fix a crash when closing an authorization minidialog with the X then
-	  immediately going offline (Paul Aurich)
+	* Fix a crash when closing an authorization minidialog with the X
+	  then immediately going offline (Paul Aurich)
+	* Fix a crash when closing Pidgin related to custom smileys (disassociate
+	  smileys from GtkIMHtml widgets when they are destroyed).
+	* Fix adding custom a custom smiley using the context menu from a
+	  conversation in the case when no custom smiley had been added before
+	  using the smiley manager.
 
 	Finch:
 	* Allow binding meta+arrow keys for actions.
--- a/libpurple/protocols/msn/nexus.c	Tue Dec 16 19:17:44 2008 +0000
+++ b/libpurple/protocols/msn/nexus.c	Tue Dec 16 19:18:41 2008 +0000
@@ -434,6 +434,9 @@
 #endif
 	char *decrypted_data;
 
+	if (resp == NULL)
+		return;
+
 	purple_debug_info("msn", "Got Update Response for %s.\n", ticket_domains[ud->id][SSO_VALID_TICKET_DOMAIN]);
 
 	enckey = xmlnode_get_child(resp->xml, "Header/Security/DerivedKeyToken");
--- a/libpurple/protocols/myspace/markup.c	Tue Dec 16 19:17:44 2008 +0000
+++ b/libpurple/protocols/myspace/markup.c	Tue Dec 16 19:18:41 2008 +0000
@@ -193,7 +193,7 @@
 	decor_str = xmlnode_get_attrib(root, "s");
 
 	/* Validate the font face, to avoid constructing invalid HTML later */
-	if (strchr(face, '\'') != NULL)
+	if (face != NULL && strchr(face, '\'') != NULL)
 		face = NULL;
 
 	height = height_str != NULL ? atol(height_str) : 12;
--- a/libpurple/protocols/myspace/message.c	Tue Dec 16 19:17:44 2008 +0000
+++ b/libpurple/protocols/myspace/message.c	Tue Dec 16 19:18:41 2008 +0000
@@ -1005,7 +1005,7 @@
  * @return MsimMessage *. Caller should msim_msg_free() when done.
  */
 MsimMessage *
-msim_parse(gchar *raw)
+msim_parse(const gchar *raw)
 {
 	MsimMessage *msg;
 	gchar *token;
@@ -1026,7 +1026,6 @@
 				"missing initial backslash: <%s>\n", raw);
 		/* XXX: Should we try to recover, and read to first backslash? */
 
-		g_free(raw);
 		return NULL;
 	}
 
@@ -1057,9 +1056,6 @@
 	}
 	g_strfreev(tokens);
 
-	/* Can free now since all data was copied to hash key/values */
-	g_free(raw);
-
 	return msg;
 }
 
@@ -1214,8 +1210,8 @@
  *
  * @return A new MsimMessage *. Must msim_msg_free() when done.
  */
-MsimMessage *
-msim_msg_dictionary_parse(gchar *raw)
+static MsimMessage *
+msim_msg_dictionary_parse(const gchar *raw)
 {
 	MsimMessage *dict;
 	gchar *item;
@@ -1275,7 +1271,7 @@
 			return msim_msg_clone((MsimMessage *)elem->data);
 
 		case MSIM_TYPE_RAW:
-			return msim_msg_dictionary_parse((gchar *)elem->data);
+			return msim_msg_dictionary_parse(elem->data);
 
 		default:
 			purple_debug_info("msim_msg_get_dictionary", "type %d unknown, name %s\n",
--- a/libpurple/protocols/myspace/message.h	Tue Dec 16 19:17:44 2008 +0000
+++ b/libpurple/protocols/myspace/message.h	Tue Dec 16 19:18:41 2008 +0000
@@ -91,8 +91,7 @@
 
 gboolean msim_msg_send(struct _MsimSession *session, MsimMessage *msg);
 
-MsimMessage *msim_parse(gchar *raw);
-MsimMessage *msim_msg_dictionary_parse(gchar *raw);
+MsimMessage *msim_parse(const gchar *raw);
 
 MsimMessageElement *msim_msg_get(MsimMessage *msg, const gchar *name);
 
--- a/libpurple/protocols/myspace/myspace.c	Tue Dec 16 19:17:44 2008 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Tue Dec 16 19:18:41 2008 +0000
@@ -1,4 +1,5 @@
-/* MySpaceIM Protocol Plugin
+/**
+ * MySpaceIM Protocol Plugin
  *
  * \author Jeff Connelly
  *
@@ -35,87 +36,430 @@
 
 #include "myspace.h"
 
-/* Internal functions */
-
-#ifdef MSIM_DEBUG_MSG
-static void print_hash_item(gpointer key, gpointer value, gpointer user_data);
-#endif
-
-static int msim_send_really_raw(PurpleConnection *gc, const char *buf, int total_bytes);
-static gboolean msim_login_challenge(MsimSession *session, MsimMessage *msg);
-static gchar *msim_compute_login_response(const gchar nonce[2 * NONCE_SIZE], const gchar *email, const gchar *password, guint *response_len);
-
-static gboolean msim_incoming_bm_record_cv(MsimSession *session, MsimMessage *msg);
-static gboolean msim_incoming_bm(MsimSession *session, MsimMessage *msg);
-static gboolean msim_incoming_status(MsimSession *session, MsimMessage *msg);
-static gboolean msim_incoming_im(MsimSession *session, MsimMessage *msg);
-/* static gboolean msim_incoming_zap(MsimSession *session, MsimMessage *msg); - in zap.c */
-static gboolean msim_incoming_action(MsimSession *session, MsimMessage *msg);
-static gboolean msim_incoming_media(MsimSession *session, MsimMessage *msg);
-static gboolean msim_incoming_unofficial_client(MsimSession *session, 
-		MsimMessage *msg);
-
-#ifdef MSIM_SEND_CLIENT_VERSION
-static gboolean msim_send_unofficial_client(MsimSession *session, gchar *username);
-#endif
-
-static void msim_get_info_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
-
-static void msim_set_status_code(MsimSession *session, guint code, gchar *statstring);
-
-static gboolean msim_process_server_info(MsimSession *session, MsimMessage *msg);
-static gboolean msim_web_challenge(MsimSession *session, MsimMessage *msg); 
-static gboolean msim_process_reply(MsimSession *session, MsimMessage *msg);
-
-static gboolean msim_preprocess_incoming(MsimSession *session, MsimMessage *msg);
-
-#ifdef MSIM_USE_KEEPALIVE
-static gboolean msim_check_alive(gpointer data);
-#endif
-
-static gboolean msim_is_username_set(MsimSession *session, MsimMessage *msg);
-
-static gboolean msim_process(MsimSession *session, MsimMessage *msg);
-
-static MsimMessage *msim_do_postprocessing(MsimMessage *msg, const gchar *uid_field_name, const gchar *uid_before, guint uid);
-static void msim_postprocess_outgoing_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
-static gboolean msim_postprocess_outgoing(MsimSession *session, MsimMessage *msg, const gchar *username, const gchar *uid_field_name, const gchar *uid_before); 
-
-static gboolean msim_error(MsimSession *session, MsimMessage *msg);
-
-static void msim_check_inbox_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
-static gboolean msim_check_inbox(gpointer data);
-
-static void msim_input_cb(gpointer gc_uncasted, gint source, PurpleInputCondition cond);
-
-
-static void msim_connect_cb(gpointer data, gint source, const gchar *error_message);
-
-static void msim_import_friends(PurplePluginAction *action);
-static void msim_import_friends_cb(MsimSession *session, MsimMessage *reply, gpointer user_data);
-static gboolean msim_get_contact_list(MsimSession *session, int what_to_do_after);
-
-static gboolean msim_uri_handler(const gchar *proto, const gchar *cmd, GHashTable *params);
-static void msim_uri_handler_addContact_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
-static void msim_uri_handler_sendIM_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
-
-/** 
- * Load the plugin.
+static void msim_set_status(PurpleAccount *account, PurpleStatus *status);
+static void msim_set_idle(PurpleConnection *gc, int time);
+
+/**
+ * Perform actual postprocessing on a message, adding userid as specified.
+ *
+ * @param msg The message to postprocess.
+ * @param uid_before Name of field where to insert new field before, or NULL for end.
+ * @param uid_field_name Name of field to add uid to.
+ * @param uid The userid to insert.
+ *
+ * If the field named by uid_field_name already exists, then its string contents will
+ * be used for the field, except "<uid>" will be replaced by the userid.
+ *
+ * If the field named by uid_field_name does not exist, it will be added before the
+ * field named by uid_before, as an integer, with the userid.
+ *
+ * Does not handle sending, or scheduling userid lookup. For that, see msim_postprocess_outgoing().
+ */
+static MsimMessage *
+msim_do_postprocessing(MsimMessage *msg, const gchar *uid_before,
+		const gchar *uid_field_name, guint uid)
+{
+	MsimMessageElement *elem;
+	msim_msg_dump("msim_do_postprocessing msg: %s\n", msg);
+
+	/* First, check - if the field already exists, replace <uid> within it */
+	if ((elem = msim_msg_get(msg, uid_field_name)) != NULL) {
+		gchar *fmt_string;
+		gchar *uid_str, *new_str;
+
+		/* Get the packed element, flattening it. This allows <uid> to be
+		 * replaced within nested data structures, since the replacement is done
+		 * on the linear, packed data, not on a complicated data structure.
+		 *
+		 * For example, if the field was originally a dictionary or a list, you
+		 * would have to iterate over all the items in it to see what needs to
+		 * be replaced. But by packing it first, the <uid> marker is easily replaced
+		 * just by a string replacement.
+		 */
+		fmt_string = msim_msg_pack_element_data(elem);
+
+		uid_str = g_strdup_printf("%d", uid);
+		new_str = purple_strreplace(fmt_string, "<uid>", uid_str);
+		g_free(uid_str);
+		g_free(fmt_string);
+
+		/* Free the old element data */
+		msim_msg_free_element_data(elem->data);
+
+		/* Replace it with our new data */
+		elem->data = new_str;
+		elem->type = MSIM_TYPE_RAW;
+
+	} else {
+		/* Otherwise, insert new field into outgoing message. */
+		msg = msim_msg_insert_before(msg, uid_before, uid_field_name, MSIM_TYPE_INTEGER, GUINT_TO_POINTER(uid));
+	}
+
+	msim_msg_dump("msim_postprocess_outgoing_cb: postprocessed msg=%s\n", msg);
+
+	return msg;
+}
+
+/**
+ * Callback for msim_postprocess_outgoing() to add a userid to a message, and send it (once receiving userid).
+ *
+ * @param session
+ * @param userinfo The user information reply message, containing the user ID
+ * @param data The message to postprocess and send.
+ *
+ * The data message should contain these fields:
+ *
+ *  _uid_field_name: string, name of field to add with userid from userinfo message
+ *  _uid_before: string, name of field before field to insert, or NULL for end
+ */
+static void
+msim_postprocess_outgoing_cb(MsimSession *session, MsimMessage *userinfo,
+		gpointer data)
+{
+	gchar *uid_field_name, *uid_before, *username;
+	guint uid;
+	MsimMessage *msg, *body;
+
+	msg = (MsimMessage *)data;
+
+	msim_msg_dump("msim_postprocess_outgoing_cb() got msg=%s\n", msg);
+
+	/* Obtain userid from userinfo message. */
+	body = msim_msg_get_dictionary(userinfo, "body");
+	g_return_if_fail(body != NULL);
+
+	uid = msim_msg_get_integer(body, "UserID");
+	msim_msg_free(body);
+
+	username = msim_msg_get_string(msg, "_username");
+
+	if (!uid) {
+		gchar *msg;
+
+		msg = g_strdup_printf(_("No such user: %s"), username);
+		if (!purple_conv_present_error(username, session->account, msg)) {
+			purple_notify_error(NULL, NULL, _("User lookup"), msg);
+		}
+
+		g_free(msg);
+		g_free(username);
+		/* TODO: free
+		 * msim_msg_free(msg);
+		 */
+		return;
+	}
+
+	uid_field_name = msim_msg_get_string(msg, "_uid_field_name");
+	uid_before = msim_msg_get_string(msg, "_uid_before");
+
+	msg = msim_do_postprocessing(msg, uid_before, uid_field_name, uid);
+
+	/* Send */
+	if (!msim_msg_send(session, msg)) {
+		msim_msg_dump("msim_postprocess_outgoing_cb: sending failed for message: %s\n", msg);
+	}
+
+
+	/* Free field names AFTER sending message, because MsimMessage does NOT copy
+	 * field names - instead, treats them as static strings (which they usually are).
+	 */
+	g_free(uid_field_name);
+	g_free(uid_before);
+	g_free(username);
+	/* TODO: free
+	 * msim_msg_free(msg);
+	 */
+}
+
+/**
+ * Postprocess and send a message.
+ *
+ * @param session
+ * @param msg Message to postprocess. Will NOT be freed.
+ * @param username Username to resolve. Assumed to be a static string (will not be freed or copied).
+ * @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 TRUE if successful.
  */
-gboolean 
-msim_load(PurplePlugin *plugin)
+static gboolean
+msim_postprocess_outgoing(MsimSession *session, MsimMessage *msg,
+		const gchar *username, const gchar *uid_field_name,
+		const gchar *uid_before)
+{
+	PurpleBuddy *buddy;
+	guint uid;
+	gboolean rc;
+
+	g_return_val_if_fail(msg != NULL, FALSE);
+
+	/* Store information for msim_postprocess_outgoing_cb(). */
+	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));
+	msg = msim_msg_append(msg, "_uid_before", MSIM_TYPE_STRING, g_strdup(uid_before));
+
+	/* First, try the most obvious. If numeric userid is given, use that directly. */
+	if (msim_is_userid(username)) {
+		uid = atol(username);
+	} else {
+		/* Next, see if on buddy list and know uid. */
+		buddy = purple_find_buddy(session->account, username);
+		if (buddy) {
+			uid = purple_blist_node_get_int(&buddy->node, "UserID");
+		} else {
+			uid = 0;
+		}
+
+		if (!buddy || !uid) {
+			/* Don't have uid offhand - need to ask for it, and wait until hear back before sending. */
+			purple_debug_info("msim", ">>> msim_postprocess_outgoing: couldn't find username %s in blist\n",
+					username ? username : "(NULL)");
+			msim_msg_dump("msim_postprocess_outgoing - scheduling lookup, msg=%s\n", msg);
+			/* TODO: where is cloned message freed? Should be in _cb. */
+			msim_lookup_user(session, username, msim_postprocess_outgoing_cb, msim_msg_clone(msg));
+			return TRUE;       /* not sure of status yet - haven't sent! */
+		}
+	}
+
+	/* Already have uid, postprocess and send msg immediately. */
+	purple_debug_info("msim", "msim_postprocess_outgoing: found username %s has uid %d\n",
+			username ? username : "(NULL)", uid);
+
+	msg = msim_do_postprocessing(msg, uid_before, uid_field_name, uid);
+
+	msim_msg_dump("msim_postprocess_outgoing: msg after (uid immediate)=%s\n", msg);
+
+	rc = msim_msg_send(session, msg);
+
+	/* TODO: free
+	 * msim_msg_free(msg);
+	 */
+
+	return rc;
+}
+
+/**
+ * Send a buddy message of a given type.
+ *
+ * @param session
+ * @param who Username to send message to.
+ * @param text Message text to send. Not freed; will be copied.
+ * @param type A MSIM_BM_* constant.
+ *
+ * @return TRUE if success, FALSE if fail.
+ *
+ * Buddy messages ('bm') include instant messages, action messages, status messages, etc.
+ */
+gboolean
+msim_send_bm(MsimSession *session, const gchar *who, const gchar *text,
+		int type)
+{
+	gboolean rc;
+	MsimMessage *msg;
+	const gchar *from_username;
+
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+	g_return_val_if_fail(who != NULL, FALSE);
+	g_return_val_if_fail(text != NULL, FALSE);
+
+	from_username = session->account->username;
+
+	g_return_val_if_fail(from_username != NULL, FALSE);
+
+	purple_debug_info("msim", "sending %d message from %s to %s: %s\n",
+				  type, from_username, who, text);
+
+	msg = msim_msg_new(
+			"bm", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(type),
+			"sesskey", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(session->sesskey),
+			/* 't' will be inserted here */
+			"cv", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(MSIM_CLIENT_VERSION),
+			"msg", MSIM_TYPE_STRING, g_strdup(text),
+			NULL);
+
+	rc = msim_postprocess_outgoing(session, msg, who, "t", "cv");
+
+	msim_msg_free(msg);
+
+	return rc;
+}
+
+/**
+ * Lookup a username by userid, from buddy list.
+ *
+ * @param wanted_uid
+ *
+ * @return Username of wanted_uid, if on blist, or NULL.
+ *         This is a static string, so don't free it. Copy it if needed.
+ *
+ */
+static const gchar *
+msim_uid2username_from_blist(PurpleAccount *account, guint wanted_uid)
 {
-	/* If compiled to use RC4 from libpurple, check if it is really there. */
-	if (!purple_ciphers_find_cipher("rc4")) {
-		purple_debug_error("msim", "rc4 not in libpurple, but it is required - not loading MySpaceIM plugin!\n");
-		purple_notify_error(plugin, _("Missing Cipher"), 
-				_("The RC4 cipher could not be found"),
-				_("Upgrade "
-					"to a libpurple with RC4 support (>= 2.0.1). MySpaceIM "
-					"plugin will not be loaded."));
-		return FALSE;
+	GSList *buddies, *cur;
+	const gchar *ret;
+
+	buddies = purple_find_buddies(account, NULL);
+
+	if (!buddies)
+	{
+		purple_debug_info("msim", "msim_uid2username_from_blist: no buddies?\n");
+		return NULL;
+	}
+
+	ret = NULL;
+
+	for (cur = buddies; cur != NULL; cur = g_slist_next(cur))
+	{
+		PurpleBuddy *buddy;
+		guint uid;
+		const gchar *name;
+
+		/* See finch/gnthistory.c */
+		buddy = cur->data;
+
+		uid = purple_blist_node_get_int(&buddy->node, "UserID");
+		name = purple_buddy_get_name(buddy);
+
+		if (uid == wanted_uid)
+		{
+			ret = name;
+			break;
+		}
 	}
-	return TRUE;
+
+	g_slist_free(buddies);
+	return ret;
+}
+
+/**
+ * Setup a callback, to be called when a reply is received with the returned rid.
+ *
+ * @param cb The callback, an MSIM_USER_LOOKUP_CB.
+ * @param data Arbitrary user data to be passed to callback (probably an MsimMessage *).
+ *
+ * @return The request/reply ID, used to link replies with requests, or -1.
+ *          Put the rid in your request, 'rid' field.
+ *
+ * TODO: Make more generic and more specific:
+ * 1) MSIM_USER_LOOKUP_CB - make it for PERSIST_REPLY, not just user lookup
+ * 2) data - make it an MsimMessage?
+ */
+guint
+msim_new_reply_callback(MsimSession *session, MSIM_USER_LOOKUP_CB cb,
+		gpointer data)
+{
+	guint rid;
+
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), -1);
+
+	rid = session->next_rid++;
+
+	g_hash_table_insert(session->user_lookup_cb, GUINT_TO_POINTER(rid), cb);
+	g_hash_table_insert(session->user_lookup_cb_data, GUINT_TO_POINTER(rid), data);
+
+	return rid;
+}
+
+/**
+ * Return the icon name for a buddy and account.
+ *
+ * @param acct The account to find the icon for, or NULL for protocol icon.
+ * @param buddy The buddy to find the icon for, or NULL for the account icon.
+ *
+ * @return The base icon name string.
+ */
+static const gchar *
+msim_list_icon(PurpleAccount *acct, PurpleBuddy *buddy)
+{
+	/* Use a MySpace icon submitted by hbons at
+	 * http://developer.pidgin.im/wiki/MySpaceIM. */
+	return "myspace";
+}
+
+/**
+ * Obtain the status text for a buddy.
+ *
+ * @param buddy The buddy to obtain status text for.
+ *
+ * @return Status text, or NULL if error. Caller g_free()'s.
+ */
+static char *
+msim_status_text(PurpleBuddy *buddy)
+{
+	MsimSession *session;
+	MsimUser *user;
+	const gchar *display_name, *headline;
+
+	g_return_val_if_fail(buddy != NULL, NULL);
+
+	user = msim_get_user_from_buddy(buddy);
+
+	session = (MsimSession *)buddy->account->gc->proto_data;
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), NULL);
+
+	display_name = headline = NULL;
+
+	/* Retrieve display name and/or headline, depending on user preference. */
+	if (purple_account_get_bool(session->account, "show_headline", TRUE)) {
+		headline = user->headline;
+	}
+
+	if (purple_account_get_bool(session->account, "show_display_name", FALSE)) {
+		display_name = user->display_name;
+	}
+
+	/* Return appropriate combination of display name and/or headline, or neither. */
+
+	if (display_name && headline) {
+		return g_strconcat(display_name, " ", headline, NULL);
+	} else if (display_name) {
+		return g_strdup(display_name);
+	} else if (headline) {
+		return g_strdup(headline);
+	}
+
+	return NULL;
+}
+
+/**
+ * Obtain the tooltip text for a buddy.
+ *
+ * @param buddy Buddy to obtain tooltip text on.
+ * @param user_info Variable modified to have the tooltip text.
+ * @param full TRUE if should obtain full tooltip text.
+ */
+static void
+msim_tooltip_text(PurpleBuddy *buddy, PurpleNotifyUserInfo *user_info,
+		gboolean full)
+{
+	MsimUser *user;
+
+	g_return_if_fail(buddy != NULL);
+	g_return_if_fail(user_info != NULL);
+
+	user = msim_get_user_from_buddy(buddy);
+
+	if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
+		MsimSession *session;
+
+		session = (MsimSession *)buddy->account->gc->proto_data;
+
+		g_return_if_fail(MSIM_SESSION_VALID(session));
+
+		/* TODO: if (full), do something different? */
+
+		/* TODO: request information? have to figure out how to do
+		 * the asynchronous lookup like oscar does (tooltip shows
+		 * 'retrieving...' if not yet available, then changes when it is).
+		 *
+		 * Right now, only show what we have on hand.
+		 */
+
+		/* Show abbreviated user info. */
+		msim_append_user_info(session, user_info, user, FALSE);
+	}
 }
 
 /**
@@ -123,7 +467,7 @@
  *
  * @return GList of status types.
  */
-GList *
+static GList *
 msim_status_types(PurpleAccount *acct)
 {
 	GList *types;
@@ -177,154 +521,141 @@
 }
 
 /**
- * Return the icon name for a buddy and account.
- *
- * @param acct The account to find the icon for, or NULL for protocol icon.
- * @param buddy The buddy to find the icon for, or NULL for the account icon.
+ * Compute the base64'd login challenge response based on username, password, nonce, and IPs.
  *
- * @return The base icon name string.
- */
-const gchar *
-msim_list_icon(PurpleAccount *acct, PurpleBuddy *buddy)
-{
-	/* Use a MySpace icon submitted by hbons at
-	 * http://developer.pidgin.im/wiki/MySpaceIM. */
-	return "myspace";
-}
-
-#ifdef MSIM_DEBUG_MSG
-static void 
-print_hash_item(gpointer key, gpointer value, gpointer user_data)
-{
-	purple_debug_info("msim", "%s=%s\n",
-			key ? (gchar *)key : "(NULL)", 
-			value ? (gchar *)value : "(NULL)");
-}
-#endif
-
-/** 
- * Send raw data (given as a NUL-terminated string) to the server.
+ * @param nonce The base64 encoded nonce ('nc') field from the server.
+ * @param email User's email address (used as login name).
+ * @param password User's cleartext password.
+ * @param response_len Will be written with response length.
  *
- * @param session 
- * @param msg The raw data to send, in a NUL-terminated string.
- *
- * @return TRUE if succeeded, FALSE if not.
- *
+ * @return Binary login challenge response, ready to send to the server.
+ * Must be g_free()'d when finished. NULL if error.
  */
-gboolean 
-msim_send_raw(MsimSession *session, const gchar *msg)
-{
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
-	g_return_val_if_fail(msg != NULL, FALSE);
-	
-	purple_debug_info("msim", "msim_send_raw: writing <%s>\n", msg);
-
-	return msim_send_really_raw(session->gc, msg, strlen(msg)) ==
-		strlen(msg);
-}
-
-/** Send raw data to the server, possibly with embedded NULs. 
- *
- * Used in prpl_info struct, so that plugins can have the most possible
- * control of what is sent over the connection. Inside this prpl, 
- * msim_send_raw() is used, since it sends NUL-terminated strings (easier).
- *
- * @param gc PurpleConnection
- * @param buf Buffer to send
- * @param total_bytes Size of buffer to send
- *
- * @return Bytes successfully sent, or -1 on error.
- */
-static int 
-msim_send_really_raw(PurpleConnection *gc, const char *buf, int total_bytes)
+static gchar *
+msim_compute_login_response(const gchar nonce[2 * NONCE_SIZE],
+		const gchar *email, const gchar *password, guint *response_len)
 {
-	int total_bytes_sent;
-	MsimSession *session;
-
-	g_return_val_if_fail(gc != NULL, -1);
-	g_return_val_if_fail(buf != NULL, -1);
-	g_return_val_if_fail(total_bytes >= 0, -1);
-
-	session = (MsimSession *)gc->proto_data;
-
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), -1);
-	
-	/* Loop until all data is sent, or a failure occurs. */
-	total_bytes_sent = 0;
-	do {
-		int bytes_sent;
-
-		bytes_sent = send(session->fd, buf + total_bytes_sent, 
-				total_bytes - total_bytes_sent, 0);
-
-		if (bytes_sent < 0) {
-			purple_debug_info("msim", "msim_send_raw(%s): send() failed: %s\n",
-					buf, g_strerror(errno));
-			return total_bytes_sent;
-		}
-		total_bytes_sent += bytes_sent;
-
-	} while(total_bytes_sent < total_bytes);
-
-	return total_bytes_sent;
-}
-
-
-/** 
- * Start logging in to the MSIM servers.
- * 
- * @param acct Account information to use to login.
- */
-void 
-msim_login(PurpleAccount *acct)
-{
-	PurpleConnection *gc;
-	const gchar *host;
-	int port;
-
-	g_return_if_fail(acct != NULL);
-	g_return_if_fail(acct->username != NULL);
-
-	purple_debug_info("msim", "logging in %s\n", acct->username);
-
-	gc = purple_account_get_connection(acct);
-	gc->proto_data = msim_session_new(acct);
-	gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_URLDESC;
-
-	/* 1. connect to server */
-	purple_connection_update_progress(gc, _("Connecting"),
-								  0,   /* which connection step this is */
-								  4);  /* total number of steps */
-
-	host = purple_account_get_string(acct, "server", MSIM_SERVER);
-	port = purple_account_get_int(acct, "port", MSIM_PORT);
-
-	/* From purple.sf.net/api:
-	 * """Note that this function name can be misleading--although it is called 
-	 * "proxy connect," it is used for establishing any outgoing TCP connection, 
-	 * whether through a proxy or not.""" */
-
-	/* Calls msim_connect_cb when connected. */
-	if (!purple_proxy_connect(gc, acct, host, port, msim_connect_cb, gc)) {
-		/* TODO: try other ports if in auto mode, then save
-		 * working port and try that first next time. */
-		purple_connection_error_reason (gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Couldn't create socket"));
-		return;
+	PurpleCipherContext *key_context;
+	PurpleCipher *sha1;
+	PurpleCipherContext *rc4;
+
+	guchar hash_pw[HASH_SIZE];
+	guchar key[HASH_SIZE];
+	gchar *password_utf16le, *password_utf8_lc;
+	GString *data;
+	guchar *data_out;
+	size_t data_out_len;
+	gsize conv_bytes_read, conv_bytes_written;
+	GError *conv_error;
+#ifdef MSIM_DEBUG_LOGIN_CHALLENGE
+	int i;
+#endif
+
+	g_return_val_if_fail(nonce != NULL, NULL);
+	g_return_val_if_fail(email != NULL, NULL);
+	g_return_val_if_fail(password != NULL, NULL);
+	g_return_val_if_fail(response_len != NULL, NULL);
+
+	/* Convert password to lowercase (required for passwords containing
+	 * uppercase characters). MySpace passwords are lowercase,
+	 * see ticket #2066. */
+	password_utf8_lc = g_utf8_strdown(password, -1);
+
+	/* Convert ASCII password to UTF16 little endian */
+	purple_debug_info("msim", "converting password to UTF-16LE\n");
+	conv_error = NULL;
+	password_utf16le = g_convert(password_utf8_lc, -1, "UTF-16LE", "UTF-8",
+			&conv_bytes_read, &conv_bytes_written, &conv_error);
+	g_free(password_utf8_lc);
+
+	g_return_val_if_fail(conv_bytes_read == strlen(password), NULL);
+
+	if (conv_error != NULL) {
+		purple_debug_error("msim",
+				"g_convert password UTF8->UTF16LE failed: %s",
+				conv_error->message);
+		g_error_free(conv_error);
+		return NULL;
 	}
+
+	/* Compute password hash */
+	purple_cipher_digest_region("sha1", (guchar *)password_utf16le,
+			conv_bytes_written, sizeof(hash_pw), hash_pw, NULL);
+	g_free(password_utf16le);
+
+#ifdef MSIM_DEBUG_LOGIN_CHALLENGE
+	purple_debug_info("msim", "pwhash = ");
+	for (i = 0; i < sizeof(hash_pw); i++)
+		purple_debug_info("msim", "%.2x ", hash_pw[i]);
+	purple_debug_info("msim", "\n");
+#endif
+
+	/* key = sha1(sha1(pw) + nonce2) */
+	sha1 = purple_ciphers_find_cipher("sha1");
+	key_context = purple_cipher_context_new(sha1, NULL);
+	purple_cipher_context_append(key_context, hash_pw, HASH_SIZE);
+	purple_cipher_context_append(key_context, (guchar *)(nonce + NONCE_SIZE), NONCE_SIZE);
+	purple_cipher_context_digest(key_context, sizeof(key), key, NULL);
+	purple_cipher_context_destroy(key_context);
+
+#ifdef MSIM_DEBUG_LOGIN_CHALLENGE
+	purple_debug_info("msim", "key = ");
+	for (i = 0; i < sizeof(key); i++) {
+		purple_debug_info("msim", "%.2x ", key[i]);
+	}
+	purple_debug_info("msim", "\n");
+#endif
+
+	rc4 = purple_cipher_context_new_by_name("rc4", NULL);
+
+	/* Note: 'key' variable is 0x14 bytes (from SHA-1 hash),
+	 * but only first 0x10 used for the RC4 key. */
+	purple_cipher_context_set_option(rc4, "key_len", (gpointer)0x10);
+	purple_cipher_context_set_key(rc4, key);
+
+	/* TODO: obtain IPs of network interfaces */
+
+	/* rc4 encrypt:
+	 * nonce1+email+IP list */
+
+	data = g_string_new(NULL);
+	g_string_append_len(data, nonce, NONCE_SIZE);
+	g_string_append(data, email);
+	g_string_append_len(data, MSIM_LOGIN_IP_LIST, MSIM_LOGIN_IP_LIST_LEN);
+
+	data_out = g_new0(guchar, data->len);
+
+	purple_cipher_context_encrypt(rc4, (const guchar *)data->str,
+			data->len, data_out, &data_out_len);
+	purple_cipher_context_destroy(rc4);
+
+	if (data_out_len != data->len) {
+		purple_debug_info("msim", "msim_compute_login_response: "
+				"data length mismatch: %" G_GSIZE_FORMAT " != %"
+				G_GSIZE_FORMAT "\n", data_out_len, data->len);
+	}
+
+	g_string_free(data, TRUE);
+
+#ifdef MSIM_DEBUG_LOGIN_CHALLENGE
+	purple_debug_info("msim", "response=<%s>\n", data_out);
+#endif
+
+	*response_len = data_out_len;
+
+	return (gchar *)data_out;
 }
 
 /**
- * Process a login challenge, sending a response. 
+ * Process a login challenge, sending a response.
  *
- * @param session 
+ * @param session
  * @param msg Login challenge message.
  *
  * @return TRUE if successful, FALSE if not
  */
-static gboolean 
-msim_login_challenge(MsimSession *session, MsimMessage *msg) 
+static gboolean
+msim_login_challenge(MsimSession *session, MsimMessage *msg)
 {
 	PurpleAccount *account;
 	gchar *response;
@@ -383,363 +714,16 @@
 }
 
 /**
- * Compute the base64'd login challenge response based on username, password, nonce, and IPs.
- *
- * @param nonce The base64 encoded nonce ('nc') field from the server.
- * @param email User's email address (used as login name).
- * @param password User's cleartext password.
- * @param response_len Will be written with response length.
- *
- * @return Binary login challenge response, ready to send to the server. 
- * Must be g_free()'d when finished. NULL if error.
- */
-static gchar *
-msim_compute_login_response(const gchar nonce[2 * NONCE_SIZE], 
-		const gchar *email, const gchar *password, guint *response_len)
-{
-	PurpleCipherContext *key_context;
-	PurpleCipher *sha1;
-	PurpleCipherContext *rc4;
-
-	guchar hash_pw[HASH_SIZE];
-	guchar key[HASH_SIZE];
-	gchar *password_utf16le, *password_utf8_lc;
-	guchar *data;
-	guchar *data_out;
-	size_t data_len, data_out_len;
-	gsize conv_bytes_read, conv_bytes_written;
-	GError *conv_error;
-#ifdef MSIM_DEBUG_LOGIN_CHALLENGE
-	int i;
-#endif
-
-	g_return_val_if_fail(nonce != NULL, NULL);
-	g_return_val_if_fail(email != NULL, NULL);
-	g_return_val_if_fail(password != NULL, NULL);
-	g_return_val_if_fail(response_len != NULL, NULL);
-
-	/* Convert password to lowercase (required for passwords containing
-	 * uppercase characters). MySpace passwords are lowercase,
-	 * see ticket #2066. */
-	password_utf8_lc = g_utf8_strdown(password, -1);
-
-	/* Convert ASCII password to UTF16 little endian */
-	purple_debug_info("msim", "converting password to UTF-16LE\n");
-	conv_error = NULL;
-	password_utf16le = g_convert(password_utf8_lc, -1, "UTF-16LE", "UTF-8", 
-			&conv_bytes_read, &conv_bytes_written, &conv_error);
-	g_free(password_utf8_lc);
-
-	g_return_val_if_fail(conv_bytes_read == strlen(password), NULL);
-
-	if (conv_error != NULL) {
-		purple_debug_error("msim", 
-				"g_convert password UTF8->UTF16LE failed: %s",
-				conv_error->message);
-		g_error_free(conv_error);
-		return NULL;
-	}
-
-	/* Compute password hash */ 
-	purple_cipher_digest_region("sha1", (guchar *)password_utf16le, 
-			conv_bytes_written, sizeof(hash_pw), hash_pw, NULL);
-	g_free(password_utf16le);
-
-#ifdef MSIM_DEBUG_LOGIN_CHALLENGE
-	purple_debug_info("msim", "pwhash = ");
-	for (i = 0; i < sizeof(hash_pw); i++)
-		purple_debug_info("msim", "%.2x ", hash_pw[i]);
-	purple_debug_info("msim", "\n");
-#endif
-
-	/* key = sha1(sha1(pw) + nonce2) */
-	sha1 = purple_ciphers_find_cipher("sha1");
-	key_context = purple_cipher_context_new(sha1, NULL);
-	purple_cipher_context_append(key_context, hash_pw, HASH_SIZE);
-	purple_cipher_context_append(key_context, (guchar *)(nonce + NONCE_SIZE), NONCE_SIZE);
-	purple_cipher_context_digest(key_context, sizeof(key), key, NULL);
-	purple_cipher_context_destroy(key_context);
-
-#ifdef MSIM_DEBUG_LOGIN_CHALLENGE
-	purple_debug_info("msim", "key = ");
-	for (i = 0; i < sizeof(key); i++) {
-		purple_debug_info("msim", "%.2x ", key[i]);
-	}
-	purple_debug_info("msim", "\n");
-#endif
-
-	rc4 = purple_cipher_context_new_by_name("rc4", NULL);
-
-	/* Note: 'key' variable is 0x14 bytes (from SHA-1 hash), 
-	 * but only first 0x10 used for the RC4 key. */
-	purple_cipher_context_set_option(rc4, "key_len", (gpointer)0x10);
-	purple_cipher_context_set_key(rc4, key);
-
-	/* TODO: obtain IPs of network interfaces */
-
-	/* rc4 encrypt:
-	 * nonce1+email+IP list */
-
-	data_len = NONCE_SIZE + strlen(email) + MSIM_LOGIN_IP_LIST_LEN;
-	data = g_new0(guchar, data_len);
-	memcpy(data, nonce, NONCE_SIZE);
-	memcpy(data + NONCE_SIZE, email, strlen(email));
-	memcpy(data + NONCE_SIZE + strlen(email), MSIM_LOGIN_IP_LIST, MSIM_LOGIN_IP_LIST_LEN);
-
-	data_out = g_new0(guchar, data_len);
-
-	purple_cipher_context_encrypt(rc4, (const guchar *)data, 
-			data_len, data_out, &data_out_len);
-	purple_cipher_context_destroy(rc4);
-	g_free(data);
-
-	if (data_out_len != data_len) {
-		purple_debug_info("msim", "msim_compute_login_response: "
-				"data length mismatch: %" G_GSIZE_FORMAT " != %"
-				G_GSIZE_FORMAT "\n", data_out_len, data_len);
-	}
-
-#ifdef MSIM_DEBUG_LOGIN_CHALLENGE
-	purple_debug_info("msim", "response=<%s>\n", data_out);
-#endif
-
-	*response_len = data_out_len;
-
-	return (gchar *)data_out;
-}
-
-/**
- * Schedule an IM to be sent once the user ID is looked up. 
- *
- * @param gc Connection.
- * @param who A user id, email, or username to send the message to.
- * @param message Instant message text to send.
- * @param flags Flags.
- *
- * @return 1 if successful or postponed, -1 if failed
- *
- * Allows sending to a user by username, email address, or userid. If
- * a username or email address is given, the userid must be looked up.
- * This function does that by calling msim_postprocess_outgoing().
- */
-int 
-msim_send_im(PurpleConnection *gc, const gchar *who, const gchar *message, 
-		PurpleMessageFlags flags)
-{
-	MsimSession *session;
-	gchar *message_msim;
-	int rc;
-	
-	g_return_val_if_fail(gc != NULL, -1);
-	g_return_val_if_fail(who != NULL, -1);
-	g_return_val_if_fail(message != NULL, -1);
-
-	/* 'flags' has many options, not used here. */
-
-	session = (MsimSession *)gc->proto_data;
-
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), -1);
-
-	message_msim = html_to_msim_markup(session, message);
-
-	if (msim_send_bm(session, who, message_msim, MSIM_BM_INSTANT)) {
-		/* Return 1 to have Purple show this IM as being sent, 0 to not. I always
-		 * return 1 even if the message could not be sent, since I don't know if
-		 * it has failed yet--because the IM is only sent after the userid is
-		 * retrieved from the server (which happens after this function returns).
-		 * If an error does occur, it should be logged to the IM window.
-		 */
-		rc = 1;
-	} else {
-		rc = -1;
-	}
-
-	g_free(message_msim);
-
-	return rc;
-}
-
-/** Send a buddy message of a given type.
- *
- * @param session
- * @param who Username to send message to.
- * @param text Message text to send. Not freed; will be copied.
- * @param type A MSIM_BM_* constant.
- *
- * @return TRUE if success, FALSE if fail.
- *
- * Buddy messages ('bm') include instant messages, action messages, status messages, etc.
- *
- */
-gboolean 
-msim_send_bm(MsimSession *session, const gchar *who, const gchar *text, 
-		int type)
-{
-	gboolean rc;
-	MsimMessage *msg;
-	const gchar *from_username;
-
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
-	g_return_val_if_fail(who != NULL, FALSE);
-	g_return_val_if_fail(text != NULL, FALSE);
-
-	from_username = session->account->username;
-
-	g_return_val_if_fail(from_username != NULL, FALSE);
-
-	purple_debug_info("msim", "sending %d message from %s to %s: %s\n",
-				  type, from_username, who, text);
-
-	msg = msim_msg_new(
-			"bm", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(type),
-			"sesskey", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(session->sesskey),
-			/* 't' will be inserted here */
-			"cv", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(MSIM_CLIENT_VERSION),
-			"msg", MSIM_TYPE_STRING, g_strdup(text),
-			NULL);
-
-	rc = msim_postprocess_outgoing(session, msg, who, "t", "cv");
-
-	msim_msg_free(msg);
-
-	return rc;
-}
-
-
-/** Record the client version in the buddy list, from an incoming message. */
-static gboolean
-msim_incoming_bm_record_cv(MsimSession *session, MsimMessage *msg)
-{
-	gchar *username, *cv;
-	gboolean ret;
-	MsimUser *user;
-
-	username = msim_msg_get_string(msg, "_username");
-	cv = msim_msg_get_string(msg, "cv");
-
-	g_return_val_if_fail(username != NULL, FALSE);
-	if (!cv) {
-		/* No client version to record, don't worry about it. */
-		g_free(username);
-		return FALSE;
-	}
-
-	user = msim_find_user(session, username);
-
-	if (user) {
-		user->client_cv = atol(cv);
-		ret = TRUE;
-	} else {
-		ret = FALSE;
-	}
-
-	g_free(username);
-	g_free(cv);
-
-	return ret;
-}
-
-/** Handle an incoming buddy message. */
-static gboolean
-msim_incoming_bm(MsimSession *session, MsimMessage *msg)
-{
-	guint bm;
-
-	bm = msim_msg_get_integer(msg, "bm");
-
-	msim_incoming_bm_record_cv(session, msg);
-
-	switch (bm) {
-		case MSIM_BM_STATUS:
-			return msim_incoming_status(session, msg);
-		case MSIM_BM_INSTANT:
-			return msim_incoming_im(session, msg);
-		case MSIM_BM_ACTION:
-			return msim_incoming_action(session, msg);
-		case MSIM_BM_MEDIA:
-			return msim_incoming_media(session, msg);
-		case MSIM_BM_UNOFFICIAL_CLIENT:
-			return msim_incoming_unofficial_client(session, msg);
-		default:
-			/* Not really an IM, but show it for informational 
-			 * purposes during development. */
-			return msim_incoming_im(session, msg);
-	}
-}
-
-/**
- * Handle an incoming instant message.
- *
- * @param session The session
- * @param msg Message from the server, containing 'f' (userid from) and 'msg'. 
- *               Should also contain username in _username from preprocessing.
- *
- * @return TRUE if successful.
- */
-static gboolean 
-msim_incoming_im(MsimSession *session, MsimMessage *msg)
-{
-	gchar *username, *msg_msim_markup, *msg_purple_markup;
-	gchar *userid;
-	time_t time_received;
-	PurpleConversation *conv;
-
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
-	g_return_val_if_fail(msg != NULL, FALSE);
-
-	username = msim_msg_get_string(msg, "_username");
-	/* I know this isn't really a string... but we need it to be one for
-	 * purple_find_conversation_with_account(). */
-	userid = msim_msg_get_string(msg, "f");
-	g_return_val_if_fail(username != NULL, FALSE);
-
-	purple_debug_info("msim_incoming_im", "UserID is %s", userid);
-
-	if (msim_is_userid(username)) {
-		purple_debug_info("msim", "Ignoring message from spambot (%s) on account %s\n",
-				username, purple_account_get_username(session->account));
-		g_free(username);
-		return FALSE;
-	}
-	
-	/* See if a conversation with their UID already exists...*/
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, userid, session->account);
-	if (conv) {
-		/* Since the conversation exists... We need to normalize it */
-		purple_conversation_set_name(conv, username);
-	}
-
-	msg_msim_markup = msim_msg_get_string(msg, "msg");
-	g_return_val_if_fail(msg_msim_markup != NULL, FALSE);
-
-	msg_purple_markup = msim_markup_to_html(session, msg_msim_markup);
-	g_free(msg_msim_markup);
-
-	time_received = msim_msg_get_integer(msg, "date");
-	if (!time_received) {
-		purple_debug_info("msim_incoming_im", "date in message not set.\n");
-		time_received = time(NULL);
-	}
-
-	serv_got_im(session->gc, username, msg_purple_markup, PURPLE_MESSAGE_RECV, time_received);
-
-	g_free(username);
-	g_free(msg_purple_markup);
-
-	return TRUE;
-}
-
-/**
  * Process unrecognized information.
  *
  * @param session
  * @param msg An MsimMessage that was unrecognized, or NULL.
  * @param note Information on what was unrecognized, or NULL.
  */
-void 
+void
 msim_unrecognized(MsimSession *session, MsimMessage *msg, gchar *note)
 {
-	/* TODO: Some more context, outwardly equivalent to a backtrace, 
+	/* TODO: Some more context, outwardly equivalent to a backtrace,
 	 * for helping figure out what this msg is for. What was going on?
 	 * But not too much information so that a user
 	 * posting this dump reveals confidential information.
@@ -747,13 +731,13 @@
 
 	/* TODO: dump unknown msgs to file, so user can send them to me
 	 * if they wish, to help add support for new messages (inspired
-	 * by Alexandr Shutko, who maintains OSCAR protocol documentation). 
+	 * by Alexandr Shutko, who maintains OSCAR protocol documentation).
 	 *
 	 * Filed enhancement ticket for libpurple as #4688.
 	 */
 
-	purple_debug_info("msim", "Unrecognized data on account for %s\n", 
-			(session && session->account && session->account->username) ? 
+	purple_debug_info("msim", "Unrecognized data on account for %s\n",
+			(session && session->account && session->account->username) ?
 			session->account->username : "(NULL)");
 	if (note) {
 		purple_debug_info("msim", "(Note: %s)\n", note);
@@ -764,562 +748,62 @@
 	}
 }
 
-/**
- * Handle an incoming action message.
- *
- * @param session
- * @param msg
- *
- * @return TRUE if successful.
- *
- */
-static gboolean 
-msim_incoming_action(MsimSession *session, MsimMessage *msg)
-{
-	gchar *msg_text, *username;
-	gboolean rc;
-
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
-	g_return_val_if_fail(msg != NULL, FALSE);
-
-	msg_text = msim_msg_get_string(msg, "msg");
-	g_return_val_if_fail(msg_text != NULL, FALSE);
-
-	username = msim_msg_get_string(msg, "_username");
-	g_return_val_if_fail(username != NULL, FALSE);
-
-	purple_debug_info("msim", "msim_incoming_action: action <%s> from <%s>\n",
-			msg_text, username);
-
-	if (g_str_equal(msg_text, "%typing%")) {
-		serv_got_typing(session->gc, username, 0, PURPLE_TYPING);
-		rc = TRUE;
-	} else if (g_str_equal(msg_text, "%stoptyping%")) {
-		serv_got_typing_stopped(session->gc, username);
-		rc = TRUE;
-	} else if (strstr(msg_text, "!!!ZAP_SEND!!!=RTE_BTN_ZAPS_")) {
-		rc = msim_incoming_zap(session, msg);
-	} else if (strstr(msg_text, "!!!GroupCount=")) {
-		/* TODO: support group chats. I think the number in msg_text has
-		 * something to do with the 'gid' field. */
-		purple_debug_info("msim", "msim_incoming_action: TODO: implement #4691, group chats: %s\n", msg_text);
-
-		rc = TRUE;
-	} else if (strstr(msg_text, "!!!Offline=")) {
-		/* TODO: support group chats. This one might mean a user
-		 * went offline or exited the chat. */
-		purple_debug_info("msim", "msim_incoming_action: TODO: implement #4691, group chats: %s\n", msg_text);
-
-		rc = TRUE;
-	} else if (msim_msg_get_integer(msg, "aid") != 0) {
-		purple_debug_info("msim", "TODO: implement #4691, group chat from %d on %d: %s\n",
-				msim_msg_get_integer(msg, "aid"),
-				msim_msg_get_integer(msg, "f"),
-				msg_text);
-
-		rc = TRUE;
-	} else {
-		msim_unrecognized(session, msg, 
-				"got to msim_incoming_action but unrecognized value for 'msg'");
-		rc = FALSE;
-	}
-
-	g_free(msg_text);
-	g_free(username);
-
-	return rc;
-}
-
-/* Process an incoming media (message background?) message. */
-static gboolean
-msim_incoming_media(MsimSession *session, MsimMessage *msg)
-{
-	gchar *username, *text;
-
-	username = msim_msg_get_string(msg, "_username");
-	text = msim_msg_get_string(msg, "msg");
-
-	g_return_val_if_fail(username != NULL, FALSE);
-	g_return_val_if_fail(text != NULL, FALSE);
-
-	purple_debug_info("msim", "msim_incoming_media: from %s, got msg=%s\n", username, text);
-
-	/* Media messages are sent when the user opens a window to someone.
-	 * Tell libpurple they started typing and stopped typing, to inform the Psychic
-	 * Mode plugin so it too can open a window to the user. */
-	serv_got_typing(session->gc, username, 0, PURPLE_TYPING);
-	serv_got_typing_stopped(session->gc, username);
-
-	g_free(username);
-
-	return TRUE;
-}
-
-/* Process an incoming "unofficial client" message. The plugin for
- * Miranda IM sends this message with the plugin information. */
-static gboolean
-msim_incoming_unofficial_client(MsimSession *session, MsimMessage *msg)
-{
-	MsimUser *user;
-	gchar *username, *client_info;
-
-	username = msim_msg_get_string(msg, "_username");
-	client_info = msim_msg_get_string(msg, "msg");
-
-	g_return_val_if_fail(username != NULL, FALSE);
-	g_return_val_if_fail(client_info != NULL, FALSE);
-
-	purple_debug_info("msim", "msim_incoming_unofficial_client: %s is using client %s\n",
-		username, client_info);
-
-	user = msim_find_user(session, username);
-	
-	g_return_val_if_fail(user != NULL, FALSE);
-
-	if (user->client_info) {
-		g_free(user->client_info);
-	}
-	user->client_info = client_info;
-
-	g_free(username);
-	/* Do not free client_info - the MsimUser now owns it. */
-
-	return TRUE;
-}
-
-
-#ifdef MSIM_SEND_CLIENT_VERSION
-/** Send our client version to another unofficial client that understands it. */
+/** Called when the session key arrives to check whether the user
+ * has a username, and set one if desired. */
 static gboolean
-msim_send_unofficial_client(MsimSession *session, gchar *username)
-{
-	gchar *our_info;
-	gboolean ret;
-
-	our_info = g_strdup_printf("Libpurple %d.%d.%d - msimprpl %s", 
-			PURPLE_MAJOR_VERSION,
-			PURPLE_MINOR_VERSION,
-			PURPLE_MICRO_VERSION,
-			MSIM_PRPL_VERSION_STRING);
-
-	ret = msim_send_bm(session, username, our_info, MSIM_BM_UNOFFICIAL_CLIENT);
-
-	return ret;
-}
-#endif
-
-/** 
- * Handle when our user starts or stops typing to another user.
- *
- * @param gc
- * @param name The buddy name to which our user is typing to
- * @param state PURPLE_TYPING, PURPLE_TYPED, PURPLE_NOT_TYPING
- *
- * @return 0
- */
-unsigned int 
-msim_send_typing(PurpleConnection *gc, const gchar *name, 
-		PurpleTypingState state)
-{
-	const gchar *typing_str;
-	MsimSession *session;
-
-	g_return_val_if_fail(gc != NULL, 0);
-	g_return_val_if_fail(name != NULL, 0);
-
-	session = (MsimSession *)gc->proto_data;
-
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), 0);
-
-	switch (state) {
-		case PURPLE_TYPING: 
-			typing_str = "%typing%"; 
-			break;
-
-		case PURPLE_TYPED:
-		case PURPLE_NOT_TYPING:
-		default:
-			typing_str = "%stoptyping%";
-			break;
-	}
-
-	purple_debug_info("msim", "msim_send_typing(%s): %d (%s)\n", name, state, typing_str);
-	msim_send_bm(session, name, typing_str, MSIM_BM_ACTION);
-	return 0;
-}
-
-
-
-/** Callback for msim_get_info(), for when user info is received. */
-static void 
-msim_get_info_cb(MsimSession *session, MsimMessage *user_info_msg, 
-		gpointer data)
-{
-	MsimMessage *msg;
-	gchar *username;
-	PurpleNotifyUserInfo *user_info;
-	MsimUser *user;
-
-	g_return_if_fail(MSIM_SESSION_VALID(session));
-
-	/* Get user{name,id} from msim_get_info, passed as an MsimMessage for 
-	   orthogonality. */
-	msg = (MsimMessage *)data;
-	g_return_if_fail(msg != NULL);
-
-	username = msim_msg_get_string(msg, "user");
-	if (!username) {
-		purple_debug_info("msim", "msim_get_info_cb: no 'user' in msg\n");
-		return;
-	}
-
-	msim_msg_free(msg);
-	purple_debug_info("msim", "msim_get_info_cb: got for user: %s\n", username);
-
-	user = msim_find_user(session, username);
-
-	if (!user) {
-		/* User isn't on blist, create a temporary user to store info. */
-		user = g_new0(MsimUser, 1);
-		user->temporary_user = TRUE;
-	}
-
-	/* Update user structure with new information */
-	msim_store_user_info(session, user_info_msg, user);
-
-	user_info = purple_notify_user_info_new();
-
-	/* Append data from MsimUser to PurpleNotifyUserInfo for display, full */
-	msim_append_user_info(session, user_info, user, TRUE);
-
-	purple_notify_userinfo(session->gc, username, user_info, NULL, NULL);
-	purple_debug_info("msim", "msim_get_info_cb: username=%s\n", username);
-
-	purple_notify_user_info_destroy(user_info);
-
-	if (user->temporary_user) {
-		g_free(user->client_info);
-		g_free(user->gender);
-		g_free(user->location);
-		g_free(user->headline);
-		g_free(user->display_name);
-		g_free(user->username);
-		g_free(user->image_url);
-		g_free(user);
-	}
-	g_free(username);
-}
-
-/** Retrieve a user's profile. 
- * @param username Username, user ID, or email address to lookup.
- */
-void 
-msim_get_info(PurpleConnection *gc, const gchar *username)
-{
-	MsimSession *session;
-	MsimUser *user;
-	gchar *user_to_lookup;
-	MsimMessage *user_msg;
-
-	g_return_if_fail(gc != NULL);
-	g_return_if_fail(username != NULL);
-
-	session = (MsimSession *)gc->proto_data;
-
-	g_return_if_fail(MSIM_SESSION_VALID(session));
-
-	/* Obtain uid of buddy. */
-	user = msim_find_user(session, username);
-
-	/* If is on buddy list, lookup by uid since it is faster. */
-	if (user && user->id) {
-		user_to_lookup = g_strdup_printf("%d", user->id);
-	} else {
-		/* Looking up buddy not on blist. Lookup by whatever user entered. */
-		user_to_lookup = g_strdup(username);
-	}
-
-	/* Pass the username to msim_get_info_cb(), because since we lookup
-	 * by userid, the userinfo message will only contain the uid (not 
-	 * the username) but it would be useful to display the username too.
-	 */
-	user_msg = msim_msg_new(
-			"user", MSIM_TYPE_STRING, g_strdup(username),
-			NULL);
-	purple_debug_info("msim", "msim_get_info, setting up lookup, user=%s\n", username);
-
-	msim_lookup_user(session, user_to_lookup, msim_get_info_cb, user_msg);
-
-	g_free(user_to_lookup); 
-}
-
-/** Set your status - callback for when user manually sets it.  */
-void
-msim_set_status(PurpleAccount *account, PurpleStatus *status)
-{
-	PurpleStatusType *type;
-	PurplePresence *pres;
-	MsimSession *session;
-	guint status_code;
-	const gchar *message;
-	gchar *stripped;
-	gchar *unrecognized_msg;
-
-	session = (MsimSession *)account->gc->proto_data;
-
-	g_return_if_fail(MSIM_SESSION_VALID(session));
-
-	type = purple_status_get_type(status);
-	pres = purple_status_get_presence(status);
-
-	switch (purple_status_type_get_primitive(type)) {
-		case PURPLE_STATUS_AVAILABLE:
-			purple_debug_info("msim", "msim_set_status: available (%d->%d)\n", PURPLE_STATUS_AVAILABLE,
-					MSIM_STATUS_CODE_ONLINE);
-			status_code = MSIM_STATUS_CODE_ONLINE;
-			break;
-
-		case PURPLE_STATUS_INVISIBLE:
-			purple_debug_info("msim", "msim_set_status: invisible (%d->%d)\n", PURPLE_STATUS_INVISIBLE,
-					MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN);
-			status_code = MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN;
-			break;
-
-		case PURPLE_STATUS_AWAY:
-			purple_debug_info("msim", "msim_set_status: away (%d->%d)\n", PURPLE_STATUS_AWAY,
-					MSIM_STATUS_CODE_AWAY);
-			status_code = MSIM_STATUS_CODE_AWAY;
-			break;
-
-		default:
-			purple_debug_info("msim", "msim_set_status: unknown "
-					"status interpreting as online");
-			status_code = MSIM_STATUS_CODE_ONLINE;
-
-			unrecognized_msg = g_strdup_printf("msim_set_status, unrecognized status type: %d\n", 
-					purple_status_type_get_primitive(type));
-			msim_unrecognized(session, NULL, unrecognized_msg);
-			g_free(unrecognized_msg);
-
-			break;
-	}
-
-	message = purple_status_get_attr_string(status, "message");
-
-	/* Status strings are plain text. */
-	if (message != NULL)
-		stripped = purple_markup_strip_html(message);
-	else
-		stripped = g_strdup("");
-
-	msim_set_status_code(session, status_code, stripped);
-
-	/* If we should be idle, set that status. Time is irrelevant here. */
-	if (purple_presence_is_idle(pres) && status_code != MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN)
-		msim_set_idle(account->gc, 1);
-
-}
-
-/** Go idle. */
-void
-msim_set_idle(PurpleConnection *gc, int time)
-{
-	MsimSession *session;
-	PurpleStatus *status;
-
-	g_return_if_fail(gc != NULL);
-
-	session = (MsimSession *)gc->proto_data;
-
-	g_return_if_fail(MSIM_SESSION_VALID(session));
-
-	status = purple_account_get_active_status(session->account);
-
-	if (time == 0) {
-		/* Going back from idle. In msim, idle is mutually exclusive 
-		 * from the other states (you can only be away or idle, but not
-		 * both, for example), so by going non-idle I go back to what
-		 * libpurple says I should be.
-		 */
-		msim_set_status(session->account, status);
-	} else {
-		const gchar *message;
-		gchar *stripped;
-
-		/* Set the idle message to the status message from the real
-		 * current status.
-		 */
-		message = purple_status_get_attr_string(status, "message");
-		if (message != NULL)
-			stripped = purple_markup_strip_html(message);
-		else
-			stripped = g_strdup("");
-
-		/* msim doesn't support idle time, so just go idle */
-		msim_set_status_code(session, MSIM_STATUS_CODE_IDLE, stripped);
-	}
-}
-
-/** Set status using an MSIM_STATUS_CODE_* value.
- * @param status_code An MSIM_STATUS_CODE_* value.
- * @param statstring Status string, must be a dynamic string (will be freed by msim_send).
- */
-static void 
-msim_set_status_code(MsimSession *session, guint status_code, gchar *statstring)
-{
-	g_return_if_fail(MSIM_SESSION_VALID(session));
-	g_return_if_fail(statstring != NULL);
-
-	purple_debug_info("msim", "msim_set_status_code: going to set status to code=%d,str=%s\n",
-			status_code, statstring);
-
-	if (!msim_send(session,
-			"status", MSIM_TYPE_INTEGER, status_code,
-			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
-			"statstring", MSIM_TYPE_STRING, statstring, 
-			"locstring", MSIM_TYPE_STRING, g_strdup(""),
-			NULL))
-	{
-		purple_debug_info("msim", "msim_set_status: failed to set status\n");
-	}
-
-}
-
-/** After a uid is resolved to username, tag it with the username and submit for processing. 
- * 
- * @param session
- * @param userinfo Response messsage to resolving request.
- * @param data MsimMessage *, the message to attach information to. 
- */
-static void 
-msim_incoming_resolved(MsimSession *session, MsimMessage *userinfo, 
-		gpointer data)
-{
-	gchar *username;
-	MsimMessage *msg, *body;
-
-	g_return_if_fail(MSIM_SESSION_VALID(session));
-	g_return_if_fail(userinfo != NULL);
-
-	body = msim_msg_get_dictionary(userinfo, "body");
-	g_return_if_fail(body != NULL);
-
-	username = msim_msg_get_string(body, "UserName");
-	g_return_if_fail(username != NULL);
-	/* Note: username will be owned by 'msg' below. */
-
-	msg = (MsimMessage *)data;
-	g_return_if_fail(msg != NULL);
-
-	/* TODO: more elegant solution than below. attach whole message? */
-	/* Special elements name beginning with '_', we'll use internally within the
-	 * program (did not come directly from the wire). */
-	msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, username); /* This makes 'msg' the owner of 'username' */
-
-	/* TODO: attach more useful information, like ImageURL */
-
-	msim_process(session, msg);
-
-	/* TODO: Free copy cloned from  msim_preprocess_incoming(). */
-	/* msim_msg_free(msg); */
-	msim_msg_free(body);
-}
-
-/* Lookup a username by userid, from buddy list. 
- *
- * @param wanted_uid
- *
- * @return Username of wanted_uid, if on blist, or NULL. 
- * 	This is a static string, so don't free it. Copy it if needed.
- *
- */
-static const gchar *
-msim_uid2username_from_blist(PurpleAccount *account, guint wanted_uid)
-{
-	GSList *buddies, *cur;
-	const gchar *ret;
-
-	buddies = purple_find_buddies(account, NULL); 
-
-	if (!buddies)
-	{
-		purple_debug_info("msim", "msim_uid2username_from_blist: no buddies?\n");
-		return NULL;
-	}
-
-	ret = NULL;
-
-	for (cur = buddies; cur != NULL; cur = g_slist_next(cur))
-	{
-		PurpleBuddy *buddy;
-		guint uid;
-		const gchar *name;
-
-		/* See finch/gnthistory.c */
-		buddy = cur->data;
-
-		uid = purple_blist_node_get_int(&buddy->node, "UserID");
-		name = purple_buddy_get_name(buddy);
-
-		if (uid == wanted_uid)
-		{
-			ret = name;
-			break;
-		}
-	}
-
-	g_slist_free(buddies);
-	return ret;
-}
-
-/** Preprocess incoming messages, resolving as needed, calling msim_process() when ready to process.
- *
- * @param session
- * @param msg MsimMessage *, freed by caller.
- */
-static gboolean 
-msim_preprocess_incoming(MsimSession *session, MsimMessage *msg)
+msim_is_username_set(MsimSession *session, MsimMessage *msg)
 {
 	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
 	g_return_val_if_fail(msg != NULL, FALSE);
-
-	if (msim_msg_get(msg, "bm") && msim_msg_get(msg, "f")) {
-		guint uid;
-		const gchar *username;
-
-		/* 'f' = userid message is from, in buddy messages */
-		uid = msim_msg_get_integer(msg, "f");
-
-		username = msim_uid2username_from_blist(session->account, uid); 
-
-		if (username) {
-			/* Know username already, use it. */
-			purple_debug_info("msim", "msim_preprocess_incoming: tagging with _username=%s\n",
-					username);
-			msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, g_strdup(username));
-			return msim_process(session, msg);
-
-		} else {
-			gchar *from;
-
-			/* Send lookup request. */
-			/* XXX: where is msim_msg_get_string() freed? make _strdup and _nonstrdup. */
-			purple_debug_info("msim", "msim_incoming: sending lookup, setting up callback\n");
-			from = msim_msg_get_string(msg, "f");
-			msim_lookup_user(session, from, msim_incoming_resolved, msim_msg_clone(msg)); 
-			g_free(from);
-
-			/* indeterminate */
-			return TRUE;
-		}
-	} else {
-		/* Nothing to resolve - send directly to processing. */
-		return msim_process(session, msg);
+	g_return_val_if_fail(session->gc != NULL, FALSE);
+
+	session->sesskey = msim_msg_get_integer(msg, "sesskey");
+	purple_debug_info("msim", "SESSKEY=<%d>\n", session->sesskey);
+
+	/* What is proof? Used to be uid, but now is 52 base64'd bytes... */
+
+	/* Comes with: proof,profileid,userid,uniquenick -- all same values
+	 * some of the time, but can vary. This is our own user ID. */
+	session->userid = msim_msg_get_integer(msg, "userid");
+
+	/* Save uid to account so this account can be looked up by uid. */
+	purple_account_set_int(session->account, "uid", session->userid);
+
+	/* Not sure what profileid is used for. */
+	if (msim_msg_get_integer(msg, "profileid") != session->userid) {
+		msim_unrecognized(session, msg,
+				"Profile ID didn't match user ID, don't know why");
 	}
+
+	/* We now know are our own username, only after we're logged in..
+	 * which is weird, but happens because you login with your email
+	 * address and not username. Will be freed in msim_session_destroy(). */
+	session->username = msim_msg_get_string(msg, "uniquenick");
+
+	/* If user lacks a username, help them get one. */
+	if (msim_msg_get_integer(msg, "uniquenick") == session->userid) {
+		purple_debug_info("msim_is_username_set", "no username is set\n");
+		purple_request_yes_no(session->gc,
+			_("MySpaceIM - No Username Set"),
+			_("You appear to have no MySpace username."),
+			_("Would you like to set one now? (Note: THIS CANNOT BE CHANGED!)"),
+			0,
+			session->account,
+			NULL,
+			NULL,
+			session->gc,
+			G_CALLBACK(msim_set_username_cb),
+			G_CALLBACK(msim_do_not_set_username_cb));
+		purple_debug_info("msim_is_username_set","'username not set' alert prompted\n");
+		return FALSE;
+	}
+	return TRUE;
 }
 
 #ifdef MSIM_USE_KEEPALIVE
-/** Check if the connection is still alive, based on last communication. */
+/**
+ * Check if the connection is still alive, based on last communication.
+ */
 static gboolean
 msim_check_alive(gpointer data)
 {
@@ -1348,7 +832,9 @@
 }
 #endif
 
-/** Handle mail reply checks. */
+/**
+ * Handle mail reply checks.
+ */
 static void
 msim_check_inbox_cb(MsimSession *session, MsimMessage *reply, gpointer data)
 {
@@ -1358,7 +844,7 @@
 	const gchar *froms[5], *tos[5], *urls[5], *subjects[5];
 
 	/* Information for each new inbox message type. */
-	static struct 
+	static struct
 	{
 		const gchar *key;
 		guint bit;
@@ -1395,7 +881,7 @@
 	for (i = 0; i < sizeof(message_types) / sizeof(message_types[0]); ++i) {
 		const gchar *key;
 		guint bit;
-		
+
 		key = message_types[i].key;
 		bit = message_types[i].bit;
 
@@ -1433,7 +919,7 @@
 		purple_notify_emails(session->gc,         /* handle */
 				n,                        /* count */
 				TRUE,                     /* detailed */
-				subjects, froms, tos, urls, 
+				subjects, froms, tos, urls,
 				NULL,                     /* PurpleNotifyCloseCallback cb */
 				NULL);                    /* gpointer user_data */
 
@@ -1442,7 +928,9 @@
 	msim_msg_free(body);
 }
 
-/* Send request to check if there is new mail. */
+/**
+ * Send request to check if there is new mail.
+ */
 static gboolean
 msim_check_inbox(gpointer data)
 {
@@ -1456,14 +944,14 @@
 	}
 
 	purple_debug_info("msim", "msim_check_inbox: checking mail\n");
-	g_return_val_if_fail(msim_send(session, 
+	g_return_val_if_fail(msim_send(session,
 			"persist", MSIM_TYPE_INTEGER, 1,
 			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
 			"cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
 			"dsn", MSIM_TYPE_INTEGER, MG_CHECK_MAIL_DSN,
 			"lid", MSIM_TYPE_INTEGER, MG_CHECK_MAIL_LID,
 			"uid", MSIM_TYPE_INTEGER, session->userid,
-			"rid", MSIM_TYPE_INTEGER, 
+			"rid", MSIM_TYPE_INTEGER,
 				msim_new_reply_callback(session, msim_check_inbox_cb, NULL),
 			"body", MSIM_TYPE_STRING, g_strdup(""),
 			NULL), TRUE);
@@ -1472,1340 +960,9 @@
 	return TRUE;
 }
 
-#ifdef MSIM_CHECK_NEWER_VERSION
-/** Callback for when a currentversion.txt has been downloaded. */
-static void
-msim_check_newer_version_cb(PurpleUtilFetchUrlData *url_data,
-		gpointer user_data,
-		const gchar *url_text,
-		gsize len,
-		const gchar *error_message)
-{
-	GKeyFile *keyfile;
-	GError *error;
-	GString *data;
-	gchar *newest_filever;
-
-	if (!url_text) {
-		purple_debug_info("msim_check_newer_version_cb",
-				"got error: %s\n", error_message);
-		return;
-	}
-
-	purple_debug_info("msim_check_newer_version_cb",
-			"url_text=%s\n", url_text ? url_text : "(NULL)");
-
-	/* Prepend [group] so that GKeyFile can parse it (requires a group). */
-	data = g_string_new(url_text);
-	purple_debug_info("msim", "data=%s\n", data->str
-			? data->str : "(NULL)");
-	data = g_string_prepend(data, "[group]\n");
-
-	purple_debug_info("msim", "data=%s\n", data->str
-			? data->str : "(NULL)");
-
-	/* url_text is variable=data\n...†*/
-
-	/* Check FILEVER, 1.0.716.0. 716 is build, MSIM_CLIENT_VERSION */
-	/* New (english) version can be downloaded from SETUPURL+SETUPFILE */
-
-	error = NULL;
-	keyfile = g_key_file_new();
-
-	/* Default list seperator is ;, but currentversion.txt doesn't have
-	 * these, so set to an unused character to avoid parsing problems. */
-	g_key_file_set_list_separator(keyfile, '\0');
-
-	g_key_file_load_from_data(keyfile, data->str, data->len,
-				G_KEY_FILE_NONE, &error);
-	g_string_free(data, TRUE);
-
-	if (error != NULL) {
-		purple_debug_info("msim_check_newer_version_cb",
-				"couldn't parse, error: %d %d %s\n",
-				error->domain, error->code, error->message);
-		g_error_free(error);
-		return;
-	}
-
-	gchar **ks;
-	guint n;
-	ks = g_key_file_get_keys(keyfile, "group", &n, NULL);
-	purple_debug_info("msim", "n=%d\n", n);
-	guint i;
-	for (i = 0; ks[i] != NULL; ++i)
-	{
-		purple_debug_info("msim", "%d=%s\n", i, ks[i]);
-	}
-
-	newest_filever = g_key_file_get_string(keyfile, "group", 
-			"FILEVER", &error);
-
-	purple_debug_info("msim_check_newer_version_cb",
-			"newest filever: %s\n", newest_filever ?
-			newest_filever : "(NULL)");
-	if (error != NULL) {
-		purple_debug_info("msim_check_newer_version_cb",
-				"error: %d %d %s\n",
-				error->domain, error->code, error->message);
-		g_error_free(error);
-	}
-
-	g_key_file_free(keyfile);			
-
-	exit(0);
-}
-#endif
-
-/** Called when the session key arrives to check whether the user
- * has a username, and set one if desired. */
-static gboolean
-msim_is_username_set(MsimSession *session, MsimMessage *msg) 
-{
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
-	g_return_val_if_fail(msg != NULL, FALSE);
-	g_return_val_if_fail(session->gc != NULL, FALSE);
-
-	session->sesskey = msim_msg_get_integer(msg, "sesskey");
-	purple_debug_info("msim", "SESSKEY=<%d>\n", session->sesskey);
-
-	/* What is proof? Used to be uid, but now is 52 base64'd bytes... */
-
-	/* Comes with: proof,profileid,userid,uniquenick -- all same values
-	 * some of the time, but can vary. This is our own user ID. */
-	session->userid = msim_msg_get_integer(msg, "userid");
-
-	/* Save uid to account so this account can be looked up by uid. */
-	purple_account_set_int(session->account, "uid", session->userid);
-
-	/* Not sure what profileid is used for. */
-	if (msim_msg_get_integer(msg, "profileid") != session->userid) {
-		msim_unrecognized(session, msg, 
-				"Profile ID didn't match user ID, don't know why");
-	}
-
-	/* We now know are our own username, only after we're logged in..
-	 * which is weird, but happens because you login with your email
-	 * address and not username. Will be freed in msim_session_destroy(). */
-	session->username = msim_msg_get_string(msg, "uniquenick");
-
-	/* If user lacks a username, help them get one. */
-	if (msim_msg_get_integer(msg, "uniquenick") == session->userid) {
-		purple_debug_info("msim_is_username_set", "no username is set\n");
-		purple_request_yes_no(session->gc,
-			_("MySpaceIM - No Username Set"),
-			_("You appear to have no MySpace username."),
-			_("Would you like to set one now? (Note: THIS CANNOT BE CHANGED!)"),
-			0,
-			session->account,
-			NULL,
-			NULL,
-			session->gc, 
-			G_CALLBACK(msim_set_username_cb), 
-			G_CALLBACK(msim_do_not_set_username_cb));
-		purple_debug_info("msim_is_username_set","'username not set' alert prompted\n");
-		return FALSE;
-	}
-	return TRUE;
-}
-
-/** Called after username is set, if necessary and we're open for business. */
-gboolean msim_we_are_logged_on(MsimSession *session) 
-{
-	MsimMessage *body;
-
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
-
-	/* The session is now set up, ready to be connected. This emits the
-	 * signedOn signal, so clients can now do anything with msimprpl, and
-	 * we're ready for it (session key, userid, username all setup). */
-	purple_connection_update_progress(session->gc, _("Connected"), 3, 4);
-	purple_connection_set_state(session->gc, PURPLE_CONNECTED);
-
-	/* Set display name to username (otherwise will show email address) */
-	purple_connection_set_display_name(session->gc, session->username);
-
-	body = msim_msg_new(
-			"UserID", MSIM_TYPE_INTEGER, session->userid,
-			NULL);
-
-	/* Request IM info about ourself. */
-	msim_send(session,
-			"persist", MSIM_TYPE_STRING, g_strdup("persist"),
-			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
-			"dsn", MSIM_TYPE_INTEGER, MG_OWN_MYSPACE_INFO_DSN,
-			"uid", MSIM_TYPE_INTEGER, session->userid,
-			"lid", MSIM_TYPE_INTEGER, MG_OWN_MYSPACE_INFO_LID,
-			"rid", MSIM_TYPE_INTEGER, session->next_rid++,
-			"body", MSIM_TYPE_DICTIONARY, body,
-			NULL);
-
-	/* Request MySpace info about ourself. */
-	msim_send(session,
-			"persist", MSIM_TYPE_STRING, g_strdup("persist"),
-			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
-			"dsn", MSIM_TYPE_INTEGER, MG_OWN_IM_INFO_DSN,
-			"uid", MSIM_TYPE_INTEGER, session->userid,
-			"lid", MSIM_TYPE_INTEGER, MG_OWN_IM_INFO_LID,
-			"rid", MSIM_TYPE_INTEGER, session->next_rid++,
-			"body", MSIM_TYPE_STRING, g_strdup(""),
-			NULL);
-
-	/* TODO: set options (persist cmd=514,dsn=1,lid=10) */
-	/* TODO: set blocklist */
-
-	/* Notify servers of our current status. */
-	purple_debug_info("msim", "msim_we_are_logged_on: notifying servers of status\n");
-	msim_set_status(session->account,
-			purple_account_get_active_status(session->account));
-
-	/* TODO: setinfo */
-	/*
-	body = msim_msg_new(
-		"TotalFriends", MSIM_TYPE_INTEGER, 666,
-		NULL);
-	msim_send(session,
-			"setinfo", MSIM_TYPE_BOOLEAN, TRUE,
-			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
-			"info", MSIM_TYPE_DICTIONARY, body,
-			NULL);
-			*/
-
-	/* Disable due to problems with timeouts. TODO: fix. */
-#ifdef MSIM_USE_KEEPALIVE
-	purple_timeout_add(MSIM_KEEPALIVE_INTERVAL_CHECK, 
-			(GSourceFunc)msim_check_alive, session);
-#endif
-
-	/* Check mail if they want to. */
-	if (purple_account_get_check_mail(session->account)) {
-		session->inbox_handle = purple_timeout_add(MSIM_MAIL_INTERVAL_CHECK, 
-				(GSourceFunc)msim_check_inbox, session);
-		msim_check_inbox(session);
-	}
-
-	msim_get_contact_list(session, MSIM_CONTACT_LIST_INITIAL_FRIENDS);
-
-	return TRUE;
-}
-
 /**
- * Process a message. 
- *
- * @param session
- * @param msg A message from the server, ready for processing (possibly with resolved username information attached). Caller frees.
- *
- * @return TRUE if successful. FALSE if processing failed.
- */
-static gboolean 
-msim_process(MsimSession *session, MsimMessage *msg)
-{
-	g_return_val_if_fail(session != NULL, FALSE);
-	g_return_val_if_fail(msg != NULL, FALSE);
-
-#ifdef MSIM_DEBUG_MSG
-	msim_msg_dump("ready to process: %s\n", msg);
-#endif
-
-	if (msim_msg_get_integer(msg, "lc") == 1) {
-		return msim_login_challenge(session, msg);
-	} else if (msim_msg_get_integer(msg, "lc") == 2) {
-		/* return msim_we_are_logged_on(session, msg); */
-		if (msim_is_username_set(session, msg)) {
-			return msim_we_are_logged_on(session);
-		} else {
-			/* No username is set... We'll wait for the callbacks to do their work */
-			/* When they're all done, the last one will call msim_we_are_logged_on() and pick up where we left off */
-			return FALSE;
-		}
-	} else if (msim_msg_get(msg, "bm"))  {
-		return msim_incoming_bm(session, msg);
-	} else if (msim_msg_get(msg, "rid")) {
-		return msim_process_reply(session, msg);
-	} else if (msim_msg_get(msg, "error")) {
-		return msim_error(session, msg);
-	} else if (msim_msg_get(msg, "ka")) {
-		return TRUE;
-	} else {
-		msim_unrecognized(session, msg, "in msim_process");
-		return FALSE;
-	}
-}
-
-/** Process the initial server information from the server. */
-static gboolean
-msim_process_server_info(MsimSession *session, MsimMessage *msg)
-{
-	MsimMessage *body;
-
-	body = msim_msg_get_dictionary(msg, "body");
-	g_return_val_if_fail(body != NULL, FALSE);
-
-	/* Example body:
-AdUnitRefreshInterval=10.
-AlertPollInterval=360.
-AllowChatRoomEmoticonSharing=False.
-ChatRoomUserIDs=78744676;163733130;1300326231;123521495;142663391.
-CurClientVersion=673.
-EnableIMBrowse=True.
-EnableIMStuffAvatars=False.
-EnableIMStuffZaps=False.
-MaxAddAllFriends=100.
-MaxContacts=1000.
-MinClientVersion=594.
-MySpaceIM_ENGLISH=78744676.
-MySpaceNowTimer=720.
-PersistenceDataTimeout=900.
-UseWebChallenge=1.
-WebTicketGoHome=False
-
-	Anything useful? TODO: use what is useful, and use it.
-*/
-	purple_debug_info("msim_process_server_info",
-			"maximum contacts: %d\n", 
-			msim_msg_get_integer(body, "MaxContacts"));
-
-	session->server_info = body;
-	/* session->server_info freed in msim_session_destroy */
-
-	return TRUE;
-}
-
-/** Process a web challenge, used to login to the web site. */
-static gboolean
-msim_web_challenge(MsimSession *session, MsimMessage *msg)
-{
-	/* TODO: web challenge, store token. #2659. */
-	return FALSE;
-}
-
-/**
- * Process a persistance message reply from the server.
- *
- * @param session 
- * @param msg Message reply from server.
- *
- * @return TRUE if successful.
- *
- * msim_lookup_user sets callback for here 
- */
-static gboolean 
-msim_process_reply(MsimSession *session, MsimMessage *msg)
-{
-	MSIM_USER_LOOKUP_CB cb;
-	gpointer data;
-	guint rid, cmd, dsn, lid;
-
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
-	g_return_val_if_fail(msg != NULL, FALSE);
-
-	msim_store_user_info(session, msg, NULL);
-
-	rid = msim_msg_get_integer(msg, "rid");
-	cmd = msim_msg_get_integer(msg, "cmd");
-	dsn = msim_msg_get_integer(msg, "dsn");
-	lid = msim_msg_get_integer(msg, "lid");
-
-	/* Unsolicited messages */
-	if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_GET)) {
-		if (dsn == MG_SERVER_INFO_DSN && lid == MG_SERVER_INFO_LID) {
-			return msim_process_server_info(session, msg);
-		} else if (dsn == MG_WEB_CHALLENGE_DSN && lid == MG_WEB_CHALLENGE_LID) {
-			return msim_web_challenge(session, msg);
-		}
-	}
-
-	/* If a callback is registered for this userid lookup, call it. */
-	cb = g_hash_table_lookup(session->user_lookup_cb, GUINT_TO_POINTER(rid));
-	data = g_hash_table_lookup(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
-
-	if (cb) {
-		purple_debug_info("msim", "msim_process_reply: calling callback now\n");
-		msim_msg_dump("for msg=%s\n", msg);
-		/* Clone message, so that the callback 'cb' can use it (needs to free it also). */
-		cb(session, msim_msg_clone(msg), data);
-		g_hash_table_remove(session->user_lookup_cb, GUINT_TO_POINTER(rid));
-		g_hash_table_remove(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
-	} else {
-		purple_debug_info("msim", 
-				"msim_process_reply: no callback for rid %d\n", rid);
-	}
-
-	return TRUE;
-}
-
-/**
- * Handle an error from the server.
- *
- * @param session 
- * @param msg The message.
- *
- * @return TRUE if successfully reported error.
- */
-static gboolean 
-msim_error(MsimSession *session, MsimMessage *msg)
-{
-	gchar *errmsg, *full_errmsg;
-	guint err;
-
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
-	g_return_val_if_fail(msg != NULL, FALSE);
-
-	err = msim_msg_get_integer(msg, "err");
-	errmsg = msim_msg_get_string(msg, "errmsg");
-
-	full_errmsg = g_strdup_printf(_("Protocol error, code %d: %s"), err, 
-			errmsg ? errmsg : "no 'errmsg' given");
-
-	g_free(errmsg);
-
-	purple_debug_info("msim", "msim_error (sesskey=%d): %s\n", 
-			session->sesskey, full_errmsg);
-
-	/* Destroy session if fatal. */
-	if (msim_msg_get(msg, "fatal")) {
-		PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
-		purple_debug_info("msim", "fatal error, closing\n");
-
-		switch (err) {
-			case MSIM_ERROR_INCORRECT_PASSWORD: /* Incorrect password */
-				reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
-				if (!purple_account_get_remember_password(session->account))
-					purple_account_set_password(session->account, NULL);
-#ifdef MSIM_MAX_PASSWORD_LENGTH
-				if (session->account->password && (strlen(session->account->password) > MSIM_MAX_PASSWORD_LENGTH)) {
-					gchar *suggestion;
-
-					suggestion = g_strdup_printf(_("%s Your password is "
-							"%d characters, greater than the "
-							"expected maximum length of %d for "
-							"MySpaceIM. Please shorten your "
-							"password at http://profileedit.myspace.com/index.cfm?fuseaction=accountSettings.changePassword and try again."),
-							full_errmsg, (int)
-							strlen(session->account->password),
-							MSIM_MAX_PASSWORD_LENGTH);
-
-					/* Replace full_errmsg. */
-					g_free(full_errmsg);
-					full_errmsg = suggestion;
-				}
-#endif		
-				break;
-			case MSIM_ERROR_LOGGED_IN_ELSEWHERE: /* Logged in elsewhere */
-				reason = PURPLE_CONNECTION_ERROR_NAME_IN_USE;
-				if (!purple_account_get_remember_password(session->account))
-					purple_account_set_password(session->account, NULL);
-				break;
-		}
-		purple_connection_error_reason (session->gc, reason, full_errmsg);
-	} else {
-		purple_notify_error(session->account, _("MySpaceIM Error"), full_errmsg, NULL);
-	}
-
-	g_free(full_errmsg);
-
-	return TRUE;
-}
-
-/**
- * Process incoming status messages.
- *
- * @param session
- * @param msg Status update message. Caller frees.
- *
- * @return TRUE if successful.
- */
-static gboolean 
-msim_incoming_status(MsimSession *session, MsimMessage *msg)
-{
-	PurpleBuddyList *blist;
-	MsimUser *user;
-	GList *list;
-	gchar *status_headline, *status_headline_escaped;
-	gint status_code, purple_status_code;
-	gchar *username;
-	gchar *unrecognized_msg;
-
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
-	g_return_val_if_fail(msg != NULL, FALSE);
-
-	msim_msg_dump("msim_status msg=%s\n", msg);
-
-	/* Helpfully looked up by msim_incoming_resolve() for us. */
-	username = msim_msg_get_string(msg, "_username");
-	g_return_val_if_fail(username != NULL, FALSE);
-
-	{
-		gchar *ss;
-
-		ss = msim_msg_get_string(msg, "msg");
-		purple_debug_info("msim", 
-				"msim_status: updating status for <%s> to <%s>\n",
-				username, ss ? ss : "(NULL)");
-		g_free(ss);
-	}
-
-	/* Example fields: 
-	 *  |s|0|ss|Offline 
-	 *  |s|1|ss|:-)|ls||ip|0|p|0 
-	 */
-	list = msim_msg_get_list(msg, "msg");
-
-	status_code = msim_msg_get_integer_from_element(g_list_nth_data(list, MSIM_STATUS_ORDINAL_ONLINE));
-	purple_debug_info("msim", "msim_status: %s's status code = %d\n", username, status_code);
-	status_headline = msim_msg_get_string_from_element(g_list_nth_data(list, MSIM_STATUS_ORDINAL_HEADLINE));
-
-	blist = purple_get_blist();
-
-	/* Add buddy if not found.
-	 * TODO: Could this be responsible for #3444? */
-	user = msim_find_user(session, username);
-	if (!user) {
-		PurpleBuddy *buddy;
-
-		purple_debug_info("msim", 
-				"msim_status: making new buddy for %s\n", username);
-		buddy = purple_buddy_new(session->account, username, NULL);
-		purple_blist_add_buddy(buddy, NULL, NULL, NULL);
-
-		user = msim_get_user_from_buddy(buddy);
-		user->id = msim_msg_get_integer(msg, "f");
-
-		/* Keep track of the user ID across sessions */
-		purple_blist_node_set_int(&buddy->node, "UserID", user->id);
-
-		msim_store_user_info(session, msg, NULL);
-	} else {
-		purple_debug_info("msim", "msim_status: found buddy %s\n", username);
-	}
-
-	if (status_headline && strcmp(status_headline, "") != 0) {
-		/* The status headline is plaintext, but libpurple treats it as HTML,
-		 * so escape any HTML characters to their entity equivalents. */
-		status_headline_escaped = g_markup_escape_text(status_headline, strlen(status_headline));
-	} else {
-		status_headline_escaped = NULL;
-	}
-
-	g_free(status_headline);
-
-	if (user->headline) 
-		g_free(user->headline);
-
-	/* don't copy; let the MsimUser own the headline, memory-wise */
-	user->headline = status_headline_escaped;
-
-	/* Set user status */
-	switch (status_code) {
-		case MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN: 
-			purple_status_code = PURPLE_STATUS_OFFLINE;
-			break;
-
-		case MSIM_STATUS_CODE_ONLINE: 
-			purple_status_code = PURPLE_STATUS_AVAILABLE;
-			break;
-
-		case MSIM_STATUS_CODE_AWAY:
-			purple_status_code = PURPLE_STATUS_AWAY;
-			break;
-
-		case MSIM_STATUS_CODE_IDLE:
-			/* Treat idle as an available status. */
-			purple_status_code = PURPLE_STATUS_AVAILABLE;
-			break;
-
-		default:
-			purple_debug_info("msim", "msim_incoming_status for %s, unknown status code %d, treating as available\n",
-						username, status_code);
-			purple_status_code = PURPLE_STATUS_AVAILABLE;
-
-			unrecognized_msg = g_strdup_printf("msim_incoming_status, unrecognized status code: %d\n", 
-					status_code);
-			msim_unrecognized(session, NULL, unrecognized_msg);
-			g_free(unrecognized_msg);
-
-	}
-
-	purple_prpl_got_user_status(session->account, username, purple_primitive_get_id_from_type(purple_status_code), NULL);
-
-	if (status_code == MSIM_STATUS_CODE_IDLE) {
-		purple_debug_info("msim", "msim_status: got idle: %s\n", username);
-		purple_prpl_got_user_idle(session->account, username, TRUE, time(NULL));
-	} else {
-		/* All other statuses indicate going back to non-idle. */
-		purple_prpl_got_user_idle(session->account, username, FALSE, time(NULL));
-	}
-
-#ifdef MSIM_SEND_CLIENT_VERSION
-	if (status_code == MSIM_STATUS_CODE_ONLINE) {
-		/* Secretly whisper to unofficial clients our own version as they come online */
-		msim_send_unofficial_client(session, username);
-	}
-#endif
-
-	if (status_code != MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN) {
-		/* Get information when they come online.
-		 * TODO: periodically refresh?
-		 */
-		purple_debug_info("msim_incoming_status", "%s came online, looking up\n", username);
-		msim_lookup_user(session, username, NULL, NULL);
-	}
-
-	g_free(username);
-	msim_msg_list_free(list);
-
-	return TRUE;
-}
-
-/** Add a buddy to user's buddy list. */
-void 
-msim_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
-{
-	MsimSession *session;
-	MsimMessage *msg;
-	MsimMessage *msg_persist;
-	MsimMessage *body;
-
-	session = (MsimSession *)gc->proto_data;
-	purple_debug_info("msim", "msim_add_buddy: want to add %s to %s\n", 
-			buddy->name, (group && group->name) ? group->name : "(no group)");
-
-	msg = msim_msg_new(
-			"addbuddy", MSIM_TYPE_BOOLEAN, TRUE,
-			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
-			/* "newprofileid" will be inserted here with uid. */
-			"reason", MSIM_TYPE_STRING, g_strdup(""),
-			NULL);
-
-	if (!msim_postprocess_outgoing(session, msg, buddy->name, "newprofileid", "reason")) {
-		purple_notify_error(NULL, NULL, _("Failed to add buddy"), _("'addbuddy' command failed."));
-		msim_msg_free(msg);
-		return;
-	}
-	msim_msg_free(msg);
-	
-	/* TODO: if addbuddy fails ('error' message is returned), delete added buddy from
-	 * buddy list since Purple adds it locally. */
-
-	body = msim_msg_new(
-			"ContactID", MSIM_TYPE_STRING, g_strdup("<uid>"),
-			"GroupName", MSIM_TYPE_STRING, g_strdup(group->name),
-			"Position", MSIM_TYPE_INTEGER, 1000,
-			"Visibility", MSIM_TYPE_INTEGER, 1,
-			"NickName", MSIM_TYPE_STRING, g_strdup(""),
-			"NameSelect", MSIM_TYPE_INTEGER, 0,
-			NULL);
-
-	/* TODO: Update blocklist. */
-
-	msg_persist = msim_msg_new(
-		"persist", MSIM_TYPE_INTEGER, 1,
-		"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
-		"cmd", MSIM_TYPE_INTEGER, MSIM_CMD_BIT_ACTION | MSIM_CMD_PUT,
-		"dsn", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_DSN,
-		"uid", MSIM_TYPE_INTEGER, session->userid,
-		"lid", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_LID,
-		/* TODO: Use msim_new_reply_callback to get rid. */
-		"rid", MSIM_TYPE_INTEGER, session->next_rid++,
-		"body", MSIM_TYPE_DICTIONARY, body,
-		NULL);
-
-	if (!msim_postprocess_outgoing(session, msg_persist, buddy->name, "body", NULL))
-	{
-		purple_notify_error(NULL, NULL, _("Failed to add buddy"), _("persist command failed"));
-		msim_msg_free(msg_persist);
-		return;
-	}
-	msim_msg_free(msg_persist);
-
-}
-
-/** Perform actual postprocessing on a message, adding userid as specified.
- *
- * @param msg The message to postprocess.
- * @param uid_before Name of field where to insert new field before, or NULL for end.
- * @param uid_field_name Name of field to add uid to.
- * @param uid The userid to insert.
- *
- * If the field named by uid_field_name already exists, then its string contents will
- * be used for the field, except "<uid>" will be replaced by the userid.
- *
- * If the field named by uid_field_name does not exist, it will be added before the
- * field named by uid_before, as an integer, with the userid.
- *
- * Does not handle sending, or scheduling userid lookup. For that, see msim_postprocess_outgoing().
- */ 
-static MsimMessage *
-msim_do_postprocessing(MsimMessage *msg, const gchar *uid_before, 
-		const gchar *uid_field_name, guint uid)
-{
-	MsimMessageElement *elem;
-	msim_msg_dump("msim_do_postprocessing msg: %s\n", msg);
-
-	/* First, check - if the field already exists, replace <uid> within it */
-	if ((elem = msim_msg_get(msg, uid_field_name)) != NULL) {
-		gchar *fmt_string;
-		gchar *uid_str, *new_str;
-
-		/* Get the packed element, flattening it. This allows <uid> to be
-		 * replaced within nested data structures, since the replacement is done
-		 * on the linear, packed data, not on a complicated data structure.
-		 *
-		 * For example, if the field was originally a dictionary or a list, you 
-		 * would have to iterate over all the items in it to see what needs to
-		 * be replaced. But by packing it first, the <uid> marker is easily replaced
-		 * just by a string replacement.
-		 */
-		fmt_string = msim_msg_pack_element_data(elem);
-
-		uid_str = g_strdup_printf("%d", uid);
-		new_str = purple_strreplace(fmt_string, "<uid>", uid_str);
-		g_free(uid_str);
-		g_free(fmt_string);
-
-		/* Free the old element data */
-		msim_msg_free_element_data(elem->data);
-
-		/* Replace it with our new data */
-		elem->data = new_str;
-		elem->type = MSIM_TYPE_RAW;
-
-	} else {
-		/* Otherwise, insert new field into outgoing message. */
-		msg = msim_msg_insert_before(msg, uid_before, uid_field_name, MSIM_TYPE_INTEGER, GUINT_TO_POINTER(uid));
-	}
-
-	msim_msg_dump("msim_postprocess_outgoing_cb: postprocessed msg=%s\n", msg);
-
-	return msg;
-}
-
-/** Callback for msim_postprocess_outgoing() to add a userid to a message, and send it (once receiving userid).
- *
- * @param session
- * @param userinfo The user information reply message, containing the user ID
- * @param data The message to postprocess and send.
- *
- * The data message should contain these fields:
- *
- *  _uid_field_name: string, name of field to add with userid from userinfo message
- *  _uid_before: string, name of field before field to insert, or NULL for end
- *
- *
-*/
-static void 
-msim_postprocess_outgoing_cb(MsimSession *session, MsimMessage *userinfo, 
-		gpointer data)
-{
-	gchar *uid_field_name, *uid_before, *username;
-	guint uid;
-	MsimMessage *msg, *body;
-
-	msg = (MsimMessage *)data;
-
-	msim_msg_dump("msim_postprocess_outgoing_cb() got msg=%s\n", msg);
-
-	/* Obtain userid from userinfo message. */
-	body = msim_msg_get_dictionary(userinfo, "body");
-	g_return_if_fail(body != NULL);
-
-	uid = msim_msg_get_integer(body, "UserID");
-	msim_msg_free(body);
-
-	username = msim_msg_get_string(msg, "_username");
-
-	if (!uid) {
-		gchar *msg;
-
-		msg = g_strdup_printf(_("No such user: %s"), username);
-		if (!purple_conv_present_error(username, session->account, msg)) { 
-			purple_notify_error(NULL, NULL, _("User lookup"), msg); 
-		}
-
-		g_free(msg);
-		g_free(username);
-		/* TODO: free
-		 * msim_msg_free(msg);
-		 */
-		return;
-	}
-
-	uid_field_name = msim_msg_get_string(msg, "_uid_field_name");
-	uid_before = msim_msg_get_string(msg, "_uid_before");
-
-	msg = msim_do_postprocessing(msg, uid_before, uid_field_name, uid);
-
-	/* Send */
-	if (!msim_msg_send(session, msg)) {
-		msim_msg_dump("msim_postprocess_outgoing_cb: sending failed for message: %s\n", msg);
-	}
-
-
-	/* Free field names AFTER sending message, because MsimMessage does NOT copy
-	 * field names - instead, treats them as static strings (which they usually are).
-	 */
-	g_free(uid_field_name);
-	g_free(uid_before);
-	g_free(username);
-	/* TODO: free 
-	 * msim_msg_free(msg);
-	 */
-}
-
-/** Postprocess and send a message.
- *
- * @param session
- * @param msg Message to postprocess. Will NOT be freed.
- * @param username Username to resolve. Assumed to be a static string (will not be freed or copied).
- * @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 TRUE if successful.
- */
-gboolean 
-msim_postprocess_outgoing(MsimSession *session, MsimMessage *msg, 
-		const gchar *username, const gchar *uid_field_name, 
-		const gchar *uid_before)
-{
-	PurpleBuddy *buddy;
-	guint uid;
-	gboolean rc;
-
-	g_return_val_if_fail(msg != NULL, FALSE);
-
-	/* Store information for msim_postprocess_outgoing_cb(). */
-	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));
-	msg = msim_msg_append(msg, "_uid_before", MSIM_TYPE_STRING, g_strdup(uid_before));
-
-	/* First, try the most obvious. If numeric userid is given, use that directly. */
-	if (msim_is_userid(username)) {
-		uid = atol(username);
-	} else {
-		/* Next, see if on buddy list and know uid. */
-		buddy = purple_find_buddy(session->account, username);
-		if (buddy) {
-			uid = purple_blist_node_get_int(&buddy->node, "UserID");
-		} else {
-			uid = 0;
-		}
-
-		if (!buddy || !uid) {
-			/* Don't have uid offhand - need to ask for it, and wait until hear back before sending. */
-			purple_debug_info("msim", ">>> msim_postprocess_outgoing: couldn't find username %s in blist\n",
-					username ? username : "(NULL)");
-			msim_msg_dump("msim_postprocess_outgoing - scheduling lookup, msg=%s\n", msg);
-			/* TODO: where is cloned message freed? Should be in _cb. */
-			msim_lookup_user(session, username, msim_postprocess_outgoing_cb, msim_msg_clone(msg));
-			return TRUE;       /* not sure of status yet - haven't sent! */
-		}
-	}
-	
-	/* Already have uid, postprocess and send msg immediately. */
-	purple_debug_info("msim", "msim_postprocess_outgoing: found username %s has uid %d\n",
-			username ? username : "(NULL)", uid);
-
-	msg = msim_do_postprocessing(msg, uid_before, uid_field_name, uid);
-
-	msim_msg_dump("msim_postprocess_outgoing: msg after (uid immediate)=%s\n", msg);
-	
-	rc = msim_msg_send(session, msg);
-
-	/* TODO: free
-	 * msim_msg_free(msg);
-	 */
-
-	return rc;
-}
-
-/** Remove a buddy from the user's buddy list. */
-void 
-msim_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
-{
-	MsimSession *session;
-	MsimMessage *delbuddy_msg;
-	MsimMessage *persist_msg;
-	MsimMessage *blocklist_msg;
-	GList *blocklist_updates;
-
-	session = (MsimSession *)gc->proto_data;
-
-	delbuddy_msg = msim_msg_new(
-				"delbuddy", MSIM_TYPE_BOOLEAN, TRUE,
-				"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
-				/* 'delprofileid' with uid will be inserted here. */
-				NULL);
-
-	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(
-			"persist", MSIM_TYPE_INTEGER, 1,
-			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
-			"cmd", MSIM_TYPE_INTEGER, MSIM_CMD_BIT_ACTION | MSIM_CMD_DELETE,
-			"dsn", MSIM_TYPE_INTEGER, MD_DELETE_BUDDY_DSN,
-			"lid", MSIM_TYPE_INTEGER, MD_DELETE_BUDDY_LID,
-			"uid", MSIM_TYPE_INTEGER, session->userid,
-			"rid", MSIM_TYPE_INTEGER, session->next_rid++,
-			/* <uid> will be replaced by postprocessing */
-			"body", MSIM_TYPE_STRING, g_strdup("ContactID=<uid>"),
-			NULL);
-
-	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_updates = NULL;
-	blocklist_updates = g_list_prepend(blocklist_updates, "a-");
-	blocklist_updates = g_list_prepend(blocklist_updates, "<uid>");
-	blocklist_updates = g_list_prepend(blocklist_updates, "b-");
-	blocklist_updates = g_list_prepend(blocklist_updates, "<uid>");
-	blocklist_updates = g_list_reverse(blocklist_updates);
-
-	blocklist_msg = msim_msg_new(
-			"blocklist", MSIM_TYPE_BOOLEAN, TRUE,
-			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
-			/* TODO: MsimMessage lists. Currently <uid> isn't replaced in lists. */
-			/* "idlist", MSIM_TYPE_STRING, g_strdup("a-|<uid>|b-|<uid>"), */
-			"idlist", MSIM_TYPE_LIST, blocklist_updates,
-			NULL);
-
-	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);
-}
-
-/**
- * Returns a string of a username in canonical form. Basically removes all the
- * spaces, lowercases the string, and looks up user IDs to usernames.
- * Normalizing tom, TOM, Tom, and 6221 wil all return 'tom'.
- *
- * Borrowed this code from oscar_normalize. Added checking for 
- * "if userid, get name before normalizing"
- */
-const char *msim_normalize(const PurpleAccount *account, const char *str) {
-	static char normalized[BUF_LEN];
-	char *tmp1, *tmp2;
-	int i, j;
-	guint id;
-
-	g_return_val_if_fail(str != NULL, NULL);
-
-	if (msim_is_userid(str)) {
-		/* Have user ID, we need to get their username first :) */
-		const char *username;
-
-		/* If the account does not exist, we can't look up the user. */
-		if (!account || !account->gc)
-			return str;
-
-		id = atol(str);
-		username = msim_uid2username_from_blist((PurpleAccount *)account, id);
-		if (!username) {
-			/* Not in buddy list... scheisse... TODO: Manual Lookup! Bug #4631 */
-			/* Note: manual lookup using msim_lookup_user() is a problem inside 
-			 * msim_normalize(), because msim_lookup_user() calls a callback function
-			 * when the user information has been looked up, but msim_normalize() expects
-			 * the result immediately. */
-			strncpy(normalized, str, BUF_LEN);
-		} else {
-			strncpy(normalized, username, BUF_LEN);
-		}
-	} else {
-		/* Have username. */
-		strncpy(normalized, str, BUF_LEN);
-	}
-
-	/* Strip spaces. */
-	for (i=0, j=0; normalized[j]; i++, j++) {
-		while (normalized[j] == ' ')
-			j++;
-		normalized[i] = normalized[j];
-	}
-	normalized[i] = '\0';
-
-	/* Lowercase and perform UTF-8 normalization. */
-	tmp1 = g_utf8_strdown(normalized, -1);
-	tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT);
-	g_snprintf(normalized, sizeof(normalized), "%s", tmp2);
-	g_free(tmp2);
-	g_free(tmp1);
-
-	/* TODO: re-add caps and spacing back to what the user wanted.
-	 * User can format their own names, for example 'msimprpl' is shown
-	 * as 'MsIm PrPl' in the official client.
-	 *
-	 * TODO: file a ticket to add this enhancement.
-	 */
-
-	return normalized;
-}
-
-static GHashTable *
-msim_get_account_text_table(PurpleAccount *unused)
-{
-	GHashTable *table;
-
-	table = g_hash_table_new(g_str_hash, g_str_equal);
-
-	g_hash_table_insert(table, "login_label", (gpointer)_("Email Address..."));
-
-	return table;
-}
-
-/** Return whether the buddy can be messaged while offline.
- *
- * The protocol supports offline messages in just the same way as online
- * messages.
- */
-gboolean 
-msim_offline_message(const PurpleBuddy *buddy)
-{
-	return TRUE;
-}
-
-/**
- * Callback when input available.
- *
- * @param gc_uncasted A PurpleConnection pointer.
- * @param source File descriptor.
- * @param cond PURPLE_INPUT_READ
- *
- * Reads the input, and calls msim_preprocess_incoming() to handle it.
- */
-static void 
-msim_input_cb(gpointer gc_uncasted, gint source, PurpleInputCondition cond)
-{
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	MsimSession *session;
-	gchar *end;
-	int n;
-
-	g_return_if_fail(gc_uncasted != NULL);
-	g_return_if_fail(source >= 0);  /* Note: 0 is a valid fd */
-
-	gc = (PurpleConnection *)(gc_uncasted);
-	account = purple_connection_get_account(gc);
-	session = gc->proto_data;
-
-	/* libpurple/eventloop.h only defines these two */
-	if (cond != PURPLE_INPUT_READ && cond != PURPLE_INPUT_WRITE) {
-		purple_debug_info("msim_input_cb", "unknown condition=%d\n", cond);
-		purple_connection_error_reason (gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Invalid input condition"));
-		return;
-	}
-
-	g_return_if_fail(cond == PURPLE_INPUT_READ);
-	g_return_if_fail(MSIM_SESSION_VALID(session));
-
-	/* Mark down that we got data, so we don't timeout. */
-	session->last_comm = time(NULL);
-
-	/* If approaching end of buffer, reallocate some more memory. */
-	if (session->rxsize < session->rxoff + MSIM_READ_BUF_SIZE) {
-		purple_debug_info("msim", 
-			"msim_input_cb: %d-byte read buffer full, rxoff=%d, " "growing by %d bytes\n",
-			session->rxsize, session->rxoff, MSIM_READ_BUF_SIZE);
-			session->rxsize += MSIM_READ_BUF_SIZE;
-			session->rxbuf = g_realloc(session->rxbuf, session->rxsize);
-		
-		return;
-	}
-
-	purple_debug_info("msim", "dynamic buffer at %d (max %d), reading up to %d\n",
-			session->rxoff, session->rxsize,
-			MSIM_READ_BUF_SIZE - session->rxoff - 1);
-
-	/* Read into buffer. On Win32, need recv() not read(). session->fd also holds
-	 * the file descriptor, but it sometimes differs from the 'source' parameter.
-	 */
-	n = recv(session->fd, 
-		 session->rxbuf + session->rxoff, 
-		 session->rxsize - session->rxoff - 1, 0);
-
-	if (n < 0 && errno == EAGAIN) {
-		return;
-	} else if (n < 0) {
-		purple_debug_error("msim", "msim_input_cb: read error, ret=%d, "
-			"error=%s, source=%d, fd=%d (%X))\n", 
-			n, g_strerror(errno), source, session->fd, session->fd);
-		purple_connection_error_reason (gc, 
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Read error"));
-		return;
-	} else if (n == 0) {
-		purple_debug_info("msim", "msim_input_cb: server disconnected\n");
-		purple_connection_error_reason (gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Server has disconnected"));
-		return;
-	}
-
-	if (n + session->rxoff > session->rxsize) {
-		purple_debug_info("msim_input_cb", "received %d bytes, pushing rxoff to %d, over buffer size of %d\n",
-				n, n + session->rxoff, session->rxsize);
-		purple_connection_error_reason (gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Read buffer full (2)"));
-		return;
-	}
-
-	/* Null terminate */
-	purple_debug_info("msim", "msim_input_cb: going to null terminate "
-			"at n=%d\n", n);
-	session->rxbuf[session->rxoff + n] = 0;
-
-#ifdef MSIM_CHECK_EMBEDDED_NULLS
-	/* Check for embedded NULs. I don't handle them, and they shouldn't occur. */
-	if (strlen(session->rxbuf + session->rxoff) != n) {
-		/* Occurs after login, but it is not a null byte. */
-		purple_debug_info("msim", "msim_input_cb: strlen=%d, but read %d bytes"
-				"--null byte encountered?\n", 
-				strlen(session->rxbuf + session->rxoff), n);
-		/*purple_connection_error_reason (gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				"Invalid message - null byte on input"); */
-		return;
-	}
-#endif
-
-	session->rxoff += n;
-	purple_debug_info("msim", "msim_input_cb: read=%d\n", n);
-
-#ifdef MSIM_DEBUG_RXBUF
-	purple_debug_info("msim", "buf=<%s>\n", session->rxbuf);
-#endif
-
-	/* Look for \\final\\ end markers. If found, process message. */
-	while((end = strstr(session->rxbuf, MSIM_FINAL_STRING))) {
-		MsimMessage *msg;
-
-#ifdef MSIM_DEBUG_RXBUF
-		purple_debug_info("msim", "in loop: buf=<%s>\n", session->rxbuf);
-#endif
-		*end = 0;
-		msg = msim_parse(g_strdup(session->rxbuf));
-		if (!msg) {
-			purple_debug_info("msim", "msim_input_cb: couldn't parse rxbuf\n");
-			purple_connection_error_reason (gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				_("Unparseable message"));
-			break;
-		} else {
-			/* Process message and then free it (processing function should
-			 * clone message if it wants to keep it afterwards.) */
-			if (!msim_preprocess_incoming(session, msg)) {
-				msim_msg_dump("msim_input_cb: preprocessing message failed on msg: %s\n", msg);
-			}
-			msim_msg_free(msg);
-		}
-
-		/* Move remaining part of buffer to beginning. */
-		session->rxoff -= strlen(session->rxbuf) + strlen(MSIM_FINAL_STRING);
-		memmove(session->rxbuf, end + strlen(MSIM_FINAL_STRING), 
-				session->rxsize - (end + strlen(MSIM_FINAL_STRING) - session->rxbuf));
-
-		/* Clear end of buffer 
-		 * memset(end, 0, MSIM_READ_BUF_SIZE - (end - session->rxbuf));
-		 */
-	}
-}
-
-/* Setup a callback, to be called when a reply is received with the returned rid.
- *
- * @param cb The callback, an MSIM_USER_LOOKUP_CB.
- * @param data Arbitrary user data to be passed to callback (probably an MsimMessage *).
- *
- * @return The request/reply ID, used to link replies with requests, or -1.
- *          Put the rid in your request, 'rid' field.
- *
- * TODO: Make more generic and more specific:
- * 1) MSIM_USER_LOOKUP_CB - make it for PERSIST_REPLY, not just user lookup
- * 2) data - make it an MsimMessage?
- */
-guint 
-msim_new_reply_callback(MsimSession *session, MSIM_USER_LOOKUP_CB cb, 
-		gpointer data)
-{
-	guint rid;
-
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), -1);
-
-	rid = session->next_rid++;
-
-	g_hash_table_insert(session->user_lookup_cb, GUINT_TO_POINTER(rid), cb);
-	g_hash_table_insert(session->user_lookup_cb_data, GUINT_TO_POINTER(rid), data);
-
-	return rid;
-}
-
-/**
- * Callback when connected. Sets up input handlers.
- *
- * @param data A PurpleConnection pointer.
- * @param source File descriptor.
- * @param error_message
- */
-static void 
-msim_connect_cb(gpointer data, gint source, const gchar *error_message)
-{
-	PurpleConnection *gc;
-	MsimSession *session;
-
-	g_return_if_fail(data != NULL);
-
-	gc = (PurpleConnection *)data;
-	session = (MsimSession *)gc->proto_data;
-
-	if (source < 0) {
-		purple_connection_error_reason (gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			g_strdup_printf(_("Couldn't connect to host: %s (%d)"), 
-					error_message ? error_message : "no message given", 
-					source));
-		return;
-	}
-
-	session->fd = source; 
-
-	gc->inpa = purple_input_add(source, PURPLE_INPUT_READ, msim_input_cb, gc);
-}
-
-			 
-/** 
- * Close the connection.
- * 
- * @param gc The connection.
- */
-void 
-msim_close(PurpleConnection *gc)
-{
-	MsimSession *session;
-
-	if (gc == NULL) {
-		return;
-	}
-
-	session = (MsimSession *)gc->proto_data;
-	if (session == NULL)
-		return;
-
-	gc->proto_data = NULL;
-
-	if (!MSIM_SESSION_VALID(session)) {
-		return;
-	}
-
-	if (session->gc->inpa) {
-		purple_input_remove(session->gc->inpa);
-	}
-
-	msim_session_destroy(session);
-}
-
-
-/**
- * Obtain the status text for a buddy.
- *
- * @param buddy The buddy to obtain status text for.
- *
- * @return Status text, or NULL if error. Caller g_free()'s.
- *
- */
-char *
-msim_status_text(PurpleBuddy *buddy)
-{
-	MsimSession *session;
-	MsimUser *user;
-	const gchar *display_name, *headline;
-
-	g_return_val_if_fail(buddy != NULL, NULL);
-
-	user = msim_get_user_from_buddy(buddy);
-
-	session = (MsimSession *)buddy->account->gc->proto_data;
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), NULL);
-
-	display_name = headline = NULL;
-
-	/* Retrieve display name and/or headline, depending on user preference. */
-	if (purple_account_get_bool(session->account, "show_headline", TRUE)) {
-		headline = user->headline;
-	}
-
-	if (purple_account_get_bool(session->account, "show_display_name", FALSE)) {
-		display_name = user->display_name;
-	} 
-
-	/* Return appropriate combination of display name and/or headline, or neither. */
-
-	if (display_name && headline) {
-		return g_strconcat(display_name, " ", headline, NULL);
-	} else if (display_name) {
-		return g_strdup(display_name);
-	} else if (headline) {
-		return g_strdup(headline);
-	}
-
-	return NULL;
-}
-
-/**
- * Obtain the tooltip text for a buddy.
- *
- * @param buddy Buddy to obtain tooltip text on.
- * @param user_info Variable modified to have the tooltip text.
- * @param full TRUE if should obtain full tooltip text.
- *
- */
-void 
-msim_tooltip_text(PurpleBuddy *buddy, PurpleNotifyUserInfo *user_info, 
-		gboolean full)
-{
-	MsimUser *user;
-
-	g_return_if_fail(buddy != NULL);
-	g_return_if_fail(user_info != NULL);
-
-	user = msim_get_user_from_buddy(buddy);
-
-	if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
-		MsimSession *session;
-
-		session = (MsimSession *)buddy->account->gc->proto_data;
-
-		g_return_if_fail(MSIM_SESSION_VALID(session));
-
-		/* TODO: if (full), do something different? */
-
-		/* TODO: request information? have to figure out how to do
-		 * the asynchronous lookup like oscar does (tooltip shows
-		 * 'retrieving...' if not yet available, then changes when it is).
-		 *
-		 * Right now, only show what we have on hand.
-		 */
-
-		/* Show abbreviated user info. */
-		msim_append_user_info(session, user_info, user, FALSE);
-	}
-}
-
-/** Add contact from server to buddy list, after looking up username.
- * Callback from msim_add_contact_from_server(). 
+ * Add contact from server to buddy list, after looking up username.
+ * Callback from msim_add_contact_from_server().
  *
  * @param data An MsimMessage * of the contact information. Will be freed.
  */
@@ -2880,11 +1037,12 @@
 	g_free(username);
 }
 
-/** Add first ContactID in contact_info to buddy's list. Used to add
- * server-side buddies to client-side list. 
+/**
+ * Add first ContactID in contact_info to buddy's list. Used to add
+ * server-side buddies to client-side list.
  *
  * @return TRUE if added.
- * */
+ */
 static gboolean
 msim_add_contact_from_server(MsimSession *session, MsimMessage *contact_info)
 {
@@ -2913,7 +1071,9 @@
 	return TRUE;
 }
 
-/** Called when contact list is received from server. */
+/**
+ * Called when contact list is received from server.
+ */
 static void
 msim_got_contact_list(MsimSession *session, MsimMessage *reply, gpointer user_data)
 {
@@ -2961,7 +1121,7 @@
 		case MSIM_CONTACT_LIST_IMPORT_TOP_FRIENDS:
 			/* TODO */
 			break;
-		
+
 		case MSIM_CONTACT_LIST_INITIAL_FRIENDS:
 			/* Nothing */
 			break;
@@ -2970,119 +1130,1734 @@
 	msim_msg_free(body);
 }
 
-/* Get contact list, calling msim_got_contact_list() with what_to_do_after as user_data gpointer. */
+/**
+ * Get contact list, calling msim_got_contact_list() with
+ * what_to_do_after as user_data gpointer.
+ */
 static gboolean
 msim_get_contact_list(MsimSession *session, int what_to_do_after)
 {
-	return msim_send(session, 
+	return msim_send(session,
 			"persist", MSIM_TYPE_INTEGER, 1,
 			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
 			"cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
 			"dsn", MSIM_TYPE_INTEGER, MG_LIST_ALL_CONTACTS_DSN,
 			"lid", MSIM_TYPE_INTEGER, MG_LIST_ALL_CONTACTS_LID,
 			"uid", MSIM_TYPE_INTEGER, session->userid,
-			"rid", MSIM_TYPE_INTEGER, 
-				msim_new_reply_callback(session, msim_got_contact_list, GUINT_TO_POINTER(what_to_do_after)), 
+			"rid", MSIM_TYPE_INTEGER,
+				msim_new_reply_callback(session, msim_got_contact_list, GUINT_TO_POINTER(what_to_do_after)),
 			"body", MSIM_TYPE_STRING, g_strdup(""),
 			NULL);
 }
 
-
-/** Called when friends have been imported to buddy list on server. */
-static void 
-msim_import_friends_cb(MsimSession *session, MsimMessage *reply, gpointer user_data)
+/** Called after username is set, if necessary and we're open for business. */
+gboolean msim_we_are_logged_on(MsimSession *session)
 {
 	MsimMessage *body;
-	gchar *completed;
-	msim_msg_dump("msim_import_friends_cb=%s", reply);
-
-	/* Check if the friends were imported successfully. */
-	body = msim_msg_get_dictionary(reply, "body");
-	g_return_if_fail(body != NULL);
-	completed = msim_msg_get_string(body, "Completed");
+
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+
+	/* Set display name to username (otherwise will show email address) */
+	purple_connection_set_display_name(session->gc, session->username);
+
+	/* The session is now set up, ready to be connected. This emits the
+	 * signedOn signal, so clients can now do anything with msimprpl, and
+	 * we're ready for it (session key, userid, username all setup). */
+	purple_connection_update_progress(session->gc, _("Connected"), 3, 4);
+	purple_connection_set_state(session->gc, PURPLE_CONNECTED);
+
+	body = msim_msg_new(
+			"UserID", MSIM_TYPE_INTEGER, session->userid,
+			NULL);
+
+	/* Request IM info about ourself. */
+	msim_send(session,
+			"persist", MSIM_TYPE_STRING, g_strdup("persist"),
+			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+			"dsn", MSIM_TYPE_INTEGER, MG_OWN_MYSPACE_INFO_DSN,
+			"uid", MSIM_TYPE_INTEGER, session->userid,
+			"lid", MSIM_TYPE_INTEGER, MG_OWN_MYSPACE_INFO_LID,
+			"rid", MSIM_TYPE_INTEGER, session->next_rid++,
+			"body", MSIM_TYPE_DICTIONARY, body,
+			NULL);
+
+	/* Request MySpace info about ourself. */
+	msim_send(session,
+			"persist", MSIM_TYPE_STRING, g_strdup("persist"),
+			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+			"dsn", MSIM_TYPE_INTEGER, MG_OWN_IM_INFO_DSN,
+			"uid", MSIM_TYPE_INTEGER, session->userid,
+			"lid", MSIM_TYPE_INTEGER, MG_OWN_IM_INFO_LID,
+			"rid", MSIM_TYPE_INTEGER, session->next_rid++,
+			"body", MSIM_TYPE_STRING, g_strdup(""),
+			NULL);
+
+	/* TODO: set options (persist cmd=514,dsn=1,lid=10) */
+	/* TODO: set blocklist */
+
+	/* Notify servers of our current status. */
+	purple_debug_info("msim", "msim_we_are_logged_on: notifying servers of status\n");
+	msim_set_status(session->account,
+			purple_account_get_active_status(session->account));
+
+	/* TODO: setinfo */
+	/*
+	body = msim_msg_new(
+		"TotalFriends", MSIM_TYPE_INTEGER, 666,
+		NULL);
+	msim_send(session,
+			"setinfo", MSIM_TYPE_BOOLEAN, TRUE,
+			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+			"info", MSIM_TYPE_DICTIONARY, body,
+			NULL);
+			*/
+
+	/* Disable due to problems with timeouts. TODO: fix. */
+#ifdef MSIM_USE_KEEPALIVE
+	purple_timeout_add(MSIM_KEEPALIVE_INTERVAL_CHECK,
+			(GSourceFunc)msim_check_alive, session);
+#endif
+
+	/* Check mail if they want to. */
+	if (purple_account_get_check_mail(session->account)) {
+		session->inbox_handle = purple_timeout_add(MSIM_MAIL_INTERVAL_CHECK,
+				(GSourceFunc)msim_check_inbox, session);
+		msim_check_inbox(session);
+	}
+
+	msim_get_contact_list(session, MSIM_CONTACT_LIST_INITIAL_FRIENDS);
+
+	return TRUE;
+}
+
+/**
+ * Record the client version in the buddy list, from an incoming message.
+ */
+static gboolean
+msim_incoming_bm_record_cv(MsimSession *session, MsimMessage *msg)
+{
+	gchar *username, *cv;
+	gboolean ret;
+	MsimUser *user;
+
+	username = msim_msg_get_string(msg, "_username");
+	cv = msim_msg_get_string(msg, "cv");
+
+	g_return_val_if_fail(username != NULL, FALSE);
+	if (!cv) {
+		/* No client version to record, don't worry about it. */
+		g_free(username);
+		return FALSE;
+	}
+
+	user = msim_find_user(session, username);
+
+	if (user) {
+		user->client_cv = atol(cv);
+		ret = TRUE;
+	} else {
+		ret = FALSE;
+	}
+
+	g_free(username);
+	g_free(cv);
+
+	return ret;
+}
+
+#ifdef MSIM_SEND_CLIENT_VERSION
+/**
+ * Send our client version to another unofficial client that understands it.
+ */
+static gboolean
+msim_send_unofficial_client(MsimSession *session, gchar *username)
+{
+	gchar *our_info;
+	gboolean ret;
+
+	our_info = g_strdup_printf("Libpurple %d.%d.%d - msimprpl %s",
+			PURPLE_MAJOR_VERSION,
+			PURPLE_MINOR_VERSION,
+			PURPLE_MICRO_VERSION,
+			MSIM_PRPL_VERSION_STRING);
+
+	ret = msim_send_bm(session, username, our_info, MSIM_BM_UNOFFICIAL_CLIENT);
+
+	return ret;
+}
+#endif
+
+/**
+ * Process incoming status messages.
+ *
+ * @param session
+ * @param msg Status update message. Caller frees.
+ *
+ * @return TRUE if successful.
+ */
+static gboolean
+msim_incoming_status(MsimSession *session, MsimMessage *msg)
+{
+	PurpleBuddyList *blist;
+	MsimUser *user;
+	GList *list;
+	gchar *status_headline, *status_headline_escaped;
+	gint status_code, purple_status_code;
+	gchar *username;
+	gchar *unrecognized_msg;
+
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+	g_return_val_if_fail(msg != NULL, FALSE);
+
+	msim_msg_dump("msim_status msg=%s\n", msg);
+
+	/* Helpfully looked up by msim_incoming_resolve() for us. */
+	username = msim_msg_get_string(msg, "_username");
+	g_return_val_if_fail(username != NULL, FALSE);
+
+	{
+		gchar *ss;
+
+		ss = msim_msg_get_string(msg, "msg");
+		purple_debug_info("msim",
+				"msim_status: updating status for <%s> to <%s>\n",
+				username, ss ? ss : "(NULL)");
+		g_free(ss);
+	}
+
+	/* Example fields:
+	 *  |s|0|ss|Offline
+	 *  |s|1|ss|:-)|ls||ip|0|p|0
+	 */
+	list = msim_msg_get_list(msg, "msg");
+
+	status_code = msim_msg_get_integer_from_element(g_list_nth_data(list, MSIM_STATUS_ORDINAL_ONLINE));
+	purple_debug_info("msim", "msim_status: %s's status code = %d\n", username, status_code);
+	status_headline = msim_msg_get_string_from_element(g_list_nth_data(list, MSIM_STATUS_ORDINAL_HEADLINE));
+
+	blist = purple_get_blist();
+
+	/* Add buddy if not found.
+	 * TODO: Could this be responsible for #3444? */
+	user = msim_find_user(session, username);
+	if (!user) {
+		PurpleBuddy *buddy;
+
+		purple_debug_info("msim",
+				"msim_status: making new buddy for %s\n", username);
+		buddy = purple_buddy_new(session->account, username, NULL);
+		purple_blist_add_buddy(buddy, NULL, NULL, NULL);
+
+		user = msim_get_user_from_buddy(buddy);
+		user->id = msim_msg_get_integer(msg, "f");
+
+		/* Keep track of the user ID across sessions */
+		purple_blist_node_set_int(&buddy->node, "UserID", user->id);
+
+		msim_store_user_info(session, msg, NULL);
+	} else {
+		purple_debug_info("msim", "msim_status: found buddy %s\n", username);
+	}
+
+	if (status_headline && strcmp(status_headline, "") != 0) {
+		/* The status headline is plaintext, but libpurple treats it as HTML,
+		 * so escape any HTML characters to their entity equivalents. */
+		status_headline_escaped = g_markup_escape_text(status_headline, strlen(status_headline));
+	} else {
+		status_headline_escaped = NULL;
+	}
+
+	g_free(status_headline);
+
+	if (user->headline)
+		g_free(user->headline);
+
+	/* don't copy; let the MsimUser own the headline, memory-wise */
+	user->headline = status_headline_escaped;
+
+	/* Set user status */
+	switch (status_code) {
+		case MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN:
+			purple_status_code = PURPLE_STATUS_OFFLINE;
+			break;
+
+		case MSIM_STATUS_CODE_ONLINE:
+			purple_status_code = PURPLE_STATUS_AVAILABLE;
+			break;
+
+		case MSIM_STATUS_CODE_AWAY:
+			purple_status_code = PURPLE_STATUS_AWAY;
+			break;
+
+		case MSIM_STATUS_CODE_IDLE:
+			/* Treat idle as an available status. */
+			purple_status_code = PURPLE_STATUS_AVAILABLE;
+			break;
+
+		default:
+			purple_debug_info("msim", "msim_incoming_status for %s, unknown status code %d, treating as available\n",
+						username, status_code);
+			purple_status_code = PURPLE_STATUS_AVAILABLE;
+
+			unrecognized_msg = g_strdup_printf("msim_incoming_status, unrecognized status code: %d\n",
+					status_code);
+			msim_unrecognized(session, NULL, unrecognized_msg);
+			g_free(unrecognized_msg);
+
+	}
+
+	purple_prpl_got_user_status(session->account, username, purple_primitive_get_id_from_type(purple_status_code), NULL);
+
+	if (status_code == MSIM_STATUS_CODE_IDLE) {
+		purple_debug_info("msim", "msim_status: got idle: %s\n", username);
+		purple_prpl_got_user_idle(session->account, username, TRUE, time(NULL));
+	} else {
+		/* All other statuses indicate going back to non-idle. */
+		purple_prpl_got_user_idle(session->account, username, FALSE, time(NULL));
+	}
+
+#ifdef MSIM_SEND_CLIENT_VERSION
+	if (status_code == MSIM_STATUS_CODE_ONLINE) {
+		/* Secretly whisper to unofficial clients our own version as they come online */
+		msim_send_unofficial_client(session, username);
+	}
+#endif
+
+	if (status_code != MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN) {
+		/* Get information when they come online.
+		 * TODO: periodically refresh?
+		 */
+		purple_debug_info("msim_incoming_status", "%s came online, looking up\n", username);
+		msim_lookup_user(session, username, NULL, NULL);
+	}
+
+	g_free(username);
+	msim_msg_list_free(list);
+
+	return TRUE;
+}
+
+/**
+ * Handle an incoming instant message.
+ *
+ * @param session The session
+ * @param msg Message from the server, containing 'f' (userid from) and 'msg'.
+ *               Should also contain username in _username from preprocessing.
+ *
+ * @return TRUE if successful.
+ */
+static gboolean
+msim_incoming_im(MsimSession *session, MsimMessage *msg)
+{
+	gchar *username, *msg_msim_markup, *msg_purple_markup;
+	gchar *userid;
+	time_t time_received;
+	PurpleConversation *conv;
+
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+	g_return_val_if_fail(msg != NULL, FALSE);
+
+	username = msim_msg_get_string(msg, "_username");
+	/* I know this isn't really a string... but we need it to be one for
+	 * purple_find_conversation_with_account(). */
+	userid = msim_msg_get_string(msg, "f");
+	g_return_val_if_fail(username != NULL, FALSE);
+
+	purple_debug_info("msim_incoming_im", "UserID is %s", userid);
+
+	if (msim_is_userid(username)) {
+		purple_debug_info("msim", "Ignoring message from spambot (%s) on account %s\n",
+				username, purple_account_get_username(session->account));
+		g_free(username);
+		return FALSE;
+	}
+
+	/* See if a conversation with their UID already exists...*/
+	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, userid, session->account);
+	if (conv) {
+		/* Since the conversation exists... We need to normalize it */
+		purple_conversation_set_name(conv, username);
+	}
+
+	msg_msim_markup = msim_msg_get_string(msg, "msg");
+	g_return_val_if_fail(msg_msim_markup != NULL, FALSE);
+
+	msg_purple_markup = msim_markup_to_html(session, msg_msim_markup);
+	g_free(msg_msim_markup);
+
+	time_received = msim_msg_get_integer(msg, "date");
+	if (!time_received) {
+		purple_debug_info("msim_incoming_im", "date in message not set.\n");
+		time_received = time(NULL);
+	}
+
+	serv_got_im(session->gc, username, msg_purple_markup, PURPLE_MESSAGE_RECV, time_received);
+
+	g_free(username);
+	g_free(msg_purple_markup);
+
+	return TRUE;
+}
+
+/**
+ * Handle an incoming action message.
+ *
+ * @param session
+ * @param msg
+ *
+ * @return TRUE if successful.
+ */
+static gboolean
+msim_incoming_action(MsimSession *session, MsimMessage *msg)
+{
+	gchar *msg_text, *username;
+	gboolean rc;
+
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+	g_return_val_if_fail(msg != NULL, FALSE);
+
+	msg_text = msim_msg_get_string(msg, "msg");
+	g_return_val_if_fail(msg_text != NULL, FALSE);
+
+	username = msim_msg_get_string(msg, "_username");
+	g_return_val_if_fail(username != NULL, FALSE);
+
+	purple_debug_info("msim", "msim_incoming_action: action <%s> from <%s>\n",
+			msg_text, username);
+
+	if (g_str_equal(msg_text, "%typing%")) {
+		serv_got_typing(session->gc, username, 0, PURPLE_TYPING);
+		rc = TRUE;
+	} else if (g_str_equal(msg_text, "%stoptyping%")) {
+		serv_got_typing_stopped(session->gc, username);
+		rc = TRUE;
+	} else if (strstr(msg_text, "!!!ZAP_SEND!!!=RTE_BTN_ZAPS_")) {
+		rc = msim_incoming_zap(session, msg);
+	} else if (strstr(msg_text, "!!!GroupCount=")) {
+		/* TODO: support group chats. I think the number in msg_text has
+		 * something to do with the 'gid' field. */
+		purple_debug_info("msim", "msim_incoming_action: TODO: implement #4691, group chats: %s\n", msg_text);
+
+		rc = TRUE;
+	} else if (strstr(msg_text, "!!!Offline=")) {
+		/* TODO: support group chats. This one might mean a user
+		 * went offline or exited the chat. */
+		purple_debug_info("msim", "msim_incoming_action: TODO: implement #4691, group chats: %s\n", msg_text);
+
+		rc = TRUE;
+	} else if (msim_msg_get_integer(msg, "aid") != 0) {
+		purple_debug_info("msim", "TODO: implement #4691, group chat from %d on %d: %s\n",
+				msim_msg_get_integer(msg, "aid"),
+				msim_msg_get_integer(msg, "f"),
+				msg_text);
+
+		rc = TRUE;
+	} else {
+		msim_unrecognized(session, msg,
+				"got to msim_incoming_action but unrecognized value for 'msg'");
+		rc = FALSE;
+	}
+
+	g_free(msg_text);
+	g_free(username);
+
+	return rc;
+}
+
+/**
+ * Process an incoming media (message background?) message.
+ */
+static gboolean
+msim_incoming_media(MsimSession *session, MsimMessage *msg)
+{
+	gchar *username, *text;
+
+	username = msim_msg_get_string(msg, "_username");
+	text = msim_msg_get_string(msg, "msg");
+
+	g_return_val_if_fail(username != NULL, FALSE);
+	g_return_val_if_fail(text != NULL, FALSE);
+
+	purple_debug_info("msim", "msim_incoming_media: from %s, got msg=%s\n", username, text);
+
+	/* Media messages are sent when the user opens a window to someone.
+	 * Tell libpurple they started typing and stopped typing, to inform the Psychic
+	 * Mode plugin so it too can open a window to the user. */
+	serv_got_typing(session->gc, username, 0, PURPLE_TYPING);
+	serv_got_typing_stopped(session->gc, username);
+
+	g_free(username);
+
+	return TRUE;
+}
+
+/**
+ * Process an incoming "unofficial client" message. The plugin for
+ * Miranda IM sends this message with the plugin information.
+ */
+static gboolean
+msim_incoming_unofficial_client(MsimSession *session, MsimMessage *msg)
+{
+	MsimUser *user;
+	gchar *username, *client_info;
+
+	username = msim_msg_get_string(msg, "_username");
+	client_info = msim_msg_get_string(msg, "msg");
+
+	g_return_val_if_fail(username != NULL, FALSE);
+	g_return_val_if_fail(client_info != NULL, FALSE);
+
+	purple_debug_info("msim", "msim_incoming_unofficial_client: %s is using client %s\n",
+		username, client_info);
+
+	user = msim_find_user(session, username);
+
+	g_return_val_if_fail(user != NULL, FALSE);
+
+	if (user->client_info) {
+		g_free(user->client_info);
+	}
+	user->client_info = client_info;
+
+	g_free(username);
+	/* Do not free client_info - the MsimUser now owns it. */
+
+	return TRUE;
+}
+
+/**
+ * Handle an incoming buddy message.
+ */
+static gboolean
+msim_incoming_bm(MsimSession *session, MsimMessage *msg)
+{
+	guint bm;
+
+	bm = msim_msg_get_integer(msg, "bm");
+
+	msim_incoming_bm_record_cv(session, msg);
+
+	switch (bm) {
+		case MSIM_BM_STATUS:
+			return msim_incoming_status(session, msg);
+		case MSIM_BM_INSTANT:
+			return msim_incoming_im(session, msg);
+		case MSIM_BM_ACTION:
+			return msim_incoming_action(session, msg);
+		case MSIM_BM_MEDIA:
+			return msim_incoming_media(session, msg);
+		case MSIM_BM_UNOFFICIAL_CLIENT:
+			return msim_incoming_unofficial_client(session, msg);
+		default:
+			/* Not really an IM, but show it for informational
+			 * purposes during development. */
+			return msim_incoming_im(session, msg);
+	}
+}
+
+/**
+ * Process the initial server information from the server.
+ */
+static gboolean
+msim_process_server_info(MsimSession *session, MsimMessage *msg)
+{
+	MsimMessage *body;
+
+	body = msim_msg_get_dictionary(msg, "body");
+	g_return_val_if_fail(body != NULL, FALSE);
+
+	/* Example body:
+AdUnitRefreshInterval=10.
+AlertPollInterval=360.
+AllowChatRoomEmoticonSharing=False.
+ChatRoomUserIDs=78744676;163733130;1300326231;123521495;142663391.
+CurClientVersion=673.
+EnableIMBrowse=True.
+EnableIMStuffAvatars=False.
+EnableIMStuffZaps=False.
+MaxAddAllFriends=100.
+MaxContacts=1000.
+MinClientVersion=594.
+MySpaceIM_ENGLISH=78744676.
+MySpaceNowTimer=720.
+PersistenceDataTimeout=900.
+UseWebChallenge=1.
+WebTicketGoHome=False
+
+	Anything useful? TODO: use what is useful, and use it.
+*/
+	purple_debug_info("msim_process_server_info",
+			"maximum contacts: %d\n",
+			msim_msg_get_integer(body, "MaxContacts"));
+
+	session->server_info = body;
+	/* session->server_info freed in msim_session_destroy */
+
+	return TRUE;
+}
+
+/**
+ * Process a web challenge, used to login to the web site.
+ */
+static gboolean
+msim_web_challenge(MsimSession *session, MsimMessage *msg)
+{
+	/* TODO: web challenge, store token. #2659. */
+	return FALSE;
+}
+
+/**
+ * Process a persistance message reply from the server.
+ *
+ * @param session
+ * @param msg Message reply from server.
+ *
+ * @return TRUE if successful.
+ *
+ * msim_lookup_user sets callback for here
+ */
+static gboolean
+msim_process_reply(MsimSession *session, MsimMessage *msg)
+{
+	MSIM_USER_LOOKUP_CB cb;
+	gpointer data;
+	guint rid, cmd, dsn, lid;
+
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+	g_return_val_if_fail(msg != NULL, FALSE);
+
+	msim_store_user_info(session, msg, NULL);
+
+	rid = msim_msg_get_integer(msg, "rid");
+	cmd = msim_msg_get_integer(msg, "cmd");
+	dsn = msim_msg_get_integer(msg, "dsn");
+	lid = msim_msg_get_integer(msg, "lid");
+
+	/* Unsolicited messages */
+	if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_GET)) {
+		if (dsn == MG_SERVER_INFO_DSN && lid == MG_SERVER_INFO_LID) {
+			return msim_process_server_info(session, msg);
+		} else if (dsn == MG_WEB_CHALLENGE_DSN && lid == MG_WEB_CHALLENGE_LID) {
+			return msim_web_challenge(session, msg);
+		}
+	}
+
+	/* If a callback is registered for this userid lookup, call it. */
+	cb = g_hash_table_lookup(session->user_lookup_cb, GUINT_TO_POINTER(rid));
+	data = g_hash_table_lookup(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
+
+	if (cb) {
+		purple_debug_info("msim", "msim_process_reply: calling callback now\n");
+		msim_msg_dump("for msg=%s\n", msg);
+		/* Clone message, so that the callback 'cb' can use it (needs to free it also). */
+		cb(session, msim_msg_clone(msg), data);
+		g_hash_table_remove(session->user_lookup_cb, GUINT_TO_POINTER(rid));
+		g_hash_table_remove(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
+	} else {
+		purple_debug_info("msim",
+				"msim_process_reply: no callback for rid %d\n", rid);
+	}
+
+	return TRUE;
+}
+
+/**
+ * Handle an error from the server.
+ *
+ * @param session
+ * @param msg The message.
+ *
+ * @return TRUE if successfully reported error.
+ */
+static gboolean
+msim_error(MsimSession *session, MsimMessage *msg)
+{
+	gchar *errmsg, *full_errmsg;
+	guint err;
+
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+	g_return_val_if_fail(msg != NULL, FALSE);
+
+	err = msim_msg_get_integer(msg, "err");
+	errmsg = msim_msg_get_string(msg, "errmsg");
+
+	full_errmsg = g_strdup_printf(_("Protocol error, code %d: %s"), err,
+			errmsg ? errmsg : "no 'errmsg' given");
+
+	g_free(errmsg);
+
+	purple_debug_info("msim", "msim_error (sesskey=%d): %s\n",
+			session->sesskey, full_errmsg);
+
+	/* Destroy session if fatal. */
+	if (msim_msg_get(msg, "fatal")) {
+		PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
+		purple_debug_info("msim", "fatal error, closing\n");
+
+		switch (err) {
+			case MSIM_ERROR_INCORRECT_PASSWORD: /* Incorrect password */
+				reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+				if (!purple_account_get_remember_password(session->account))
+					purple_account_set_password(session->account, NULL);
+#ifdef MSIM_MAX_PASSWORD_LENGTH
+				if (session->account->password && (strlen(session->account->password) > MSIM_MAX_PASSWORD_LENGTH)) {
+					gchar *suggestion;
+
+					suggestion = g_strdup_printf(_("%s Your password is "
+							"%d characters, greater than the "
+							"expected maximum length of %d for "
+							"MySpaceIM. Please shorten your "
+							"password at http://profileedit.myspace.com/index.cfm?fuseaction=accountSettings.changePassword and try again."),
+							full_errmsg, (int)
+							strlen(session->account->password),
+							MSIM_MAX_PASSWORD_LENGTH);
+
+					/* Replace full_errmsg. */
+					g_free(full_errmsg);
+					full_errmsg = suggestion;
+				}
+#endif
+				break;
+			case MSIM_ERROR_LOGGED_IN_ELSEWHERE: /* Logged in elsewhere */
+				reason = PURPLE_CONNECTION_ERROR_NAME_IN_USE;
+				if (!purple_account_get_remember_password(session->account))
+					purple_account_set_password(session->account, NULL);
+				break;
+		}
+		purple_connection_error_reason (session->gc, reason, full_errmsg);
+	} else {
+		purple_notify_error(session->account, _("MySpaceIM Error"), full_errmsg, NULL);
+	}
+
+	g_free(full_errmsg);
+
+	return TRUE;
+}
+
+/**
+ * Process a message.
+ *
+ * @param session
+ * @param msg A message from the server, ready for processing (possibly with resolved username information attached). Caller frees.
+ *
+ * @return TRUE if successful. FALSE if processing failed.
+ */
+static gboolean
+msim_process(MsimSession *session, MsimMessage *msg)
+{
+	g_return_val_if_fail(session != NULL, FALSE);
+	g_return_val_if_fail(msg != NULL, FALSE);
+
+#ifdef MSIM_DEBUG_MSG
+	msim_msg_dump("ready to process: %s\n", msg);
+#endif
+
+	if (msim_msg_get_integer(msg, "lc") == 1) {
+		return msim_login_challenge(session, msg);
+	} else if (msim_msg_get_integer(msg, "lc") == 2) {
+		/* return msim_we_are_logged_on(session, msg); */
+		if (msim_is_username_set(session, msg)) {
+			return msim_we_are_logged_on(session);
+		} else {
+			/* No username is set... We'll wait for the callbacks to do their work */
+			/* When they're all done, the last one will call msim_we_are_logged_on() and pick up where we left off */
+			return FALSE;
+		}
+	} else if (msim_msg_get(msg, "bm"))  {
+		return msim_incoming_bm(session, msg);
+	} else if (msim_msg_get(msg, "rid")) {
+		return msim_process_reply(session, msg);
+	} else if (msim_msg_get(msg, "error")) {
+		return msim_error(session, msg);
+	} else if (msim_msg_get(msg, "ka")) {
+		return TRUE;
+	} else {
+		msim_unrecognized(session, msg, "in msim_process");
+		return FALSE;
+	}
+}
+
+/**
+ * After a uid is resolved to username, tag it with the username and submit for processing.
+ *
+ * @param session
+ * @param userinfo Response messsage to resolving request.
+ * @param data MsimMessage *, the message to attach information to.
+ */
+static void
+msim_incoming_resolved(MsimSession *session, MsimMessage *userinfo,
+		gpointer data)
+{
+	gchar *username;
+	MsimMessage *msg, *body;
+
+	g_return_if_fail(MSIM_SESSION_VALID(session));
+	g_return_if_fail(userinfo != NULL);
+
+	body = msim_msg_get_dictionary(userinfo, "body");
 	g_return_if_fail(body != NULL);
+
+	username = msim_msg_get_string(body, "UserName");
+	g_return_if_fail(username != NULL);
+	/* Note: username will be owned by 'msg' below. */
+
+	msg = (MsimMessage *)data;
+	g_return_if_fail(msg != NULL);
+
+	/* TODO: more elegant solution than below. attach whole message? */
+	/* Special elements name beginning with '_', we'll use internally within the
+	 * program (did not come directly from the wire). */
+	msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, username); /* This makes 'msg' the owner of 'username' */
+
+	/* TODO: attach more useful information, like ImageURL */
+
+	msim_process(session, msg);
+
+	/* TODO: Free copy cloned from  msim_preprocess_incoming(). */
+	/* msim_msg_free(msg); */
 	msim_msg_free(body);
-	if (!g_str_equal(completed, "True"))
-	{
-		purple_debug_info("msim_import_friends_cb",
-				"failed to import friends: %s", completed);
-		purple_notify_error(session->account, _("Add friends from MySpace.com"),
-				_("Importing friends failed"), NULL);
-		g_free(completed);
+}
+
+/**
+ * Preprocess incoming messages, resolving as needed, calling
+ * msim_process() when ready to process.
+ *
+ * @param session
+ * @param msg MsimMessage *, freed by caller.
+ */
+static gboolean
+msim_preprocess_incoming(MsimSession *session, MsimMessage *msg)
+{
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+	g_return_val_if_fail(msg != NULL, FALSE);
+
+	if (msim_msg_get(msg, "bm") && msim_msg_get(msg, "f")) {
+		guint uid;
+		const gchar *username;
+
+		/* 'f' = userid message is from, in buddy messages */
+		uid = msim_msg_get_integer(msg, "f");
+
+		username = msim_uid2username_from_blist(session->account, uid);
+
+		if (username) {
+			/* Know username already, use it. */
+			purple_debug_info("msim", "msim_preprocess_incoming: tagging with _username=%s\n",
+					username);
+			msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, g_strdup(username));
+			return msim_process(session, msg);
+
+		} else {
+			gchar *from;
+
+			/* Send lookup request. */
+			/* XXX: where is msim_msg_get_string() freed? make _strdup and _nonstrdup. */
+			purple_debug_info("msim", "msim_incoming: sending lookup, setting up callback\n");
+			from = msim_msg_get_string(msg, "f");
+			msim_lookup_user(session, from, msim_incoming_resolved, msim_msg_clone(msg));
+			g_free(from);
+
+			/* indeterminate */
+			return TRUE;
+		}
+	} else {
+		/* Nothing to resolve - send directly to processing. */
+		return msim_process(session, msg);
+	}
+}
+
+/**
+ * Callback when input available.
+ *
+ * @param gc_uncasted A PurpleConnection pointer.
+ * @param source File descriptor.
+ * @param cond PURPLE_INPUT_READ
+ *
+ * Reads the input, and calls msim_preprocess_incoming() to handle it.
+ */
+static void
+msim_input_cb(gpointer gc_uncasted, gint source, PurpleInputCondition cond)
+{
+	PurpleConnection *gc;
+	PurpleAccount *account;
+	MsimSession *session;
+	gchar *end;
+	int n;
+
+	g_return_if_fail(gc_uncasted != NULL);
+	g_return_if_fail(source >= 0);  /* Note: 0 is a valid fd */
+
+	gc = (PurpleConnection *)(gc_uncasted);
+	account = purple_connection_get_account(gc);
+	session = gc->proto_data;
+
+	/* libpurple/eventloop.h only defines these two */
+	if (cond != PURPLE_INPUT_READ && cond != PURPLE_INPUT_WRITE) {
+		purple_debug_info("msim_input_cb", "unknown condition=%d\n", cond);
+		purple_connection_error_reason (gc,
+			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+			_("Invalid input condition"));
 		return;
 	}
-	g_free(completed);
-
-	purple_debug_info("msim_import_friends_cb",
-			"added friends to server-side buddy list, requesting new contacts from server");
-
-	msim_get_contact_list(session, MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS);
-
-	/* TODO: show, X friends have been added */
+
+	g_return_if_fail(cond == PURPLE_INPUT_READ);
+	g_return_if_fail(MSIM_SESSION_VALID(session));
+
+	/* Mark down that we got data, so we don't timeout. */
+	session->last_comm = time(NULL);
+
+	/* If approaching end of buffer, reallocate some more memory. */
+	if (session->rxsize < session->rxoff + MSIM_READ_BUF_SIZE) {
+		purple_debug_info("msim",
+			"msim_input_cb: %d-byte read buffer full, rxoff=%d, " "growing by %d bytes\n",
+			session->rxsize, session->rxoff, MSIM_READ_BUF_SIZE);
+			session->rxsize += MSIM_READ_BUF_SIZE;
+			session->rxbuf = g_realloc(session->rxbuf, session->rxsize);
+
+		return;
+	}
+
+	purple_debug_info("msim", "dynamic buffer at %d (max %d), reading up to %d\n",
+			session->rxoff, session->rxsize,
+			MSIM_READ_BUF_SIZE - session->rxoff - 1);
+
+	/* Read into buffer. On Win32, need recv() not read(). session->fd also holds
+	 * the file descriptor, but it sometimes differs from the 'source' parameter.
+	 */
+	n = recv(session->fd,
+		 session->rxbuf + session->rxoff,
+		 session->rxsize - session->rxoff - 1, 0);
+
+	if (n < 0 && errno == EAGAIN) {
+		return;
+	} else if (n < 0) {
+		purple_debug_error("msim", "msim_input_cb: read error, ret=%d, "
+			"error=%s, source=%d, fd=%d (%X))\n",
+			n, g_strerror(errno), source, session->fd, session->fd);
+		purple_connection_error_reason (gc,
+			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+			_("Read error"));
+		return;
+	} else if (n == 0) {
+		purple_debug_info("msim", "msim_input_cb: server disconnected\n");
+		purple_connection_error_reason (gc,
+			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+			_("Server has disconnected"));
+		return;
+	}
+
+	if (n + session->rxoff > session->rxsize) {
+		purple_debug_info("msim_input_cb", "received %d bytes, pushing rxoff to %d, over buffer size of %d\n",
+				n, n + session->rxoff, session->rxsize);
+		purple_connection_error_reason (gc,
+			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+			_("Read buffer full (2)"));
+		return;
+	}
+
+	/* Null terminate */
+	purple_debug_info("msim", "msim_input_cb: going to null terminate "
+			"at n=%d\n", n);
+	session->rxbuf[session->rxoff + n] = 0;
+
+#ifdef MSIM_CHECK_EMBEDDED_NULLS
+	/* Check for embedded NULs. I don't handle them, and they shouldn't occur. */
+	if (strlen(session->rxbuf + session->rxoff) != n) {
+		/* Occurs after login, but it is not a null byte. */
+		purple_debug_info("msim", "msim_input_cb: strlen=%d, but read %d bytes"
+				"--null byte encountered?\n",
+				strlen(session->rxbuf + session->rxoff), n);
+		/*purple_connection_error_reason (gc,
+				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+				"Invalid message - null byte on input"); */
+		return;
+	}
+#endif
+
+	session->rxoff += n;
+	purple_debug_info("msim", "msim_input_cb: read=%d\n", n);
+
+#ifdef MSIM_DEBUG_RXBUF
+	purple_debug_info("msim", "buf=<%s>\n", session->rxbuf);
+#endif
+
+	/* Look for \\final\\ end markers. If found, process message. */
+	while((end = strstr(session->rxbuf, MSIM_FINAL_STRING))) {
+		MsimMessage *msg;
+
+#ifdef MSIM_DEBUG_RXBUF
+		purple_debug_info("msim", "in loop: buf=<%s>\n", session->rxbuf);
+#endif
+		*end = 0;
+		msg = msim_parse(session->rxbuf);
+		if (!msg) {
+			purple_debug_info("msim", "msim_input_cb: couldn't parse rxbuf\n");
+			purple_connection_error_reason (gc,
+				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+				_("Unparseable message"));
+			break;
+		} else {
+			/* Process message and then free it (processing function should
+			 * clone message if it wants to keep it afterwards.) */
+			if (!msim_preprocess_incoming(session, msg)) {
+				msim_msg_dump("msim_input_cb: preprocessing message failed on msg: %s\n", msg);
+			}
+			msim_msg_free(msg);
+		}
+
+		/* Move remaining part of buffer to beginning. */
+		session->rxoff -= strlen(session->rxbuf) + strlen(MSIM_FINAL_STRING);
+		memmove(session->rxbuf, end + strlen(MSIM_FINAL_STRING),
+				session->rxsize - (end + strlen(MSIM_FINAL_STRING) - session->rxbuf));
+
+		/* Clear end of buffer
+		 * memset(end, 0, MSIM_READ_BUF_SIZE - (end - session->rxbuf));
+		 */
+	}
 }
 
-/** Import friends from myspace.com. */
-static void msim_import_friends(PurplePluginAction *action)
+/**
+ * Callback when connected. Sets up input handlers.
+ *
+ * @param data A PurpleConnection pointer.
+ * @param source File descriptor.
+ * @param error_message
+ */
+static void
+msim_connect_cb(gpointer data, gint source, const gchar *error_message)
 {
 	PurpleConnection *gc;
 	MsimSession *session;
-	gchar *group_name;
-
-	gc = (PurpleConnection *)action->context;
+
+	g_return_if_fail(data != NULL);
+
+	gc = (PurpleConnection *)data;
+	session = (MsimSession *)gc->proto_data;
+
+	if (source < 0) {
+		purple_connection_error_reason (gc,
+			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+			g_strdup_printf(_("Couldn't connect to host: %s (%d)"),
+					error_message ? error_message : "no message given",
+					source));
+		return;
+	}
+
+	session->fd = source;
+
+	gc->inpa = purple_input_add(source, PURPLE_INPUT_READ, msim_input_cb, gc);
+}
+
+/**
+ * Start logging in to the MSIM servers.
+ *
+ * @param acct Account information to use to login.
+ */
+static void
+msim_login(PurpleAccount *acct)
+{
+	PurpleConnection *gc;
+	const gchar *host;
+	int port;
+
+	g_return_if_fail(acct != NULL);
+	g_return_if_fail(acct->username != NULL);
+
+	purple_debug_info("msim", "logging in %s\n", acct->username);
+
+	gc = purple_account_get_connection(acct);
+	gc->proto_data = msim_session_new(acct);
+	gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_URLDESC;
+
+	/* 1. connect to server */
+	purple_connection_update_progress(gc, _("Connecting"),
+								  0,   /* which connection step this is */
+								  4);  /* total number of steps */
+
+	host = purple_account_get_string(acct, "server", MSIM_SERVER);
+	port = purple_account_get_int(acct, "port", MSIM_PORT);
+
+	/* From purple.sf.net/api:
+	 * """Note that this function name can be misleading--although it is called
+	 * "proxy connect," it is used for establishing any outgoing TCP connection,
+	 * whether through a proxy or not.""" */
+
+	/* Calls msim_connect_cb when connected. */
+	if (!purple_proxy_connect(gc, acct, host, port, msim_connect_cb, gc)) {
+		/* TODO: try other ports if in auto mode, then save
+		 * working port and try that first next time. */
+		purple_connection_error_reason (gc,
+			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+			_("Couldn't create socket"));
+		return;
+	}
+}
+
+/**
+ * Close the connection.
+ *
+ * @param gc The connection.
+ */
+static void
+msim_close(PurpleConnection *gc)
+{
+	MsimSession *session;
+
+	if (gc == NULL) {
+		return;
+	}
+
+	session = (MsimSession *)gc->proto_data;
+	if (session == NULL)
+		return;
+
+	gc->proto_data = NULL;
+
+	if (!MSIM_SESSION_VALID(session)) {
+		return;
+	}
+
+	if (session->gc->inpa) {
+		purple_input_remove(session->gc->inpa);
+	}
+
+	msim_session_destroy(session);
+}
+
+/**
+ * Schedule an IM to be sent once the user ID is looked up.
+ *
+ * @param gc Connection.
+ * @param who A user id, email, or username to send the message to.
+ * @param message Instant message text to send.
+ * @param flags Flags.
+ *
+ * @return 1 if successful or postponed, -1 if failed
+ *
+ * Allows sending to a user by username, email address, or userid. If
+ * a username or email address is given, the userid must be looked up.
+ * This function does that by calling msim_postprocess_outgoing().
+ */
+static int
+msim_send_im(PurpleConnection *gc, const gchar *who, const gchar *message,
+		PurpleMessageFlags flags)
+{
+	MsimSession *session;
+	gchar *message_msim;
+	int rc;
+
+	g_return_val_if_fail(gc != NULL, -1);
+	g_return_val_if_fail(who != NULL, -1);
+	g_return_val_if_fail(message != NULL, -1);
+
+	/* 'flags' has many options, not used here. */
+
+	session = (MsimSession *)gc->proto_data;
+
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), -1);
+
+	message_msim = html_to_msim_markup(session, message);
+
+	if (msim_send_bm(session, who, message_msim, MSIM_BM_INSTANT)) {
+		/* Return 1 to have Purple show this IM as being sent, 0 to not. I always
+		 * return 1 even if the message could not be sent, since I don't know if
+		 * it has failed yet--because the IM is only sent after the userid is
+		 * retrieved from the server (which happens after this function returns).
+		 * If an error does occur, it should be logged to the IM window.
+		 */
+		rc = 1;
+	} else {
+		rc = -1;
+	}
+
+	g_free(message_msim);
+
+	return rc;
+}
+
+/**
+ * Handle when our user starts or stops typing to another user.
+ *
+ * @param gc
+ * @param name The buddy name to which our user is typing to
+ * @param state PURPLE_TYPING, PURPLE_TYPED, PURPLE_NOT_TYPING
+ *
+ * @return 0
+ */
+static unsigned int
+msim_send_typing(PurpleConnection *gc, const gchar *name,
+		PurpleTypingState state)
+{
+	const gchar *typing_str;
+	MsimSession *session;
+
+	g_return_val_if_fail(gc != NULL, 0);
+	g_return_val_if_fail(name != NULL, 0);
+
 	session = (MsimSession *)gc->proto_data;
 
-	group_name = "MySpace Friends";
-
-	g_return_if_fail(msim_send(session, 
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), 0);
+
+	switch (state) {
+		case PURPLE_TYPING:
+			typing_str = "%typing%";
+			break;
+
+		case PURPLE_TYPED:
+		case PURPLE_NOT_TYPING:
+		default:
+			typing_str = "%stoptyping%";
+			break;
+	}
+
+	purple_debug_info("msim", "msim_send_typing(%s): %d (%s)\n", name, state, typing_str);
+	msim_send_bm(session, name, typing_str, MSIM_BM_ACTION);
+	return 0;
+}
+
+/**
+ * Callback for msim_get_info(), for when user info is received.
+ */
+static void
+msim_get_info_cb(MsimSession *session, MsimMessage *user_info_msg,
+		gpointer data)
+{
+	MsimMessage *msg;
+	gchar *username;
+	PurpleNotifyUserInfo *user_info;
+	MsimUser *user;
+
+	g_return_if_fail(MSIM_SESSION_VALID(session));
+
+	/* Get user{name,id} from msim_get_info, passed as an MsimMessage for
+	   orthogonality. */
+	msg = (MsimMessage *)data;
+	g_return_if_fail(msg != NULL);
+
+	username = msim_msg_get_string(msg, "user");
+	if (!username) {
+		purple_debug_info("msim", "msim_get_info_cb: no 'user' in msg\n");
+		return;
+	}
+
+	msim_msg_free(msg);
+	purple_debug_info("msim", "msim_get_info_cb: got for user: %s\n", username);
+
+	user = msim_find_user(session, username);
+
+	if (!user) {
+		/* User isn't on blist, create a temporary user to store info. */
+		user = g_new0(MsimUser, 1);
+		user->temporary_user = TRUE;
+	}
+
+	/* Update user structure with new information */
+	msim_store_user_info(session, user_info_msg, user);
+
+	user_info = purple_notify_user_info_new();
+
+	/* Append data from MsimUser to PurpleNotifyUserInfo for display, full */
+	msim_append_user_info(session, user_info, user, TRUE);
+
+	purple_notify_userinfo(session->gc, username, user_info, NULL, NULL);
+	purple_debug_info("msim", "msim_get_info_cb: username=%s\n", username);
+
+	purple_notify_user_info_destroy(user_info);
+
+	if (user->temporary_user) {
+		g_free(user->client_info);
+		g_free(user->gender);
+		g_free(user->location);
+		g_free(user->headline);
+		g_free(user->display_name);
+		g_free(user->username);
+		g_free(user->image_url);
+		g_free(user);
+	}
+	g_free(username);
+}
+
+/**
+ * Retrieve a user's profile.
+ * @param username Username, user ID, or email address to lookup.
+ */
+static void
+msim_get_info(PurpleConnection *gc, const gchar *username)
+{
+	MsimSession *session;
+	MsimUser *user;
+	gchar *user_to_lookup;
+	MsimMessage *user_msg;
+
+	g_return_if_fail(gc != NULL);
+	g_return_if_fail(username != NULL);
+
+	session = (MsimSession *)gc->proto_data;
+
+	g_return_if_fail(MSIM_SESSION_VALID(session));
+
+	/* Obtain uid of buddy. */
+	user = msim_find_user(session, username);
+
+	/* If is on buddy list, lookup by uid since it is faster. */
+	if (user && user->id) {
+		user_to_lookup = g_strdup_printf("%d", user->id);
+	} else {
+		/* Looking up buddy not on blist. Lookup by whatever user entered. */
+		user_to_lookup = g_strdup(username);
+	}
+
+	/* Pass the username to msim_get_info_cb(), because since we lookup
+	 * by userid, the userinfo message will only contain the uid (not
+	 * the username) but it would be useful to display the username too.
+	 */
+	user_msg = msim_msg_new(
+			"user", MSIM_TYPE_STRING, g_strdup(username),
+			NULL);
+	purple_debug_info("msim", "msim_get_info, setting up lookup, user=%s\n", username);
+
+	msim_lookup_user(session, user_to_lookup, msim_get_info_cb, user_msg);
+
+	g_free(user_to_lookup);
+}
+
+/**
+ * Set status using an MSIM_STATUS_CODE_* value.
+ * @param status_code An MSIM_STATUS_CODE_* value.
+ * @param statstring Status string, must be a dynamic string (will be freed by msim_send).
+ */
+static void
+msim_set_status_code(MsimSession *session, guint status_code, gchar *statstring)
+{
+	g_return_if_fail(MSIM_SESSION_VALID(session));
+	g_return_if_fail(statstring != NULL);
+
+	purple_debug_info("msim", "msim_set_status_code: going to set status to code=%d,str=%s\n",
+			status_code, statstring);
+
+	if (!msim_send(session,
+			"status", MSIM_TYPE_INTEGER, status_code,
+			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+			"statstring", MSIM_TYPE_STRING, statstring,
+			"locstring", MSIM_TYPE_STRING, g_strdup(""),
+			NULL))
+	{
+		purple_debug_info("msim", "msim_set_status: failed to set status\n");
+	}
+}
+
+/**
+ * Set your status - callback for when user manually sets it.
+ */
+static void
+msim_set_status(PurpleAccount *account, PurpleStatus *status)
+{
+	PurpleStatusType *type;
+	PurplePresence *pres;
+	MsimSession *session;
+	guint status_code;
+	const gchar *message;
+	gchar *stripped;
+	gchar *unrecognized_msg;
+
+	session = (MsimSession *)account->gc->proto_data;
+
+	g_return_if_fail(MSIM_SESSION_VALID(session));
+
+	type = purple_status_get_type(status);
+	pres = purple_status_get_presence(status);
+
+	switch (purple_status_type_get_primitive(type)) {
+		case PURPLE_STATUS_AVAILABLE:
+			purple_debug_info("msim", "msim_set_status: available (%d->%d)\n", PURPLE_STATUS_AVAILABLE,
+					MSIM_STATUS_CODE_ONLINE);
+			status_code = MSIM_STATUS_CODE_ONLINE;
+			break;
+
+		case PURPLE_STATUS_INVISIBLE:
+			purple_debug_info("msim", "msim_set_status: invisible (%d->%d)\n", PURPLE_STATUS_INVISIBLE,
+					MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN);
+			status_code = MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN;
+			break;
+
+		case PURPLE_STATUS_AWAY:
+			purple_debug_info("msim", "msim_set_status: away (%d->%d)\n", PURPLE_STATUS_AWAY,
+					MSIM_STATUS_CODE_AWAY);
+			status_code = MSIM_STATUS_CODE_AWAY;
+			break;
+
+		default:
+			purple_debug_info("msim", "msim_set_status: unknown "
+					"status interpreting as online");
+			status_code = MSIM_STATUS_CODE_ONLINE;
+
+			unrecognized_msg = g_strdup_printf("msim_set_status, unrecognized status type: %d\n",
+					purple_status_type_get_primitive(type));
+			msim_unrecognized(session, NULL, unrecognized_msg);
+			g_free(unrecognized_msg);
+
+			break;
+	}
+
+	message = purple_status_get_attr_string(status, "message");
+
+	/* Status strings are plain text. */
+	if (message != NULL)
+		stripped = purple_markup_strip_html(message);
+	else
+		stripped = g_strdup("");
+
+	msim_set_status_code(session, status_code, stripped);
+
+	/* If we should be idle, set that status. Time is irrelevant here. */
+	if (purple_presence_is_idle(pres) && status_code != MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN)
+		msim_set_idle(account->gc, 1);
+}
+
+/**
+ * Go idle.
+ */
+static void
+msim_set_idle(PurpleConnection *gc, int time)
+{
+	MsimSession *session;
+	PurpleStatus *status;
+
+	g_return_if_fail(gc != NULL);
+
+	session = (MsimSession *)gc->proto_data;
+
+	g_return_if_fail(MSIM_SESSION_VALID(session));
+
+	status = purple_account_get_active_status(session->account);
+
+	if (time == 0) {
+		/* Going back from idle. In msim, idle is mutually exclusive
+		 * from the other states (you can only be away or idle, but not
+		 * both, for example), so by going non-idle I go back to what
+		 * libpurple says I should be.
+		 */
+		msim_set_status(session->account, status);
+	} else {
+		const gchar *message;
+		gchar *stripped;
+
+		/* Set the idle message to the status message from the real
+		 * current status.
+		 */
+		message = purple_status_get_attr_string(status, "message");
+		if (message != NULL)
+			stripped = purple_markup_strip_html(message);
+		else
+			stripped = g_strdup("");
+
+		/* msim doesn't support idle time, so just go idle */
+		msim_set_status_code(session, MSIM_STATUS_CODE_IDLE, stripped);
+	}
+}
+
+/**
+ * Add a buddy to user's buddy list.
+ */
+static void
+msim_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
+{
+	MsimSession *session;
+	MsimMessage *msg;
+	MsimMessage *msg_persist;
+	MsimMessage *body;
+
+	session = (MsimSession *)gc->proto_data;
+	purple_debug_info("msim", "msim_add_buddy: want to add %s to %s\n",
+			buddy->name, (group && group->name) ? group->name : "(no group)");
+
+	msg = msim_msg_new(
+			"addbuddy", MSIM_TYPE_BOOLEAN, TRUE,
+			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+			/* "newprofileid" will be inserted here with uid. */
+			"reason", MSIM_TYPE_STRING, g_strdup(""),
+			NULL);
+
+	if (!msim_postprocess_outgoing(session, msg, buddy->name, "newprofileid", "reason")) {
+		purple_notify_error(NULL, NULL, _("Failed to add buddy"), _("'addbuddy' command failed."));
+		msim_msg_free(msg);
+		return;
+	}
+	msim_msg_free(msg);
+
+	/* TODO: if addbuddy fails ('error' message is returned), delete added buddy from
+	 * buddy list since Purple adds it locally. */
+
+	body = msim_msg_new(
+			"ContactID", MSIM_TYPE_STRING, g_strdup("<uid>"),
+			"GroupName", MSIM_TYPE_STRING, g_strdup(group->name),
+			"Position", MSIM_TYPE_INTEGER, 1000,
+			"Visibility", MSIM_TYPE_INTEGER, 1,
+			"NickName", MSIM_TYPE_STRING, g_strdup(""),
+			"NameSelect", MSIM_TYPE_INTEGER, 0,
+			NULL);
+
+	/* TODO: Update blocklist. */
+
+	msg_persist = msim_msg_new(
+		"persist", MSIM_TYPE_INTEGER, 1,
+		"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+		"cmd", MSIM_TYPE_INTEGER, MSIM_CMD_BIT_ACTION | MSIM_CMD_PUT,
+		"dsn", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_DSN,
+		"uid", MSIM_TYPE_INTEGER, session->userid,
+		"lid", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_LID,
+		/* TODO: Use msim_new_reply_callback to get rid. */
+		"rid", MSIM_TYPE_INTEGER, session->next_rid++,
+		"body", MSIM_TYPE_DICTIONARY, body,
+		NULL);
+
+	if (!msim_postprocess_outgoing(session, msg_persist, buddy->name, "body", NULL))
+	{
+		purple_notify_error(NULL, NULL, _("Failed to add buddy"), _("persist command failed"));
+		msim_msg_free(msg_persist);
+		return;
+	}
+	msim_msg_free(msg_persist);
+}
+
+/**
+ * Remove a buddy from the user's buddy list.
+ */
+static void
+msim_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
+{
+	MsimSession *session;
+	MsimMessage *delbuddy_msg;
+	MsimMessage *persist_msg;
+	MsimMessage *blocklist_msg;
+	GList *blocklist_updates;
+
+	session = (MsimSession *)gc->proto_data;
+
+	delbuddy_msg = msim_msg_new(
+				"delbuddy", MSIM_TYPE_BOOLEAN, TRUE,
+				"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+				/* 'delprofileid' with uid will be inserted here. */
+				NULL);
+
+	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(
 			"persist", MSIM_TYPE_INTEGER, 1,
 			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
-			"cmd", MSIM_TYPE_INTEGER, MSIM_CMD_PUT,
-			"dsn", MSIM_TYPE_INTEGER, MC_IMPORT_ALL_FRIENDS_DSN,
-			"lid", MSIM_TYPE_INTEGER, MC_IMPORT_ALL_FRIENDS_LID,
+			"cmd", MSIM_TYPE_INTEGER, MSIM_CMD_BIT_ACTION | MSIM_CMD_DELETE,
+			"dsn", MSIM_TYPE_INTEGER, MD_DELETE_BUDDY_DSN,
+			"lid", MSIM_TYPE_INTEGER, MD_DELETE_BUDDY_LID,
 			"uid", MSIM_TYPE_INTEGER, session->userid,
-			"rid", MSIM_TYPE_INTEGER, 
-				msim_new_reply_callback(session, msim_import_friends_cb, NULL),
-			"body", MSIM_TYPE_STRING,
-				g_strdup_printf("GroupName=%s", group_name),
-			NULL));
-
-
+			"rid", MSIM_TYPE_INTEGER, session->next_rid++,
+			/* <uid> will be replaced by postprocessing */
+			"body", MSIM_TYPE_STRING, g_strdup("ContactID=<uid>"),
+			NULL);
+
+	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_updates = NULL;
+	blocklist_updates = g_list_prepend(blocklist_updates, "a-");
+	blocklist_updates = g_list_prepend(blocklist_updates, "<uid>");
+	blocklist_updates = g_list_prepend(blocklist_updates, "b-");
+	blocklist_updates = g_list_prepend(blocklist_updates, "<uid>");
+	blocklist_updates = g_list_reverse(blocklist_updates);
+
+	blocklist_msg = msim_msg_new(
+			"blocklist", MSIM_TYPE_BOOLEAN, TRUE,
+			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+			/* TODO: MsimMessage lists. Currently <uid> isn't replaced in lists. */
+			/* "idlist", MSIM_TYPE_STRING, g_strdup("a-|<uid>|b-|<uid>"), */
+			"idlist", MSIM_TYPE_LIST, blocklist_updates,
+			NULL);
+
+	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);
 }
 
-/** Actions menu for account. */
-GList *
-msim_actions(PurplePlugin *plugin, gpointer context)
+/**
+ * Returns a string of a username in canonical form. Basically removes all the
+ * spaces, lowercases the string, and looks up user IDs to usernames.
+ * Normalizing tom, TOM, Tom, and 6221 wil all return 'tom'.
+ *
+ * Borrowed this code from oscar_normalize. Added checking for
+ * "if userid, get name before normalizing"
+ */
+static const char *msim_normalize(const PurpleAccount *account, const char *str) {
+	static char normalized[BUF_LEN];
+	char *tmp1, *tmp2;
+	int i, j;
+	guint id;
+
+	g_return_val_if_fail(str != NULL, NULL);
+
+	if (msim_is_userid(str)) {
+		/* Have user ID, we need to get their username first :) */
+		const char *username;
+
+		/* If the account does not exist, we can't look up the user. */
+		if (!account || !account->gc)
+			return str;
+
+		id = atol(str);
+		username = msim_uid2username_from_blist((PurpleAccount *)account, id);
+		if (!username) {
+			/* Not in buddy list... scheisse... TODO: Manual Lookup! Bug #4631 */
+			/* Note: manual lookup using msim_lookup_user() is a problem inside
+			 * msim_normalize(), because msim_lookup_user() calls a callback function
+			 * when the user information has been looked up, but msim_normalize() expects
+			 * the result immediately. */
+			strncpy(normalized, str, BUF_LEN);
+		} else {
+			strncpy(normalized, username, BUF_LEN);
+		}
+	} else {
+		/* Have username. */
+		strncpy(normalized, str, BUF_LEN);
+	}
+
+	/* Strip spaces. */
+	for (i=0, j=0; normalized[j]; i++, j++) {
+		while (normalized[j] == ' ')
+			j++;
+		normalized[i] = normalized[j];
+	}
+	normalized[i] = '\0';
+
+	/* Lowercase and perform UTF-8 normalization. */
+	tmp1 = g_utf8_strdown(normalized, -1);
+	tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT);
+	g_snprintf(normalized, sizeof(normalized), "%s", tmp2);
+	g_free(tmp2);
+	g_free(tmp1);
+
+	/* TODO: re-add caps and spacing back to what the user wanted.
+	 * User can format their own names, for example 'msimprpl' is shown
+	 * as 'MsIm PrPl' in the official client.
+	 *
+	 * TODO: file a ticket to add this enhancement.
+	 */
+
+	return normalized;
+}
+
+/**
+ * Return whether the buddy can be messaged while offline.
+ *
+ * The protocol supports offline messages in just the same way as online
+ * messages.
+ */
+static gboolean
+msim_offline_message(const PurpleBuddy *buddy)
 {
-	PurpleConnection *gc;
-	GList *menu;
-	PurplePluginAction *act;
-
-	gc = (PurpleConnection *)context;
-
-	menu = NULL;
-
-#if 0
-	/* TODO: find out how */
-	act = purple_plugin_action_new(_("Find people..."), msim_);
-	menu = g_list_append(menu, act);
-
-	act = purple_plugin_action_new(_("Change IM name..."), NULL);
-	menu = g_list_append(menu, act);
-#endif
-
-	act = purple_plugin_action_new(_("Add friends from MySpace.com"), msim_import_friends);
-	menu = g_list_append(menu, act);
-
-	return menu;
+	return TRUE;
 }
 
-/** Callbacks called by Purple, to access this plugin. */
+/**
+ * Send raw data to the server, possibly with embedded NULs.
+ *
+ * Used in prpl_info struct, so that plugins can have the most possible
+ * control of what is sent over the connection. Inside this prpl,
+ * msim_send_raw() is used, since it sends NUL-terminated strings (easier).
+ *
+ * @param gc PurpleConnection
+ * @param buf Buffer to send
+ * @param total_bytes Size of buffer to send
+ *
+ * @return Bytes successfully sent, or -1 on error.
+ */
+static int
+msim_send_really_raw(PurpleConnection *gc, const char *buf, int total_bytes)
+{
+	int total_bytes_sent;
+	MsimSession *session;
+
+	g_return_val_if_fail(gc != NULL, -1);
+	g_return_val_if_fail(buf != NULL, -1);
+	g_return_val_if_fail(total_bytes >= 0, -1);
+
+	session = (MsimSession *)gc->proto_data;
+
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), -1);
+
+	/* Loop until all data is sent, or a failure occurs. */
+	total_bytes_sent = 0;
+	do {
+		int bytes_sent;
+
+		bytes_sent = send(session->fd, buf + total_bytes_sent,
+				total_bytes - total_bytes_sent, 0);
+
+		if (bytes_sent < 0) {
+			purple_debug_info("msim", "msim_send_raw(%s): send() failed: %s\n",
+					buf, g_strerror(errno));
+			return total_bytes_sent;
+		}
+		total_bytes_sent += bytes_sent;
+
+	} while(total_bytes_sent < total_bytes);
+
+	return total_bytes_sent;
+}
+
+/**
+ * Send raw data (given as a NUL-terminated string) to the server.
+ *
+ * @param session
+ * @param msg The raw data to send, in a NUL-terminated string.
+ *
+ * @return TRUE if succeeded, FALSE if not.
+ *
+ */
+gboolean
+msim_send_raw(MsimSession *session, const gchar *msg)
+{
+	size_t len;
+
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+	g_return_val_if_fail(msg != NULL, FALSE);
+
+	purple_debug_info("msim", "msim_send_raw: writing <%s>\n", msg);
+	len = strlen(msg);
+
+	return msim_send_really_raw(session->gc, msg, len) == len;
+}
+
+static GHashTable *
+msim_get_account_text_table(PurpleAccount *unused)
+{
+	GHashTable *table;
+
+	table = g_hash_table_new(g_str_hash, g_str_equal);
+
+	g_hash_table_insert(table, "login_label", (gpointer)_("Email Address..."));
+
+	return table;
+}
+
+/**
+ * Callbacks called by Purple, to access this plugin.
+ */
 static PurplePluginProtocolInfo prpl_info = {
 	/* options */
 	  OPT_PROTO_USE_POINTSIZE        /* specify font size in sane point size */
 	| OPT_PROTO_MAIL_CHECK,
 
-	/* | OPT_PROTO_IM_IMAGE - TODO: direct images. */    
+	/* | OPT_PROTO_IM_IMAGE - TODO: direct images. */
 	NULL,              /* user_splits */
 	NULL,              /* protocol_options */
 	NO_BUDDY_ICONS,    /* icon_spec - TODO: eventually should add this */
@@ -3152,9 +2927,120 @@
 	msim_get_account_text_table,              /* get_account_text_table */
 };
 
-
-
-/** Based on MSN's plugin info comments. */
+/**
+ * Load the plugin.
+ */
+static gboolean
+msim_load(PurplePlugin *plugin)
+{
+	/* If compiled to use RC4 from libpurple, check if it is really there. */
+	if (!purple_ciphers_find_cipher("rc4")) {
+		purple_debug_error("msim", "rc4 not in libpurple, but it is required - not loading MySpaceIM plugin!\n");
+		purple_notify_error(plugin, _("Missing Cipher"),
+				_("The RC4 cipher could not be found"),
+				_("Upgrade "
+					"to a libpurple with RC4 support (>= 2.0.1). MySpaceIM "
+					"plugin will not be loaded."));
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/**
+ * Called when friends have been imported to buddy list on server.
+ */
+static void
+msim_import_friends_cb(MsimSession *session, MsimMessage *reply, gpointer user_data)
+{
+	MsimMessage *body;
+	gchar *completed;
+	msim_msg_dump("msim_import_friends_cb=%s", reply);
+
+	/* Check if the friends were imported successfully. */
+	body = msim_msg_get_dictionary(reply, "body");
+	g_return_if_fail(body != NULL);
+	completed = msim_msg_get_string(body, "Completed");
+	g_return_if_fail(body != NULL);
+	msim_msg_free(body);
+	if (!g_str_equal(completed, "True"))
+	{
+		purple_debug_info("msim_import_friends_cb",
+				"failed to import friends: %s", completed);
+		purple_notify_error(session->account, _("Add friends from MySpace.com"),
+				_("Importing friends failed"), NULL);
+		g_free(completed);
+		return;
+	}
+	g_free(completed);
+
+	purple_debug_info("msim_import_friends_cb",
+			"added friends to server-side buddy list, requesting new contacts from server");
+
+	msim_get_contact_list(session, MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS);
+
+	/* TODO: show, X friends have been added */
+}
+
+/**
+ * Import friends from myspace.com.
+ */
+static void msim_import_friends(PurplePluginAction *action)
+{
+	PurpleConnection *gc;
+	MsimSession *session;
+	gchar *group_name;
+
+	gc = (PurpleConnection *)action->context;
+	session = (MsimSession *)gc->proto_data;
+
+	group_name = "MySpace Friends";
+
+	g_return_if_fail(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_IMPORT_ALL_FRIENDS_DSN,
+			"lid", MSIM_TYPE_INTEGER, MC_IMPORT_ALL_FRIENDS_LID,
+			"uid", MSIM_TYPE_INTEGER, session->userid,
+			"rid", MSIM_TYPE_INTEGER,
+				msim_new_reply_callback(session, msim_import_friends_cb, NULL),
+			"body", MSIM_TYPE_STRING,
+				g_strdup_printf("GroupName=%s", group_name),
+			NULL));
+}
+
+/**
+ * Actions menu for account.
+ */
+static GList *
+msim_actions(PurplePlugin *plugin, gpointer context)
+{
+	PurpleConnection *gc;
+	GList *menu;
+	PurplePluginAction *act;
+
+	gc = (PurpleConnection *)context;
+
+	menu = NULL;
+
+#if 0
+	/* TODO: find out how */
+	act = purple_plugin_action_new(_("Find people..."), msim_);
+	menu = g_list_append(menu, act);
+
+	act = purple_plugin_action_new(_("Change IM name..."), NULL);
+	menu = g_list_append(menu, act);
+#endif
+
+	act = purple_plugin_action_new(_("Add friends from MySpace.com"), msim_import_friends);
+	menu = g_list_append(menu, act);
+
+	return menu;
+}
+
+/**
+ * Based on MSN's plugin info comments.
+ */
 static PurplePluginInfo info = {
 	PURPLE_PLUGIN_MAGIC,
 	PURPLE_MAJOR_VERSION,
@@ -3188,32 +3074,18 @@
 	NULL                                              /**< reserved4      */
 };
 
-
 #ifdef MSIM_SELF_TEST
-/** Test functions.
+/*
+ * Test functions.
  * Used to test or try out the internal workings of msimprpl. If you're reading
  * this code for the first time, these functions can be instructive in learning
  * how msimprpl is architected.
  */
-void 
-msim_test_all(void) {
-	guint failures;
-
-
-	failures = 0;
-	failures += msim_test_msg();
-	failures += msim_test_escaping();
-
-	if (failures) {
-		purple_debug_info("msim", "msim_test_all HAD FAILURES: %d\n", failures);
-	} else {
-		purple_debug_info("msim", "msim_test_all - all tests passed!\n");
-	}
-	exit(0);
-}
-
-/** Test MsimMessage for basic functionality. */
-int 
+
+/**
+ * Test MsimMessage for basic functionality.
+ */
+static int
 msim_test_msg(void)
 {
 	MsimMessage *msg, *msg_cloned, *msg2;
@@ -3290,8 +3162,10 @@
 	return failures;
 }
 
-/** Test protocol-level escaping/unescaping. */
-int 
+/**
+ * Test protocol-level escaping/unescaping.
+ */
+static int
 msim_test_escaping(void)
 {
 	guint failures;
@@ -3322,87 +3196,146 @@
 
 	return failures;
 }
+
+static void
+msim_test_all(void)
+{
+	guint failures;
+
+	failures = 0;
+	failures += msim_test_msg();
+	failures += msim_test_escaping();
+
+	if (failures) {
+		purple_debug_info("msim", "msim_test_all HAD FAILURES: %d\n", failures);
+	} else {
+		purple_debug_info("msim", "msim_test_all - all tests passed!\n");
+	}
+	exit(0);
+}
 #endif
 
-static gboolean
-msim_uri_handler(const gchar *proto, const gchar *cmd, GHashTable *params)
+#ifdef MSIM_CHECK_NEWER_VERSION
+/**
+ * Callback for when a currentversion.txt has been downloaded.
+ */
+static void
+msim_check_newer_version_cb(PurpleUtilFetchUrlData *url_data,
+		gpointer user_data,
+		const gchar *url_text,
+		gsize len,
+		const gchar *error_message)
 {
-	PurpleAccount *account;
-	MsimSession *session;
-	GList *l;
-	gchar *uid_str, *cid_str;
-	guint uid, cid;
-
-	if (g_ascii_strcasecmp(proto, "myim"))
-		return FALSE;
-
-	/* Parameters are case-insensitive. */
-	uid_str = g_hash_table_lookup(params, "uid");
-	cid_str = g_hash_table_lookup(params, "cid");
-
-	uid = uid_str ? atol(uid_str) : 0;
-	cid = cid_str ? atol(cid_str) : 0;
-
-	/* Need a contact. */
-	g_return_val_if_fail(cid != 0, FALSE);
-
-	/* TODO: if auto=true, "Add all the people on this page to my IM List!", on
-	 * http://collect.myspace.com/index.cfm?fuseaction=im.friendslist. Don't need a cid. */
-
-	/* Convert numeric contact ID back to a string. Needed for looking up. Don't just
-	 * directly use cid directly from parameters, because it might not be numeric. 
-	 * It is trivial to change this to allow cID to be a username, but that's not how
-	 * the official MySpaceIM client works, so don't provide that functionality. */
-	cid_str = g_strdup_printf("%d", cid);
-
-
-	/* Find our account with specified user id, or use first connected account if uid=0. */
-	account = NULL;
-	l = purple_accounts_get_all();
-	while (l) {
-		if (purple_account_is_connected(l->data) &&
-			(uid == 0 || purple_account_get_int(l->data, "uid", 0) == uid)) {
-			account = l->data;
-			break;
-		}
-		l = l->next;
+	GKeyFile *keyfile;
+	GError *error;
+	GString *data;
+	gchar *newest_filever;
+
+	if (!url_text) {
+		purple_debug_info("msim_check_newer_version_cb",
+				"got error: %s\n", error_message);
+		return;
+	}
+
+	purple_debug_info("msim_check_newer_version_cb",
+			"url_text=%s\n", url_text ? url_text : "(NULL)");
+
+	/* Prepend [group] so that GKeyFile can parse it (requires a group). */
+	data = g_string_new(url_text);
+	purple_debug_info("msim", "data=%s\n", data->str
+			? data->str : "(NULL)");
+	data = g_string_prepend(data, "[group]\n");
+
+	purple_debug_info("msim", "data=%s\n", data->str
+			? data->str : "(NULL)");
+
+	/* url_text is variable=data\n...†*/
+
+	/* Check FILEVER, 1.0.716.0. 716 is build, MSIM_CLIENT_VERSION */
+	/* New (english) version can be downloaded from SETUPURL+SETUPFILE */
+
+	error = NULL;
+	keyfile = g_key_file_new();
+
+	/* Default list seperator is ;, but currentversion.txt doesn't have
+	 * these, so set to an unused character to avoid parsing problems. */
+	g_key_file_set_list_separator(keyfile, '\0');
+
+	g_key_file_load_from_data(keyfile, data->str, data->len,
+				G_KEY_FILE_NONE, &error);
+	g_string_free(data, TRUE);
+
+	if (error != NULL) {
+		purple_debug_info("msim_check_newer_version_cb",
+				"couldn't parse, error: %d %d %s\n",
+				error->domain, error->code, error->message);
+		g_error_free(error);
+		return;
 	}
 
-	if (!account) {
-		purple_notify_error(NULL, _("myim URL handler"), 
-				_("No suitable MySpaceIM account could be found to open this myim URL."),
-				_("Enable the proper MySpaceIM account and try again."));
-		g_free(cid_str);
-		return FALSE;
+	gchar **ks;
+	guint n;
+	ks = g_key_file_get_keys(keyfile, "group", &n, NULL);
+	purple_debug_info("msim", "n=%d\n", n);
+	guint i;
+	for (i = 0; ks[i] != NULL; ++i)
+	{
+		purple_debug_info("msim", "%d=%s\n", i, ks[i]);
+	}
+
+	newest_filever = g_key_file_get_string(keyfile, "group",
+			"FILEVER", &error);
+
+	purple_debug_info("msim_check_newer_version_cb",
+			"newest filever: %s\n", newest_filever ?
+			newest_filever : "(NULL)");
+	if (error != NULL) {
+		purple_debug_info("msim_check_newer_version_cb",
+				"error: %d %d %s\n",
+				error->domain, error->code, error->message);
+		g_error_free(error);
 	}
 
-	session = (MsimSession *)account->gc->proto_data;
-	g_return_val_if_fail(session != NULL, FALSE);
-
-	/* Lookup userid to username. TODO: push this down, to IM sending/contact 
-	 * adding functions. */
-
-	/* myim:sendIM?uID=USERID&cID=CONTACTID */
-	if (!g_ascii_strcasecmp(cmd, "sendIM")) {
-		msim_lookup_user(session, cid_str, (MSIM_USER_LOOKUP_CB)msim_uri_handler_sendIM_cb, NULL);
-		g_free(cid_str);
-		return TRUE;
-
-	/* myim:addContact?uID=USERID&cID=CONTACTID */
-	} else if (!g_ascii_strcasecmp(cmd, "addContact")) {
-		msim_lookup_user(session, cid_str, (MSIM_USER_LOOKUP_CB)msim_uri_handler_addContact_cb, NULL);
-		g_free(cid_str);
-		return TRUE;
+	g_key_file_free(keyfile);
+
+	exit(0);
+}
+#endif
+
+/**
+ Handle a myim:addContact command, after username has been looked up.
+ */
+static void
+msim_uri_handler_addContact_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
+{
+	MsimMessage *body;
+	gchar *username;
+
+	body = msim_msg_get_dictionary(userinfo, "body");
+	username = msim_msg_get_string(body, "UserName");
+	msim_msg_free(body);
+
+	if (!username) {
+		guint uid;
+
+		uid = msim_msg_get_integer(userinfo, "UserID");
+		g_return_if_fail(uid != 0);
+
+		username = g_strdup_printf("%d", uid);
 	}
 
-	return FALSE;
+	purple_blist_request_add_buddy(session->account, username, _("Buddies"), NULL);
+
+	g_free(username);
 }
 
 /* TODO: move uid->username resolving to IM sending and buddy adding functions,
  * so that user can manually add or IM by userid and username automatically
  * looked up if possible? */
- 
-/** Handle a myim:sendIM URI command, after username has been looked up. */
+
+/**
+ * Handle a myim:sendIM URI command, after username has been looked up.
+ */
 static void
 msim_uri_handler_sendIM_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
 {
@@ -3436,35 +3369,95 @@
 	g_free(username);
 }
 
-/** Handle a myim:addContact command, after username has been looked up. */
-static void
-msim_uri_handler_addContact_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
+static gboolean
+msim_uri_handler(const gchar *proto, const gchar *cmd, GHashTable *params)
 {
-	MsimMessage *body;
-	gchar *username;
-
-	body = msim_msg_get_dictionary(userinfo, "body");
-	username = msim_msg_get_string(body, "UserName");
-	msim_msg_free(body);
-
-	if (!username) {
-		guint uid;
-
-		uid = msim_msg_get_integer(userinfo, "UserID");
-		g_return_if_fail(uid != 0);
-
-		username = g_strdup_printf("%d", uid);
+	PurpleAccount *account;
+	MsimSession *session;
+	GList *l;
+	gchar *uid_str, *cid_str;
+	guint uid, cid;
+
+	if (g_ascii_strcasecmp(proto, "myim"))
+		return FALSE;
+
+	/* Parameters are case-insensitive. */
+	uid_str = g_hash_table_lookup(params, "uid");
+	cid_str = g_hash_table_lookup(params, "cid");
+
+	uid = uid_str ? atol(uid_str) : 0;
+	cid = cid_str ? atol(cid_str) : 0;
+
+	/* Need a contact. */
+	g_return_val_if_fail(cid != 0, FALSE);
+
+	/* TODO: if auto=true, "Add all the people on this page to my IM List!", on
+	 * http://collect.myspace.com/index.cfm?fuseaction=im.friendslist. Don't need a cid. */
+
+	/* Convert numeric contact ID back to a string. Needed for looking up. Don't just
+	 * directly use cid directly from parameters, because it might not be numeric.
+	 * It is trivial to change this to allow cID to be a username, but that's not how
+	 * the official MySpaceIM client works, so don't provide that functionality. */
+	cid_str = g_strdup_printf("%d", cid);
+
+
+	/* Find our account with specified user id, or use first connected account if uid=0. */
+	account = NULL;
+	l = purple_accounts_get_all();
+	while (l) {
+		if (purple_account_is_connected(l->data) &&
+			(uid == 0 || purple_account_get_int(l->data, "uid", 0) == uid)) {
+			account = l->data;
+			break;
+		}
+		l = l->next;
 	}
 
-
-	purple_blist_request_add_buddy(session->account, username, _("Buddies"), NULL);
-
-	g_free(username);
+	if (!account) {
+		purple_notify_error(NULL, _("myim URL handler"),
+				_("No suitable MySpaceIM account could be found to open this myim URL."),
+				_("Enable the proper MySpaceIM account and try again."));
+		g_free(cid_str);
+		return FALSE;
+	}
+
+	session = (MsimSession *)account->gc->proto_data;
+	g_return_val_if_fail(session != NULL, FALSE);
+
+	/* Lookup userid to username. TODO: push this down, to IM sending/contact
+	 * adding functions. */
+
+	/* myim:sendIM?uID=USERID&cID=CONTACTID */
+	if (!g_ascii_strcasecmp(cmd, "sendIM")) {
+		msim_lookup_user(session, cid_str, (MSIM_USER_LOOKUP_CB)msim_uri_handler_sendIM_cb, NULL);
+		g_free(cid_str);
+		return TRUE;
+
+	/* myim:addContact?uID=USERID&cID=CONTACTID */
+	} else if (!g_ascii_strcasecmp(cmd, "addContact")) {
+		msim_lookup_user(session, cid_str, (MSIM_USER_LOOKUP_CB)msim_uri_handler_addContact_cb, NULL);
+		g_free(cid_str);
+		return TRUE;
+	}
+
+	return FALSE;
 }
 
-/** Initialize plugin. */
-void 
-init_plugin(PurplePlugin *plugin) 
+#ifdef MSIM_DEBUG_MSG
+static void
+print_hash_item(gpointer key, gpointer value, gpointer user_data)
+{
+	purple_debug_info("msim", "%s=%s\n",
+			key ? (gchar *)key : "(NULL)",
+			value ? (gchar *)value : "(NULL)");
+}
+#endif
+
+/**
+ * Initialize plugin.
+ */
+static void
+init_plugin(PurplePlugin *plugin)
 {
 #ifdef MSIM_SELF_TEST
 	msim_test_all();
@@ -3515,7 +3508,7 @@
 #endif
 
 	/* Code below only runs once. Based on oscar.c's oscar_init(). */
-	if (initialized) 
+	if (initialized)
 		return;
 
 	initialized = TRUE;
--- a/libpurple/protocols/myspace/myspace.h	Tue Dec 16 19:17:44 2008 +0000
+++ b/libpurple/protocols/myspace/myspace.h	Tue Dec 16 19:18:41 2008 +0000
@@ -69,12 +69,12 @@
 /*#define MSIM_DEBUG_LOGIN_CHALLENGE*/
 /*#define MSIM_DEBUG_RXBUF            */
 
-/* Encode unknown HTML tags from IM clients in messages as [tag], instead of 
+/* Encode unknown HTML tags from IM clients in messages as [tag], instead of
  * ignoring. Useful for debugging */
 /*#define MSIM_MARKUP_SHOW_UNKNOWN_TAGS  */
 
 /* Define to cause init_plugin() to run some tests and print
- * the results to the Purple debug log, then exit. Useful to 
+ * the results to the Purple debug log, then exit. Useful to
  * run with 'pidgin -d' to see the output. Don't define if
  * you want to actually use the plugin! */
 /*#define MSIM_SELF_TEST            */
@@ -119,8 +119,7 @@
 #define MSIM_KEEPALIVE_INTERVAL_CHECK   (30 * 1000)
 
 /* Time to check for new mail (milliseconds) */
-#define MSIM_MAIL_INTERVAL_CHECK    (60 * 1000) 
-
+#define MSIM_MAIL_INTERVAL_CHECK    (60 * 1000)
 
 /* Constants */
 #define HASH_SIZE                   0x14        /**< Size of SHA-1 hash for login */
@@ -143,7 +142,7 @@
 #define MSIM_AUTH_CHALLENGE_LENGTH  0x40
 
 /* TODO: obtain IPs of network interfaces from user's machine, instead of
- * hardcoding these values below (used in msim_compute_login_response). 
+ * hardcoding these values below (used in msim_compute_login_response).
  * This is not immediately
  * important because you can still connect and perform basic
  * functions of the protocol. There is also a high chance that the addreses
@@ -173,7 +172,6 @@
 #define MSIM_STATUS_CODE_IDLE                 2
 #define MSIM_STATUS_CODE_AWAY                 5
 
-
 /* Inbox status bitfield values for MsimSession.inbox_status. */
 #define MSIM_INBOX_MAIL                 (1 << 0)
 #define MSIM_INBOX_BLOG_COMMENT         (1 << 1)
@@ -191,49 +189,13 @@
 #define MSIM_ERROR_LOGGED_IN_ELSEWHERE          6
 
 /* Functions */
-gboolean msim_load(PurplePlugin *plugin);
-GList *msim_status_types(PurpleAccount *acct);
-
-const gchar *msim_list_icon(PurpleAccount *acct, PurpleBuddy *buddy);
 gboolean msim_send_raw(MsimSession *session, const gchar *msg);
 
-void msim_login(PurpleAccount *acct);
-int msim_send_im(PurpleConnection *gc, const gchar *who, const gchar *message, PurpleMessageFlags flags);
-unsigned int msim_send_typing(PurpleConnection *gc, const gchar *name, PurpleTypingState state);
-
-void msim_get_info(PurpleConnection *gc, const gchar *name);
-
-void msim_set_status(PurpleAccount *account, PurpleStatus *status);
-void msim_set_idle(PurpleConnection *gc, int time);
-
-void msim_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
-void msim_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
-
-const char *msim_normalize(const PurpleAccount *account, const char *str);
-
-gboolean msim_offline_message(const PurpleBuddy *buddy);
-
-void msim_close(PurpleConnection *gc);
-
-char *msim_status_text(PurpleBuddy *buddy);
-void msim_tooltip_text(PurpleBuddy *buddy, PurpleNotifyUserInfo *user_info, gboolean full);
-GList *msim_actions(PurplePlugin *plugin, gpointer context);
-
-#ifdef MSIM_SELF_TEST
-void msim_test_all(void) __attribute__((__noreturn__));
-int msim_test_msg(void);
-int msim_test_escaping(void);
-#endif
-
 gboolean msim_send_bm(MsimSession *session, const gchar *who, const gchar *text, int type);
 
 gboolean msim_we_are_logged_on(MsimSession *session);
 
-
 void msim_unrecognized(MsimSession *session, MsimMessage *msg, gchar *note);
 guint msim_new_reply_callback(MsimSession *session, MSIM_USER_LOOKUP_CB cb, gpointer data);
 
-
-void init_plugin(PurplePlugin *plugin);
-
 #endif /* !_MYSPACE_MYSPACE_H */
--- a/libpurple/protocols/myspace/persist.h	Tue Dec 16 19:17:44 2008 +0000
+++ b/libpurple/protocols/myspace/persist.h	Tue Dec 16 19:18:41 2008 +0000
@@ -43,7 +43,7 @@
 /** Define a set of _DSN and _LID constants for a persistance request. */
 #define MSIM_PERSIST_DSN_LID(name,dsn,lid)             \
     static const int name##_DSN = dsn;                 \
-    static const int name##_LID = lid;                        
+    static const int name##_LID = lid;
 
 /* Can't do this, errors:
  *     persist.h:51:3: error: '#' is not followed by a macro parameter
--- a/libpurple/protocols/myspace/session.c	Tue Dec 16 19:17:44 2008 +0000
+++ b/libpurple/protocols/myspace/session.c	Tue Dec 16 19:18:41 2008 +0000
@@ -17,7 +17,6 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-
 #include "myspace.h"
 
 /* Session methods */
@@ -47,9 +46,9 @@
 	session->fd = -1;
 
 	/* TODO: Remove. */
-	session->user_lookup_cb = g_hash_table_new_full(g_direct_hash, 
+	session->user_lookup_cb = g_hash_table_new_full(g_direct_hash,
 			g_direct_equal, NULL, NULL);  /* do NOT free function pointers! (values) */
-	session->user_lookup_cb_data = g_hash_table_new_full(g_direct_hash, 
+	session->user_lookup_cb_data = g_hash_table_new_full(g_direct_hash,
 			g_direct_equal, NULL, NULL);/* TODO: we don't know what the values are,
 											 they could be integers inside gpointers
 											 or strings, so I don't freed them.
@@ -65,7 +64,7 @@
 	session->last_comm = time(NULL);
 	session->inbox_status = 0;
 	session->inbox_handle = 0;
-	
+
 	return session;
 }
 
@@ -74,11 +73,11 @@
  *
  * @param session The session to destroy.
  */
-void 
+void
 msim_session_destroy(MsimSession *session)
 {
 	g_return_if_fail(MSIM_SESSION_VALID(session));
-	
+
 	session->magic = -1;
 
 	g_free(session->rxbuf);
@@ -91,7 +90,7 @@
 	if (session->server_info) {
 		msim_msg_free(session->server_info);
 	}
-	
+
 	/* Stop checking the inbox at the end of the session. */
 	if (session->inbox_handle) {
 		purple_timeout_remove(session->inbox_handle);
@@ -99,4 +98,3 @@
 
 	g_free(session);
 }
-
--- a/libpurple/protocols/myspace/session.h	Tue Dec 16 19:17:44 2008 +0000
+++ b/libpurple/protocols/myspace/session.h	Tue Dec 16 19:18:41 2008 +0000
@@ -54,7 +54,6 @@
 /* Check if an MsimSession is valid */
 #define MSIM_SESSION_VALID(s) (session != NULL && session->magic == MSIM_SESSION_STRUCT_MAGIC)
 
-
 MsimSession *msim_session_new(PurpleAccount *acct);
 void msim_session_destroy(MsimSession *session);
 
--- a/libpurple/protocols/myspace/user.c	Tue Dec 16 19:17:44 2008 +0000
+++ b/libpurple/protocols/myspace/user.c	Tue Dec 16 19:18:41 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 *
@@ -47,7 +39,10 @@
 		return NULL;
 	}
 }
-/** Get the MsimUser from a PurpleBuddy, creating it if needed. */
+
+/**
+ * Get the MsimUser from a PurpleBuddy, creating it if needed.
+ */
 MsimUser *
 msim_get_user_from_buddy(PurpleBuddy *buddy)
 {
@@ -65,14 +60,16 @@
 		user->buddy = buddy;
 		user->id = purple_blist_node_get_int(&buddy->node, "UserID");
 		buddy->proto_data = (gpointer)user;
-	} 
+	}
 
 	user = (MsimUser *)(buddy->proto_data);
 
 	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)
 {
@@ -89,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
@@ -99,7 +97,7 @@
 	gchar *str;
 	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);
@@ -185,7 +183,39 @@
 	}
 }
 
-/** 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.
  *
@@ -224,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;
 
@@ -242,14 +272,15 @@
 			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")) {
@@ -286,7 +317,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);
@@ -294,7 +325,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);
@@ -342,7 +373,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.
@@ -354,9 +386,8 @@
  *
  * If the function has no buddy information, this function
  * is a no-op (and returns FALSE).
- *
  */
-gboolean 
+gboolean
 msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user)
 {
 	gchar *username;
@@ -373,13 +404,13 @@
 	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);
@@ -391,8 +422,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;
@@ -410,7 +441,7 @@
 		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. 
+		 * 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(). */
@@ -425,6 +456,58 @@
 	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.
  *
@@ -434,7 +517,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;
@@ -460,8 +543,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;
@@ -486,231 +569,88 @@
 			"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, 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, *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");
+	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");
 	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_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);
+	g_free(errmsg);
 }
 
 /**
@@ -721,7 +661,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)
 {
@@ -765,82 +705,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, 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);
+}
--- a/libpurple/protocols/myspace/user.h	Tue Dec 16 19:17:44 2008 +0000
+++ b/libpurple/protocols/myspace/user.h	Tue Dec 16 19:18:41 2008 +0000
@@ -42,7 +42,7 @@
 	gboolean temporary_user;
 } MsimUser;
 
-/* Callback function pointer type for when a user's information is received, 
+/* 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, MsimMessage *userinfo, gpointer data);
 
@@ -51,8 +51,6 @@
 void msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full);
 gboolean msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user);
 gboolean msim_is_userid(const gchar *user);
-gboolean msim_is_email(const gchar *user);
-gboolean msim_is_valid_username(const gchar *user);
 void msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data);
 void msim_set_username_cb(PurpleConnection *gc);
 void msim_do_not_set_username_cb(PurpleConnection *gc);
--- a/libpurple/protocols/myspace/zap.c	Tue Dec 16 19:17:44 2008 +0000
+++ b/libpurple/protocols/myspace/zap.c	Tue Dec 16 19:18:41 2008 +0000
@@ -20,10 +20,6 @@
 #include "myspace.h"
 #include "zap.h"
 
-static gboolean msim_send_zap(MsimSession *session, const gchar *username, guint code);
-static void msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr);
-
-
 /** Get zap types. */
 GList *
 msim_attention_types(PurpleAccount *acct)
@@ -100,6 +96,33 @@
 	return types;
 }
 
+/** Send a zap to a user. */
+static gboolean
+msim_send_zap(MsimSession *session, const gchar *username, guint code)
+{
+	gchar *zap_string;
+	gboolean rc;
+
+	g_return_val_if_fail(session != NULL, FALSE);
+	g_return_val_if_fail(username != NULL, FALSE);
+
+	/* Construct and send the actual zap command. */
+	zap_string = g_strdup_printf("!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", code);
+
+	if (!msim_send_bm(session, username, zap_string, MSIM_BM_ACTION)) {
+		purple_debug_info("msim_send_zap",
+				"msim_send_bm failed: zapping %s with %s\n",
+				username, zap_string);
+		rc = FALSE;
+	} else {
+		rc = TRUE;
+	}
+
+	g_free(zap_string);
+
+	return rc;
+}
+
 /** Send a zap */
 gboolean
 msim_send_attention(PurpleConnection *gc, const gchar *username, guint code)
@@ -130,33 +153,6 @@
 	return TRUE;
 }
 
-/** Send a zap to a user. */
-static gboolean
-msim_send_zap(MsimSession *session, const gchar *username, guint code)
-{
-	gchar *zap_string;
-	gboolean rc;
-
-	g_return_val_if_fail(session != NULL, FALSE);
-	g_return_val_if_fail(username != NULL, FALSE);
-
-	/* Construct and send the actual zap command. */
-	zap_string = g_strdup_printf("!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", code);
-
-	if (!msim_send_bm(session, username, zap_string, MSIM_BM_ACTION)) {
-		purple_debug_info("msim_send_zap_from_menu", "msim_send_bm failed: zapping %s with %s\n",
-				username, zap_string);
-		rc = FALSE;
-	} else {
-		rc = TRUE;
-	}
-	
-	g_free(zap_string);
-
-	return rc;
-
-}
-
 /** Zap someone. Callback from msim_blist_node_menu zap menu. */
 static void
 msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr)
@@ -248,5 +244,3 @@
 
 	return TRUE;
 }
-
-
--- a/libpurple/protocols/simple/simple.c	Tue Dec 16 19:17:44 2008 +0000
+++ b/libpurple/protocols/simple/simple.c	Tue Dec 16 19:18:41 2008 +0000
@@ -1942,7 +1942,8 @@
 	if (userserver[1] == NULL || userserver[1][0] == '\0') {
 		purple_connection_error_reason(gc,
 			PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
-			_("SIP connect server not specified"));
+			_("Unable to connect to server. Please enter the "
+			  "address of the server you wish to connect to."));
 		return;
 	}
 
--- a/po/fi.po	Tue Dec 16 19:17:44 2008 +0000
+++ b/po/fi.po	Tue Dec 16 19:18:41 2008 +0000
@@ -10,8 +10,8 @@
 msgstr ""
 "Project-Id-Version: Pidgin\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-12-01 15:52-0800\n"
-"PO-Revision-Date: 2008-09-30 19:46+0300\n"
+"POT-Creation-Date: 2008-12-16 00:12+0200\n"
+"PO-Revision-Date: 2008-12-16 00:16+0200\n"
 "Last-Translator: Timo Jyrinki <timo.jyrinki@iki.fi>\n"
 "Language-Team: \n"
 "MIME-Version: 1.0\n"
@@ -4650,6 +4650,19 @@
 msgid "Unable to retrieve MSN Address Book"
 msgstr "MSN-osoitekirjaa ei onnistuttu noutamaan"
 
+#. only notify the user about problems adding to the friends list
+#. * maybe we should do something else for other lists, but it probably
+#. * won't cause too many problems if we just ignore it
+#, c-format
+msgid "Unable to add \"%s\"."
+msgstr "Ei voi lisätä \"%s\"."
+
+msgid "Buddy Add error"
+msgstr "Tuttavan lisäysvirhe"
+
+msgid "The username specified does not exist."
+msgstr "Syötetty käyttäjänimi ei ole olemassa."
+
 #, c-format
 msgid "Buddy list synchronization issue in %s (%s)"
 msgstr "Tuttavien synkronointiongelma käyttäjätilillä %s (%s)"
@@ -4971,6 +4984,12 @@
 msgid "Page"
 msgstr "Lähetä"
 
+msgid "Playing a game"
+msgstr "Pelaamassa peliä"
+
+msgid "Working"
+msgstr "Tekee töitä"
+
 msgid "Has you"
 msgstr "Olet hänen listallaan"
 
@@ -5007,6 +5026,12 @@
 msgid "Album"
 msgstr "Levy"
 
+msgid "Game Title"
+msgstr "Pelin nimi"
+
+msgid "Office Title"
+msgstr "Kappaleen nimi"
+
 msgid "Set Friendly Name..."
 msgstr "Aseta tuttavanimi..."
 
@@ -5197,8 +5222,8 @@
 "Käyttäjän profiilista ei löytynyt mitään tietoja. Käyttäjää ei "
 "todennäköisesti ole olemassa."
 
-msgid "Profile URL"
-msgstr "Profiilin URL"
+msgid "View web profile"
+msgstr "Näytä WWW-profiili"
 
 #. *< type
 #. *< ui_requirement
@@ -5446,19 +5471,15 @@
 msgid "Do you want to delete this buddy from your address book as well?"
 msgstr "Haluatko poistaa tämän tuttavan myös osoitekirjastasi?"
 
-#. only notify the user about problems adding to the friends list
-#. * maybe we should do something else for other lists, but it probably
-#. * won't cause too many problems if we just ignore it
-#, c-format
-msgid "Unable to add \"%s\"."
-msgstr "Ei voi lisätä \"%s\"."
-
 msgid "The username specified is invalid."
 msgstr "Syötetty käyttäjänimi on virheellinen."
 
 msgid "This Hotmail account may not be active."
 msgstr "Tämä Hotmail-tili ei välttämättä ole aktiivinen."
 
+msgid "Profile URL"
+msgstr "Profiilin URL"
+
 #. *< type
 #. *< ui_requirement
 #. *< flags
@@ -5472,18 +5493,12 @@
 msgid "MSN Protocol Plugin"
 msgstr "MSN-yhteyskäytäntöliitännäinen"
 
-msgid "Missing Cipher"
-msgstr "Salaus puuttuu"
-
-msgid "The RC4 cipher could not be found"
-msgstr "RC4-salausta ei löydetty"
-
-msgid ""
-"Upgrade to a libpurple with RC4 support (>= 2.0.1). MySpaceIM plugin will "
-"not be loaded."
-msgstr ""
-"Päivitä libpurpleen jossa RC4-tuki (>= 2.0.1). MySpaceIM-liitännäistä ei "
-"ladattu."
+#, c-format
+msgid "No such user: %s"
+msgstr "Käyttäjää ei löydy: %s"
+
+msgid "User lookup"
+msgstr "Käyttäjän haku"
 
 msgid "Reading challenge"
 msgstr "Luetaan tunnistushaastetta"
@@ -5494,11 +5509,17 @@
 msgid "Logging in"
 msgstr "Kirjaudutaan sisään"
 
-#, c-format
-msgid "Connection to server lost (no data received within %d second)"
-msgid_plural "Connection to server lost (no data received within %d seconds)"
-msgstr[0] "Yhteys palvelimelle katkesi (dataa ei vastaanotettu %d sekunnissa)"
-msgstr[1] "Yhteys palvelimelle katkesi (dataa ei vastaanotettu %d sekunnissa)"
+msgid "MySpaceIM - No Username Set"
+msgstr "MySpaceIM - Käyttäjänimeä ei asetettu"
+
+msgid "You appear to have no MySpace username."
+msgstr "Sinulla ei näytä olevan MySpace-käyttäjänimeä."
+
+msgid "Would you like to set one now? (Note: THIS CANNOT BE CHANGED!)"
+msgstr "Haluatko asettaa sen nyt? (Huom: TÄTÄ EI VOI MUUTTAA)"
+
+msgid "Lost connection with server"
+msgstr "Yhteys palvelimeen katkesi"
 
 #. Can't write _()'d strings in array initializers. Workaround.
 msgid "New mail messages"
@@ -5519,14 +5540,25 @@
 msgid "MySpace"
 msgstr "MySpace"
 
-msgid "MySpaceIM - No Username Set"
-msgstr "MySpaceIM - Käyttäjänimeä ei asetettu"
-
-msgid "You appear to have no MySpace username."
-msgstr "Sinulla ei näytä olevan MySpace-käyttäjänimeä."
-
-msgid "Would you like to set one now? (Note: THIS CANNOT BE CHANGED!)"
-msgstr "Haluatko asettaa sen nyt? (Huom: TÄTÄ EI VOI MUUTTAA)"
+msgid "IM Friends"
+msgstr "Pikaviestikaverit"
+
+#, c-format
+msgid ""
+"%d buddy was added or updated from the server (including buddies already on "
+"the server-side list)"
+msgid_plural ""
+"%d buddies were added or updated from the server (including buddies already "
+"on the server-side list)"
+msgstr[0] ""
+"%d tuttava lisättiin tai päivitettiin palvelimelta (mukaan lukien jo "
+"palvelinpuolen luettelossa olevat)"
+msgstr[1] ""
+"%d tuttavaa lisättiin tai päivitettiin palvelimelta (mukaan lukien jo "
+"palvelinpuolen luettelossa olevat)"
+
+msgid "Add contacts from server"
+msgstr "Lisää tuttavia palvelimelta"
 
 #. The session is now set up, ready to be connected. This emits the
 #. * signedOn signal, so clients can now do anything with msimprpl, and
@@ -5553,31 +5585,6 @@
 msgid "MySpaceIM Error"
 msgstr "MySpaceIM-virhe"
 
-msgid "Failed to add buddy"
-msgstr "Tuttavan lisääminen epäonnistui"
-
-msgid "'addbuddy' command failed."
-msgstr "\"addbuddy\"-komento epäonnistui."
-
-msgid "persist command failed"
-msgstr "persist-komento epäonnistui"
-
-#, c-format
-msgid "No such user: %s"
-msgstr "Käyttäjää ei löydy: %s"
-
-msgid "User lookup"
-msgstr "Käyttäjän haku"
-
-msgid "Failed to remove buddy"
-msgstr "Tuttavaa poistaminen epäonnistui"
-
-msgid "'delbuddy' command failed"
-msgstr "\"delbuddy\"-komento epäonnistui"
-
-msgid "blocklist command failed"
-msgstr "blocklist-komento epäonnistui"
-
 msgid "Invalid input condition"
 msgstr "Epäkelpo syötetila"
 
@@ -5591,25 +5598,36 @@
 msgid "Couldn't connect to host: %s (%d)"
 msgstr "Yhteyttä isäntään ei voi muodostaa: %s (%d)"
 
-msgid "IM Friends"
-msgstr "Pikaviestikaverit"
-
-#, c-format
-msgid ""
-"%d buddy was added or updated from the server (including buddies already on "
-"the server-side list)"
-msgid_plural ""
-"%d buddies were added or updated from the server (including buddies already "
-"on the server-side list)"
-msgstr[0] ""
-"%d tuttava lisättiin tai päivitettiin palvelimelta (mukaan lukien jo "
-"palvelinpuolen luettelossa olevat)"
-msgstr[1] ""
-"%d tuttavaa lisättiin tai päivitettiin palvelimelta (mukaan lukien jo "
-"palvelinpuolen luettelossa olevat)"
-
-msgid "Add contacts from server"
-msgstr "Lisää tuttavia palvelimelta"
+msgid "Failed to add buddy"
+msgstr "Tuttavan lisääminen epäonnistui"
+
+msgid "'addbuddy' command failed."
+msgstr "\"addbuddy\"-komento epäonnistui."
+
+msgid "persist command failed"
+msgstr "persist-komento epäonnistui"
+
+msgid "Failed to remove buddy"
+msgstr "Tuttavaa poistaminen epäonnistui"
+
+msgid "'delbuddy' command failed"
+msgstr "\"delbuddy\"-komento epäonnistui"
+
+msgid "blocklist command failed"
+msgstr "blocklist-komento epäonnistui"
+
+msgid "Missing Cipher"
+msgstr "Salaus puuttuu"
+
+msgid "The RC4 cipher could not be found"
+msgstr "RC4-salausta ei löydetty"
+
+msgid ""
+"Upgrade to a libpurple with RC4 support (>= 2.0.1). MySpaceIM plugin will "
+"not be loaded."
+msgstr ""
+"Päivitä libpurpleen jossa RC4-tuki (>= 2.0.1). MySpaceIM-liitännäistä ei "
+"ladattu."
 
 msgid "Add friends from MySpace.com"
 msgstr "Lisää kavereita MySpacesta"
@@ -5651,9 +5669,6 @@
 msgid "User"
 msgstr "Käyttäjä"
 
-msgid "Profile"
-msgstr "Profiili"
-
 msgid "Headline"
 msgstr "Otsikko"
 
@@ -5666,16 +5681,6 @@
 msgid "Client Version"
 msgstr "Asiakasohjelman versio"
 
-#. Protocol won't log in now without a username set.. Disconnect
-msgid "No username set"
-msgstr "Käyttäjänimeä ei asetettu"
-
-msgid "MySpaceIM - Please Set a Username"
-msgstr "MySpaceIM - Aseta käyttäjänimi"
-
-msgid "Please enter a username to check its availability:"
-msgstr "Syötä käyttäjänimi tarkistaaksesi sen saatavuus:"
-
 msgid "MySpaceIM - Username Available"
 msgstr "MySpaceIM - Käyttäjänimi saatavilla"
 
@@ -5685,12 +5690,22 @@
 msgid "ONCE SET, THIS CANNOT BE CHANGED!"
 msgstr "KUN TÄMÄ ON KERRAN ASETETTU, SITÄ EI VOI MUUTTAA"
 
+msgid "MySpaceIM - Please Set a Username"
+msgstr "MySpaceIM - Aseta käyttäjänimi"
+
 msgid "This username is unavailable."
 msgstr "Tämä käyttäjänimi ei ole saatavilla."
 
 msgid "Please try another username:"
 msgstr "Yritä toista käyttäjänimeä:"
 
+#. Protocol won't log in now without a username set.. Disconnect
+msgid "No username set"
+msgstr "Käyttäjänimeä ei asetettu"
+
+msgid "Please enter a username to check its availability:"
+msgstr "Syötä käyttäjänimi tarkistaaksesi sen saatavuus:"
+
 #. TODO: icons for each zap
 #. Lots of comments for translators:
 #. Zap means "to strike suddenly and forcefully as if with a
@@ -6631,6 +6646,9 @@
 msgid "Member Since"
 msgstr "Rekisteröitynyt"
 
+msgid "Profile"
+msgstr "Profiili"
+
 msgid "Your AIM connection may be lost."
 msgstr "AIM-yhteytesi saattaa olla katkennut."
 
@@ -6819,13 +6837,11 @@
 "tulee olla oikea sähköpostiosoite, tai alkaa kirjaimella ja sisältää vain "
 "kirjaimia, numeroita ja välilyöntejä, tai sisältää vain numeroita."
 
-#, fuzzy
 msgid "Unable to Add"
 msgstr "Lisääminen epäonnistui"
 
-#, fuzzy
 msgid "Unable to Retrieve Buddy List"
-msgstr "Tuttavien nouto ei onnistunut"
+msgstr "Tuttavien noutaminen ei onnistunut"
 
 msgid ""
 "The AIM servers were temporarily unable to send your buddy list.  Your buddy "
@@ -7123,16 +7139,14 @@
 msgid "Other"
 msgstr "Muu"
 
-#, fuzzy
 msgid "Visible"
-msgstr "Näkymätön"
-
-msgid "Firend Only"
-msgstr ""
-
-#, fuzzy
+msgstr "Näkyvissä"
+
+msgid "Friend Only"
+msgstr "Vain kaverit"
+
 msgid "Private"
-msgstr "Yksityisyys"
+msgstr "Yksityinen"
 
 msgid "QQ Number"
 msgstr "QQ-numero"
@@ -7149,9 +7163,8 @@
 msgid "Phone Number"
 msgstr "Puhelinnumero"
 
-#, fuzzy
 msgid "Authorize adding"
-msgstr "Valtuuta tuttava?"
+msgstr "Valtuuta lisäys"
 
 msgid "Cellphone Number"
 msgstr "Matkapuhelinnumero"
@@ -7159,100 +7172,82 @@
 msgid "Personal Introduction"
 msgstr "Henkilökohtainen esittely"
 
-#, fuzzy
 msgid "City/Area"
-msgstr "Paikkakunta"
-
-#, fuzzy
+msgstr "Paikkakunta/alue"
+
 msgid "Publish Mobile"
-msgstr "Oma matkapuhelin"
-
-#, fuzzy
+msgstr "Julkaise matkapuhelin"
+
 msgid "Publish Contact"
-msgstr "Anna kontaktiryhmälle lempinimi"
+msgstr "Julkaise yhteystiedot"
 
 msgid "College"
 msgstr "Yliopisto"
 
-#, fuzzy
 msgid "Horoscope"
 msgstr "Horoskooppimerkki"
 
-#, fuzzy
 msgid "Zodiac"
 msgstr "Eläinradan merkki"
 
-#, fuzzy
 msgid "Blood"
-msgstr "Estetty"
-
-#, fuzzy
+msgstr "Veriryhmä"
+
 msgid "True"
-msgstr "härkä"
-
-#, fuzzy
+msgstr "Tosi"
+
 msgid "False"
-msgstr "Epäonnistunut"
-
-#, fuzzy
+msgstr "Epätosi"
+
 msgid "Modify Contact"
-msgstr "Muokkaa tiliä"
-
-#, fuzzy
+msgstr "Muokkaa yhteystietoa"
+
 msgid "Modify Address"
-msgstr "Kotiosoite"
-
-#, fuzzy
+msgstr "Muokkaa osoitetta"
+
 msgid "Modify Extended Information"
-msgstr "Muokkaa tietojani"
-
-#, fuzzy
+msgstr "Muokkaa lisätietoja"
+
 msgid "Modify Information"
 msgstr "Muokkaa tietoja"
 
 msgid "Update"
 msgstr "Päivitä"
 
-#, fuzzy
 msgid "Could not change buddy information."
-msgstr "Muuta tuttavan tietoja."
-
-#, c-format
-msgid "%d needs Q&A"
-msgstr ""
-
-#, fuzzy
-msgid "Add buddy Q&A"
-msgstr "Lisää tuttava"
-
-#, fuzzy
-msgid "Input answer here"
-msgstr "Anna syy tähän"
+msgstr "Tuttavan tietojen muuttaminen ei onnistunut."
+
+#, c-format
+msgid "%u requires verification"
+msgstr "%u pyytää valtuutusta"
+
+msgid "Add buddy question"
+msgstr "Lisää tuttavakysymys"
+
+msgid "Enter answer here"
+msgstr "Syötä vastaus tähän"
 
 msgid "Send"
 msgstr "Lähetä"
 
-#, fuzzy
 msgid "Invalid answer."
-msgstr "Virheellinen salasana"
+msgstr "Virheellinen vastaus."
 
 msgid "Authorization denied message:"
 msgstr "Valtuutuksen eväysviesti:"
 
-#, fuzzy
-msgid "Sorry, You are not my style."
-msgstr "Pahoittelut, en ole kiinnostunut..."
-
-#, c-format
-msgid "%d needs authentication"
-msgstr "Käyttäjä %d tarvitsee valtuutuksen"
-
-#, fuzzy
+msgid "Sorry, you're not my style."
+msgstr "Pahoittelut, et ole tyyliäni."
+
+#, c-format
+msgid "%u needs authorization"
+msgstr "%u tarvitsee valtuutuksen"
+
 msgid "Add buddy authorize"
-msgstr "Lisää tuttava tuttavaluetteloon?"
-
-msgid "Input request here"
-msgstr "Anna syy tähän"
+msgstr "Lisää tuttavavaltuutus"
+
+msgid "Enter request here"
+msgstr "Syötä pyyntö tähän"
 
 msgid "Would you be my friend?"
 msgstr "Haluaisitko olla kaverini?"
@@ -7260,28 +7255,25 @@
 msgid "QQ Buddy"
 msgstr "QQ-tuttava"
 
-#, fuzzy
 msgid "Add buddy"
 msgstr "Lisää tuttava"
 
 msgid "Invalid QQ Number"
 msgstr "Epäkelpo QQ-numero"
 
-#, fuzzy
 msgid "Failed sending authorize"
-msgstr "Voisitko valtuuttaa minut?"
-
-#, fuzzy, c-format
-msgid "Failed removing buddy %d"
-msgstr "Tuttavaa poistaminen epäonnistui"
-
-#, fuzzy, c-format
+msgstr "Valtuutuksen lähetys epäonnistui"
+
+#, c-format
+msgid "Failed removing buddy %u"
+msgstr "Tuttavan %u poistaminen epäonnistui"
+
+#, c-format
 msgid "Failed removing me from %d's buddy list"
-msgstr "Poista toisen tuttavista"
-
-#, fuzzy
+msgstr "%d:n tuttavalistalta poistuminen epäonnistui"
+
 msgid "No reason given"
-msgstr "Syytä ei annettu."
+msgstr "Syytä ei annettu"
 
 #. only need to get value
 #, c-format
@@ -7291,7 +7283,7 @@
 msgid "Would you like to add him?"
 msgstr "Haluatko lisätä hänet?"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Rejected by %s"
 msgstr "%s hylkäsi pyynnön"
 
@@ -7314,59 +7306,55 @@
 msgid "You can only search for permanent Qun\n"
 msgstr "Voit etsiä vain pysyviä Quneja\n"
 
-#, fuzzy
+msgid "(Invalid UTF-8 string)"
+msgstr "(Viallinen UTF-8-merkkijono)"
+
 msgid "Not member"
-msgstr "En ole jäsen"
+msgstr "Ei jäsen"
 
 msgid "Member"
 msgstr "Jäsen"
 
-#, fuzzy
 msgid "Requesting"
-msgstr "Pyyntövalintaikkuna"
-
-#, fuzzy
+msgstr "Pyydetään"
+
 msgid "Admin"
-msgstr "Ylläpitäjän hälytys"
-
-#, fuzzy
+msgstr "Ylläpitäjä"
+
 msgid "Notice"
-msgstr "Huomautus:"
-
-#, fuzzy
+msgstr "Huomautus"
+
 msgid "Detail"
 msgstr "Yksityiskohdat"
 
 msgid "Creator"
 msgstr "Luoja"
 
-#, fuzzy
 msgid "About me"
-msgstr "Tietoja %sistä"
-
-#, fuzzy
+msgstr "Omat tiedot"
+
 msgid "Category"
-msgstr "Keskusteluvirhe"
-
-#, fuzzy
+msgstr "Luokka"
+
 msgid "The Qun does not allow others to join"
-msgstr "Tämä ryhmä ei salli muiden liittyä"
-
-#, fuzzy
+msgstr "Tämä Qun ei salli muiden liittyä"
+
 msgid "Join QQ Qun"
-msgstr "Liity ryhmäkeskusteluun"
-
-#, c-format
-msgid "Successfully joined Qun %s (%d)"
-msgstr ""
-
-#, fuzzy
+msgstr "Liity QQ Quniin"
+
+msgid "Input request here"
+msgstr "Anna syy tähän"
+
+#, c-format
+msgid "Successfully joined Qun %s (%u)"
+msgstr "Liityttiin onnistuneesti Quniin %s (%u)"
+
 msgid "Successfully joined Qun"
-msgstr "Qun-jäsentä muokattu onnistuneesti"
-
-#, c-format
-msgid "Qun %d denied to join"
-msgstr "Qun %d kielsi liittymisen"
+msgstr "Liityttiin onnistuneesti Quniin"
+
+#, c-format
+msgid "Qun %u denied from joining"
+msgstr "Qun %u kielsi liittymisen"
 
 msgid "QQ Qun Operation"
 msgstr "QQ Qun -toiminta"
@@ -7374,12 +7362,11 @@
 msgid "Failed:"
 msgstr "Epäonnistui:"
 
-msgid "Join Qun, Unknow Reply"
+msgid "Join Qun, Unknown Reply"
 msgstr "Quniin liittyminen, tuntematon vastaus"
 
-#, fuzzy
 msgid "Quit Qun"
-msgstr "QQ Qun"
+msgstr "Poistu Qunista"
 
 msgid ""
 "Note, if you are the creator, \n"
@@ -7388,51 +7375,47 @@
 "Huomaa, että olet samalla Qunin luoja, \n"
 "Tämä toiminto poistaa lopulta tämän Qunin."
 
-#, fuzzy
-msgid "Sorry, you are not our style ..."
-msgstr "Pahoittelut, en ole kiinnostunut..."
-
-#, fuzzy
-msgid "Successfully changed Qun member"
-msgstr "Qun-jäsentä muokattu onnistuneesti"
-
-#, fuzzy
+msgid "Sorry, you are not our style"
+msgstr "Pahoittelut, et ole tyyliämme"
+
+msgid "Successfully changed Qun members"
+msgstr "Qun-jäseniä muokattu onnistuneesti"
+
 msgid "Successfully changed Qun information"
 msgstr "Qun-tietojen muokkaus onnistui"
 
 msgid "You have successfully created a Qun"
 msgstr "Qun:n luonti onnistui"
 
-#, fuzzy
-msgid "Would you like to set detailed information now?"
-msgstr "Haluatko asettaa Qun:n yksityiskohdat nyt?"
+msgid "Would you like to set up detailed information now?"
+msgstr "Haluatko asettaa yksityiskohtaiset tiedot nyt?"
 
 msgid "Setup"
 msgstr "Asetukset"
 
-#, fuzzy, c-format
-msgid "%d requested to join Qun %d for %s"
-msgstr "%d pyysi liittymään Quniin %d"
-
-#, c-format
-msgid "%d request to join Qun %d"
-msgstr "%d pyysi liittymään Quniin %d"
-
-#, fuzzy, c-format
-msgid "Failed to join Qun %d, operated by admin %d"
-msgstr "Liittyminen tuttavan seuraan keskusteluhuoneeseen epäonnistui"
-
-#, c-format
-msgid "<b>Joining Qun %d is approved by admin %d for %s</b>"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "<b>Removed buddy %d.</b>"
-msgstr "Poista tuttava"
-
-#, c-format
-msgid "<b>New buddy %d joined.</b>"
-msgstr ""
+#, c-format
+msgid "%u requested to join Qun %u for %s"
+msgstr "%u pyysi liittymään Quniin %u: %s"
+
+#, c-format
+msgid "%u request to join Qun %u"
+msgstr "%u pyysi liittymään Quniin %u"
+
+#, c-format
+msgid "Failed to join Qun %u, operated by admin %u"
+msgstr "Liittyminen Quniin %u epäonnistui, ylläpitäjä %u"
+
+#, c-format
+msgid "<b>Joining Qun %u is approved by admin %u for %s</b>"
+msgstr "<b>Quniin %u liittyminen hyväksyttiin ylläpitäjän %u toimesta: %s</b>"
+
+#, c-format
+msgid "<b>Removed buddy %u.</b>"
+msgstr "<b>Poistettiin tuttava %u.</b>"
+
+#, c-format
+msgid "<b>New buddy %u joined.</b>"
+msgstr "<b>Uusi tuttava %u liittyi.</b>"
 
 #, c-format
 msgid "Unknown-%d"
@@ -7468,37 +7451,36 @@
 msgid "Invalid name"
 msgstr "Epäkelpo nimi"
 
-#, fuzzy
 msgid "Select icon..."
-msgstr "Valitse kansio..."
-
-#, fuzzy, c-format
+msgstr "Valitse kuvake..."
+
+#, c-format
 msgid "<b>Login time</b>: %d-%d-%d, %d:%d:%d<br>\n"
-msgstr "<b>Kirjautumisaika</b>: %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Kirjautumisaika</b>: %d-%d-%d, %d:%d:%d<br>\n"
+
+#, c-format
 msgid "<b>Total Online Buddies</b>: %d<br>\n"
-msgstr "<b>Parhaillaan kirjautuneena</b>: %d<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Yhteensä tuttavia linjoilla</b>: %d<br>\n"
+
+#, c-format
 msgid "<b>Last Refresh</b>: %d-%d-%d, %d:%d:%d<br>\n"
-msgstr "<b>Viimeisin päivitys:</b> %s<br>\n"
+msgstr "<b>Viimeisin päivitys</b>: %d-%d-%d, %d:%d:%d<br>\n"
 
 #, c-format
 msgid "<b>Server</b>: %s<br>\n"
 msgstr "<b>Palvelin:</b>: %s<br>\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "<b>Client Tag</b>: %s<br>\n"
-msgstr "<b>Kirjautumisaika</b>: %s<br>\n"
+msgstr "<b>Asiakasmerkintä</b>: %s<br>\n"
 
 #, c-format
 msgid "<b>Connection Mode</b>: %s<br>\n"
 msgstr "<b>Yhteystila</b>: %s<br>\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "<b>My Internet IP</b>: %s:%d<br>\n"
-msgstr "<b>Internet-osoitteeni:</b> %s<br>\n"
+msgstr "<b>Internet-IP-osoitteeni</b>: %s:%d<br>\n"
 
 #, c-format
 msgid "<b>Sent</b>: %lu<br>\n"
@@ -7520,45 +7502,41 @@
 msgid "<b>Received Duplicate</b>: %lu<br>\n"
 msgstr "<b>Vastaanotettiin moneen kertaan</b>: %lu<br>\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "<b>Time</b>: %d-%d-%d, %d:%d:%d<br>\n"
-msgstr "<b>Kirjautumisaika</b>: %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Aika</b>: %d-%d-%d, %d:%d:%d<br>\n"
+
+#, c-format
 msgid "<b>IP</b>: %s<br>\n"
-msgstr "<b>Palvelin:</b>: %s<br>\n"
+msgstr "<b>IP</b>: %s<br>\n"
 
 msgid "Login Information"
 msgstr "Kirjautumistietoja"
 
-#, fuzzy
 msgid "<p><b>Original Author</b>:<br>\n"
-msgstr "<b>Ulkoinen käyttäjä</b><br>"
+msgstr "<p><b>Alkuperäinen tekijä</b>:<br>\n"
 
 msgid "<p><b>Code Contributors</b>:<br>\n"
-msgstr ""
-
-#, fuzzy
+msgstr "<p><b>Koodin tuottajat</b>:<br>\n"
+
 msgid "<p><b>Lovely Patch Writers</b>:<br>\n"
-msgstr "<b>Viimeisin päivitys:</b> %s<br>\n"
-
-#, fuzzy
+msgstr "<p><b>Ihanat päivitysten kirjoittajat</b>:<br>\n"
+
 msgid "<p><b>Acknowledgement</b>:<br>\n"
-msgstr "<b>Lähetetty</b>: %lu<br>\n"
+msgstr "<p><b>Tunnustus</b>:<br>\n"
 
 msgid "<p><i>And, all the boys in the backroom...</i><br>\n"
-msgstr ""
+msgstr "<p><i>Ja, kaikki pojat takahuoneessa...</i><br>\n"
 
 msgid "<i>Feel free to join us!</i> :)"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "About OpenQ r%s"
-msgstr "Tietoja %sistä"
-
-#, fuzzy
+msgstr "<i>Liity vapaasti joukkoomme!</i> :)"
+
+#, c-format
+msgid "About OpenQ %s"
+msgstr "Tietoja OpenQ %s:sta"
+
 msgid "Change Icon"
-msgstr "Tallenna kuvake"
+msgstr "Vaihda kuvake"
 
 msgid "Change Password"
 msgstr "Vaihda salasana"
@@ -7567,11 +7545,10 @@
 msgstr "Tilin tiedot"
 
 msgid "Update all QQ Quns"
-msgstr ""
-
-#, fuzzy
+msgstr "Päivitä kaikki QQ Qunit"
+
 msgid "About OpenQ"
-msgstr "Tietoja %sistä"
+msgstr "Tietoja OpenQ:sta"
 
 #. *< type
 #. *< ui_requirement
@@ -7583,27 +7560,24 @@
 #. *< version
 #. *  summary
 #. *  description
-#, fuzzy
 msgid "QQ Protocol Plugin"
 msgstr "QQ-yhteyskäytäntöliitännäinen"
 
 msgid "Auto"
 msgstr "Auto"
 
-#, fuzzy
 msgid "Select Server"
-msgstr "Valitse käyttäjä"
+msgstr "Valitse palvelin"
 
 msgid "QQ2005"
-msgstr ""
+msgstr "QQ2005"
 
 msgid "QQ2007"
-msgstr ""
+msgstr "QQ2007"
 
 msgid "QQ2008"
-msgstr ""
-
-#. #endif
+msgstr "QQ2008"
+
 msgid "Connect by TCP"
 msgstr "Yhdistetään käyttäen TCP:tä"
 
@@ -7613,25 +7587,18 @@
 msgid "Show server news"
 msgstr "Näytä palvelinuutiset"
 
-#, fuzzy
 msgid "Keep alive interval (seconds)"
-msgstr "Jatkuvan yhteydenpidon aikaväli (s)"
-
-#, fuzzy
+msgstr "Jatkuvan yhteydenpidon aikaväli (sekunneissa)"
+
 msgid "Update interval (seconds)"
-msgstr "Päivitysten aikaväli (s)"
-
-#, fuzzy
-msgid "Can not decrypt server reply"
-msgstr "Kirjautumisvastauksen salausta ei voi purkaa"
-
-#, fuzzy
-msgid "Can not decrypt get server reply"
-msgstr "Kirjautumisvastauksen salausta ei voi purkaa"
+msgstr "Päivitysten aikaväli (sekunneissa)"
+
+msgid "Cannot decrypt server reply"
+msgstr "Palvelinvastauksen salausta ei voi purkaa"
 
 #, c-format
 msgid "Failed requesting token, 0x%02X"
-msgstr ""
+msgstr "Poletin pyyntö epäonnistui, 0x%02X"
 
 #, c-format
 msgid "Invalid token len, %d"
@@ -7639,56 +7606,53 @@
 
 #. extend redirect used in QQ2006
 msgid "Redirect_EX is not currently supported"
-msgstr ""
+msgstr "Redirect_EX ei ole tällä hetkellä tuettuna"
 
 #. need activation
 #. need activation
 #. need activation
-#, fuzzy
 msgid "Activation required"
-msgstr "Vaatii rekisteröinnin"
-
-#, fuzzy, c-format
-msgid "Unknow reply code when login (0x%02X)"
-msgstr "Epäkelpo poletin vastauskoodi, 0x%02X"
-
-msgid "Keep alive error"
-msgstr "Jatkuvan yhteydenpidon virhe"
-
-#, fuzzy
-msgid "Requesting captcha ..."
-msgstr "Pyydetään käyttäjän %s huomiota..."
-
-msgid "Checking code of captcha ..."
-msgstr ""
-
-msgid "Failed captcha verify"
-msgstr ""
-
-#, fuzzy
+msgstr "Vaatii aktivoinnin"
+
+#, c-format
+msgid "Unknown reply code when logging in (0x%02X)"
+msgstr "Tuntematon vastauskoodi kirjauduttaessa (0x%02X)"
+
+msgid "Could not decrypt server reply"
+msgstr "Palvelinvastauksen salausta ei voi purkaa"
+
+msgid "Requesting captcha"
+msgstr "Pyydetään captchaa"
+
+msgid "Checking captcha"
+msgstr "Tarkistetaan captchaa"
+
+msgid "Failed captcha verification"
+msgstr "Captchan tarkistus epäonnistui"
+
 msgid "Captcha Image"
-msgstr "Tallenna kuva"
-
-#, fuzzy
+msgstr "Captcha-kuva"
+
 msgid "Enter code"
-msgstr "Anna salasana"
-
-msgid "QQ Captcha Verifing"
-msgstr ""
-
-#, fuzzy
+msgstr "Syötä koodi"
+
+msgid "QQ Captcha Verification"
+msgstr "QQ-Captcha-tarkistus"
+
 msgid "Enter the text from the image"
-msgstr "Anna ryhmän nimi"
-
-#, c-format
-msgid "Unknow reply code when checking password (0x%02X)"
-msgstr ""
-
-#, c-format
-msgid ""
-"Unknow reply code when login (0x%02X):\n"
+msgstr "Syötä teksti kuvasta"
+
+#, c-format
+msgid "Unknown reply when checking password (0x%02X)"
+msgstr "Tuntematon vastaus tarkistettaessa salasanaa (0x%02X)"
+
+#, c-format
+msgid ""
+"Unknown reply code when logging in (0x%02X):\n"
 "%s"
 msgstr ""
+"Tuntematon vastauskoosi kirjauduttaessa sisään (0x%02X):\n"
+"%s"
 
 #. we didn't successfully connect. tdt->toc_fd is valid here
 msgid "Unable to connect."
@@ -7697,14 +7661,6 @@
 msgid "Socket error"
 msgstr "Pistokevirhe"
 
-#, c-format
-msgid ""
-"Lost connection with server:\n"
-"%d, %s"
-msgstr ""
-"Yhteys palvelimeen katkesi:\n"
-"%d, %s"
-
 msgid "Unable to read from socket"
 msgstr "Ei kyetty lukemaan pistoketta"
 
@@ -7714,12 +7670,11 @@
 msgid "Connection lost"
 msgstr "Yhteys katkesi"
 
-#, fuzzy
-msgid "Get server ..."
-msgstr "Aseta käyttäjätiedot..."
-
-msgid "Request token"
-msgstr "Pyydä poletti"
+msgid "Getting server"
+msgstr "Haetaan palvelinta"
+
+msgid "Requesting token"
+msgstr "Pyydetään polettia"
 
 msgid "Couldn't resolve host"
 msgstr "Yhteyttä isäntään ei voi löytää"
@@ -7727,63 +7682,62 @@
 msgid "Invalid server or port"
 msgstr "Epäkelpo palvelin tai portti"
 
-#, fuzzy
-msgid "Connecting server ..."
-msgstr "Yhdistä palvelimeen"
+msgid "Connecting to server"
+msgstr "Yhdistetään palvelimelle"
 
 msgid "QQ Error"
 msgstr "QQ-virhe"
 
-# c-format
-msgid "Failed to send IM."
-msgstr "Viestin lähettäminen epäonnistui."
-
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Server News:\n"
 "%s\n"
 "%s\n"
 "%s"
-msgstr "QQ-palvelimen uutisia"
+msgstr ""
+"Palvelimen uutisia:\n"
+"%s\n"
+"%s\n"
+"%s"
+
+#, c-format
+msgid "%s:%s"
+msgstr "%s:%s"
 
 #, c-format
 msgid "From %s:"
 msgstr "Lähettäjä %s:"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Server notice From %s: \n"
 "%s"
-msgstr "Palvelimen ohjeet: %s"
-
-msgid "Unknow SERVER CMD"
+msgstr ""
+"Palvelinilmoitus käyttäjältä %s: \n"
+"%s"
+
+msgid "Unknown SERVER CMD"
 msgstr "Tuntematon SERVER CMD"
 
 #, c-format
 msgid ""
 "Error reply of %s(0x%02X)\n"
-"Room %d, reply 0x%02X"
-msgstr ""
-"Virheellinen vastaus kohteesta %s(0x%02X)\n"
-"Huone %d, vastaus 0x%02X"
+"Room %u, reply 0x%02X"
+msgstr ""
+"Virheellinen vastaus %s(0x%02X)\n"
+"Huone %u, vastaus 0x%02X"
 
 msgid "QQ Qun Command"
 msgstr "QQ-Qun-komento"
 
-#, fuzzy, c-format
-msgid "Not a member of room \"%s\"\n"
-msgstr "Sinä et ole ryhmän \"%s\" jäsen\n"
-
-msgid "Can not decrypt login reply"
+msgid "Could not decrypt login reply"
 msgstr "Kirjautumisvastauksen salausta ei voi purkaa"
 
-#, fuzzy
-msgid "Unknow LOGIN CMD"
-msgstr "Tuntematon vastaus-CMD"
-
-#, fuzzy
-msgid "Unknow CLIENT CMD"
-msgstr "Tuntematon SERVER CMD"
+msgid "Unknown LOGIN CMD"
+msgstr "Tuntematon LOGIN CMD"
+
+msgid "Unknown CLIENT CMD"
+msgstr "Tuntematon CLIENT CMD"
 
 #, c-format
 msgid "%d has declined the file %s"
@@ -9746,13 +9700,8 @@
 msgid "Last Update"
 msgstr "Edellinen päivitys"
 
-#, c-format
-msgid "User information for %s unavailable"
-msgstr "%s:n käyttäjätiedot eivät ole saatavilla"
-
-msgid ""
-"Sorry, this profile seems to be in a language or format that is not "
-"supported at this time."
+msgid ""
+"This profile is in a language or format that is not supported at this time."
 msgstr ""
 "Tämä profiili näyttää käyttävän kieltä tai muotoa jota ei tueta tällä "
 "hetkellä."
@@ -10363,7 +10312,7 @@
 msgid "Protocol"
 msgstr "Yhteyskäytäntö"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "<span size='larger' weight='bold'>Welcome to %s!</span>\n"
 "\n"
@@ -10377,10 +10326,10 @@
 msgstr ""
 "<span size='larger' weight='bold'>Tervetuloa %siin!</span>\n"
 "\n"
-"Pikaviestintilejä ei ole määritelty. Yhdistääksesi %sillä napsauta <b>Lisää</"
-"b>-painiketta ja määritä ensimmäisen käyttäjätilisi tiedot. Jos haluat %sin "
-"yhdistävän useampiin pikaviestintileihin, napsauta uudestaan <b>Lisää</b>-"
-"painiketta määritelläksesi ne kaikki.\n"
+"Pikaviestintilejä ei ole määritelty. Yhdistääksesi %sillä napsauta "
+"<b>Lisää...</b>-painiketta ja määritä ensimmäisen käyttäjätilisi tiedot. Jos "
+"haluat %sin yhdistävän useampiin pikaviestintileihin, napsauta uudelleen "
+"<b>Lisää...</b>-painiketta määritelläksesi ne kaikki.\n"
 "\n"
 "Voit palata tähän ikkunaan lisäämään, muokkaamaan tai poistamaan tilejä "
 "valitsemalla <b>Käyttäjätilit->Tilien hallinta</b> Tuttavat-ikkunassa."
@@ -10805,9 +10754,8 @@
 msgid "Auto_join when account becomes online."
 msgstr "Liity automaattisesti kun käyttä_jätili pääsee linjoille."
 
-#, fuzzy
 msgid "_Remain in chat after window is closed."
-msgstr "Piilota ry_hmäkeskustelu kun ikkuna on suljettu."
+msgstr "Pysy _ryhmäkeskustelussa ikkunan sulkemisen jälkeen."
 
 msgid "Please enter the name of the group to be added."
 msgstr "Anna lisättävän ryhmän nimi."
@@ -11181,11 +11129,10 @@
 msgstr "Vakavat virheet"
 
 msgid "bug master"
-msgstr ""
-
-#, fuzzy
+msgstr "ohjelmavirheiden hallitsija"
+
 msgid "artist"
-msgstr "Esittäjä"
+msgstr "esittäjä"
 
 #. feel free to not translate this
 msgid "Ka-Hing Cheung"
@@ -11194,9 +11141,8 @@
 msgid "support"
 msgstr "tuki"
 
-#, fuzzy
 msgid "webmaster"
-msgstr "kehittäjä & verkkosivujen ylläpitäjä"
+msgstr "verkkosivujen ylläpitäjä"
 
 msgid "Senior Contributor/QA"
 msgstr "Vanhempi osallistuja/laadunvarmistus"
@@ -11218,7 +11164,7 @@
 msgstr "tuki/laadunvarmistus"
 
 msgid "XMPP"
-msgstr ""
+msgstr "XMPP"
 
 msgid "original author"
 msgstr "alkuperäinen tekijä"
@@ -12080,7 +12026,7 @@
 "                      Ilman tätä vain ensimmäinen tili otetaan käyttöön).\n"
 "  -v, --version       näytä nykyinen versionumero ja poistu\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "%s %s has segfaulted and attempted to dump a core file.\n"
 "This is a bug in the software and has happened through\n"
@@ -12107,11 +12053,6 @@
 "pinolistaus muistivedostiedostosta. Jos et tiedä kuinka\n"
 "pinolistaus (backtrace) haetaan, lue ohjeita osoitteessa\n"
 "%swiki/GetABacktrace\n"
-"\n"
-"Jos tarvitset lisäapua, lähetä pikaviesti joko tunnukselle SeanEgn tai "
-"LSchiere (AIMissa). Seanin ja Luken yhteystiedot muilla yhteyskäytännöillä "
-"ovat osoitteessa\n"
-"%swiki/DeveloperPages\n"
 
 #. Translators may want to transliterate the name.
 #. It is not to be translated.
@@ -12806,13 +12747,11 @@
 msgid "Custom Smiley Manager"
 msgstr "Omien hymiöiden hallinta"
 
-#, fuzzy
 msgid "Click to change your buddyicon for this account."
-msgstr "Käytä tätä tuttavakuvaketta tälle käyttäjät_ilille:"
-
-#, fuzzy
+msgstr "Napsauta muuttaaksesi tämän käyttäjätilin tuttavakuvaketta."
+
 msgid "Click to change your buddyicon for all accounts."
-msgstr "Käytä tätä tuttavakuvaketta tälle käyttäjät_ilille:"
+msgstr "Napsauta muuttaaksesi kaikkien käyttäjätilien tuttavakuvaketta."
 
 msgid "Waiting for network connection"
 msgstr "Odotetaan verkkoyhteyttä"
@@ -12948,13 +12887,11 @@
 msgid "_Invite"
 msgstr "_Kutsu"
 
-#, fuzzy
 msgid "_Modify..."
-msgstr "_Muokkaa"
-
-#, fuzzy
+msgstr "_Muokkaa..."
+
 msgid "_Add..."
-msgstr "_Lisää"
+msgstr "_Lisää..."
 
 msgid "_Open Mail"
 msgstr "_Avaa sähköposti"
@@ -12977,12 +12914,11 @@
 msgid "none"
 msgstr "ei mitään"
 
-#, fuzzy
 msgid "Small"
-msgstr "_Pienempi"
+msgstr "Pienet"
 
 msgid "Smaller versions of the default smilies"
-msgstr ""
+msgstr "Pienemmät versiot oletushymiöistä"
 
 msgid "Response Probability:"
 msgstr "Vastaustodennäköisyys:"
@@ -13446,9 +13382,8 @@
 msgid "Set window manager \"_URGENT\" hint"
 msgstr "Aseta ikkunointiohjelman \"_URGENT\"(kiireellinen)-lippu"
 
-#, fuzzy
 msgid "_Flash window"
-msgstr "_Ryhmäkeskusteluikkunoille"
+msgstr "_Välkäytä ikkunaa"
 
 #. Raise window method button
 msgid "R_aise conversation window"
@@ -13633,18 +13568,16 @@
 
 #, c-format
 msgid "You can upgrade to %s %s today."
-msgstr ""
+msgstr "Voit päivittää versioon %s %s."
 
 msgid "New Version Available"
 msgstr "Uusi versio saatavilla"
 
-#, fuzzy
 msgid "Later"
-msgstr "Päiväys"
-
-#, fuzzy
+msgstr "Myöhemmin"
+
 msgid "Download Now"
-msgstr "Lataa %s: %s"
+msgstr "Lataa nyt"
 
 #. *< type
 #. *< ui_requirement
@@ -13964,6 +13897,47 @@
 "Tätä liitännäistä voidaan käyttää XMPP-palvelimien tai -asiakasohjelmien "
 "virheenjäljitykseen."
 
+#~ msgid "Connection to server lost (no data received within %d second)"
+#~ msgid_plural ""
+#~ "Connection to server lost (no data received within %d seconds)"
+#~ msgstr[0] ""
+#~ "Yhteys palvelimelle katkesi (dataa ei vastaanotettu %d sekunnissa)"
+#~ msgstr[1] ""
+#~ "Yhteys palvelimelle katkesi (dataa ei vastaanotettu %d sekunnissa)"
+
+#, fuzzy
+#~ msgid "Add buddy Q&A"
+#~ msgstr "Lisää tuttava"
+
+#, fuzzy
+#~ msgid "Can not decrypt get server reply"
+#~ msgstr "Kirjautumisvastauksen salausta ei voi purkaa"
+
+#~ msgid "Keep alive error"
+#~ msgstr "Jatkuvan yhteydenpidon virhe"
+
+#~ msgid ""
+#~ "Lost connection with server:\n"
+#~ "%d, %s"
+#~ msgstr ""
+#~ "Yhteys palvelimeen katkesi:\n"
+#~ "%d, %s"
+
+#, fuzzy
+#~ msgid "Connecting server ..."
+#~ msgstr "Yhdistä palvelimeen"
+
+# c-format
+#~ msgid "Failed to send IM."
+#~ msgstr "Viestin lähettäminen epäonnistui."
+
+#, fuzzy
+#~ msgid "Not a member of room \"%s\"\n"
+#~ msgstr "Sinä et ole ryhmän \"%s\" jäsen\n"
+
+#~ msgid "User information for %s unavailable"
+#~ msgstr "%s:n käyttäjätiedot eivät ole saatavilla"
+
 #~ msgid "A group with the name already exists."
 #~ msgstr "Valitun niminen ryhmä on jo olemassa"
 
@@ -14059,15 +14033,6 @@
 #~ msgid "Change Qun information"
 #~ msgstr "Kanavatiedot"
 
-#~ msgid ""
-#~ "%s\n"
-#~ "\n"
-#~ "%s"
-#~ msgstr ""
-#~ "%s\n"
-#~ "\n"
-#~ "%s"
-
 #~ msgid "System Message"
 #~ msgstr "Järjestelmäviesti"
 
@@ -15919,9 +15884,6 @@
 #~ msgid "Away title: "
 #~ msgstr "Poissaolon otsikko: "
 
-#~ msgid "Buddy List Error"
-#~ msgstr "Tuttavalistan virhe"
-
 #~ msgid ""
 #~ "Usage: %s command [OPTIONS] [URI]\n"
 #~ "\n"
--- a/po/fr.po	Tue Dec 16 19:17:44 2008 +0000
+++ b/po/fr.po	Tue Dec 16 19:18:41 2008 +0000
@@ -21,8 +21,8 @@
 msgstr ""
 "Project-Id-Version: Pidgin\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-12-01 15:52-0800\n"
-"PO-Revision-Date: 2008-08-26 14:30+0200\n"
+"POT-Creation-Date: 2008-12-16 10:10+0100\n"
+"PO-Revision-Date: 2008-12-16 10:09+0100\n"
 "Last-Translator: Éric Boumaour <zongo_fr@users.sourceforge.net>\n"
 "Language-Team: fr <fr@li.org>\n"
 "MIME-Version: 1.0\n"
@@ -85,7 +85,6 @@
 msgid "Remember password"
 msgstr "Mémoriser le mot de passe"
 
-#, fuzzy
 msgid "There are no protocol plugins installed."
 msgstr "Aucun plugin de protocole n'est installé."
 
@@ -1526,10 +1525,10 @@
 msgstr "Pas de groupement"
 
 msgid "Nested Subgroup"
-msgstr ""
+msgstr "Sous-groupe emboité"
 
 msgid "Nested Grouping (experimental)"
-msgstr ""
+msgstr "Emboitage de groupes (expérimental)"
 
 msgid "Provides alternate buddylist grouping options."
 msgstr "Fournit des options supplémentaires pour le regroupement des contacts."
@@ -1848,7 +1847,7 @@
 
 #, c-format
 msgid "Resolver process exited without answering our request"
-msgstr ""
+msgstr "Le processus de résolution s'est arrêté sans répondre."
 
 #, c-format
 msgid "Thread creation failure: %s"
@@ -4578,7 +4577,6 @@
 
 #. this should probably be part of global smiley theme settings later on,
 #. shared with MSN
-#, fuzzy
 msgid "Show Custom Smileys"
 msgstr "Afficher les frimousses personnalisées"
 
@@ -4708,6 +4706,19 @@
 msgid "Unable to retrieve MSN Address Book"
 msgstr "Impossible de récupérer le carnet d'adresses MSN"
 
+#. only notify the user about problems adding to the friends list
+#. * maybe we should do something else for other lists, but it probably
+#. * won't cause too many problems if we just ignore it
+#, c-format
+msgid "Unable to add \"%s\"."
+msgstr "Impossible d'ajouter « %s »"
+
+msgid "Buddy Add error"
+msgstr "Erreur à l'ajout de l'utilisateur"
+
+msgid "The username specified does not exist."
+msgstr "Le nom d'utilisateur fourni est non valide."
+
 #, c-format
 msgid "Buddy list synchronization issue in %s (%s)"
 msgstr "Problème de synchronisation de la liste de contact avec %s (%s)"
@@ -4936,9 +4947,9 @@
 msgid "Passport account not yet verified"
 msgstr "Le compte Passeport n'est pas encore validé"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Passport account suspended"
-msgstr "Le compte Passeport n'est pas encore validé"
+msgstr "Le compte Passeport est suspendu"
 
 #, c-format
 msgid "Bad ticket"
@@ -4952,13 +4963,11 @@
 msgid "MSN Error: %s\n"
 msgstr "Erreur MSN : %s\n"
 
-#, fuzzy
 msgid "Other Contacts"
-msgstr "Méthodes de contact préférées"
-
-#, fuzzy
+msgstr "AUtres contacts"
+
 msgid "Non-IM Contacts"
-msgstr "Supprimer un contact"
+msgstr "Contacts non instantanés"
 
 msgid "Nudge"
 msgstr "Nudge"
@@ -5031,6 +5040,12 @@
 msgid "Page"
 msgstr "Envoyer"
 
+msgid "Playing a game"
+msgstr "Joue"
+
+msgid "Working"
+msgstr "Travaille"
+
 msgid "Has you"
 msgstr "Vous êtes dans sa liste"
 
@@ -5067,6 +5082,12 @@
 msgid "Album"
 msgstr "Album"
 
+msgid "Game Title"
+msgstr "Nom du jeu"
+
+msgid "Office Title"
+msgstr "Nom du travail"
+
 msgid "Set Friendly Name..."
 msgstr "Changer l'alias..."
 
@@ -5259,8 +5280,8 @@
 "Impossible de récupérer des informations sur le profil de l'utilisateur. Il "
 "est possible que cet utilisateur n'existe pas."
 
-msgid "Profile URL"
-msgstr "Lien du profil"
+msgid "View web profile"
+msgstr "Voir le profil web"
 
 #. *< type
 #. *< ui_requirement
@@ -5315,9 +5336,8 @@
 msgid "Unable to add user"
 msgstr "Impossible d'ajouter un utilisateur"
 
-#, fuzzy
 msgid "The following users are missing from your addressbook"
-msgstr "Voici les résultats de votre recherche."
+msgstr "Les utilisateurs suivants manquent dans votre carnet d'adresse"
 
 #, c-format
 msgid "Unable to add user on %s (%s)"
@@ -5509,20 +5529,11 @@
 msgid "%s has removed you from his or her buddy list."
 msgstr "L'utilisateur %s vous a supprimé de sa liste de contacts."
 
-#, fuzzy
 msgid "Delete Buddy from Address Book?"
-msgstr "Ajouter au carnet d'adresses"
-
-#, fuzzy
+msgstr "Supprimer le contact du carnet d'adresses ?"
+
 msgid "Do you want to delete this buddy from your address book as well?"
-msgstr "Voulez-vous l'ajouter à votre liste de contacts ?"
-
-#. only notify the user about problems adding to the friends list
-#. * maybe we should do something else for other lists, but it probably
-#. * won't cause too many problems if we just ignore it
-#, c-format
-msgid "Unable to add \"%s\"."
-msgstr "Impossible d'ajouter « %s »"
+msgstr "Voulez-vous aussi supprimer ce contact de votre carnet d'adresses ?"
 
 msgid "The username specified is invalid."
 msgstr "Le nom d'utilisateur fourni est non valide."
@@ -5530,6 +5541,9 @@
 msgid "This Hotmail account may not be active."
 msgstr "Ce compte Hotmail ne semble pas être actif."
 
+msgid "Profile URL"
+msgstr "Lien du profil"
+
 #. *< type
 #. *< ui_requirement
 #. *< flags
@@ -5543,18 +5557,12 @@
 msgid "MSN Protocol Plugin"
 msgstr "Plugin pour le protocole MSN"
 
-msgid "Missing Cipher"
-msgstr "Chiffre manquant"
-
-msgid "The RC4 cipher could not be found"
-msgstr "Le chiffre RC4 n'a pas été trouvé."
-
-msgid ""
-"Upgrade to a libpurple with RC4 support (>= 2.0.1). MySpaceIM plugin will "
-"not be loaded."
-msgstr ""
-"Le plugin MySpaceIM ne sera pas chargé. Mettez à jour libpurple avec le "
-"support de RC4 (>= 2.0.1)."
+#, c-format
+msgid "No such user: %s"
+msgstr "Utilisateur inconnu : %s"
+
+msgid "User lookup"
+msgstr "Recherche d'utilisateur"
 
 msgid "Reading challenge"
 msgstr "Lecture du défi"
@@ -5565,12 +5573,19 @@
 msgid "Logging in"
 msgstr "Connexion"
 
-#, c-format
-msgid "Connection to server lost (no data received within %d second)"
-msgid_plural "Connection to server lost (no data received within %d seconds)"
-msgstr[0] "Connexion avec le serveur perdue (aucune donnée depuis %d seconde)."
-msgstr[1] ""
-"Connexion avec le serveur perdue (aucune donnée depuis %d secondes)."
+msgid "MySpaceIM - No Username Set"
+msgstr "MySpaceIM - Aucun nom d'utilisateur fourni"
+
+msgid "You appear to have no MySpace username."
+msgstr "Il semblerait que vous n'aillez pas de nom d'utilisateur MySpace."
+
+msgid "Would you like to set one now? (Note: THIS CANNOT BE CHANGED!)"
+msgstr ""
+"Voulez-vous en fournir un maintenant ? (Attention : IL NE POURRA PLUS ÊTRE "
+"CHANGÉ !)"
+
+msgid "Lost connection with server"
+msgstr "Connexion perdue avec le serveur"
 
 #. Can't write _()'d strings in array initializers. Workaround.
 msgid "New mail messages"
@@ -5591,16 +5606,25 @@
 msgid "MySpace"
 msgstr "MySpace"
 
-msgid "MySpaceIM - No Username Set"
-msgstr "MySpaceIM - Aucun nom d'utilisateur fourni"
-
-msgid "You appear to have no MySpace username."
-msgstr "Il semblerait que vous n'aillez pas de nom d'utilisateur MySpace."
-
-msgid "Would you like to set one now? (Note: THIS CANNOT BE CHANGED!)"
-msgstr ""
-"Voulez-vous en fournir un maintenant ? (Attention : IL NE POURRA PLUS ÊTRE "
-"CHANGÉ !)"
+msgid "IM Friends"
+msgstr "Amis de messagerie"
+
+#, c-format
+msgid ""
+"%d buddy was added or updated from the server (including buddies already on "
+"the server-side list)"
+msgid_plural ""
+"%d buddies were added or updated from the server (including buddies already "
+"on the server-side list)"
+msgstr[0] ""
+"%d contact a été ajouté ou mis à jour depuis le serveur (y compris les "
+"contacts déjà sur la liste du serveur)."
+msgstr[1] ""
+"%d contacts ont été ajoutés ou mis à jour depuis le serveur (y compris les "
+"contacts déjà sur la liste du serveur)."
+
+msgid "Add contacts from server"
+msgstr "Ajouter les contacts du serveur"
 
 #. The session is now set up, ready to be connected. This emits the
 #. * signedOn signal, so clients can now do anything with msimprpl, and
@@ -5627,31 +5651,6 @@
 msgid "MySpaceIM Error"
 msgstr "Erreur MySpaceIM"
 
-msgid "Failed to add buddy"
-msgstr "Échec lors de l'ajout du contact."
-
-msgid "'addbuddy' command failed."
-msgstr "Échec de la commande « addbuddy »."
-
-msgid "persist command failed"
-msgstr "Échec de la commande « persist »."
-
-#, c-format
-msgid "No such user: %s"
-msgstr "Utilisateur inconnu : %s"
-
-msgid "User lookup"
-msgstr "Recherche d'utilisateur"
-
-msgid "Failed to remove buddy"
-msgstr "Échec lors de la suppression du contact."
-
-msgid "'delbuddy' command failed"
-msgstr "Échec de la commande « delbuddy »."
-
-msgid "blocklist command failed"
-msgstr "Échec de la commande « blocklist »."
-
 msgid "Invalid input condition"
 msgstr "Condition de saisie non valide."
 
@@ -5665,25 +5664,36 @@
 msgid "Couldn't connect to host: %s (%d)"
 msgstr "Impossible de se connecter à l'hôte : %s (%d)"
 
-msgid "IM Friends"
-msgstr "Amis de messagerie"
-
-#, c-format
-msgid ""
-"%d buddy was added or updated from the server (including buddies already on "
-"the server-side list)"
-msgid_plural ""
-"%d buddies were added or updated from the server (including buddies already "
-"on the server-side list)"
-msgstr[0] ""
-"%d contact a été ajouté ou mis à jour depuis le serveur (y compris les "
-"contacts déjà sur la liste du serveur)."
-msgstr[1] ""
-"%d contacts ont été ajoutés ou mis à jour depuis le serveur (y compris les "
-"contacts déjà sur la liste du serveur)."
-
-msgid "Add contacts from server"
-msgstr "Ajouter les contacts du serveur"
+msgid "Failed to add buddy"
+msgstr "Échec lors de l'ajout du contact."
+
+msgid "'addbuddy' command failed."
+msgstr "Échec de la commande « addbuddy »."
+
+msgid "persist command failed"
+msgstr "Échec de la commande « persist »."
+
+msgid "Failed to remove buddy"
+msgstr "Échec lors de la suppression du contact."
+
+msgid "'delbuddy' command failed"
+msgstr "Échec de la commande « delbuddy »."
+
+msgid "blocklist command failed"
+msgstr "Échec de la commande « blocklist »."
+
+msgid "Missing Cipher"
+msgstr "Chiffre manquant"
+
+msgid "The RC4 cipher could not be found"
+msgstr "Le chiffre RC4 n'a pas été trouvé."
+
+msgid ""
+"Upgrade to a libpurple with RC4 support (>= 2.0.1). MySpaceIM plugin will "
+"not be loaded."
+msgstr ""
+"Le plugin MySpaceIM ne sera pas chargé. Mettez à jour libpurple avec le "
+"support de RC4 (>= 2.0.1)."
 
 msgid "Add friends from MySpace.com"
 msgstr "Ajouter les amis de MySpace.com"
@@ -5725,9 +5735,6 @@
 msgid "User"
 msgstr "Utilisateur"
 
-msgid "Profile"
-msgstr "Informations"
-
 msgid "Headline"
 msgstr "En-tête"
 
@@ -5740,16 +5747,6 @@
 msgid "Client Version"
 msgstr "Version du client"
 
-#. Protocol won't log in now without a username set.. Disconnect
-msgid "No username set"
-msgstr "Aucun nom d'utilisateur fourni"
-
-msgid "MySpaceIM - Please Set a Username"
-msgstr "MySpaceIM -  Veuillez fournir un nom d'utilisateur"
-
-msgid "Please enter a username to check its availability:"
-msgstr "Saisissez un nom d'utilisateur pour vérifier sa disponibilité :"
-
 msgid "MySpaceIM - Username Available"
 msgstr "MySpaceIM - Nom d'utilisateur disponible"
 
@@ -5759,12 +5756,22 @@
 msgid "ONCE SET, THIS CANNOT BE CHANGED!"
 msgstr "Une fois choisi, IL NE POURRA PAS ÊTRE CHANGÉ !"
 
+msgid "MySpaceIM - Please Set a Username"
+msgstr "MySpaceIM -  Veuillez fournir un nom d'utilisateur"
+
 msgid "This username is unavailable."
 msgstr "Ce nom d'utilisateur n'est pas disponible."
 
 msgid "Please try another username:"
 msgstr "Veuillez en essayer un autre :"
 
+#. Protocol won't log in now without a username set.. Disconnect
+msgid "No username set"
+msgstr "Aucun nom d'utilisateur fourni"
+
+msgid "Please enter a username to check its availability:"
+msgstr "Saisissez un nom d'utilisateur pour vérifier sa disponibilité :"
+
 #. TODO: icons for each zap
 #. Lots of comments for translators:
 #. Zap means "to strike suddenly and forcefully as if with a
@@ -6212,7 +6219,7 @@
 msgstr "Plugin pour le protocole AIM"
 
 msgid "ICQ UIN..."
-msgstr ""
+msgstr "UIN ICQ..."
 
 #. *< type
 #. *< ui_requirement
@@ -6545,8 +6552,8 @@
 "You may be disconnected shortly.  You may want to use TOC until this is "
 "fixed.  Check %s for updates."
 msgstr ""
-"Vous risquez être déconnecté sous peu. Essayer d'utiliser TOC en attendant. "
-"Regardez %s pour plus d'informations."
+"Vous risquez d'être déconnecté sous peu. Veuillez essayer d'utiliser TOC "
+"entre-temps si cela arrive. Visitez %s pour plus d'informations."
 
 msgid "Unable to get a valid AIM login hash."
 msgstr "Impossible de récupérer un code de connexion AIM valide."
@@ -6723,6 +6730,9 @@
 msgid "Member Since"
 msgstr "Inscrit depuis"
 
+msgid "Profile"
+msgstr "Informations"
+
 msgid "Your AIM connection may be lost."
 msgstr "Votre connexion AIM risque d'être coupée"
 
@@ -6914,11 +6924,9 @@
 "soit commencer par une lettre et contenir uniquement des lettres, des "
 "chiffres et des espaces, soit contenir uniquement des chiffres."
 
-#, fuzzy
 msgid "Unable to Add"
 msgstr "Impossible d'ajouter"
 
-#, fuzzy
 msgid "Unable to Retrieve Buddy List"
 msgstr "Impossible de récupérer la liste de contacts"
 
@@ -7219,16 +7227,14 @@
 msgid "Other"
 msgstr "Autre"
 
-#, fuzzy
 msgid "Visible"
-msgstr "Invisible"
-
-msgid "Firend Only"
-msgstr ""
-
-#, fuzzy
+msgstr "Visible"
+
+msgid "Friend Only"
+msgstr "Amis seulement"
+
 msgid "Private"
-msgstr "Filtres"
+msgstr "Privé"
 
 msgid "QQ Number"
 msgstr "Numéro QQ"
@@ -7245,9 +7251,8 @@
 msgid "Phone Number"
 msgstr "Téléphone fixe"
 
-#, fuzzy
 msgid "Authorize adding"
-msgstr "Autoriser le contact ?"
+msgstr "Autoriser l'ajout"
 
 msgid "Cellphone Number"
 msgstr "Téléphone portable"
@@ -7255,132 +7260,108 @@
 msgid "Personal Introduction"
 msgstr "Informations personnelles"
 
-#, fuzzy
 msgid "City/Area"
-msgstr "Localité"
-
-#, fuzzy
+msgstr "Ville/Localité"
+
 msgid "Publish Mobile"
-msgstr "Téléphone portable personnel"
-
-#, fuzzy
+msgstr "Publier le téléphone portable"
+
 msgid "Publish Contact"
-msgstr "Donner un alias à un contact"
+msgstr "Publier les informations de contact"
 
 msgid "College"
 msgstr "Éducation"
 
-#, fuzzy
 msgid "Horoscope"
 msgstr "Signe du zodiaque"
 
-#, fuzzy
 msgid "Zodiac"
 msgstr "Signe du zodiaque chinois"
 
-#, fuzzy
 msgid "Blood"
-msgstr "Bloqué"
-
-#, fuzzy
+msgstr "Groupe sanguin"
+
 msgid "True"
-msgstr "Taureau"
-
-#, fuzzy
+msgstr "Vrai"
+
 msgid "False"
-msgstr "Échec"
-
-#, fuzzy
+msgstr "Faux"
+
 msgid "Modify Contact"
-msgstr "Modification du compte"
-
-#, fuzzy
+msgstr "Modifier les infos de contact"
+
 msgid "Modify Address"
-msgstr "Adresse personnelle"
-
-#, fuzzy
+msgstr "Modifier l'adresse"
+
 msgid "Modify Extended Information"
-msgstr "Modifier mes informations"
-
-#, fuzzy
+msgstr "Modifier mes infos étendues"
+
 msgid "Modify Information"
 msgstr "Modifier mes informations"
 
-#, fuzzy
 msgid "Update"
-msgstr "Dernière mise à jour"
-
-#, fuzzy
+msgstr "Mettre à jour"
+
 msgid "Could not change buddy information."
-msgstr "Veuillez saisir les informations du contact."
-
-#, c-format
-msgid "%d needs Q&A"
-msgstr ""
-
-#, fuzzy
-msgid "Add buddy Q&A"
-msgstr "Ajouter le contact"
-
-#, fuzzy
-msgid "Input answer here"
-msgstr "Saisissez votre demande"
+msgstr "Impossible de changer les informations du contact."
+
+#, c-format
+msgid "%u requires verification"
+msgstr "%u demande une vérification"
+
+msgid "Add buddy question"
+msgstr "Ajouter une question pour les nouveaux contacts"
+
+msgid "Enter answer here"
+msgstr "Saisissez la réponse ici"
 
 msgid "Send"
 msgstr "Envoyer"
 
-#, fuzzy
 msgid "Invalid answer."
-msgstr "Nom d'utilisateur non valide."
+msgstr "Réponse non valide."
 
 msgid "Authorization denied message:"
 msgstr "Message de refus d'autorisation :"
 
-#, fuzzy
-msgid "Sorry, You are not my style."
-msgstr "Désolé, tu n'es pas mon genre..."
-
-#, fuzzy, c-format
-msgid "%d needs authentication"
-msgstr "L'utilisateur %d demande une authentification."
-
-#, fuzzy
+msgid "Sorry, you're not my style."
+msgstr "Désolé, tu n'es pas mon genre."
+
+#, c-format
+msgid "%u needs authorization"
+msgstr "%u demande une autorisation"
+
 msgid "Add buddy authorize"
-msgstr "Ajouter cet utilisateur à la liste de contacts ?"
-
-msgid "Input request here"
+msgstr "Ajouter une autorisation de contact"
+
+msgid "Enter request here"
 msgstr "Saisissez votre demande"
 
 msgid "Would you be my friend?"
 msgstr "Veux-tu être mon ami ?"
 
-#, fuzzy
 msgid "QQ Buddy"
-msgstr "Contact"
-
-#, fuzzy
+msgstr "Contact QQ"
+
 msgid "Add buddy"
-msgstr "Ajouter le contact"
-
-#, fuzzy
+msgstr "Ajouter un contact"
+
 msgid "Invalid QQ Number"
-msgstr "QQ Face non valide"
-
-#, fuzzy
+msgstr "Numéro QQ non valide"
+
 msgid "Failed sending authorize"
-msgstr "Autorise moi, s'il te plaît !"
-
-#, fuzzy, c-format
-msgid "Failed removing buddy %d"
-msgstr "Échec lors de la suppression du contact."
-
-#, fuzzy, c-format
+msgstr "Échec à l'envoi de l'autorisation"
+
+#, c-format
+msgid "Failed removing buddy %u"
+msgstr "Échec lors de la suppression du contact %u"
+
+#, c-format
 msgid "Failed removing me from %d's buddy list"
-msgstr "L'utilisateur %s vous a supprimé de sa liste de contacts."
-
-#, fuzzy
+msgstr "Échec lors de ma suppression de la liste de %d"
+
 msgid "No reason given"
-msgstr "Pas de raison"
+msgstr "Pas de raison donnée"
 
 #. only need to get value
 #, c-format
@@ -7390,9 +7371,9 @@
 msgid "Would you like to add him?"
 msgstr "Voulez-vous l'ajouter ?"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Rejected by %s"
-msgstr "Refuser"
+msgstr "Refusé par %s"
 
 #, c-format
 msgid "Message: %s"
@@ -7407,81 +7388,73 @@
 msgid "QQ Qun"
 msgstr "QQ Qun"
 
-#, fuzzy
 msgid "Please enter Qun number"
-msgstr "Saisissez le nouveau nom pour %s"
-
-#, fuzzy
+msgstr "Saisissez le numéro Qun"
+
 msgid "You can only search for permanent Qun\n"
-msgstr "Vous ne pouvez cherche que les groupes QQ permanents.\n"
-
-#, fuzzy
+msgstr "Vous ne pouvez chercher que les Qun permanents.\n"
+
+msgid "(Invalid UTF-8 string)"
+msgstr "(Chaine de caractères UTF-8 non valide)"
+
 msgid "Not member"
-msgstr "Je n'en suis pas membre."
+msgstr "Non membre"
 
 msgid "Member"
 msgstr "Membre"
 
-#, fuzzy
 msgid "Requesting"
-msgstr "Boite de message pour requête"
-
-#, fuzzy
+msgstr "Demande en cours"
+
 msgid "Admin"
-msgstr "Adium"
-
-#, fuzzy
+msgstr "Admin"
+
 msgid "Notice"
-msgstr "Commentaire"
-
-#, fuzzy
+msgstr "Envoi d'infos"
+
 msgid "Detail"
-msgstr "Par défaut"
+msgstr "Détail"
 
 msgid "Creator"
 msgstr "Créateur"
 
-#, fuzzy
 msgid "About me"
-msgstr "À propos de %s"
-
-#, fuzzy
+msgstr "À mon propos"
+
 msgid "Category"
-msgstr "Erreur de discussion"
-
-#, fuzzy
+msgstr "Catégorie"
+
 msgid "The Qun does not allow others to join"
-msgstr "Ce groupe est fermé aux inscriptions."
-
-#, fuzzy
+msgstr "Ce Qun est fermé aux inscriptions"
+
 msgid "Join QQ Qun"
-msgstr "Rejoindre une discussion"
-
-#, c-format
-msgid "Successfully joined Qun %s (%d)"
-msgstr ""
-
-#, fuzzy
+msgstr "Rejoindre un Qun QQ"
+
+msgid "Input request here"
+msgstr "Saisissez votre demande"
+
+#, c-format
+msgid "Successfully joined Qun %s (%u)"
+msgstr "Entrée réussie dans le Qun %s (%u)"
+
 msgid "Successfully joined Qun"
-msgstr "Vous avez modifié la liste des membres du Qun."
-
-#, c-format
-msgid "Qun %d denied to join"
-msgstr ""
+msgstr "Entrée réussie dans le Qun"
+
+#, c-format
+msgid "Qun %u denied from joining"
+msgstr "L'entrée dans le Qun %u a été refusée"
 
 msgid "QQ Qun Operation"
 msgstr "Opération QQ Qun"
 
-#, fuzzy
 msgid "Failed:"
-msgstr "Échec"
-
-msgid "Join Qun, Unknow Reply"
-msgstr ""
-
-#, fuzzy
+msgstr "Échec :"
+
+msgid "Join Qun, Unknown Reply"
+msgstr "Joindre un Qun, réponse inconnue"
+
 msgid "Quit Qun"
-msgstr "QQ Qun"
+msgstr "Parir du Qun"
 
 msgid ""
 "Note, if you are the creator, \n"
@@ -7490,51 +7463,47 @@
 "Note : si vous en êtes le créateur, \n"
 "cette opération peut supprimer ce Qun."
 
-#, fuzzy
-msgid "Sorry, you are not our style ..."
-msgstr "Désolé, tu n'es pas mon genre..."
-
-#, fuzzy
-msgid "Successfully changed Qun member"
+msgid "Sorry, you are not our style"
+msgstr "Désolés, tu n'es pas notre genre."
+
+msgid "Successfully changed Qun members"
 msgstr "Vous avez modifié la liste des membres du Qun."
 
-#, fuzzy
 msgid "Successfully changed Qun information"
 msgstr "Vous avez modifié les informations du Qun."
 
 msgid "You have successfully created a Qun"
 msgstr "Vous avez créé un Qun."
 
-#, fuzzy
-msgid "Would you like to set detailed information now?"
-msgstr "Voulez-vous modifier les paramètres du Qun maintenant ?"
+msgid "Would you like to set up detailed information now?"
+msgstr "Voulez-vous modifier les infos détaillées maintenant ?"
 
 msgid "Setup"
 msgstr "Options"
 
-#, fuzzy, c-format
-msgid "%d requested to join Qun %d for %s"
-msgstr "L'utilisateur %d demande à rejoindre le groupe %d."
-
-#, fuzzy, c-format
-msgid "%d request to join Qun %d"
-msgstr "L'utilisateur %d demande à rejoindre le groupe %d."
-
-#, fuzzy, c-format
-msgid "Failed to join Qun %d, operated by admin %d"
-msgstr "Impossible de joindre le contact dans la discussion"
-
-#, c-format
-msgid "<b>Joining Qun %d is approved by admin %d for %s</b>"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "<b>Removed buddy %d.</b>"
-msgstr "Supprimer un contact"
-
-#, c-format
-msgid "<b>New buddy %d joined.</b>"
-msgstr ""
+#, c-format
+msgid "%u requested to join Qun %u for %s"
+msgstr "L'utilisateur %u demande à rejoindre le Qun %u pour %s"
+
+#, c-format
+msgid "%u request to join Qun %u"
+msgstr "L'utilisateur %u demande à rejoindre le Qun %u"
+
+#, c-format
+msgid "Failed to join Qun %u, operated by admin %u"
+msgstr "Échec pour rejoindre le Qun %u, administré par %u"
+
+#, c-format
+msgid "<b>Joining Qun %u is approved by admin %u for %s</b>"
+msgstr "<b>L'entrée dans le Qun %u a été approuvée par l'admin %u pour %s</b>"
+
+#, c-format
+msgid "<b>Removed buddy %u.</b>"
+msgstr "<b>Contact supprimé %u.</b>"
+
+#, c-format
+msgid "<b>New buddy %u joined.</b>"
+msgstr "<b>Nouveau contact %u entré.</b>"
 
 #, c-format
 msgid "Unknown-%d"
@@ -7558,9 +7527,8 @@
 msgid " Video"
 msgstr " Vidéo"
 
-#, fuzzy
 msgid " Zone"
-msgstr "Aucun"
+msgstr " Zone"
 
 msgid "Flag"
 msgstr "Drapeau"
@@ -7571,110 +7539,104 @@
 msgid "Invalid name"
 msgstr "Nom d'utilisateur non valide"
 
-#, fuzzy
 msgid "Select icon..."
-msgstr "Choisir un dossier..."
-
-#, fuzzy, c-format
+msgstr "Choisir une icône..."
+
+#, c-format
 msgid "<b>Login time</b>: %d-%d-%d, %d:%d:%d<br>\n"
-msgstr "<b>Heure de connexion :</b> %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Heure de connexion :</b> %d-%d-%d, %d:%d:%d<br>\n"
+
+#, c-format
 msgid "<b>Total Online Buddies</b>: %d<br>\n"
-msgstr "<b>Connectés :</b> %d<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Contacts connectés :</b> %d<br>\n"
+
+#, c-format
 msgid "<b>Last Refresh</b>: %d-%d-%d, %d:%d:%d<br>\n"
-msgstr "<b>Dernière mise à jour :</b> %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Dernière mise à jour :</b> %d-%d-%d, %d:%d:%d<br>\n"
+
+#, c-format
 msgid "<b>Server</b>: %s<br>\n"
-msgstr "<b>Serveur :</b> %s: %d<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Serveur :</b> %s<br>\n"
+
+#, c-format
 msgid "<b>Client Tag</b>: %s<br>\n"
-msgstr "<b>Heure de connexion :</b> %s<br>\n"
+msgstr "<b>Étiquette du client :</b> %s<br>\n"
 
 #, c-format
 msgid "<b>Connection Mode</b>: %s<br>\n"
 msgstr "<b>Type de connexion :</b> %s<br>\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "<b>My Internet IP</b>: %s:%d<br>\n"
-msgstr "<b>Type de connexion :</b> %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Adresse internet IP :</b> %s:%d<br>\n"
+
+#, c-format
 msgid "<b>Sent</b>: %lu<br>\n"
-msgstr "<b>Serveur :</b> %s: %d<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Envoyés :</b> %lu<br>\n"
+
+#, c-format
 msgid "<b>Resend</b>: %lu<br>\n"
-msgstr "<b>Dernière mise à jour :</b> %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Ré-envoyés :</b> %lu<br>\n"
+
+#, c-format
 msgid "<b>Lost</b>: %lu<br>\n"
-msgstr "<b>Dernière mise à jour :</b> %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Perdus :</b> %lu<br>\n"
+
+#, c-format
 msgid "<b>Received</b>: %lu<br>\n"
-msgstr "<b>Serveur :</b> %s: %d<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Reçus :</b> %lu<br>\n"
+
+#, c-format
 msgid "<b>Received Duplicate</b>: %lu<br>\n"
-msgstr "<b>Adresse IP publiée :</b> %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Doubles reçus :</b> %lu<br>\n"
+
+#, c-format
 msgid "<b>Time</b>: %d-%d-%d, %d:%d:%d<br>\n"
-msgstr "<b>Heure de connexion :</b> %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Heure :</b> %d-%d-%d, %d:%d:%d<br>\n"
+
+#, c-format
 msgid "<b>IP</b>: %s<br>\n"
-msgstr "<b>Serveur :</b> %s: %d<br>\n"
+msgstr "<b>IP :</b> %s<br>\n"
 
 msgid "Login Information"
 msgstr "Informations de connexion"
 
 msgid "<p><b>Original Author</b>:<br>\n"
-msgstr ""
+msgstr "<p><b>Auteur original :</b><br>\n"
 
 msgid "<p><b>Code Contributors</b>:<br>\n"
-msgstr ""
-
-#, fuzzy
+msgstr "<p><b>Contributeurs au code :</b><br>\n"
+
 msgid "<p><b>Lovely Patch Writers</b>:<br>\n"
-msgstr "<b>Dernière mise à jour :</b> %s<br>\n"
-
-#, fuzzy
+msgstr "<p><b>Charmants contributeurs de patchs :</b><br>\n"
+
 msgid "<p><b>Acknowledgement</b>:<br>\n"
-msgstr "<b>Serveur :</b> %s: %d<br>\n"
+msgstr "<p><b>Remerciements :</b><br>\n"
 
 msgid "<p><i>And, all the boys in the backroom...</i><br>\n"
-msgstr ""
+msgstr "<p><i>et tous les personnes dans les coulisses...</i><br>\n"
 
 msgid "<i>Feel free to join us!</i> :)"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "About OpenQ r%s"
-msgstr "À propos de %s"
-
-#, fuzzy
+msgstr "<i>N'hésitez pas à mous rejoindre !</i> :)"
+
+#, c-format
+msgid "About OpenQ %s"
+msgstr "À propos de OpenQ %s"
+
 msgid "Change Icon"
-msgstr "Enregistrer l'icône"
+msgstr "Changer l'icône"
 
 msgid "Change Password"
 msgstr "Changer de mot de passe"
 
-#, fuzzy
 msgid "Account Information"
-msgstr "Informations de connexion"
+msgstr "Informations du compte"
 
 msgid "Update all QQ Quns"
-msgstr ""
-
-#, fuzzy
+msgstr "Mettre à jour tous les Quns QQ"
+
 msgid "About OpenQ"
-msgstr "À propos de %s"
+msgstr "À propos de OpenQ"
 
 #. *< type
 #. *< ui_requirement
@@ -7686,59 +7648,45 @@
 #. *< version
 #. *  summary
 #. *  description
-#, fuzzy
 msgid "QQ Protocol Plugin"
 msgstr "Plugin pour le protocole QQ"
 
-#, fuzzy
 msgid "Auto"
-msgstr "Auteur"
-
-#, fuzzy
+msgstr "Auto"
+
 msgid "Select Server"
-msgstr "Choisir l'utilisateur"
+msgstr "Choisir le serveur"
 
 msgid "QQ2005"
-msgstr ""
+msgstr "QQ2005"
 
 msgid "QQ2007"
-msgstr ""
+msgstr "QQ2007"
 
 msgid "QQ2008"
-msgstr ""
-
-#. #endif
-#, fuzzy
+msgstr "QQ2008"
+
 msgid "Connect by TCP"
 msgstr "Connexion par TCP"
 
-#, fuzzy
 msgid "Show server notice"
-msgstr "Port du serveur"
-
-#, fuzzy
+msgstr "Afficher les infos du serveur"
+
 msgid "Show server news"
-msgstr "Hôte du serveur"
-
-#, fuzzy
+msgstr "Afficher les nouveautés du serveur"
+
 msgid "Keep alive interval (seconds)"
-msgstr "Délai(s) de Keep alive"
-
-#, fuzzy
+msgstr "Délai de Keep alive (en secondes)"
+
 msgid "Update interval (seconds)"
-msgstr "Délai(s) de mise à jour"
-
-#, fuzzy
-msgid "Can not decrypt server reply"
-msgstr "Impossible de déchiffrer la réponse de connexion"
-
-#, fuzzy
-msgid "Can not decrypt get server reply"
-msgstr "Impossible de déchiffrer la réponse de connexion"
+msgstr "Délai de mise à jour (en secondes)"
+
+msgid "Cannot decrypt server reply"
+msgstr "Impossible de déchiffrer la réponse du serveur"
 
 #, c-format
 msgid "Failed requesting token, 0x%02X"
-msgstr ""
+msgstr "Échec lors de la demande du token, 0x%02X"
 
 #, c-format
 msgid "Invalid token len, %d"
@@ -7746,56 +7694,53 @@
 
 #. extend redirect used in QQ2006
 msgid "Redirect_EX is not currently supported"
-msgstr ""
+msgstr "Redirect_EX n'est pas supportée pour l'instant"
 
 #. need activation
 #. need activation
 #. need activation
-#, fuzzy
 msgid "Activation required"
-msgstr "Erreur d'enregistrement"
-
-#, fuzzy, c-format
-msgid "Unknow reply code when login (0x%02X)"
-msgstr "Code du token de réponse non valide : 0x%02X"
-
-msgid "Keep alive error"
-msgstr "Erreur de Keep alive"
-
-#, fuzzy
-msgid "Requesting captcha ..."
-msgstr "Attire l'attention de %s..."
-
-msgid "Checking code of captcha ..."
-msgstr ""
-
-msgid "Failed captcha verify"
-msgstr ""
-
-#, fuzzy
+msgstr "Activation nécessaire"
+
+#, c-format
+msgid "Unknown reply code when logging in (0x%02X)"
+msgstr "Réponse inconnue à la connexion (0x%02X)"
+
+msgid "Could not decrypt server reply"
+msgstr "Impossible de déchiffrer la réponse du serveur"
+
+msgid "Requesting captcha"
+msgstr "Demande de captcha"
+
+msgid "Checking captcha"
+msgstr "Vérification du code du captcha"
+
+msgid "Failed captcha verification"
+msgstr "Échec à la vérification du captcha"
+
 msgid "Captcha Image"
-msgstr "Enregistrer l'image"
-
-#, fuzzy
+msgstr "Image captcha"
+
 msgid "Enter code"
-msgstr "Saisissez le mot de passe"
-
-msgid "QQ Captcha Verifing"
-msgstr ""
-
-#, fuzzy
+msgstr "Saisissez le code"
+
+msgid "QQ Captcha Verification"
+msgstr "Vérification du captcha QQ"
+
 msgid "Enter the text from the image"
-msgstr "Saisissez le nom du groupe"
-
-#, c-format
-msgid "Unknow reply code when checking password (0x%02X)"
-msgstr ""
-
-#, c-format
-msgid ""
-"Unknow reply code when login (0x%02X):\n"
+msgstr "Saisissez le texte de l'image"
+
+#, c-format
+msgid "Unknown reply when checking password (0x%02X)"
+msgstr "Réponse inconnue à la vérification du mot de passe (0x%02X)"
+
+#, c-format
+msgid ""
+"Unknown reply code when logging in (0x%02X):\n"
 "%s"
 msgstr ""
+"Réponse inconnue à la connexion (0x%02X) :\n"
+"%s"
 
 #. we didn't successfully connect. tdt->toc_fd is valid here
 msgid "Unable to connect."
@@ -7804,14 +7749,6 @@
 msgid "Socket error"
 msgstr "Erreur de socket."
 
-#, c-format
-msgid ""
-"Lost connection with server:\n"
-"%d, %s"
-msgstr ""
-"Connexion perdue avec le serveur :\n"
-"%d, %s"
-
 msgid "Unable to read from socket"
 msgstr "Impossible de lire le socket."
 
@@ -7821,81 +7758,74 @@
 msgid "Connection lost"
 msgstr "Connexion perdue."
 
-#, fuzzy
-msgid "Get server ..."
-msgstr "Modifier les informations..."
-
-#, fuzzy
-msgid "Request token"
-msgstr "Requête refusée"
+msgid "Getting server"
+msgstr "Récupération du serveur"
+
+msgid "Requesting token"
+msgstr "Requête d'un token"
 
 msgid "Couldn't resolve host"
 msgstr "Impossible de trouver l'adresse de l'hôte."
 
-#, fuzzy
 msgid "Invalid server or port"
-msgstr "Erreur non valide"
-
-#, fuzzy
-msgid "Connecting server ..."
-msgstr "Serveur de connexion"
-
-#, fuzzy
+msgstr "Serveur ou port non valide"
+
+msgid "Connecting to server"
+msgstr "Connexion au serveur"
+
 msgid "QQ Error"
-msgstr "Erreur QQid"
-
-msgid "Failed to send IM."
-msgstr "Impossible d'envoyer le message."
-
-#, fuzzy, c-format
+msgstr "Erreur QQ"
+
+#, c-format
 msgid ""
 "Server News:\n"
 "%s\n"
 "%s\n"
 "%s"
-msgstr "Relais de serveur ICQ"
-
-#, fuzzy, c-format
+msgstr ""
+"Nouveautés du serveur :\n"
+"%s\n"
+"%s\n"
+"%s"
+
+#, c-format
+msgid "%s:%s"
+msgstr "%s : %s"
+
+#, c-format
 msgid "From %s:"
-msgstr "De"
-
-#, fuzzy, c-format
+msgstr "De %s :"
+
+#, c-format
 msgid ""
 "Server notice From %s: \n"
 "%s"
-msgstr "Instructions du serveur : %s"
-
-msgid "Unknow SERVER CMD"
-msgstr ""
-
-#, fuzzy, c-format
+msgstr ""
+"Info du serveur de %s : \n"
+"%s"
+
+msgid "Unknown SERVER CMD"
+msgstr "Commande SERVER inconnue"
+
+#, c-format
 msgid ""
 "Error reply of %s(0x%02X)\n"
-"Room %d, reply 0x%02X"
-msgstr ""
-"Réponse %s(0x%02X )\n"
-"Envoi %s(0x%02X )\n"
-"Salon id %d, réponse [0x%02X]: \n"
-"%s"
-
-#, fuzzy
+"Room %u, reply 0x%02X"
+msgstr ""
+"Erreur à la réponse %s(0x%02X)\n"
+"Salon %u, réponse 0x%02X"
+
 msgid "QQ Qun Command"
-msgstr "Commande"
-
-#, fuzzy, c-format
-msgid "Not a member of room \"%s\"\n"
-msgstr "Vous n'êtes pas membre du groupe « %s ».\n"
-
-msgid "Can not decrypt login reply"
+msgstr "Commande Qun QQ"
+
+msgid "Could not decrypt login reply"
 msgstr "Impossible de déchiffrer la réponse de connexion"
 
-#, fuzzy
-msgid "Unknow LOGIN CMD"
-msgstr "Raison inconnue"
-
-#, fuzzy
-msgid "Unknow CLIENT CMD"
-msgstr "Raison inconnue"
+msgid "Unknown LOGIN CMD"
+msgstr "Commande LOGIN inconnue"
+
+msgid "Unknown CLIENT CMD"
+msgstr "Commande CLIENT inconnue"
 
 #, c-format
 msgid "%d has declined the file %s"
@@ -9770,9 +9700,8 @@
 msgid "doodle: Request user to start a Doodle session"
 msgstr "doodle : Envoie une demande pour un séance de griffonnage."
 
-#, fuzzy
 msgid "Yahoo ID..."
-msgstr "ID Yahoo!"
+msgstr "ID Yahoo..."
 
 #. *< type
 #. *< ui_requirement
@@ -9880,13 +9809,8 @@
 msgid "Last Update"
 msgstr "Dernière mise à jour"
 
-#, c-format
-msgid "User information for %s unavailable"
-msgstr "Les informations sur %s ne sont pas disponibles"
-
-msgid ""
-"Sorry, this profile seems to be in a language or format that is not "
-"supported at this time."
+msgid ""
+"This profile is in a language or format that is not supported at this time."
 msgstr ""
 "Désolé, ce profil a l'air d'être dans une langue ou un format non supporté "
 "pour l'instant."
@@ -10329,9 +10253,9 @@
 msgid "Unable to connect to %s"
 msgstr "Impossible de se connecter à %s."
 
-#, fuzzy, c-format
+#, c-format
 msgid "Error reading from %s: response too long (%d bytes limit)"
-msgstr "Erreur à la lecture depuis %s : %s"
+msgstr "Erreur à la lecture depuis %s : réponse trop longue (%d octets max)"
 
 #, c-format
 msgid ""
@@ -10505,7 +10429,7 @@
 msgid "Protocol"
 msgstr "Protocole"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "<span size='larger' weight='bold'>Welcome to %s!</span>\n"
 "\n"
@@ -10517,7 +10441,7 @@
 "You can come back to this window to add, edit, or remove accounts from "
 "<b>Accounts->Manage Accounts</b> in the Buddy List window"
 msgstr ""
-"<span weight='bold' size='larger'>Bienvenue dans %s !</span>\n"
+"<span size='larger' weight='bold'>Bienvenue dans %s !</span>\n"
 "\n"
 "Vous n'avez aucun compte configuré. Pour vous connecter avec %s, cliquez le "
 "bouton <b>Ajouter</b> ci-dessous et configurez votre premier compte. Si vous "
@@ -10525,7 +10449,7 @@
 "b> autant de fois que nécessaire.\n"
 "\n"
 "Pour retrouver cette fenêtre afin d'ajouter, modifier ou supprimer des "
-"comptes, choisissez <b>Comptes->Gérer les comptes</b> dans le menu de la "
+"comptes, choisissez <b>Comptes->Gérer les comptes</b> dans la fenêtre de la "
 "liste de contacts."
 
 #, c-format
@@ -10951,9 +10875,8 @@
 msgid "Auto_join when account becomes online."
 msgstr "Rejoindre _automatiquement quand le compte est activé."
 
-#, fuzzy
 msgid "_Remain in chat after window is closed."
-msgstr "_Cacher le salon de discussions quand la fenêtre est fermée."
+msgstr "_Rester dans le salon de discussions quand la fenêtre est fermée."
 
 msgid "Please enter the name of the group to be added."
 msgstr "Saisissez le nom du groupe à ajouter"
@@ -11329,11 +11252,10 @@
 msgstr "Erreur critique"
 
 msgid "bug master"
-msgstr ""
-
-#, fuzzy
+msgstr "maitre des bogues"
+
 msgid "artist"
-msgstr "Artiste"
+msgstr "artiste"
 
 #. feel free to not translate this
 msgid "Ka-Hing Cheung"
@@ -11342,9 +11264,8 @@
 msgid "support"
 msgstr "support"
 
-#, fuzzy
 msgid "webmaster"
-msgstr "codeur et webmestre"
+msgstr "webmestre"
 
 msgid "Senior Contributor/QA"
 msgstr "contribuant senior/QA"
@@ -11366,7 +11287,7 @@
 msgstr "support/QA"
 
 msgid "XMPP"
-msgstr ""
+msgstr "XMPP"
 
 msgid "original author"
 msgstr "auteur original"
@@ -11443,9 +11364,8 @@
 msgid "French"
 msgstr "Français"
 
-#, fuzzy
 msgid "Irish"
-msgstr "Kurde"
+msgstr "Irlandais"
 
 msgid "Galician"
 msgstr "Galicien"
@@ -11864,14 +11784,12 @@
 msgid "Color to draw hyperlinks."
 msgstr "Couleur pour afficher les liens hypertextes"
 
-#, fuzzy
 msgid "Hyperlink visited color"
-msgstr "Couleur des liens hypertextes"
-
-#, fuzzy
+msgstr "Couleur des liens visités"
+
 msgid "Color to draw hyperlinks after it has been visited (or activated)."
 msgstr ""
-"Couleur pour afficher les liens hypertextes quand la souris les survole."
+"Couleur pour afficher les liens hypertextes une fois visités (ou activés)."
 
 msgid "Hyperlink prelight color"
 msgstr "Couleur de surlignage des liens hypertextes"
@@ -12246,7 +12164,7 @@
 "activé)\n"
 "  -v, --version       affiche le numéro de la version actuelle\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "%s %s has segfaulted and attempted to dump a core file.\n"
 "This is a bug in the software and has happened through\n"
@@ -12274,12 +12192,6 @@
 "core. Si vous ne savez pas comment procéder, veuillez suivre\n"
 "les indications sur\n"
 "%swiki/GetABacktrace\n"
-"\n"
-"Si vous avez besoin d'une aide supplémentaire, veuillez contacter\n"
-"par AIM SeanEgn ou LSchiere (en anglais). Les informations pour\n"
-"contacter Sean ou Luke en utilisant un autre protocole sont\n"
-"disponibles sur\n"
-"%swiki/DeveloperPages\n"
 
 #. Translators may want to transliterate the name.
 #. It is not to be translated.
@@ -12750,20 +12662,17 @@
 "_Commande pour le son :\n"
 "(%s pour le nom de fichier)"
 
-#, fuzzy
 msgid "M_ute sounds"
-msgstr "_Silencieux"
+msgstr "Silencieu_x"
 
 msgid "Sounds when conversation has _focus"
 msgstr "Jouer les sons quand la conversation est en _avant-plan"
 
-#, fuzzy
 msgid "_Enable sounds:"
-msgstr "Activer les sons :"
-
-#, fuzzy
+msgstr "Activer les _sons :"
+
 msgid "V_olume:"
-msgstr "Volume :"
+msgstr "_Volume :"
 
 msgid "Play"
 msgstr "Jouer"
@@ -12984,13 +12893,11 @@
 msgid "Custom Smiley Manager"
 msgstr "Gestionnaire de frimousses personnalisée"
 
-#, fuzzy
 msgid "Click to change your buddyicon for this account."
-msgstr "Utiliser cette _icône pour ce compte :"
-
-#, fuzzy
+msgstr "Cliquer pour changer votre icône pour ce compte."
+
 msgid "Click to change your buddyicon for all accounts."
-msgstr "Utiliser cette _icône pour ce compte :"
+msgstr "Cliquer pour changer votre icône pour tous les comptes."
 
 msgid "Waiting for network connection"
 msgstr "En attente de connexion réseau."
@@ -13128,13 +13035,11 @@
 msgid "_Invite"
 msgstr "_Inviter"
 
-#, fuzzy
 msgid "_Modify..."
-msgstr "_Modifier"
-
-#, fuzzy
+msgstr "_Modifier..."
+
 msgid "_Add..."
-msgstr "_Ajouter"
+msgstr "_Ajouter..."
 
 msgid "_Open Mail"
 msgstr "_Ouvrir le courrier"
@@ -13157,12 +13062,11 @@
 msgid "none"
 msgstr "aucun"
 
-#, fuzzy
 msgid "Small"
-msgstr "Courriel"
+msgstr "Petits"
 
 msgid "Smaller versions of the default smilies"
-msgstr ""
+msgstr "Versions de taille inférieure des frimousses par défaut"
 
 msgid "Response Probability:"
 msgstr "Probabilité de réponse :"
@@ -13644,9 +13548,8 @@
 msgid "Set window manager \"_URGENT\" hint"
 msgstr "Envoyer le message « _URGENT » au gestionnaire de fenêtres"
 
-#, fuzzy
 msgid "_Flash window"
-msgstr "Les fenêtres de _discussions"
+msgstr "_Faire clignoter la fenêtres"
 
 #. Raise window method button
 msgid "R_aise conversation window"
@@ -13732,9 +13635,8 @@
 msgid "Hyperlink Color"
 msgstr "Couleur des liens hypertextes"
 
-#, fuzzy
 msgid "Visited Hyperlink Color"
-msgstr "Couleur des liens hypertextes"
+msgstr "Couleur des liens visités"
 
 msgid "Highlighted Message Name Color"
 msgstr "Nom de la couleur des messages en surbrillance"
@@ -13829,18 +13731,16 @@
 
 #, c-format
 msgid "You can upgrade to %s %s today."
-msgstr ""
+msgstr "Vous pouvez mettre à jour %s %s aujourd'hui."
 
 msgid "New Version Available"
 msgstr "Nouvelle version disponible"
 
-#, fuzzy
 msgid "Later"
-msgstr "Date"
-
-#, fuzzy
+msgstr "Plus tard"
+
 msgid "Download Now"
-msgstr "Téléchargement de %s : %s"
+msgstr "Télécharger maintenant"
 
 #. *< type
 #. *< ui_requirement
@@ -14153,334 +14053,44 @@
 msgid "This plugin is useful for debbuging XMPP servers or clients."
 msgstr "Ce plugin est utile pour débugger les clients ou serveurs XMPP."
 
-#~ msgid "A group with the name already exists."
-#~ msgstr "Un groupe avec ce nom existe déjà."
-
-#~ msgid "Primary Information"
-#~ msgstr "Informations principales"
-
-#~ msgid "Blood Type"
-#~ msgstr "Groupe sanguin"
-
-#, fuzzy
-#~ msgid "Update information"
-#~ msgstr "Mettre à jour mes informations"
-
-#, fuzzy
-#~ msgid "Successed:"
-#~ msgstr "Vitesse :"
+#~ msgid "Connection to server lost (no data received within %d second)"
+#~ msgid_plural ""
+#~ "Connection to server lost (no data received within %d seconds)"
+#~ msgstr[0] ""
+#~ "Connexion avec le serveur perdue (aucune donnée depuis %d seconde)."
+#~ msgstr[1] ""
+#~ "Connexion avec le serveur perdue (aucune donnée depuis %d secondes)."
+
+#~ msgid "%d needs Q&A"
+#~ msgstr "%d a besoin d'une réponse"
+
+#~ msgid "Add buddy Q&A"
+#~ msgstr "Ajouter une réponse de contact"
+
+#~ msgid "Can not decrypt get server reply"
+#~ msgstr "Impossible de récupérer la réponse du serveur"
+
+#~ msgid "Keep alive error"
+#~ msgstr "Erreur de Keep alive"
 
 #~ msgid ""
-#~ "Setting custom faces is not currently supported. Please choose an image "
-#~ "from %s."
-#~ msgstr ""
-#~ "Choisir une figure personnalisée ne marche pas encore. Veuillez choisir "
-#~ "une image dans %s."
-
-#~ msgid "Invalid QQ Face"
-#~ msgstr "QQ Face non valide"
-
-#~ msgid "You rejected %d's request"
-#~ msgstr "Vous avez rejeté la demande de %d."
-
-#~ msgid "Reject request"
-#~ msgstr "Refus de demande"
-
-#~ msgid "Add buddy with auth request failed"
-#~ msgstr "Ajout d'un contact avec échec d'authentification"
-
-#, fuzzy
-#~ msgid "Add into %d's buddy list"
-#~ msgstr "Impossible de charger la liste de contacts."
-
-#, fuzzy
-#~ msgid "QQ Number Error"
-#~ msgstr "Numéro QQ"
-
-#~ msgid "Group Description"
-#~ msgstr "Description du groupe"
-
-#~ msgid "Auth"
-#~ msgstr "Authentification"
-
-#~ msgid "Approve"
-#~ msgstr "Approuver"
-
-#, fuzzy
-#~ msgid "Successed to join Qun %d, operated by admin %d"
+#~ "Lost connection with server:\n"
+#~ "%d, %s"
 #~ msgstr ""
-#~ "Votre demande pour rejoindre le groupe %d a été refusée par "
-#~ "l'administrateur %d."
-
-#, fuzzy
-#~ msgid "[%d] removed from Qun \"%d\""
-#~ msgstr "Vous (%d) avez quitté le groupe %d."
-
-#, fuzzy
-#~ msgid "[%d] added to Qun \"%d\""
-#~ msgstr "Vous (%d) avez rejoint le groupe %d."
-
-#~ msgid "I am a member"
-#~ msgstr "J'en suis membre."
-
-#, fuzzy
-#~ msgid "I am requesting"
-#~ msgstr "Mauvaise requête"
-
-#~ msgid "I am the admin"
-#~ msgstr "J'en suis administrateur."
-
-#~ msgid "Unknown status"
-#~ msgstr "État inconnu."
-
-#, fuzzy
-#~ msgid "Remove from Qun"
-#~ msgstr "Supprimer un groupe"
-
-#~ msgid "You entered a group ID outside the acceptable range"
-#~ msgstr "Vous avez saisi un ID de groupe hors de l'intervalle autorisé."
-
-#~ msgid "Are you sure you want to leave this Qun?"
-#~ msgstr "Êtes-vous sûr de vouloir quitter ce Qun ?"
-
-#~ msgid "Do you want to approve the request?"
-#~ msgstr "Voulez-vous accepter cette demande ?"
-
-#, fuzzy
-#~ msgid "Change Qun member"
-#~ msgstr "Téléphone fixe"
-
-#, fuzzy
-#~ msgid "Change Qun information"
-#~ msgstr "Informations du salon"
-
-#, fuzzy
-#~ msgid ""
-#~ "%s\n"
-#~ "\n"
-#~ "%s"
-#~ msgstr "%s (%s)"
-
-#~ msgid "System Message"
-#~ msgstr "Message système"
-
-#~ msgid "<b>Last Login IP</b>: %s<br>\n"
-#~ msgstr "<b>Adresse IP à la dernière connexion :</b> %s<br>\n"
-
-#~ msgid "<b>Last Login Time</b>: %s\n"
-#~ msgstr "<b>Temps de connexion la dernière fois :</b> %s\n"
-
-#~ msgid "Set My Information"
-#~ msgstr "Changer mes informations"
-
-#, fuzzy
-#~ msgid "Leave the QQ Qun"
-#~ msgstr "Quitter ce QQ Qun"
-
-#~ msgid "Block this buddy"
-#~ msgstr "Bloquer ce contact"
-
-#~ msgid "Invalid token reply code, 0x%02X"
-#~ msgstr "Code du token de réponse non valide : 0x%02X"
-
-#, fuzzy
-#~ msgid "Error password: %s"
-#~ msgstr "Erreur lors du changement du mot de passe"
-
-#, fuzzy
-#~ msgid "Failed to connect all servers"
-#~ msgstr "Impossible de se connecter au serveur."
-
-#~ msgid "Connecting server %s, retries %d"
-#~ msgstr "Connexion au serveur %s, tentatives %d"
-
-#, fuzzy
-#~ msgid "Do you approve the requestion?"
-#~ msgstr "Voulez-vous accepter cette demande ?"
-
-#, fuzzy
-#~ msgid "Do you add the buddy?"
-#~ msgstr "Voulez-vous ajouter ce contact à votre liste ?"
-
-#, fuzzy
-#~ msgid "%s added you [%s] to buddy list"
-#~ msgstr "L'utilisateur %s vous (%s) a ajouté à sa liste de contacts."
-
-#, fuzzy
-#~ msgid "QQ Budy"
-#~ msgstr "Contact"
-
-#~ msgid "%s wants to add you [%s] as a friend"
-#~ msgstr "%s veut vous (%s) ajouter en tant que contact."
-
-#, fuzzy
-#~ msgid "%s is not in buddy list"
-#~ msgstr "L'utilisateur %s n'est pas dans votre liste de contacts."
-
-#, fuzzy
-#~ msgid "Would you add?"
-#~ msgstr "Voulez-vous l'ajouter ?"
-
-#~ msgid "%s"
-#~ msgstr "%s"
-
-#, fuzzy
-#~ msgid "QQ Server Notice"
-#~ msgstr "Port du serveur"
-
-#, fuzzy
-#~ msgid "Network disconnected"
-#~ msgstr "Correspondant déconnecté"
-
-#~ msgid "developer"
-#~ msgstr "codeur"
-
-#~ msgid "XMPP developer"
-#~ msgstr "codeur XMPP"
-
-#~ msgid "Artists"
-#~ msgstr "Artistes"
-
-#~ msgid ""
-#~ "You are using %s version %s.  The current version is %s.  You can get it "
-#~ "from <a href=\"%s\">%s</a><hr>"
-#~ msgstr ""
-#~ "Vous utilisez %s version %s. La dernière version est %s. Vous pouvez la "
-#~ "télécharger depuis <a href=\"%s\">%s</a><hr>"
-
-#~ msgid "<b>ChangeLog:</b><br>%s"
-#~ msgstr "<b>Nouveautés :</b><br>%s"
-
-#~ msgid "EOF while reading from resolver process"
-#~ msgstr "Fin de fichier à la lecture du processus de résolution de noms."
-
-#~ msgid "Your information has been updated"
-#~ msgstr "Vos informations ont été mises à jour."
-
-#~ msgid "Input your reason:"
-#~ msgstr "Saisissez votre raison :"
-
-#~ msgid "You have successfully removed a buddy"
-#~ msgstr "Vous avez supprimé un contact."
-
-#~ msgid "You have successfully removed yourself from your friend's buddy list"
-#~ msgstr "Vous avez été supprimé de la liste d'un contact."
-
-#~ msgid "You have added %d to buddy list"
-#~ msgstr "Vous avez ajouté l'utilisateur %d à votre liste de contacts."
-
-#~ msgid "Invalid QQid"
-#~ msgstr "QQid non valide"
-
-#~ msgid "Please enter external group ID"
-#~ msgstr "Veuillez saisir un ID de groupe externe."
-
-#~ msgid "Reason: %s"
-#~ msgstr "Raison : %s"
-
-#~ msgid "Your request to join group %d has been approved by admin %d"
-#~ msgstr ""
-#~ "Votre demande pour rejoindre le groupe %d a été acceptée par "
-#~ "l'administrateur %d."
-
-#~ msgid "This group has been added to your buddy list"
-#~ msgstr "Ce groupe a été ajouté à votre liste de contacts."
-
-#~ msgid "I am applying to join"
-#~ msgstr "Je demande à être membre."
-
-#~ msgid "You have successfully left the group"
-#~ msgstr "Vous avez quitté ce groupe."
-
-#~ msgid "QQ Group Auth"
-#~ msgstr "Authentification QQ du groupe"
-
-#~ msgid "Your authorization request has been accepted by the QQ server"
-#~ msgstr ""
-#~ "Votre opération d'authentification a été acceptée par le serveur QQ."
-
-#~ msgid "Enter your reason:"
-#~ msgstr "Saisissez votre raison :"
-
-#~ msgid " Space"
-#~ msgstr "Espace"
-
-#~ msgid "<b>Real hostname</b>: %s: %d<br>\n"
-#~ msgstr "<b>Hôte réel :</b> %s: %d<br>\n"
-
-#~ msgid "Show Login Information"
-#~ msgstr "Afficher les informations de connexion"
-
-#~ msgid "resend interval(s)"
-#~ msgstr "Délai(s) de réenvoi"
-
-#~ msgid "hostname is NULL or port is 0"
-#~ msgstr "Le nom d'hôte est NULL ou le port est 0"
-
-#~ msgid "Unable to login. Check debug log."
-#~ msgstr ""
-#~ "Impossible de se connecter, veuillez vérifier les messages de débuggage."
-
-#~ msgid "Unable to login"
-#~ msgstr "Impossible de se connecter."
-
-#~ msgid "Failed room reply"
-#~ msgstr "Échec à la réponse du salon"
-
-#~ msgid "User %s rejected your request"
-#~ msgstr "L'utilisateur %s a refusé votre demande."
-
-#~ msgid "User %s approved your request"
-#~ msgstr "L'utilisateur %s a accepté votre demande."
-
-#~ msgid "Notice from: %s"
-#~ msgstr "Annonce de : %s"
-
-#~ msgid "Code [0x%02X]: %s"
-#~ msgstr "Code [0x%02X] : %s"
-
-#~ msgid "Group Operation Error"
-#~ msgstr "Erreur sur une opération du groupe."
-
-#~ msgid "Error setting socket options"
-#~ msgstr "Erreur à la mise en place des paramètres de la connexion."
-
-#~ msgid ""
-#~ "Windows Live ID authentication: cannot find authenticate token in server "
-#~ "response"
-#~ msgstr ""
-#~ "Authentification Windows Live ID : impossible de trouver le jeton "
-#~ "d'authentification dans la réponse du serveur."
-
-#~ msgid "Windows Live ID authentication Failed"
-#~ msgstr "Échec de l'authentification Windows Live ID"
-
-#~ msgid "Too evil (sender)"
-#~ msgstr "Trop méchant (envoyeur)"
-
-#~ msgid "Too evil (receiver)"
-#~ msgstr "Trop méchant (destinataire)"
-
-#~ msgid "Available Message"
-#~ msgstr "Message de disponibilité"
-
-#~ msgid "Away Message"
-#~ msgstr "Message d'absence"
-
-#~ msgid "<i>(retrieving)</i>"
-#~ msgstr " <i>(en cours de récupération)</i>"
-
-#~ msgid "Error requesting login token"
-#~ msgstr "Erreur à la demande d'un token de connexion"
-
-#~ msgid "TCP Address"
-#~ msgstr "Adresse TCP"
-
-#~ msgid "UDP Address"
-#~ msgstr "Adresse UDP"
-
-#~ msgid "Screen name:"
-#~ msgstr "Nom d'utilisateur :"
+#~ "Connexion perdue avec le serveur :\n"
+#~ "%d, %s"
+
+#~ msgid "Connecting server ..."
+#~ msgstr "Connexion au serveur..."
+
+#~ msgid "Failed to send IM."
+#~ msgstr "Impossible d'envoyer le message."
+
+#~ msgid "Not a member of room \"%s\"\n"
+#~ msgstr "Vous n'êtes pas membre du groupe « %s ».\n"
+
+#~ msgid "User information for %s unavailable"
+#~ msgstr "Les informations sur %s ne sont pas disponibles"
 
 #~ msgid "Someone says your screen name in chat"
 #~ msgstr "Quelqu'un dit votre nom d'utilisateur dans la discussion"
@@ -14493,54 +14103,6 @@
 #~ "connexion non cryptée. Voulez-vous autoriser ceci et continuer "
 #~ "l'authentification ?"
 
-#~ msgid "Use GSSAPI (Kerberos v5) for authentication"
-#~ msgstr "Utiliser GSSAPI (Kerberos v5) pour l'authentification"
-
-#~ msgid "Invalid screen name"
-#~ msgstr "Nom d'utilisateur non valide."
-
-#~ msgid "Invalid screen name."
-#~ msgstr "Nom d'utilisateur non valide."
-
-#~ msgid "Screen _name:"
-#~ msgstr "_Nom d'utilisateur :"
-
-#~ msgid ""
-#~ "%s%s<span weight=\"bold\">Written by:</span>\t%s\n"
-#~ "<span weight=\"bold\">Website:</span>\t\t%s\n"
-#~ "<span weight=\"bold\">Filename:</span>\t\t%s"
-#~ msgstr ""
-#~ "%s%s<span weight=\"bold\">Auteur :</span> %s\n"
-#~ "<span weight=\"bold\">Page web :</span> %s\n"
-#~ "<span weight=\"bold\">Fichier :</span> %s"
-
-#~ msgid ""
-#~ "The contact availability plugin (cap) is used to display statistical "
-#~ "information about buddies in a users contact list."
-#~ msgstr ""
-#~ "Ce plugin est utilisé pour afficher des informations statistiques à "
-#~ "propos des contacts de l'utilisateur."
-
-#~ msgid "Screen name sent"
-#~ msgstr "Nom d'utilisateur envoyé"
-
-#~ msgid "Screen name"
-#~ msgstr "Nom d'utilisateur"
-
-#~ msgid "_Merge"
-#~ msgstr "_Fusionner"
-
-#~ msgid ""
-#~ "Please enter the screen name of the person you would like to add to your "
-#~ "buddy list. You may optionally enter an alias, or nickname,  for the "
-#~ "buddy. The alias will be displayed in place of the screen name whenever "
-#~ "possible.\n"
-#~ msgstr ""
-#~ "Saisissez le nom d'utilisateur de la personne que vous voulez ajouter à "
-#~ "votre liste de contacts. Vous pouvez choisir un alias ou surnom pour le "
-#~ "contact. L'alias sera affiché à la place du nom d'utilisateur chaque fois "
-#~ "que cela est possible.\n"
-
 #~ msgid "A_ccount:"
 #~ msgstr "_Compte :"