changeset 25804:9100b9176a16

propagate from branch 'im.pidgin.pidgin' (head a03e0bee477b05d1143ef3e5607d990c1120da34) to branch 'im.pidgin.cpw.malu.xmpp.idle' (head e0c18c146f94850aa81c1e4094e7fe549d028148)
author Marcus Lundblad <ml@update.uu.se>
date Wed, 17 Dec 2008 18:01:08 +0000
parents c2054d8d23fc (diff) f03a067fcfba (current diff)
children 6fed1bb3b02e
files libpurple/protocols/jabber/buddy.c libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/presence.c libpurple/protocols/myspace/CHANGES libpurple/protocols/myspace/ChangeLog libpurple/protocols/myspace/LICENSE libpurple/protocols/myspace/release.sh
diffstat 119 files changed, 6926 insertions(+), 7917 deletions(-) [+]
line wrap: on
line diff
--- a/COPYING	Sun Dec 07 01:42:47 2008 +0000
+++ b/COPYING	Wed Dec 17 18:01:08 2008 +0000
@@ -1,8 +1,8 @@
 		    GNU GENERAL PUBLIC LICENSE
 		       Version 2, June 1991
 
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-     51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
@@ -15,7 +15,7 @@
 General Public License applies to most of the Free Software
 Foundation's software and to any other program whose authors commit to
 using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
+the GNU Lesser General Public License instead.)  You can apply it to
 your programs, too.
 
   When we speak of free software, we are referring to freedom, not
@@ -55,7 +55,7 @@
 
   The precise terms and conditions for copying, distribution and
 modification follow.
-
+
 		    GNU GENERAL PUBLIC LICENSE
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 
@@ -110,7 +110,7 @@
     License.  (Exception: if the Program itself is interactive but
     does not normally print such an announcement, your work based on
     the Program is not required to print an announcement.)
-
+
 These requirements apply to the modified work as a whole.  If
 identifiable sections of that work are not derived from the Program,
 and can be reasonably considered independent and separate works in
@@ -168,7 +168,7 @@
 access to copy the source code from the same place counts as
 distribution of the source code, even though third parties are not
 compelled to copy the source along with the object code.
-
+
   4. You may not copy, modify, sublicense, or distribute the Program
 except as expressly provided under this License.  Any attempt
 otherwise to copy, modify, sublicense or distribute the Program is
@@ -225,7 +225,7 @@
 
 This section is intended to make thoroughly clear what is believed to
 be a consequence of the rest of this License.
-
+
   8. If the distribution and/or use of the Program is restricted in
 certain countries either by patents or by copyrighted interfaces, the
 original copyright holder who places the Program under this License
@@ -278,7 +278,7 @@
 POSSIBILITY OF SUCH DAMAGES.
 
 		     END OF TERMS AND CONDITIONS
-
+
 	    How to Apply These Terms to Your New Programs
 
   If you develop a new program, and you want it to be of the greatest
@@ -291,7 +291,7 @@
 the "copyright" line and a pointer to where the full notice is found.
 
     <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) 19yy  <name of author>
+    Copyright (C) <year>  <name of author>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -303,17 +303,16 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
 
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 Also add information on how to contact you by electronic and paper mail.
 
 If the program is interactive, make it output a short notice like this
 when it starts in an interactive mode:
 
-    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision version 69, Copyright (C) year name of author
     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
     This is free software, and you are welcome to redistribute it
     under certain conditions; type `show c' for details.
@@ -336,5 +335,5 @@
 This General Public License does not permit incorporating your program into
 proprietary programs.  If your program is a subroutine library, you may
 consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
+library.  If this is what you want to do, use the GNU Lesser General
 Public License instead of this License.
--- a/COPYRIGHT	Sun Dec 07 01:42:47 2008 +0000
+++ b/COPYRIGHT	Wed Dec 17 18:01:08 2008 +0000
@@ -207,6 +207,7 @@
 Benjamin Kahn
 Anders Kaseorg
 Praveen Karadakal
+Jaromír Karmazín
 John Kelm
 Jochen Kemnade
 Akuke Kok
@@ -271,6 +272,7 @@
 David Mohr
 Andrew Molloy
 Michael Monreal
+Laurent Montaron
 Marco Monteiro
 Benjamin Moody
 John Moody
--- a/ChangeLog	Sun Dec 07 01:42:47 2008 +0000
+++ b/ChangeLog	Wed Dec 17 18:01:08 2008 +0000
@@ -1,25 +1,33 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
-version 2.5.3 (??/??/????):
+version 2.5.3 (12/??/2008):
 	libpurple:
-	* Fix an error with MSN offline messages by shipping the *new*
-	  "Microsoft Secure Server Authority" and the
-	  "Microsoft Internet Authority" certificates.  People that use
-	  --with-system-ssl-certs and GnuTLS need to include these in the
-	  system certs directory.
 	* 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)
-	* Fix a crash in SIMPLE when a malformed message is received.
-	* 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 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.
+	  The recommended version to use is still QQ2005.
+	* 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)
 
 	Gadu-Gadu:
 	* Fix some problems with Gadu-Gadu buddy icons (Adam Strzelecki)
@@ -27,23 +35,57 @@
 	* Gadu-Gadu now does proper charset translations where needed (Adam
 	  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.
+	* 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.
+	* Many other fixes and code cleanup.
+
+	MySpace:
+	* Respect your privacy settings set using the official MySpace client
+	  (Mark Doliner)
+	* Add support for blocking buddies (Mark Doliner)
+	* Fix a bug where buddies didn't appear in their correct groups the
+	  first time you sign into your account (Mark Doliner)
+	* Support for foreground and background font colors in outgoing IMs
+	* Support for background font colors in incoming IMs
+
+	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)
+
 	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.
-	
+	* 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)
 
@@ -53,14 +95,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 compatibility with old GTK+ yet again
+	* 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/ChangeLog.API	Sun Dec 07 01:42:47 2008 +0000
+++ b/ChangeLog.API	Wed Dec 17 18:01:08 2008 +0000
@@ -1,5 +1,11 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.5.3:
+	libpurple
+		Changed:
+		* purple_util_fetch_url and purple_util_fetch_url_request can
+		  now fetch https URLs
+
 version 2.5.0 (08/18/2008):
 	libpurple:
 		Added:
--- a/ChangeLog.win32	Sun Dec 07 01:42:47 2008 +0000
+++ b/ChangeLog.win32	Wed Dec 17 18:01:08 2008 +0000
@@ -1,3 +1,7 @@
+version 2.5.3 (12/??/2008):
+	* Upgrade SILC to use the 1.1.8 toolkit
+	* Updated included Meanwhile library to include patch referenced in #7563
+
 version 2.5.2 (10/19/2008):
 	* Updated GTK+ to 2.12.12
 	  This will resolve an issue with stuff in QQ appearing as "(NULL)"
@@ -28,7 +32,7 @@
 
 version 2.4.0 (02/29/2008):
 	* Updated GTK+ to 2.12.8
-	* Updated include Meanwhile library to include patches referenced at:
+	* Updated included Meanwhile library to include patches referenced at:
 	  https://sourceforge.net/tracker/?func=detail&atid=656718&aid=1626349&group_id=110565
 	* Build the xmpp protocol with SASL support (and include Cyrus SASL
 	  2.1.22).
--- a/configure.ac	Sun Dec 07 01:42:47 2008 +0000
+++ b/configure.ac	Wed Dec 17 18:01:08 2008 +0000
@@ -1173,6 +1173,8 @@
 			"-Wendif-labels" \
 			"-Werror-implicit-function-declaration" \
 			"-Wextra -Wno-sign-compare -Wno-unused-parameter" \
+			"-Wformat-security" \
+				"-Werror=format-security" \
 			"-Winit-self" \
 			"-Wmissing-declarations" \
 			"-Wmissing-noreturn" \
--- a/libpurple/account.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/account.c	Wed Dec 17 18:01:08 2008 +0000
@@ -75,6 +75,7 @@
 	gpointer userdata;
 	PurpleAccountRequestAuthorizationCb auth_cb;
 	PurpleAccountRequestAuthorizationCb deny_cb;
+	guint ref;
 } PurpleAccountRequestInfo;
 
 static PurpleAccountUiOps *account_ui_ops = NULL;
@@ -1211,6 +1212,18 @@
 		ui_ops->request_add(account, remote_user, id, alias, message);
 }
 
+static PurpleAccountRequestInfo *
+purple_account_request_info_unref(PurpleAccountRequestInfo *info)
+{
+	if (--info->ref)
+		return info;
+
+	/* TODO: This will leak info->user_data, but there is no callback to just clean that up */
+	g_free(info->user);
+	g_free(info);
+	return NULL;
+}
+
 static void
 purple_account_request_close_info(PurpleAccountRequestInfo *info)
 {
@@ -1221,11 +1234,7 @@
 	if (ops != NULL && ops->close_account_request != NULL)
 		ops->close_account_request(info->ui_handle);
 
-	/* TODO: This will leak info->user_data, but there is no callback to just clean that up */
-
-	g_free(info->user);
-	g_free(info);
-
+	purple_account_request_info_unref(info);
 }
 
 void
@@ -1278,8 +1287,7 @@
 	purple_signal_emit(purple_accounts_get_handle(),
 			"account-authorization-granted", info->account, info->user);
 
-	g_free(info->user);
-	g_free(info);
+	purple_account_request_info_unref(info);
 }
 
 static void
@@ -1294,8 +1302,7 @@
 	purple_signal_emit(purple_accounts_get_handle(),
 			"account-authorization-denied", info->account, info->user);
 
-	g_free(info->user);
-	g_free(info);
+	purple_account_request_info_unref(info);
 }
 
 void *
@@ -1332,11 +1339,18 @@
 		info->deny_cb   = deny_cb;
 		info->userdata  = user_data;
 		info->user      = g_strdup(remote_user);
+		info->ref       = 2;  /* We hold an extra ref to make sure info remains valid
+		                         if any of the callbacks are called synchronously. We
+		                         unref it after the function call */
+
 		info->ui_handle = ui_ops->request_authorize(account, remote_user, id, alias, message,
 							    on_list, request_auth_cb, request_deny_cb, info);
 
-		handles = g_list_append(handles, info);
-		return info->ui_handle;
+		info = purple_account_request_info_unref(info);
+		if (info) {
+			handles = g_list_append(handles, info);
+			return info->ui_handle;
+		}
 	}
 
 	return NULL;
--- a/libpurple/blist.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/blist.h	Wed Dec 17 18:01:08 2008 +0000
@@ -71,7 +71,7 @@
 
 typedef enum
 {
-	PURPLE_BLIST_NODE_FLAG_NO_SAVE      = 1 << 0, /**< node should not be saved with the buddy list */
+	PURPLE_BLIST_NODE_FLAG_NO_SAVE      = 1 << 0 /**< node should not be saved with the buddy list */
 
 } PurpleBlistNodeFlags;
 
--- a/libpurple/certificate.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/certificate.c	Wed Dec 17 18:01:08 2008 +0000
@@ -748,9 +748,9 @@
 # ifdef SSL_CERTIFICATES_DIR
 		x509_ca_paths = g_list_append(NULL, g_strdup(SSL_CERTIFICATES_DIR));
 # else
-		x509_ca_paths = g_list_append(NULL, g_build_filename(DATADIR,
-						   "purple", "ca-certs", NULL));
 # endif
+		x509_ca_paths = g_list_append(x509_ca_paths,
+			g_build_filename(DATADIR, "purple", "ca-certs", NULL));
 #endif
 	}
 
--- a/libpurple/cmds.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/cmds.h	Wed Dec 17 18:01:08 2008 +0000
@@ -38,7 +38,7 @@
 	PURPLE_CMD_STATUS_NOT_FOUND,
 	PURPLE_CMD_STATUS_WRONG_ARGS,
 	PURPLE_CMD_STATUS_WRONG_PRPL,
-	PURPLE_CMD_STATUS_WRONG_TYPE,
+	PURPLE_CMD_STATUS_WRONG_TYPE
 } PurpleCmdStatus;
 
 /** Commands registered with the core return one of these values when run.
@@ -51,7 +51,7 @@
 typedef enum _PurpleCmdRet {
 	PURPLE_CMD_RET_OK,       /**< Everything's okay; Don't look for another command to call. */
 	PURPLE_CMD_RET_FAILED,   /**< The command failed, but stop looking.*/
-	PURPLE_CMD_RET_CONTINUE, /**< Continue, looking for other commands with the same name to call. */
+	PURPLE_CMD_RET_CONTINUE /**< Continue, looking for other commands with the same name to call. */
 } PurpleCmdRet;
 
 #define PURPLE_CMD_FUNC(func) ((PurpleCmdFunc)func)
@@ -76,7 +76,7 @@
 	PURPLE_CMD_P_PLUGIN    =  3000,
 	PURPLE_CMD_P_ALIAS     =  4000,
 	PURPLE_CMD_P_HIGH      =  5000,
-	PURPLE_CMD_P_VERY_HIGH =  6000,
+	PURPLE_CMD_P_VERY_HIGH =  6000
 } PurpleCmdPriority;
 
 /** Flags used to set various properties of commands.  Every command should
@@ -93,7 +93,7 @@
 	/** Command is usable only for a particular prpl. */
 	PURPLE_CMD_FLAG_PRPL_ONLY        = 0x04,
 	/** Incorrect arguments to this command should be accepted anyway. */
-	PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS = 0x08,
+	PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS = 0x08
 } PurpleCmdFlag;
 
 
--- a/libpurple/connection.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/connection.h	Wed Dec 17 18:01:08 2008 +0000
@@ -44,7 +44,7 @@
 	PURPLE_CONNECTION_NO_FONTSIZE = 0x0020, /**< Connection does not send/receive font sizes */
 	PURPLE_CONNECTION_NO_URLDESC = 0x0040,  /**< Connection does not support descriptions with links */ 
 	PURPLE_CONNECTION_NO_IMAGES = 0x0080,  /**< Connection does not support sending of images */
-	PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY = 0x0100, /**< Connection supports sending and receiving custom smileys */
+	PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY = 0x0100 /**< Connection supports sending and receiving custom smileys */
 
 } PurpleConnectionFlags;
 
--- a/libpurple/conversation.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/conversation.h	Wed Dec 17 18:01:08 2008 +0000
@@ -84,7 +84,7 @@
 	PURPLE_CONV_UPDATE_TITLE,
 	PURPLE_CONV_UPDATE_CHATLEFT,
 
-	PURPLE_CONV_UPDATE_FEATURES, /**< The features for a chat have changed */
+	PURPLE_CONV_UPDATE_FEATURES  /**< The features for a chat have changed */
 
 } PurpleConvUpdateType;
 
@@ -126,7 +126,7 @@
 	PURPLE_MESSAGE_NOTIFY      = 0x2000, /**< Message is a notification */
 	PURPLE_MESSAGE_NO_LINKIFY  = 0x4000, /**< Message should not be auto-
 										   linkified @since 2.1.0 */
-	PURPLE_MESSAGE_INVISIBLE   = 0x8000, /**< Message should not be displayed */
+	PURPLE_MESSAGE_INVISIBLE   = 0x8000  /**< Message should not be displayed */
 } PurpleMessageFlags;
 
 /**
@@ -139,7 +139,7 @@
 	PURPLE_CBFLAGS_HALFOP        = 0x0002, /**< Half-op                      */
 	PURPLE_CBFLAGS_OP            = 0x0004, /**< Channel Op or Moderator      */
 	PURPLE_CBFLAGS_FOUNDER       = 0x0008, /**< Channel Founder              */
-	PURPLE_CBFLAGS_TYPING        = 0x0010, /**< Currently typing             */
+	PURPLE_CBFLAGS_TYPING        = 0x0010  /**< Currently typing             */
 
 } PurpleConvChatBuddyFlags;
 
--- a/libpurple/dnssrv.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/dnssrv.c	Wed Dec 17 18:01:08 2008 +0000
@@ -336,6 +336,12 @@
 	static gboolean initialized = FALSE;
 #endif
 
+	if (!protocol || !*protocol || !transport || !*transport || !domain || !*domain) {
+		purple_debug_error("dnssrv", "Wrong arguments\n");
+		cb(NULL, 0, extradata);
+		g_return_val_if_reached(NULL);
+	}
+
 	query = g_strdup_printf("_%s._%s.%s", protocol, transport, domain);
 	purple_debug_info("dnssrv","querying SRV record for %s\n", query);
 
--- a/libpurple/plugins/perl/common/Account.xs	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/plugins/perl/common/Account.xs	Wed Dec 17 18:01:08 2008 +0000
@@ -107,7 +107,7 @@
     t_GL = NULL;
     t_len = av_len((AV *)SvRV(status_types));
 
-    for (i = 0; i < t_len; i++)
+    for (i = 0; i <= t_len; i++)
         t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(status_types), i, 0)));
 
     purple_account_set_status_types(account, t_GL);
@@ -209,7 +209,7 @@
     t_GL = NULL;
     t_len = av_len((AV *)SvRV(list));
 
-    for (i = 0; i < t_len; i++)
+    for (i = 0; i <= t_len; i++)
         t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(list), i, 0)));
 
     purple_account_add_buddies(account, t_GL);
@@ -238,13 +238,13 @@
     t_GL1 = NULL;
     t_len = av_len((AV *)SvRV(A));
 
-    for (i = 0; i < t_len; i++)
+    for (i = 0; i <= t_len; i++)
         t_GL1 = g_list_append(t_GL1, SvPVutf8_nolen(*av_fetch((AV *)SvRV(A), i, 0)));
 
     t_GL2 = NULL;
     t_len = av_len((AV *)SvRV(B));
 
-    for (i = 0; i < t_len; i++)
+    for (i = 0; i <= t_len; i++)
         t_GL2 = g_list_append(t_GL2, SvPVutf8_nolen(*av_fetch((AV *)SvRV(B), i, 0)));
 
     purple_account_remove_buddies(account, t_GL1, t_GL2);
--- a/libpurple/plugins/perl/common/AccountOpts.xs	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/plugins/perl/common/AccountOpts.xs	Wed Dec 17 18:01:08 2008 +0000
@@ -44,7 +44,7 @@
 	t_GL = NULL;
 	t_len = av_len((AV *)SvRV(values));
 
-	for (i = 0; i < t_len; i++)
+	for (i = 0; i <= t_len; i++)
 		t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(values), i, 0)));
 
 	RETVAL  = purple_account_option_list_new(text, pref_name, t_GL);
@@ -132,7 +132,7 @@
 	t_GL = NULL;
 	t_len = av_len((AV *)SvRV(values));
 
-	for (i = 0; i < t_len; i++)
+	for (i = 0; i <= t_len; i++)
 		t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(values), i, 0)));
 
 	purple_account_option_set_list(option, t_GL);
--- a/libpurple/plugins/perl/common/Certificate.xs	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/plugins/perl/common/Certificate.xs	Wed Dec 17 18:01:08 2008 +0000
@@ -231,8 +231,8 @@
 		int len = 0, i = 0;
 		struct cb_data *d = NULL;
 	PPCODE:
-		len = av_len(cert_chain) + 1;
-		for(i = 0; i < len; i++) {
+		len = av_len(cert_chain);
+		for(i = 0; i <= len; i++) {
 			SV **sv = av_fetch(cert_chain, i, 0);
 			if(!sv || !purple_perl_is_ref_object(*sv)) {
 				g_list_free(l);
--- a/libpurple/plugins/perl/common/Conversation.xs	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/plugins/perl/common/Conversation.xs	Wed Dec 17 18:01:08 2008 +0000
@@ -336,7 +336,7 @@
 	t_GL = NULL;
 	t_len = av_len((AV *)SvRV(users));
 
-	for (i = 0; i < t_len; i++)
+	for (i = 0; i <= t_len; i++)
 		t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(users), i, 0)));
 
 	for (l = purple_conv_chat_set_users(chat, t_GL); l != NULL; l = l->next) {
@@ -374,7 +374,7 @@
 	t_GL = NULL;
 	t_len = av_len((AV *)SvRV(ignored));
 
-	for (i = 0; i < t_len; i++)
+	for (i = 0; i <= t_len; i++)
 		t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(ignored), i, 0)));
 
 	for (l = purple_conv_chat_set_ignored(chat, t_GL); l != NULL; l = l->next) {
@@ -431,19 +431,19 @@
 	t_GL_users = NULL;
 	t_len = av_len((AV *)SvRV(users));
 
-	for (i = 0; i < t_len; i++)
+	for (i = 0; i <= t_len; i++)
 		t_GL_users = g_list_append(t_GL_users, SvPVutf8_nolen(*av_fetch((AV *)SvRV(users), i, 0)));
 
 	t_GL_flags = NULL;
 	t_len = av_len((AV *)SvRV(flags));
 
-	for (i = 0; i < t_len; i++)
+	for (i = 0; i <= t_len; i++)
 		t_GL_flags = g_list_append(t_GL_flags, SvPVutf8_nolen(*av_fetch((AV *)SvRV(flags), i, 0)));
 
 	t_GL_extra_msgs = NULL;
 	t_len = av_len((AV *)SvRV(extra_msgs));
 
-	for (i = 0; i < t_len; i++)
+	for (i = 0; i <= t_len; i++)
 		t_GL_extra_msgs = g_list_append(t_GL_extra_msgs, SvPVutf8_nolen(*av_fetch((AV *)SvRV(extra_msgs), i, 0)));
 
 	purple_conv_chat_add_users(chat, t_GL_users, t_GL_extra_msgs, t_GL_flags, new_arrivals);
--- a/libpurple/plugins/perl/common/Prefs.xs	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/plugins/perl/common/Prefs.xs	Wed Dec 17 18:01:08 2008 +0000
@@ -53,7 +53,7 @@
 	t_GL = NULL;
 	t_len = av_len((AV *)SvRV(value));
 
-	for (i = 0; i < t_len; i++)
+	for (i = 0; i <= t_len; i++)
 		t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(value), i, 0)));
 
 	purple_prefs_add_string_list(name, t_GL);
@@ -75,7 +75,7 @@
 	t_GL = NULL;
 	t_len = av_len((AV *)SvRV(value));
 
-	for (i = 0; i < t_len; i++)
+	for (i = 0; i <= t_len; i++)
 		t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(value), i, 0)));
 
 	purple_prefs_add_path_list(name, t_GL);
@@ -204,7 +204,7 @@
 	t_GL = NULL;
 	t_len = av_len((AV *)SvRV(value));
 
-	for (i = 0; i < t_len; i++)
+	for (i = 0; i <= t_len; i++)
 		t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(value), i, 0)));
 
 	purple_prefs_set_string_list(name, t_GL);
@@ -226,7 +226,7 @@
 	t_GL = NULL;
 	t_len = av_len((AV *)SvRV(value));
 
-	for (i = 0; i < t_len; i++)
+	for (i = 0; i <= t_len; i++)
 		t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(value), i, 0)));
 
 	purple_prefs_set_path_list(name, t_GL);
--- a/libpurple/plugins/perl/common/Roomlist.xs	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/plugins/perl/common/Roomlist.xs	Wed Dec 17 18:01:08 2008 +0000
@@ -80,7 +80,7 @@
 	t_GL = NULL;
 	t_len = av_len((AV *)SvRV(fields));
 
-	for (i = 0; i < t_len; i++)
+	for (i = 0; i <= t_len; i++)
 		t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(fields), i, 0)));
 
 	purple_roomlist_set_fields(list, t_GL);
--- a/libpurple/plugins/perl/common/Status.xs	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/plugins/perl/common/Status.xs	Wed Dec 17 18:01:08 2008 +0000
@@ -85,7 +85,7 @@
 	t_GL = NULL;
 	t_len = av_len((AV *)SvRV(source_list));
 
-	for (i = 0; i < t_len; i++) {
+	for (i = 0; i <= t_len; i++) {
 		t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(source_list), i, 0)));
 	}
 	purple_presence_add_list(presence, t_GL);
@@ -381,7 +381,7 @@
 	t_GL = NULL;
 	t_len = av_len((AV *)SvRV(status_types));
 
-	for (i = 0; i < t_len; i++) {
+	for (i = 0; i <= t_len; i++) {
 		t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(status_types), i, 0)));
 	}
 	RETVAL = (PurpleStatusType *)purple_status_type_find_with_id(t_GL, id);
--- a/libpurple/protocols/bonjour/bonjour.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c	Wed Dec 17 18:01:08 2008 +0000
@@ -376,20 +376,20 @@
 	}
 
 	/* Only show first/last name if there is a nickname set (to avoid duplication) */
-	if (bb->nick != NULL) {
-		if (bb->first != NULL)
+	if (bb->nick != NULL && *bb->nick != '\0') {
+		if (bb->first != NULL && *bb->first != '\0')
 			purple_notify_user_info_add_pair(user_info, _("First name"), bb->first);
-		if (bb->first != NULL)
+		if (bb->last != NULL && *bb->last != '\0')
 			purple_notify_user_info_add_pair(user_info, _("Last name"), bb->last);
 	}
 
-	if (bb->email != NULL)
+	if (bb->email != NULL && *bb->email != '\0')
 		purple_notify_user_info_add_pair(user_info, _("Email"), bb->email);
 
-	if (bb->AIM != NULL)
+	if (bb->AIM != NULL && *bb->AIM != '\0')
 		purple_notify_user_info_add_pair(user_info, _("AIM Account"), bb->AIM);
 
-	if (bb->jid!= NULL)
+	if (bb->jid != NULL && *bb->jid != '\0')
 		purple_notify_user_info_add_pair(user_info, _("XMPP Account"), bb->jid);
 }
 
--- a/libpurple/protocols/bonjour/bonjour_ft.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/bonjour/bonjour_ft.c	Wed Dec 17 18:01:08 2008 +0000
@@ -411,8 +411,10 @@
 	BonjourData *bd;
 	PurpleXfer *xfer;
 
-	if(pc == NULL || packet == NULL || pb == NULL)
-		return;
+	g_return_if_fail(pc != NULL);
+	g_return_if_fail(packet != NULL);
+	g_return_if_fail(pb != NULL);
+
 	bd = (BonjourData*) pc->proto_data;
 	if(bd == NULL)
 		return;
@@ -488,8 +490,9 @@
 	xmlnode *query;
 	BonjourData *bd;
 
-	if(pc == NULL || packet == NULL || pb == NULL)
-		return;
+	g_return_if_fail(pc != NULL);
+	g_return_if_fail(packet != NULL);
+	g_return_if_fail(pb != NULL);
 
 	bd = (BonjourData*) pc->proto_data;
 	if(bd == NULL)
--- a/libpurple/protocols/bonjour/bonjour_ft.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/bonjour/bonjour_ft.h	Wed Dec 17 18:01:08 2008 +0000
@@ -27,7 +27,7 @@
 typedef enum {
 	XEP_BYTESTREAMS = 1,
 	XEP_IBB = 2,
-	XEP_UNKNOWN = 4,
+	XEP_UNKNOWN = 4
 } XepSiMode;
 
 struct _XepXfer
--- a/libpurple/protocols/bonjour/buddy.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/bonjour/buddy.c	Wed Dec 17 18:01:08 2008 +0000
@@ -161,7 +161,7 @@
 	name = purple_buddy_get_name(buddy);
 
 	/* Create the alias for the buddy using the first and the last name */
-	if (bonjour_buddy->nick)
+	if (bonjour_buddy->nick && *bonjour_buddy->nick)
 		serv_got_alias(purple_account_get_connection(account), name, bonjour_buddy->nick);
 	else {
 		gchar *alias = NULL;
--- a/libpurple/protocols/bonjour/jabber.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Wed Dec 17 18:01:08 2008 +0000
@@ -77,7 +77,7 @@
 };
 
 static void
-xep_iq_parse(xmlnode *packet, PurpleConnection *connection, PurpleBuddy *pb);
+xep_iq_parse(xmlnode *packet, PurpleBuddy *pb);
 
 static BonjourJabberConversation *
 bonjour_jabber_conv_new(PurpleBuddy *pb, PurpleAccount *account, const char *ip) {
@@ -128,7 +128,7 @@
 
 	if (contents) {
 		char *bodystart = strchr(contents, '>');
-		char *bodyend = strrchr(bodystart, '<');
+		char *bodyend = bodystart ? strrchr(bodystart, '<') : NULL;
 		if (bodystart && bodyend && (bodystart + 1) != bodyend) {
 			*bodyend = '\0';
 			memmove(contents, bodystart + 1, (bodyend - bodystart));
@@ -364,11 +364,36 @@
 	if (!strcmp(packet->name, "message"))
 		_jabber_parse_and_write_message_to_ui(packet, pb);
 	else if(!strcmp(packet->name, "iq"))
-		xep_iq_parse(packet, NULL, pb);
+		xep_iq_parse(packet, pb);
 	else
 		purple_debug_warning("bonjour", "Unknown packet: %s\n", packet->name ? packet->name : "(null)");
 }
 
+static void bonjour_jabber_stream_ended(BonjourJabberConversation *bconv) {
+
+	/* Inform the user that the conversation has been closed */
+	BonjourBuddy *bb = NULL;
+
+	purple_debug_info("bonjour", "Recieved conversation close notification from %s.\n", bconv->pb ? bconv->pb->name : "(unknown)");
+
+	if(bconv->pb != NULL)
+		bb = bconv->pb->proto_data;
+#if 0
+	if(bconv->pb != NULL) {
+		PurpleConversation *conv;
+		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bconv->pb->name, bconv->pb->account);
+		if (conv != NULL) {
+			char *tmp = g_strdup_printf(_("%s has closed the conversation."), bconv->pb->name);
+			purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
+			g_free(tmp);
+		}
+	}
+#endif
+	/* Close the socket, clear the watcher and free memory */
+	bonjour_jabber_close_conversation(bconv);
+	if(bb)
+		bb->conversation = NULL;
+}
 
 static void
 _client_socket_handler(gpointer data, gint socket, PurpleInputCondition condition)
@@ -414,35 +439,6 @@
 	bonjour_parser_process(bconv, message, message_length);
 }
 
-void bonjour_jabber_stream_ended(BonjourJabberConversation *bconv) {
-
-	purple_debug_info("bonjour", "Recieved conversation close notification from %s.\n", bconv->pb ? bconv->pb->name : "(unknown)");
-
-	/* Inform the user that the conversation has been closed */
-	if (bconv != NULL) {
-		BonjourBuddy *bb = NULL;
-
-		if(bconv->pb != NULL)
-			bb = bconv->pb->proto_data;
-#if 0
-		if(bconv->pb != NULL) {
-			PurpleConversation *conv;
-			conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bconv->pb->name, bconv->pb->account);
-			if (conv != NULL) {
-				char *tmp = g_strdup_printf(_("%s has closed the conversation."), bconv->pb->name);
-				purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
-				g_free(tmp);
-			}
-		}
-#endif
-		/* Close the socket, clear the watcher and free memory */
-		bonjour_jabber_close_conversation(bconv);
-		if(bb)
-			bb->conversation = NULL;
-	}
-}
-
-
 struct _stream_start_data {
 	char *msg;
 };
@@ -1162,14 +1158,12 @@
 check_if_blocked(PurpleBuddy *pb)
 {
 	gboolean blocked = FALSE;
-	GSList *l = NULL;
-	PurpleAccount *acc = NULL;
+	GSList *l;
+	PurpleAccount *acc = purple_buddy_get_account(pb);
 
-	if(pb == NULL)
+	if(acc == NULL)
 		return FALSE;
 
-	acc = pb->account;
-
 	for(l = acc->deny; l != NULL; l = l->next) {
 		if(!purple_utf8_strcasecmp(pb->name, (char *)l->data)) {
 			purple_debug_info("bonjour", "%s has been blocked by %s.\n", pb->name, acc->username);
@@ -1181,25 +1175,19 @@
 }
 
 static void
-xep_iq_parse(xmlnode *packet, PurpleConnection *connection, PurpleBuddy *pb)
+xep_iq_parse(xmlnode *packet, PurpleBuddy *pb)
 {
-	xmlnode *child = NULL;
-
-	if(packet == NULL || pb == NULL)
-		return;
-
-	if(connection == NULL) {
-		if(pb->account != NULL)
-			connection = (pb->account)->gc;
-	}
+	xmlnode *child;
 
 	if(check_if_blocked(pb))
 		return;
 
 	if ((child = xmlnode_get_child(packet, "si")) || (child = xmlnode_get_child(packet, "error")))
-		xep_si_parse(connection, packet, pb);
+		xep_si_parse(purple_account_get_connection(pb->account),
+			packet, pb);
 	else
-		xep_bytestreams_parse(connection, packet, pb);
+		xep_bytestreams_parse(purple_account_get_connection(pb->account),
+			packet, pb);
 }
 
 int
--- a/libpurple/protocols/bonjour/jabber.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/bonjour/jabber.h	Wed Dec 17 18:01:08 2008 +0000
@@ -79,8 +79,6 @@
 
 void bonjour_jabber_stream_started(BonjourJabberConversation *bconv);
 
-void bonjour_jabber_stream_ended(BonjourJabberConversation *bconv);
-
 void bonjour_jabber_process_packet(PurpleBuddy *pb, xmlnode *packet);
 
 void bonjour_jabber_stop(BonjourJabber *data);
--- a/libpurple/protocols/jabber/auth.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/jabber/auth.c	Wed Dec 17 18:01:08 2008 +0000
@@ -613,9 +613,7 @@
 	} else if(!strcmp(type, "result")) {
 		query = xmlnode_get_child(packet, "query");
 		if(js->stream_id && xmlnode_get_child(query, "digest")) {
-			unsigned char hashval[20];
-			char *s, h[41], *p;
-			int i;
+			char *s, *hash;
 
 			iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
 			query = xmlnode_get_child(iq->node, "query");
@@ -626,14 +624,9 @@
 
 			x = xmlnode_new_child(query, "digest");
 			s = g_strdup_printf("%s%s", js->stream_id, pw);
-
-			purple_cipher_digest_region("sha1", (guchar *)s, strlen(s),
-									  sizeof(hashval), hashval, NULL);
-
-			p = h;
-			for(i=0; i<20; i++, p+=2)
-				snprintf(p, 3, "%02x", hashval[i]);
-			xmlnode_insert_data(x, h, -1);
+			hash = jabber_calculate_data_sha1sum(s, strlen(s));
+			xmlnode_insert_data(x, hash, -1);
+			g_free(hash);
 			g_free(s);
 			jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
 			jabber_iq_send(iq);
--- a/libpurple/protocols/jabber/buddy.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Wed Dec 17 18:01:08 2008 +0000
@@ -19,7 +19,6 @@
  *
  */
 #include "internal.h"
-#include "cipher.h"
 #include "debug.h"
 #include "imgstore.h"
 #include "prpl.h"
@@ -456,9 +455,6 @@
 		gsize avatar_len;
 		xmlnode *photo, *binval, *type;
 		gchar *enc;
-		int i;
-		unsigned char hashval[20];
-		char *p, hash[41];
 
 		if(!vc_node) {
 			vc_node = xmlnode_new("vCard");
@@ -478,16 +474,7 @@
 		binval = xmlnode_new_child(photo, "BINVAL");
 		enc = purple_base64_encode(avatar_data, avatar_len);
 
-		purple_cipher_digest_region("sha1", avatar_data,
-								  avatar_len, sizeof(hashval),
-								  hashval, NULL);
-
-		purple_imgstore_unref(img);
-
-		p = hash;
-		for(i=0; i<20; i++, p+=2)
-			snprintf(p, 3, "%02x", hashval[i]);
-		js->avatar_hash = g_strdup(hash);
+		js->avatar_hash = jabber_calculate_data_sha1sum(avatar_data, avatar_len);
 
 		xmlnode_insert_data(binval, enc, -1);
 		g_free(enc);
@@ -550,19 +537,9 @@
 				char *lengthstring, *widthstring, *heightstring;
 				
 				/* compute the sha1 hash */
-				PurpleCipherContext *ctx;
-				unsigned char digest[20];
-				char *hash;
+				char *hash = jabber_calculate_data_sha1sum(purple_imgstore_get_data(img), purple_imgstore_get_size(img));
 				char *base64avatar;
 				
-				ctx = purple_cipher_context_new_by_name("sha1", NULL);
-				purple_cipher_context_append(ctx, purple_imgstore_get_data(img), purple_imgstore_get_size(img));
-				purple_cipher_context_digest(ctx, sizeof(digest), digest, NULL);
-				purple_cipher_context_destroy(ctx);
-				
-				/* convert digest to a string */
-				hash = g_strdup_printf("%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x",digest[0],digest[1],digest[2],digest[3],digest[4],digest[5],digest[6],digest[7],digest[8],digest[9],digest[10],digest[11],digest[12],digest[13],digest[14],digest[15],digest[16],digest[17],digest[18],digest[19]);
-				
 				publish = xmlnode_new("publish");
 				xmlnode_set_attrib(publish,"node",AVATARNAMESPACEDATA);
 				
@@ -1412,31 +1389,25 @@
 						(bintext = xmlnode_get_data(child))) {
 					gsize size;
 					guchar *data;
-					int i;
-					unsigned char hashval[20];
-					char *p, hash[41];
 					gboolean photo = (strcmp(child->name, "PHOTO") == 0);
 
 					data = purple_base64_decode(bintext, &size);
 					if (data) {
 						char *img_text;
+						char *hash;
 
 						jbi->vcard_imgids = g_slist_prepend(jbi->vcard_imgids, GINT_TO_POINTER(purple_imgstore_add_with_id(g_memdup(data, size), size, "logo.png")));
 						img_text = g_strdup_printf("<img id='%d'>", GPOINTER_TO_INT(jbi->vcard_imgids->data));
 
 						purple_notify_user_info_add_pair(user_info, (photo ? _("Photo") : _("Logo")), img_text);
 
-						purple_cipher_digest_region("sha1", (guchar *)data, size,
-								sizeof(hashval), hashval, NULL);
-						p = hash;
-						for(i=0; i<20; i++, p+=2)
-							snprintf(p, 3, "%02x", hashval[i]);
-
+						hash = jabber_calculate_data_sha1sum(data, size);
 						purple_buddy_icons_set_for_user(js->gc->account, bare_jid,
 								data, size, hash);
-						g_free(bintext);
+						g_free(hash);
 						g_free(img_text);
 					}
+					g_free(bintext);
 				}
 			}
 			g_free(text);
@@ -1530,9 +1501,12 @@
 		purple_buddy_icons_set_for_user(purple_connection_get_account(js->gc), from, NULL, 0, NULL);
 	} else {
 		xmlnode *info, *goodinfo = NULL;
-		
+		gboolean has_children = FALSE;
+
 		/* iterate over all info nodes to get one we can use */
 		for(info = metadata->child; info; info = info->next) {
+			if(info->type == XMLNODE_TYPE_TAG)
+				has_children = TRUE;
 			if(info->type == XMLNODE_TYPE_TAG && !strcmp(info->name,"info")) {
 				const char *type = xmlnode_get_attrib(info,"type");
 				const char *id = xmlnode_get_attrib(info,"id");
@@ -1547,7 +1521,9 @@
 					goodinfo = info;
 			}
 		}
-		if(goodinfo) {
+		if(has_children == FALSE) {
+			purple_buddy_icons_set_for_user(purple_connection_get_account(js->gc), from, NULL, 0, NULL);
+		} else if(goodinfo) {
 			const char *url = xmlnode_get_attrib(goodinfo, "url");
 			const char *id = xmlnode_get_attrib(goodinfo,"id");
 			
--- a/libpurple/protocols/jabber/jabber.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Wed Dec 17 18:01:08 2008 +0000
@@ -200,7 +200,7 @@
 		if (requested_resource != NULL) {
 			resource = xmlnode_new_child(bind, "resource");
 			xmlnode_insert_data(resource, requested_resource, -1);
-			free(requested_resource);
+			g_free(requested_resource);
 		}
 
 		jabber_iq_set_callback(iq, jabber_bind_result_cb, NULL);
--- a/libpurple/protocols/jabber/jutil.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/jabber/jutil.c	Wed Dec 17 18:01:08 2008 +0000
@@ -20,7 +20,9 @@
  */
 #include "internal.h"
 #include "account.h"
+#include "cipher.h"
 #include "conversation.h"
+#include "debug.h"
 #include "server.h"
 #include "util.h"
 #include "xmlnode.h"
@@ -236,3 +238,29 @@
 	return NULL;
 }
 
+/* The same as purple_util_get_image_checksum, but guaranteed to remain SHA1 */
+char *
+jabber_calculate_data_sha1sum(gconstpointer data, size_t len)
+{
+	PurpleCipherContext *context;
+	static gchar digest[41];
+
+	context = purple_cipher_context_new_by_name("sha1", NULL);
+	if (context == NULL)
+	{
+		purple_debug_error("jabber", "Could not find sha1 cipher\n");
+		g_return_val_if_reached(NULL);
+	}
+
+	/* Hash the data */
+	purple_cipher_context_append(context, data, len);
+	if (!purple_cipher_context_digest_to_str(context, sizeof(digest), digest, NULL))
+	{
+		purple_debug_error("jabber", "Failed to get SHA-1 digest.\n");
+		g_return_val_if_reached(NULL);
+	}
+	purple_cipher_context_destroy(context);
+
+	return g_strdup(digest);
+}
+
--- a/libpurple/protocols/jabber/jutil.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/jabber/jutil.h	Wed Dec 17 18:01:08 2008 +0000
@@ -42,4 +42,5 @@
 
 PurpleConversation *jabber_find_unnormalized_conv(const char *name, PurpleAccount *account);
 
+char *jabber_calculate_data_sha1sum(gconstpointer data, size_t len);
 #endif /* _PURPLE_JABBER_JUTIL_H_ */
--- a/libpurple/protocols/jabber/message.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/jabber/message.c	Wed Dec 17 18:01:08 2008 +0000
@@ -571,12 +571,39 @@
 
 	for(child = packet->child; child; child = child->next) {
 		const char *xmlns = xmlnode_get_namespace(child);
-		if(!xmlns)
-			xmlns = "";
 		if(child->type != XMLNODE_TYPE_TAG)
 			continue;
 
-		if(!strcmp(child->name, "subject") && !strcmp(xmlns,"jabber:client")) {
+		if(!strcmp(child->name, "error")) {
+			const char *code = xmlnode_get_attrib(child, "code");
+			char *code_txt = NULL;
+			char *text = xmlnode_get_data(child);
+			if (!text) {
+				xmlnode *enclosed_text_node;
+				
+				if ((enclosed_text_node = xmlnode_get_child(child, "text")))
+					text = xmlnode_get_data(enclosed_text_node);
+			}
+
+			if(code)
+				code_txt = g_strdup_printf(_("(Code %s)"), code);
+
+			if(!jm->error)
+				jm->error = g_strdup_printf("%s%s%s",
+						text ? text : "",
+						text && code_txt ? " " : "",
+						code_txt ? code_txt : "");
+
+			g_free(code_txt);
+			g_free(text);
+		} else if (xmlns == NULL) {
+			/* QuLogic: Not certain this is correct, but it would have happened
+			   with the previous code. */
+			if(!strcmp(child->name, "x"))
+				jm->etc = g_list_append(jm->etc, child);
+			/* The following tests expect xmlns != NULL */
+			continue;
+		} else if(!strcmp(child->name, "subject") && !strcmp(xmlns,"jabber:client")) {
 			if(!jm->subject)
 				jm->subject = xmlnode_get_data(child);
 		} else if(!strcmp(child->name, "thread") && !strcmp(xmlns,"jabber:client")) {
@@ -706,46 +733,24 @@
 				jm->eventitems = g_list_append(jm->eventitems, items);
 		} else if(!strcmp(child->name, "attention") && !strcmp(xmlns,"http://www.xmpp.org/extensions/xep-0224.html#ns")) {
 			jm->hasBuzz = TRUE;
-		} else if(!strcmp(child->name, "error")) {
-			const char *code = xmlnode_get_attrib(child, "code");
-			char *code_txt = NULL;
-			char *text = xmlnode_get_data(child);
-			if (!text) {
-				xmlnode *enclosed_text_node;
-				
-				if ((enclosed_text_node = xmlnode_get_child(child, "text")))
-					text = xmlnode_get_data(enclosed_text_node);
-			}
-
-			if(code)
-				code_txt = g_strdup_printf(_("(Code %s)"), code);
-
-			if(!jm->error)
-				jm->error = g_strdup_printf("%s%s%s",
-						text ? text : "",
-						text && code_txt ? " " : "",
-						code_txt ? code_txt : "");
-
-			g_free(code_txt);
-			g_free(text);
-		} else if(!strcmp(child->name, "delay") && xmlns && !strcmp(xmlns,"urn:xmpp:delay")) {
+		} else if(!strcmp(child->name, "delay") && !strcmp(xmlns,"urn:xmpp:delay")) {
 			const char *timestamp = xmlnode_get_attrib(child, "stamp");
 			jm->delayed = TRUE;
 			if(timestamp)
 				jm->sent = purple_str_to_time(timestamp, TRUE, NULL, NULL, NULL);
 		} else if(!strcmp(child->name, "x")) {
-			if(xmlns && !strcmp(xmlns, "jabber:x:event")) {
+			if(!strcmp(xmlns, "jabber:x:event")) {
 				if(xmlnode_get_child(child, "composing")) {
 					if(jm->chat_state == JM_STATE_ACTIVE)
 						jm->chat_state = JM_STATE_COMPOSING;
 					jm->typing_style |= JM_TS_JEP_0022;
 				}
-			} else if(xmlns && !strcmp(xmlns, "jabber:x:delay")) {
+			} else if(!strcmp(xmlns, "jabber:x:delay")) {
 				const char *timestamp = xmlnode_get_attrib(child, "stamp");
 				jm->delayed = TRUE;
 				if(timestamp)
 					jm->sent = purple_str_to_time(timestamp, TRUE, NULL, NULL, NULL);
-			} else if(xmlns && !strcmp(xmlns, "jabber:x:conference") &&
+			} else if(!strcmp(xmlns, "jabber:x:conference") &&
 					jm->type != JABBER_MESSAGE_GROUPCHAT_INVITE &&
 					jm->type != JABBER_MESSAGE_ERROR) {
 				const char *jid = xmlnode_get_attrib(child, "jid");
@@ -754,8 +759,7 @@
 					g_free(jm->to);
 					jm->to = g_strdup(jid);
 				}
-			} else if(xmlns && !strcmp(xmlns,
-						"http://jabber.org/protocol/muc#user") &&
+			} else if(!strcmp(xmlns, "http://jabber.org/protocol/muc#user") &&
 					jm->type != JABBER_MESSAGE_ERROR) {
 				xmlnode *invite = xmlnode_get_child(child, "invite");
 				if(invite) {
--- a/libpurple/protocols/jabber/presence.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/jabber/presence.c	Wed Dec 17 18:01:08 2008 +0000
@@ -151,8 +151,7 @@
 					  (a && !b) || (a && a[0] != '\0' && b && b[0] == '\0') || (a && b && strcmp(a,b)))
 	/* check if there are any differences to the <presence> and send them in that case */
 	if (allowBuzz != js->allowBuzz || js->old_state != state || CHANGED(js->old_msg, stripped) ||
-		js->old_priority != priority || CHANGED(js->old_avatarhash, js->avatar_hash) ||
-		js->old_idle != js->idle) {
+		js->old_priority != priority || CHANGED(js->old_avatarhash, js->avatar_hash)) {
 		js->allowBuzz = allowBuzz;
 
 		presence = jabber_presence_create_js(js, state, stripped, priority);
@@ -179,7 +178,6 @@
 		js->old_avatarhash = g_strdup(js->avatar_hash);
 		js->old_state = state;
 		js->old_priority = priority;
-		js->old_idle = js->idle;
 	}
 	g_free(stripped);
 
@@ -262,16 +260,6 @@
 		g_free(pstr);
 	}
 
-	/* if we are idle and not offline, include idle */
-	if (js->idle && state != JABBER_BUDDY_STATE_UNAVAILABLE) {
-		xmlnode *query = xmlnode_new_child(presence, "query");
-		gchar seconds[10];
-		g_snprintf(seconds, 10, "%d", (int) (time(NULL) - js->idle));
-		
-		xmlnode_set_namespace(query, "jabber:iq:last");
-		xmlnode_set_attrib(query, "seconds", seconds);
-	}
-	
 	/* JEP-0115 */
 	c = xmlnode_new_child(presence, "c");
 	xmlnode_set_namespace(c, "http://jabber.org/protocol/caps");
@@ -439,7 +427,6 @@
 	JabberBuddyResource *jbr = NULL, *found_jbr = NULL;
 	PurpleConvChatBuddyFlags flags = PURPLE_CBFLAGS_NONE;
 	gboolean delayed = FALSE;
-	const gchar *stamp = NULL; /* from <delayed/> element */
 	PurpleBuddy *b = NULL;
 	char *buddy_name;
 	JabberBuddyState state = JABBER_BUDDY_STATE_UNKNOWN;
@@ -447,8 +434,7 @@
 	gboolean muc = FALSE;
 	char *avatar_hash = NULL;
 	xmlnode *caps = NULL;
-	int idle = 0;
-	
+
 	if(!(jb = jabber_buddy_find(js, from, TRUE)))
 		return;
 
@@ -527,7 +513,6 @@
 		} else if(!strcmp(y->name, "delay") && !strcmp(xmlns, "urn:xmpp:delay")) {
 			/* XXX: compare the time.  jabber:x:delay can happen on presence packets that aren't really and truly delayed */
 			delayed = TRUE;
-			stamp = xmlnode_get_attrib(y, "stamp");
 		} else if(xmlns && !strcmp(y->name, "c") && !strcmp(xmlns, "http://jabber.org/protocol/caps")) {
 			caps = y; /* store for later, when creating buddy resource */
 		} else if(!strcmp(y->name, "x")) {
@@ -535,7 +520,6 @@
 			if(xmlns && !strcmp(xmlns, "jabber:x:delay")) {
 				/* XXX: compare the time.  jabber:x:delay can happen on presence packets that aren't really and truly delayed */
 				delayed = TRUE;
-				stamp = xmlnode_get_attrib(y, "stamp");
 			} else if(xmlns && !strcmp(xmlns, "http://jabber.org/protocol/muc#user")) {
 				xmlnode *z;
 
@@ -586,29 +570,9 @@
 					avatar_hash = xmlnode_get_data(photo);
 				}
 			}
-		} else if (!strcmp(y->name, "query") && 
-			!strcmp(xmlnode_get_namespace(y), "jabber:iq:last")) {
-			/* resource has specified idle */
-			const gchar *seconds = xmlnode_get_attrib(y, "seconds");
-			if (seconds) {
-				/* we may need to take "delayed" into account here */
-				idle = atoi(seconds);
-			}
 		}
 	}
 
-	purple_debug_info("jabber", "got %d seconds idle from presence\n", idle);
-	
-	if (idle && delayed && stamp) {
-		/* if we have a delayed presence, we need to add the delay to the idle
-		 value */
-		time_t offset = time(NULL) - purple_str_to_time(stamp, TRUE, NULL, NULL,
-			NULL);
-		purple_debug_info("jabber", "got delay %s yielding %ld s offset\n",
-			stamp, offset);
-		idle += offset; 
-	}
-	
 
 	if(jid->node && (chat = jabber_chat_find(js, jid->node, jid->domain))) {
 		static int i = 1;
@@ -783,12 +747,6 @@
 		} else {
 			jbr = jabber_buddy_track_resource(jb, jid->resource, priority,
 					state, status);
-			if (idle) {
-				jbr->idle = time(NULL) - idle;
-			} else {
-				jbr->idle = 0;
-			}
-			
 			if(caps) {
 				const char *node = xmlnode_get_attrib(caps,"node");
 				const char *ver = xmlnode_get_attrib(caps,"ver");
@@ -807,7 +765,6 @@
 		if((found_jbr = jabber_buddy_find_resource(jb, NULL))) {
 			jabber_google_presence_incoming(js, buddy_name, found_jbr);
 			purple_prpl_got_user_status(js->gc->account, buddy_name, jabber_buddy_state_get_status_id(found_jbr->state), "priority", found_jbr->priority, "message", found_jbr->status, NULL);
-			purple_prpl_got_user_idle(js->gc->account, buddy_name, found_jbr->idle, found_jbr->idle);
 		} else {
 			purple_prpl_got_user_status(js->gc->account, buddy_name, "offline", status ? "message" : NULL, status, NULL);
 		}
--- a/libpurple/protocols/jabber/si.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/jabber/si.c	Wed Dec 17 18:01:08 2008 +0000
@@ -23,7 +23,6 @@
 #include "internal.h"
 
 #include "blist.h"
-#include "cipher.h"
 #include "debug.h"
 #include "ft.h"
 #include "request.h"
@@ -183,9 +182,6 @@
 {
 	JabberSIXfer *jsx = xfer->data;
 	JabberBytestreamsStreamhost *streamhost;
-	char *dstaddr, *p;
-	int i;
-	unsigned char hashval[20];
 	JabberID *dstjid;
 
 	if(!jsx->streamhosts) {
@@ -221,6 +217,7 @@
 	/* TODO: Deal with zeroconf */
 
 	if(dstjid != NULL && streamhost->host && streamhost->port > 0) {
+		char *dstaddr, *hash;
 		jsx->gpi = purple_proxy_info_new();
 		purple_proxy_info_set_type(jsx->gpi, PURPLE_PROXY_SOCKS5);
 		purple_proxy_info_set_host(jsx->gpi, streamhost->host);
@@ -234,17 +231,13 @@
 			dstaddr = g_strdup_printf("%s%s@%s/%s%s@%s/%s", jsx->stream_id, dstjid->node, dstjid->domain, dstjid->resource,
 				jsx->js->user->node, jsx->js->user->domain, jsx->js->user->resource);
 
-		purple_cipher_digest_region("sha1", (guchar *)dstaddr, strlen(dstaddr),
-				sizeof(hashval), hashval, NULL);
-		g_free(dstaddr);
-		dstaddr = g_malloc(41);
-		p = dstaddr;
-		for(i=0; i<20; i++, p+=2)
-			snprintf(p, 3, "%02x", hashval[i]);
+		/* Per XEP-0065, the 'host' must be SHA1(SID + from JID + to JID) */
+		hash = jabber_calculate_data_sha1sum(dstaddr, strlen(dstaddr));
 
 		jsx->connect_data = purple_proxy_connect_socks5(NULL, jsx->gpi,
-				dstaddr, 0,
+				hash, 0,
 				jabber_si_bytestreams_connect_cb, xfer);
+		g_free(hash);
 		g_free(dstaddr);
 
 		/* When selecting a streamhost, timeout after STREAMHOST_CONNECT_TIMEOUT seconds, otherwise it takes forever */
@@ -361,11 +354,9 @@
 {
 	PurpleXfer *xfer = data;
 	JabberSIXfer *jsx = xfer->data;
-	int i;
 	char buffer[256];
 	int len;
-	char *dstaddr, *p;
-	unsigned char hashval[20];
+	char *dstaddr, *hash;
 	const char *host;
 
 	purple_debug_info("jabber", "in jabber_si_xfer_bytestreams_send_read_again_cb\n");
@@ -421,23 +412,20 @@
 			jsx->js->user->node, jsx->js->user->domain,
 			jsx->js->user->resource, xfer->who);
 
-	purple_cipher_digest_region("sha1", (guchar *)dstaddr, strlen(dstaddr),
-				    sizeof(hashval), hashval, NULL);
-	g_free(dstaddr);
-	dstaddr = g_malloc(41);
-	p = dstaddr;
-	for(i=0; i<20; i++, p+=2)
-		snprintf(p, 3, "%02x", hashval[i]);
+	/* Per XEP-0065, the 'host' must be SHA1(SID + from JID + to JID) */
+	hash = jabber_calculate_data_sha1sum(dstaddr, strlen(dstaddr));
 
-	if(jsx->rxqueue[4] != 40 || strncmp(dstaddr, jsx->rxqueue+5, 40) ||
+	if(jsx->rxqueue[4] != 40 || strncmp(hash, jsx->rxqueue+5, 40) ||
 			jsx->rxqueue[45] != 0x00 || jsx->rxqueue[46] != 0x00) {
 		purple_debug_error("jabber", "someone connected with the wrong info!\n");
 		close(source);
 		purple_xfer_cancel_remote(xfer);
+		g_free(hash);
 		g_free(dstaddr);
 		return;
 	}
 
+	g_free(hash);
 	g_free(dstaddr);
 
 	g_free(jsx->rxqueue);
--- a/libpurple/protocols/msn/contact.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/contact.c	Wed Dec 17 18:01:08 2008 +0000
@@ -176,28 +176,6 @@
 	return 0;
 }
 
-/* get Network */
-/* QuLogic: These names don't really refer to the MsnNetwork,
- *          but I haven't yet written the code to properly use them.
- */
-static MsnNetwork
-msn_get_network(char *type)
-{
-	g_return_val_if_fail(type != NULL, 0);
-
-	if (!strcmp(type,"Regular")) {
-		return MSN_NETWORK_PASSPORT;
-	}
-	if (!strcmp(type,"Live")) {
-		return MSN_NETWORK_PASSPORT;
-	}
-	if (!strcmp(type,"LivePending")) {
-		return MSN_NETWORK_PASSPORT;
-	}
-
-	return MSN_NETWORK_UNKNOWN;
-}
-
 /* Create the AddressBook in the server, if we don't have one */
 static void
 msn_create_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data)
@@ -245,9 +223,31 @@
 	char *type = xmlnode_get_data(xmlnode_get_child(member, "Type"));
 	char *member_id = xmlnode_get_data(xmlnode_get_child(member, "MembershipId"));
 	MsnUser *user = msn_userlist_find_add_user(session->userlist, passport, NULL);
+	xmlnode *annotation;
+	guint nid = MSN_NETWORK_UNKNOWN;
 
-	purple_debug_info("msn", "CL: %s name: %s, Type: %s, MembershipID: %s\n",
-		node, passport, type, member_id == NULL ? "(null)" : member_id);
+	/* For EmailMembers, the network must be found in the annotations. */
+	if (!strcmp(node, "PassportName")) {
+		nid = MSN_NETWORK_PASSPORT;
+	} else {
+		for (annotation = xmlnode_get_child(member, "Annotations/Annotation");
+		     annotation;
+		     annotation = xmlnode_get_next_twin(annotation)) {
+			char *name = xmlnode_get_data(xmlnode_get_child(annotation, "Name"));
+			if (name && !strcmp(name, "MSN.IM.BuddyType")) {
+				char *value = xmlnode_get_data(xmlnode_get_child(annotation, "Value"));
+				if (value != NULL)
+					nid = strtoul(value, NULL, 10);
+				g_free(value);
+			}
+			g_free(name);
+		}
+	}
+ 
+	purple_debug_info("msn", "CL: %s name: %s, Type: %s, MembershipID: %s, NetworkID: %u\n",
+		node, passport, type, member_id == NULL ? "(null)" : member_id, nid);
+
+	msn_user_set_network(user, nid);
 
 	if (member_id) {
 		user->membership_id[list] = atoi(member_id);
@@ -445,16 +445,16 @@
 		if ((groupInfo = xmlnode_get_child(group, "groupInfo")) && (groupname = xmlnode_get_child(groupInfo, "name")))
 			group_name = xmlnode_get_data(groupname);
 
-		msn_group_new(session->userlist, group_id, group_name);
-
-		if (group_id == NULL){
+		if (group_id == NULL) {
 			/* Group of ungroupped buddies */
 			g_free(group_name);
 			continue;
 		}
 
+		msn_group_new(session->userlist, group_id, group_name);
+
 		purple_debug_info("msn", "AB group_id: %s, name: %s\n", group_id, group_name ? group_name : "(null)");
-		if ((purple_find_group(group_name)) == NULL){
+		if ((purple_find_group(group_name)) == NULL) {
 			PurpleGroup *g = purple_group_new(group_name);
 			purple_blist_add_group(g, NULL);
 		}
@@ -528,7 +528,6 @@
 		xmlnode *contactId, *contactInfo, *contactType, *passportName, *displayName, *guid, *groupIds, *messenger_user;
 		xmlnode *annotation;
 		MsnUser *user;
-		MsnNetwork networkId;
 
 		if (!(contactId = xmlnode_get_child(contactNode,"contactId"))
 				|| !(contactInfo = xmlnode_get_child(contactNode, "contactInfo"))
@@ -569,7 +568,6 @@
 			g_free(is_messenger_user);
 		}
 
-		networkId = msn_get_network(type);
 		passportName = xmlnode_get_child(contactInfo, "passportName");
 		if (passportName == NULL) {
 			xmlnode *emailsNode, *contactEmailNode, *emailNode;
@@ -600,7 +598,6 @@
 				if (msnEnabled && !strcmp(msnEnabled, "true")) {
 					/*Messenger enabled, Get the Passport*/
 					purple_debug_info("msn", "AB Yahoo User %s\n", passport ? passport : "(null)");
-					networkId = MSN_NETWORK_YAHOO;
 					g_free(msnEnabled);
 					break;
 				} else {
@@ -628,6 +625,15 @@
 			name = xmlnode_get_data(xmlnode_get_child(annotation, "Name"));
 			if (!strcmp(name, "AB.NickName"))
 				alias = xmlnode_get_data(xmlnode_get_child(annotation, "Value"));
+			else if (!strcmp(name, "MSN.IM.HasSharedFolder"))
+				; /* Do nothing yet... */
+			else if (!strcmp(name, "AB.Spouse"))
+				; /* Do nothing yet... */
+			else if (!strcmp(name, "MSN.Mobile.ContactId"))
+				; /* Do nothing yet... */
+			else
+				purple_debug_info("msn",
+				                  "Unknown AB contact annotation: %s\n", name);
 			g_free(name);
 		}
 
@@ -639,7 +645,6 @@
 
 		user = msn_userlist_find_add_user(session->userlist, passport, Name);
 		msn_user_set_uid(user, uid);
-		msn_user_set_network(user, networkId);
 		msn_user_set_mobile_phone(user, mobile_number);
 
 		groupIds = xmlnode_get_child(contactInfo, "groupIds");
@@ -870,7 +875,7 @@
 	gpointer data)
 {
 	MsnCallbackState *state = data;
-	xmlnode *faultcode;
+	xmlnode *fault;
 	char *faultcode_str;
 
 	if (resp == NULL) {
@@ -880,9 +885,9 @@
 		return;
 	}
 
-	faultcode = xmlnode_get_child(resp->xml, "Body/Fault/faultcode");
+	fault = xmlnode_get_child(resp->xml, "Body/Fault");
 
-	if (faultcode == NULL) {
+	if (fault == NULL) {
 		/* No errors */
 		if (state->cb)
 			((MsnSoapCallback)state->cb)(req, resp, data);
@@ -890,7 +895,7 @@
 		return;
 	}
 
-	faultcode_str = xmlnode_get_data(faultcode);
+	faultcode_str = xmlnode_get_data(xmlnode_get_child(fault, "faultcode"));
 
 	if (faultcode_str && g_str_equal(faultcode_str, "q0:BadContextToken")) {
 		purple_debug_info("msn",
@@ -903,12 +908,15 @@
 	}
 	else
 	{
-		/* We don't know how to respond to this faultcode, so just log it */
-		/* XXX: Probably should notify the user or undo the change or something? */
-		char *str = xmlnode_to_str(xmlnode_get_child(resp->xml, "Body/Fault"), NULL);
-		purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n",
-		                   msn_contact_operation_str(state->action), str);
-		g_free(str);
+		if (state->cb) {
+			((MsnSoapCallback)state->cb)(req, resp, data);
+		} else {
+			/* We don't know how to respond to this faultcode, so log it */
+			char *str = xmlnode_to_str(fault, NULL);
+			purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n",
+			                   msn_contact_operation_str(state->action), str);
+			g_free(str);
+		}
 		msn_callback_state_free(state);
 	}
 
@@ -943,21 +951,44 @@
 	MsnUser *user;
 	xmlnode *guid;
 
+	xmlnode *fault;
+
 	g_return_if_fail(session != NULL);
+	userlist = session->userlist;
+
+	fault = xmlnode_get_child(resp->xml, "Body/Fault");
+	if (fault != NULL) {
+		char *errorcode = xmlnode_get_data(xmlnode_get_child(fault, "detail/errorcode"));
+		if (errorcode && !strcmp(errorcode, "EmailDomainIsFederated")) {
+			/* Do something special! */
+			purple_debug_error("msn", "Contact is from a federated domain, but don't know what to do yet!\n");
 
-	userlist = session->userlist;
+		} else if (errorcode && !strcmp(errorcode, "InvalidPassportUser")) {
+			PurpleBuddy *buddy = purple_find_buddy(session->account, state->who);
+			char *str = g_strdup_printf(_("Unable to add \"%s\"."), state->who);
+			purple_notify_error(state->session, _("Buddy Add error"), str,
+			                    _("The username specified does not exist."));
+			g_free(str);
+			msn_userlist_rem_buddy(userlist, state->who);
+			if (buddy != NULL)
+				purple_blist_remove_buddy(buddy);
+
+		} else {
+			/* We don't know how to respond to this faultcode, so log it */
+			char *fault_str = xmlnode_to_str(fault, NULL);
+			if (fault_str != NULL) {
+				purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n",
+				                   msn_contact_operation_str(state->action), fault_str);
+				g_free(fault_str);
+			}
+		}
+		return;
+	}
 
 	purple_debug_info("msn", "Contact added successfully\n");
 
-	/* the code this block is replacing didn't send ADL for yahoo contacts,
-	 * but i haven't confirmed this is WLM's behaviour wrt yahoo contacts
-	 */
-	if ( !msn_user_is_yahoo(session->account, state->who) ) {
-		msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL);
-		msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL);
-	}
-
-	msn_notification_send_fqy(session, state->who);
+	msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL);
+	msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL);
 
 	user = msn_userlist_find_add_user(userlist, state->who, state->who);
 	msn_user_add_group_id(user, state->guid);
@@ -976,6 +1007,7 @@
 void
 msn_add_contact(MsnSession *session, MsnCallbackState *state, const char *passport)
 {
+	MsnUser *user;
 	gchar *body = NULL;
 	gchar *contact_xml = NULL;
 
@@ -993,7 +1025,21 @@
 
 	purple_debug_info("msn", "Adding contact %s to contact list\n", passport);
 
-	contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport);
+	user = msn_userlist_find_user(session->userlist, passport);
+	if (user == NULL) {
+		purple_debug_warning("msn", "Unable to retrieve user %s from the userlist!\n", passport);
+		return; /* guess this never happened! */
+	}
+
+	if (user->networkid != MSN_NETWORK_PASSPORT) {
+		contact_xml = g_strdup_printf(MSN_CONTACT_EMAIL_XML,
+		                              user->networkid == MSN_NETWORK_YAHOO ?
+		                                  "Messenger2" :
+		                                  "Messenger3",
+		                              passport, 0);
+	} else {
+		contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport);
+	}
 	body = g_strdup_printf(MSN_ADD_CONTACT_TEMPLATE, contact_xml);
 
 	state->body = xmlnode_from_str(body, -1);
@@ -1011,11 +1057,41 @@
 	gpointer data)
 {
 	MsnCallbackState *state = data;
+	MsnSession *session = state->session;
 	MsnUserList *userlist;
+	xmlnode *fault;
+
+	g_return_if_fail(session != NULL);
+	userlist = session->userlist;
+
+	fault = xmlnode_get_child(resp->xml, "Body/Fault");
+	if (fault != NULL) {
+		char *errorcode = xmlnode_get_data(xmlnode_get_child(fault, "detail/errorcode"));
+		if (errorcode && !strcmp(errorcode, "EmailDomainIsFederated")) {
+			/* Do something special! */
+			purple_debug_error("msn", "Contact is from a federated domain, but don't know what to do yet!\n");
 
-	g_return_if_fail(data != NULL);
+		} else if (errorcode && !strcmp(errorcode, "InvalidPassportUser")) {
+			PurpleBuddy *buddy = purple_find_buddy(session->account, state->who);
+			char *str = g_strdup_printf(_("Unable to add \"%s\"."), state->who);
+			purple_notify_error(session, _("Buddy Add error"), str,
+			                    _("The username specified does not exist."));
+			g_free(str);
+			msn_userlist_rem_buddy(userlist, state->who);
+			if (buddy != NULL)
+				purple_blist_remove_buddy(buddy);
 
-	userlist = state->session->userlist;
+		} else {
+			/* We don't know how to respond to this faultcode, so log it */
+			char *fault_str = xmlnode_to_str(fault, NULL);
+			if (fault_str != NULL) {
+				purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n",
+				                   msn_contact_operation_str(state->action), fault_str);
+				g_free(fault_str);
+			}
+		}
+		return;
+	}
 
 	if (msn_userlist_add_buddy_to_group(userlist, state->who,
 			state->new_group_name)) {
@@ -1036,11 +1112,8 @@
 			g_free(uid);
 		}
 
-		if ( !msn_user_is_yahoo(state->session->account, state->who) ) {
-			msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL);
-			msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL);
-		}
-		msn_notification_send_fqy(state->session, state->who);
+		msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL);
+		msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL);
 
 		if (msn_userlist_user_is_in_list(user, MSN_LIST_PL)) {
 			msn_del_contact_from_list(state->session, NULL, state->who, MSN_LIST_PL);
@@ -1095,8 +1168,14 @@
 		return; /* guess this never happened! */
 	}
 
-	if (user != NULL && user->uid != NULL) {
+	if (user->uid != NULL) {
 		contact_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid);
+	} else if (user->networkid != MSN_NETWORK_PASSPORT) {
+		contact_xml = g_strdup_printf(MSN_CONTACT_EMAIL_XML,
+		                              user->networkid == MSN_NETWORK_YAHOO ?
+		                                  "Messenger2" :
+		                                  "Messenger3",
+		                              passport, 0);
 	} else {
 		contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport);
 	}
@@ -1120,6 +1199,17 @@
 	MsnCallbackState *state = data;
 	MsnUserList *userlist = state->session->userlist;
 	MsnUser *user = msn_userlist_find_user_with_id(userlist, state->uid);
+	xmlnode *fault;
+
+	/* We don't know how to respond to this faultcode, so log it */
+	fault = xmlnode_get_child(resp->xml, "Body/Fault");
+	if (fault != NULL) {
+		char *fault_str = xmlnode_to_str(fault, NULL);
+		purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n",
+		                   msn_contact_operation_str(state->action), fault_str);
+		g_free(fault_str);
+		return;
+	}
 
 	purple_debug_info("msn", "Delete contact successful\n");
 
@@ -1140,8 +1230,8 @@
 		contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid);
 		purple_debug_info("msn", "Deleting contact with contactId: %s\n", user->uid);
 	} else {
-		contact_id_xml = g_strdup_printf(MSN_CONTACT_XML, user->passport);
-		purple_debug_info("msn", "Deleting contact with passport: %s\n", user->passport);
+		purple_debug_info("msn", "Unable to delete contact %s without a ContactId\n", user->passport);
+		return;
 	}
 
 	state = msn_callback_state_new(session);
@@ -1165,6 +1255,17 @@
 	gpointer data)
 {
 	MsnCallbackState *state = data;
+	xmlnode *fault;
+
+	/* We don't know how to respond to this faultcode, so log it */
+	fault = xmlnode_get_child(resp->xml, "Body/Fault");
+	if (fault != NULL) {
+		char *fault_str = xmlnode_to_str(fault, NULL);
+		purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n",
+		                   msn_contact_operation_str(state->action), fault_str);
+		g_free(fault_str);
+		return;
+	}
 
 	if (msn_userlist_rem_buddy_from_group(state->session->userlist,
 			state->who, state->old_group_name)) {
@@ -1235,6 +1336,19 @@
 msn_update_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp,
 	gpointer data)
 {
+	MsnCallbackState *state = (MsnCallbackState *)data;
+	xmlnode *fault;
+
+	/* We don't know how to respond to this faultcode, so log it */
+	fault = xmlnode_get_child(resp->xml, "Body/Fault");
+	if (fault != NULL) {
+		char *fault_str = xmlnode_to_str(fault, NULL);
+		purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n",
+		                   msn_contact_operation_str(state->action), fault_str);
+		g_free(fault_str);
+		return;
+	}
+
 	purple_debug_info("msn", "Contact updated successfully\n");
 }
 
@@ -1312,6 +1426,17 @@
 {
 	MsnCallbackState *state = data;
 	MsnSession *session = state->session;
+	xmlnode *fault;
+
+	/* We don't know how to respond to this faultcode, so log it */
+	fault = xmlnode_get_child(resp->xml, "Body/Fault");
+	if (fault != NULL) {
+		char *fault_str = xmlnode_to_str(fault, NULL);
+		purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n",
+		                   msn_contact_operation_str(state->action), fault_str);
+		g_free(fault_str);
+		return;
+	}
 
 	purple_debug_info("msn", "Contact %s deleted successfully from %s list on server!\n", state->who, MsnMemberRole[state->list_id]);
 
@@ -1339,10 +1464,13 @@
 			  const gchar *passport, const MsnListId list)
 {
 	gchar *body = NULL, *member = NULL;
+	const char *type = "PassportMember";
+	gchar *federate = NULL;
 	MsnSoapPartnerScenario partner_scenario;
 	MsnUser *user;
 
 	g_return_if_fail(session != NULL);
+	g_return_if_fail(session->userlist != NULL);
 	g_return_if_fail(passport != NULL);
 	g_return_if_fail(list < 5);
 
@@ -1354,21 +1482,27 @@
 	msn_callback_state_set_list_id(state, list);
 	msn_callback_state_set_who(state, passport);
 
+	user = msn_userlist_find_user(session->userlist, passport);
+	if (user && user->networkid != MSN_NETWORK_PASSPORT) {
+		type = "EmailMember";
+		federate = g_strdup_printf(MSN_MEMBER_FEDERATED_ANNOTATION_XML,
+		                           user->networkid);
+	}
+	
 	if (list == MSN_LIST_PL) {
-		g_return_if_fail(session->userlist != NULL);
-
-		user = msn_userlist_find_user(session->userlist, passport);
-
 		partner_scenario = MSN_PS_CONTACT_API;
-		member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML, user->membership_id[MSN_LIST_PL]);
+		member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML,
+		                         type, user->membership_id[MSN_LIST_PL],
+		                         federate ? federate : "");
 	} else {
 		/* list == MSN_LIST_AL || list == MSN_LIST_BL */
 		partner_scenario = MSN_PS_BLOCK_UNBLOCK;
-		
-		member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, passport);
+		member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML,
+		                         type, passport,
+		                         federate ? federate : "");
 	}
 
-	body = g_strdup_printf(MSN_CONTACT_DELECT_FROM_LIST_TEMPLATE,
+	body = g_strdup_printf(MSN_CONTACT_DELETE_FROM_LIST_TEMPLATE,
 		MsnSoapPartnerScenarioText[partner_scenario],
 		MsnMemberRole[list], member);
 
@@ -1378,6 +1512,7 @@
 	state->cb = msn_del_contact_from_list_read_cb;
 	msn_contact_request(state);
 
+	g_free(federate);
 	g_free(member);
 	g_free(body);
 }
@@ -1387,8 +1522,18 @@
 	gpointer data)
 {
 	MsnCallbackState *state = data;
+	xmlnode *fault;
 
-	g_return_if_fail(state != NULL);
+	/* We don't know how to respond to this faultcode, so log it */
+	fault = xmlnode_get_child(resp->xml, "Body/Fault");
+	if (fault != NULL) {
+		char *fault_str = xmlnode_to_str(fault, NULL);
+		purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n",
+		                   msn_contact_operation_str(state->action), fault_str);
+		g_free(fault_str);
+		return;
+	}
+
 	g_return_if_fail(state->session != NULL);
 
 	purple_debug_info("msn", "Contact %s added successfully to %s list on server!\n", state->who, MsnMemberRole[state->list_id]);
@@ -1415,7 +1560,10 @@
 			const gchar *passport, const MsnListId list)
 {
 	gchar *body = NULL, *member = NULL;
+	const char *type = "PassportMember";
+	gchar *federate = NULL;
 	MsnSoapPartnerScenario partner_scenario;
+	MsnUser *user;
 
 	g_return_if_fail(session != NULL);
 	g_return_if_fail(passport != NULL);
@@ -1429,9 +1577,16 @@
 	msn_callback_state_set_list_id(state, list);
 	msn_callback_state_set_who(state, passport);
 
-	partner_scenario = (list == MSN_LIST_RL) ? MSN_PS_CONTACT_API : MSN_PS_BLOCK_UNBLOCK;
+	user = msn_userlist_find_user(session->userlist, passport);
+	if (user && user->networkid != MSN_NETWORK_PASSPORT) {
+		type = "EmailMember";
+		federate = g_strdup_printf(MSN_MEMBER_FEDERATED_ANNOTATION_XML,
+		                           user->networkid);
+	}
 
-	member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, state->who);
+	partner_scenario = (list == MSN_LIST_RL) ? MSN_PS_CONTACT_API : MSN_PS_BLOCK_UNBLOCK;
+	member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML,
+	                         type, state->who, federate ? federate : "");
 
 	body = g_strdup_printf(MSN_CONTACT_ADD_TO_LIST_TEMPLATE,
 		MsnSoapPartnerScenarioText[partner_scenario],
@@ -1443,6 +1598,7 @@
 	state->cb = msn_add_contact_to_list_read_cb;
 	msn_contact_request(state);
 
+	g_free(federate);
 	g_free(member);
 	g_free(body);
 }
@@ -1482,6 +1638,17 @@
 	MsnCallbackState *state = data;
 	MsnSession *session;
 	MsnUserList *userlist;
+	xmlnode *fault;
+
+	/* We don't know how to respond to this faultcode, so log it */
+	fault = xmlnode_get_child(resp->xml, "Body/Fault");
+	if (fault != NULL) {
+		char *fault_str = xmlnode_to_str(fault, NULL);
+		purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n",
+		                   msn_contact_operation_str(state->action), fault_str);
+		g_free(fault_str);
+		return;
+	}
 
 	purple_debug_info("msn", "Group request successful.\n");
 
@@ -1661,3 +1828,4 @@
 	g_free(escaped_group_name);
 	g_free(body);
 }
+
--- a/libpurple/protocols/msn/contact.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/contact.h	Wed Dec 17 18:01:08 2008 +0000
@@ -211,6 +211,27 @@
 		"</contactInfo>"\
 	"</Contact>"
 
+#define MSN_CONTACT_ID_XML \
+	"<Contact>"\
+		"<contactId>%s</contactId>"\
+	"</Contact>"
+
+#define MSN_CONTACT_EMAIL_XML \
+	"<Contact>"\
+		"<contactInfo>"\
+			"<emails>"\
+				"<ContactEmail>"\
+					"<contactEmailType>%s</contactEmailType>"\
+					"<email>%s</email>"\
+					"<isMessengerEnabled>true</isMessengerEnabled>"\
+					"<Capability>%d</Capability>"\
+					"<MessengerEnabledExternally>false</MessengerEnabledExternally>"\
+					"<propertiesChanged/>"\
+				"</ContactEmail>"\
+			"</emails>"\
+		"</contactInfo>"\
+	"</Contact>"
+
 #define MSN_ADD_CONTACT_TEMPLATE	"<?xml version=\"1.0\" encoding=\"utf-8\"?>"\
 "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\
 	" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\
@@ -275,7 +296,6 @@
 
 /* Delete a contact from the Contact List */
 #define MSN_CONTACT_DEL_SOAP_ACTION	"http://www.msn.com/webservices/AddressBook/ABContactDelete"
-#define MSN_CONTACT_ID_XML		"<Contact><contactId>%s</contactId></Contact>"
 #define MSN_DEL_CONTACT_TEMPLATE	"<?xml version=\"1.0\" encoding=\"utf-8\"?>"\
 "<soap:Envelope"\
 	" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\
@@ -376,22 +396,32 @@
 #define MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION	"http://www.msn.com/webservices/AddressBook/DeleteMember"
 
 #define MSN_MEMBER_PASSPORT_XML	\
-	"<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"PassportMember\">"\
+	"<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"%s\">"\
 		"<Type>Passport</Type>"\
 		"<State>Accepted</State>"\
 		"<PassportName>%s</PassportName>"\
+		"%s"\
 	"</Member>"
 
 #define MSN_MEMBER_MEMBERSHIPID_XML	\
-	"<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"PassportMember\">"\
+	"<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"%s\">"\
 		"<Type>Passport</Type>"\
 		"<MembershipId>%u</MembershipId>"\
 		"<State>Accepted</State>"\
+		"%s"\
 	"</Member>"
 
+#define MSN_MEMBER_FEDERATED_ANNOTATION_XML \
+	"<Annotations>"\
+		"<Annotation>"\
+			"<Name>MSN.IM.BuddyType</Name>"\
+			"<Value>%02d:</Value>"\
+		"</Annotation>"\
+	"</Annotations>"
+
 /* first delete contact from allow list */
 
-#define MSN_CONTACT_DELECT_FROM_LIST_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\
+#define MSN_CONTACT_DELETE_FROM_LIST_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\
 "<soap:Envelope"\
 	" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\
 	" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\
@@ -586,7 +616,7 @@
 	MSN_ADD_GROUP       = 0x10,
 	MSN_DEL_GROUP       = 0x20,
 	MSN_RENAME_GROUP    = 0x40,
-	MSN_UPDATE_INFO     = 0x80,
+	MSN_UPDATE_INFO     = 0x80
 } MsnCallbackAction;
 
 typedef struct _MsnCallbackState MsnCallbackState;
--- a/libpurple/protocols/msn/msg.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/msg.c	Wed Dec 17 18:01:08 2008 +0000
@@ -231,6 +231,25 @@
 	{
 		const char *key, *value;
 
+		/* If this line starts with whitespace, it's been folded from the
+		   previous line and won't have ':'. */
+		if ((**cur == ' ') || (**cur == '\t')) {
+			tokens = g_strsplit(g_strchug(*cur), "=\"", 2);
+			key = tokens[0];
+			value = tokens[1];
+
+			/* The only one I care about is 'boundary' (which is folded from
+			   the key 'Content-Type'), so only process that. */
+			if (!strcmp(key, "boundary")) {
+				char *end = strchr(value, '\"');
+				*end = '\0';
+				msn_message_set_attr(msg, key, value);
+			}
+
+			g_strfreev(tokens);
+			continue;
+		}
+
 		tokens = g_strsplit(*cur, ": ", 2);
 
 		key = tokens[0];
--- a/libpurple/protocols/msn/msn.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/msn.c	Wed Dec 17 18:01:08 2008 +0000
@@ -647,25 +647,41 @@
 	presence = purple_buddy_get_presence(buddy);
 	status = purple_presence_get_active_status(presence);
 
-	/* I think status message should take precedence over media */
-	msg = purple_status_get_attr_string(status, "message");
-	if (msg && *msg)
-		return g_markup_escape_text(msg, -1);
-
 	if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
-		const char *title, *artist;
+		const char *title, *game, *office;
 		char *media, *esc;
 		status = purple_presence_get_status(presence, "tune");
 		title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
-		artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
-
-		media = g_strdup_printf("%s%s%s", title, artist ? " - " : "",
-				artist ? artist : "");
+
+		game = purple_status_get_attr_string(status, "game");
+		office = purple_status_get_attr_string(status, "office");
+
+		if (title && *title) {
+			const char *artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
+			const char *album = purple_status_get_attr_string(status, PURPLE_TUNE_ALBUM);
+			media = g_strdup_printf("%s%s%s%s%s%s", title,
+			                        (artist && *artist) ? " - " : "",
+			                        (artist && *artist) ? artist : "",
+			                        (album && *album) ? " (" : "",
+			                        (album && *album) ? album : "",
+			                        (album && *album) ? ")" : "");
+		}
+		else if (game && *game)
+			media = g_strdup_printf("Playing %s", game);
+		else if (office && *office)
+			media = g_strdup_printf("Editing %s", office);
+		else
+			return NULL;
 		esc = g_markup_escape_text(media, -1);
 		g_free(media);
 		return esc;
 	}
 
+	/* Official client says media takes precedence over message */
+	msg = purple_status_get_attr_string(status, "message");
+	if (msg && *msg)
+		return g_markup_escape_text(msg, -1);
+
 	return NULL;
 }
 
@@ -681,6 +697,7 @@
 	if (purple_presence_is_online(presence))
 	{
 		const char *psm, *name;
+		const char *mediatype = NULL;
 		char *currentmedia = NULL;
 		char *tmp;
 
@@ -688,10 +705,20 @@
 		if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
 			PurpleStatus *tune = purple_presence_get_status(presence, "tune");
 			const char *title = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE);
-			const char *artist = purple_status_get_attr_string(tune, PURPLE_TUNE_ARTIST);
-			const char *album = purple_status_get_attr_string(tune, PURPLE_TUNE_ALBUM);
-			currentmedia = purple_util_format_song_info(title, artist, album, NULL);
-			/* We could probably just use user->media.title etc. here */
+			const char *game = purple_status_get_attr_string(tune, "game");
+			const char *office = purple_status_get_attr_string(tune, "office");
+			if (title && *title) {
+				const char *artist = purple_status_get_attr_string(tune, PURPLE_TUNE_ARTIST);
+				const char *album = purple_status_get_attr_string(tune, PURPLE_TUNE_ALBUM);
+				mediatype = _("Now Listening");
+				currentmedia = purple_util_format_song_info(title, artist, album, NULL);
+			} else if (game && *game) {
+				mediatype = _("Playing a game");
+				currentmedia = g_strdup(game);
+			} else if (office && *office) {
+				mediatype = _("Working");
+				currentmedia = g_strdup(office);
+			}
 		}
 
 		if (!purple_status_is_available(status)) {
@@ -745,7 +772,7 @@
 		}
 
 		if (currentmedia) {
-			purple_notify_user_info_add_pair(user_info, _("Now Listening"), currentmedia);
+			purple_notify_user_info_add_pair(user_info, mediatype, currentmedia);
 			g_free(currentmedia);
 		}
 	}
@@ -840,6 +867,8 @@
 			PURPLE_TUNE_ARTIST, _("Artist"), purple_value_new(PURPLE_TYPE_STRING),
 			PURPLE_TUNE_ALBUM, _("Album"), purple_value_new(PURPLE_TYPE_STRING),
 			PURPLE_TUNE_TITLE, _("Title"), purple_value_new(PURPLE_TYPE_STRING),
+			"game", _("Game Title"), purple_value_new(PURPLE_TYPE_STRING),
+			"office", _("Office Title"), purple_value_new(PURPLE_TYPE_STRING),
 			NULL);
 	types = g_list_append(types, status);
 
@@ -1389,6 +1418,7 @@
 	MsnSession *session;
 	MsnUserList *userlist;
 	const char *who;
+	MsnUser *user;
 
 	session = gc->proto_data;
 	userlist = session->userlist;
@@ -1414,21 +1444,19 @@
 		purple_debug_info("msn", "msn_add_buddy: %s\n", who);
 #endif
 
-#if 0
-	/* Which is the max? */
-	if (session->fl_users_count >= 150)
-	{
-		purple_debug_info("msn", "Too many buddies\n");
-		/* Buddy list full */
-		/* TODO: purple should be notified of this */
-		return;
-	}
-#endif
-
 	/* XXX - Would group ever be NULL here?  I don't think so...
 	 * shx: Yes it should; MSN handles non-grouped buddies, and this is only
 	 * internal. */
-	msn_userlist_add_buddy(userlist, who, group ? group->name : NULL);
+	user = msn_userlist_find_user(userlist, who);
+	if ((user != NULL) && (user->networkid != MSN_NETWORK_UNKNOWN)) {
+		/* We already know this buddy and their network. This function knows
+		   what to do with users already in the list and stuff... */
+		msn_userlist_add_buddy(userlist, who, group ? group->name : NULL);
+	} else {
+		/* We need to check the network for this buddy first */
+		msn_userlist_save_pending_buddy(userlist, who, group ? group->name : NULL);
+		msn_notification_send_fqy(session, who);
+	}
 }
 
 static void
@@ -1811,7 +1839,7 @@
 		if (b->server_alias)
 		{
 			char *nicktext = g_markup_escape_text(b->server_alias, -1);
-			tmp = g_strdup_printf("<font sml=\"msn\">%s</font><br>", nicktext);
+			tmp = g_strdup_printf("<font sml=\"msn\">%s</font>", nicktext);
 			purple_notify_user_info_add_pair(user_info, _("Nickname"), tmp);
 			g_free(tmp);
 			g_free(nicktext);
@@ -1917,9 +1945,8 @@
 
 	if (error_message != NULL || url_text == NULL || strcmp(url_text, "") == 0)
 	{
-		tmp = g_strdup_printf("<b>%s</b>", _("Error retrieving profile"));
-		purple_notify_user_info_add_pair(user_info, NULL, tmp);
-		g_free(tmp);
+		purple_notify_user_info_add_pair(user_info,
+				_("Error retrieving profile"), NULL);
 
 		purple_notify_userinfo(info_data->gc, info_data->name, user_info, NULL, NULL);
 		purple_notify_user_info_destroy(user_info);
@@ -2260,21 +2287,24 @@
 		char *p = strstr(url_buffer, "<form id=\"profile_form\" name=\"profile_form\" action=\"http&#58;&#47;&#47;spaces.live.com&#47;profile.aspx&#63;cid&#61;0\"");
 		PurpleBuddy *b = purple_find_buddy
 				(purple_connection_get_account(info_data->gc), info_data->name);
-		purple_notify_user_info_add_pair(user_info, _("Error retrieving profile"),
-									   ((p && b) ? _("The user has not created a public profile.") :
-										(p ? _("MSN reported not being able to find the user's profile. "
-											   "This either means that the user does not exist, "
-											   "or that the user exists "
-											   "but has not created a public profile.") :
-										 _("Could not find "	/* This should never happen */
-										   "any information in the user's profile. "
-										   "The user most likely does not exist."))));
+		purple_notify_user_info_add_pair(user_info,
+				_("Error retrieving profile"), NULL);
+		purple_notify_user_info_add_pair(user_info, NULL,
+				((p && b) ? _("The user has not created a public profile.") :
+					(p ? _("MSN reported not being able to find the user's profile. "
+							"This either means that the user does not exist, "
+							"or that the user exists "
+							"but has not created a public profile.") :
+						_("Could not find "	/* This should never happen */
+							"any information in the user's profile. "
+							"The user most likely does not exist."))));
 	}
 
 	/* put a link to the actual profile URL */
-	tmp = g_strdup_printf("<a href=\"%s%s\">%s%s</a>",
-					PROFILE_URL, info_data->name, PROFILE_URL, info_data->name);
-	purple_notify_user_info_add_pair(user_info, _("Profile URL"), tmp);
+	purple_notify_user_info_add_section_break(user_info);
+	tmp = g_strdup_printf("<a href=\"%s%s\">%s</a>",
+			PROFILE_URL, info_data->name, _("View web profile"));
+	purple_notify_user_info_add_pair(user_info, NULL, tmp);
 	g_free(tmp);
 
 #if PHOTO_SUPPORT
--- a/libpurple/protocols/msn/nexus.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/nexus.c	Wed Dec 17 18:01:08 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/msn/notification.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/notification.c	Wed Dec 17 18:01:08 2008 +0000
@@ -849,10 +849,35 @@
 fqy_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
 			 size_t len)
 {
-	purple_debug_info("msn", "FQY payload:\n%s\n", payload);
-	g_return_if_fail(cmdproc->session != NULL);
-/*	msn_notification_post_adl(cmdproc, payload, len); */
-/*	msn_get_address_book(cmdproc->session, MSN_AB_SAVE_CONTACT, NULL, NULL); */
+	MsnUserList *userlist;
+	xmlnode *ml, *d, *c;
+	const char *domain;
+	const char *local;
+	const char *type;
+	char *passport;
+	MsnNetwork network = MSN_NETWORK_PASSPORT;
+
+	userlist = cmdproc->session->userlist;
+
+	/* FQY response:
+	    <ml><d n="domain.com"><c n="local-node" t="network" /></d></ml> */
+	ml = xmlnode_from_str(payload, len);
+	d = xmlnode_get_child(ml, "d");
+	c = xmlnode_get_child(d, "c");
+	domain = xmlnode_get_attrib(d, "n");
+	local = xmlnode_get_attrib(c, "n");
+	type = xmlnode_get_attrib(c, "t");
+
+	passport = g_strdup_printf("%s@%s", local, domain);
+
+	if (type != NULL)
+		network = (MsnNetwork)strtoul(type, NULL, 10);
+	purple_debug_info("msn", "FQY response says %s is from network %d\n",
+	                  passport, network);
+	msn_userlist_add_pending_buddy(userlist, passport, network);
+
+	g_free(passport);
+	xmlnode_free(ml);
 }
 
 static void
@@ -1578,7 +1603,7 @@
 	MsnUser *user;
 	const char *passport;
 	char *psm_str, *str;
-	CurrentMedia media = {NULL, NULL, NULL};
+	CurrentMedia media = {CURRENT_MEDIA_UNKNOWN, NULL, NULL, NULL};
 
 	session = cmdproc->session;
 	account = session->account;
@@ -1933,7 +1958,7 @@
 
 void
 msn_notification_add_buddy_to_list(MsnNotification *notification, MsnListId list_id,
-							  const char *who)
+							  MsnUser *user)
 {
 	MsnCmdProc *cmdproc;
 	MsnListOp list_op = 1 << list_id;
@@ -1946,8 +1971,8 @@
 	adl_node = xmlnode_new("ml");
 	adl_node->child = NULL;
 
-	msn_add_contact_xml(notification->session, adl_node, who, list_op,
-						MSN_NETWORK_PASSPORT);
+	msn_add_contact_xml(notification->session, adl_node, user->passport,
+	                    list_op, user->networkid);
 
 	payload = xmlnode_to_str(adl_node,&payload_len);
 	xmlnode_free(adl_node);
@@ -1959,7 +1984,7 @@
 
 void
 msn_notification_rem_buddy_from_list(MsnNotification *notification, MsnListId list_id,
-						   const char *who)
+						   MsnUser *user)
 {
 	MsnCmdProc *cmdproc;
 	MsnTransaction *trans;
@@ -1973,7 +1998,8 @@
 	rml_node = xmlnode_new("ml");
 	rml_node->child = NULL;
 
-	msn_add_contact_xml(notification->session, rml_node, who, list_op, MSN_NETWORK_PASSPORT);
+	msn_add_contact_xml(notification->session, rml_node, user->passport,
+	                    list_op, user->networkid);
 
 	payload = xmlnode_to_str(rml_node, &payload_len);
 	xmlnode_free(rml_node);
--- a/libpurple/protocols/msn/notification.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/notification.h	Wed Dec 17 18:01:08 2008 +0000
@@ -42,6 +42,7 @@
 #include "session.h"
 #include "servconn.h"
 #include "cmdproc.h"
+#include "user.h"
 
 struct _MsnNotification
 {
@@ -64,9 +65,9 @@
 void msn_notification_init(void);
 
 void msn_notification_add_buddy_to_list(MsnNotification *notification,
-					MsnListId list_id, const char *who);
+					MsnListId list_id, MsnUser *user);
 void msn_notification_rem_buddy_from_list(MsnNotification *notification,
-					  MsnListId list_id, const char *who);
+					  MsnListId list_id, MsnUser *user);
 
 void msn_notification_send_fqy(MsnSession *session, const char *passport);
 
--- a/libpurple/protocols/msn/oim.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/oim.c	Wed Dec 17 18:01:08 2008 +0000
@@ -594,47 +594,91 @@
 msn_oim_report_to_user(MsnOimRecvData *rdata, const char *msg_str)
 {
 	MsnMessage *message;
-	char *date,*from,*decode_msg;
+	const char *date;
+	const char *from;
+	char *decode_msg = NULL;
 	gsize body_len;
 	char **tokens;
-	char *start,*end;
-	int has_nick = 0;
-	char *passport_str, *passport;
+	char *passport = NULL;
 	time_t stamp;
 
 	message = msn_message_new(MSN_MSG_UNKNOWN);
 
 	msn_message_parse_payload(message, msg_str, strlen(msg_str),
-							  MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM);
+	                          MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM);
 	purple_debug_info("msn", "oim body:{%s}\n", message->body);
-	decode_msg = (char *)purple_base64_decode(message->body,&body_len);
-	date =	(char *)g_hash_table_lookup(message->attr_table, "Date");
-	from =	(char *)g_hash_table_lookup(message->attr_table, "From");
-	if (strstr(from," ")) {
-		has_nick = 1;
-	}
-	if (has_nick) {
-		tokens = g_strsplit(from , " " , 2);
-		passport_str = g_strdup(tokens[1]);
-		purple_debug_info("msn", "oim Date:{%s},nickname:{%s},tokens[1]:{%s} passport{%s}\n",
-							date, tokens[0], tokens[1], passport_str);
+
+	if (!strcmp(msn_message_get_attr(message, "X-OIMProxy"), "MOSMS")) {
+		char *boundary;
+		char **part;
+
+		from = msn_message_get_attr(message, "X-OIM-originatingSource");
+
+		/* Match number to user's mobile number, FROM is a phone number
+		   if the other side pages you using your phone number */
+		if (!strncmp(from, "tel:+", 5)) {
+			MsnUser *user =	msn_userlist_find_user_with_mobile_phone(
+					rdata->oim->session->userlist, from + 4);
+
+			if (user && user->passport)
+				passport = g_strdup(user->passport);
+		}
+		if (passport == NULL)
+			passport = g_strdup(from);
+
+		boundary = g_strdup_printf("--%s" MSG_OIM_LINE_DEM,
+		                           msn_message_get_attr(message, "boundary"));
+		tokens = g_strsplit(message->body, boundary, 0);
+
+		/* tokens+1 to skip the "This is a multipart message..." text */
+		for (part = tokens+1; *part != NULL; part++) {
+			MsnMessage *multipart;
+			const char *type;
+			multipart = msn_message_new(MSN_MSG_UNKNOWN);
+			msn_message_parse_payload(multipart, *part, strlen(*part),
+			                          MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM);
+
+			type = msn_message_get_content_type(multipart);
+			if (type && !strcmp(type, "text/plain")) {
+				decode_msg = (char *)purple_base64_decode(multipart->body, &body_len);
+				msn_message_destroy(multipart);
+				break;
+			}
+			msn_message_destroy(multipart);
+		}
+
 		g_strfreev(tokens);
+		g_free(boundary);
+
+		if (decode_msg == NULL) {
+			purple_debug_error("msn", "Couldn't find text/plain OIM message.\n");
+			g_free(passport);
+			return;
+		}
 	} else {
-		passport_str = g_strdup(from);
-		purple_debug_info("msn", "oim Date:{%s},passport{%s}\n",
-					date, passport_str);
+		char *start, *end;
+
+		from = msn_message_get_attr(message, "From");
+		decode_msg = (char *)purple_base64_decode(message->body, &body_len);
+
+		tokens = g_strsplit(from, " ", 2);
+		if (tokens[1] != NULL)
+			from = (const char *)tokens[1];
+
+		start = strchr(from, '<') + 1;
+		end = strchr(from, '>');
+		passport = g_strndup(start, end - start);
+
+		g_strfreev(tokens);
 	}
-	start = strstr(passport_str,"<");
-	start += 1;
-	end = strstr(passport_str,">");
-	passport = g_strndup(start,end - start);
-	g_free(passport_str);
-	purple_debug_info("msn", "oim Date:{%s},passport{%s}\n", date, passport);
 
+	date = msn_message_get_attr(message, "Date");
 	stamp = msn_oim_parse_timestamp(date);
+	purple_debug_info("msn", "oim Date:{%s},passport{%s}\n",
+	                  date, passport);
 
 	serv_got_im(rdata->oim->session->account->gc, passport, decode_msg, 0,
-		stamp);
+	            stamp);
 
 	/*Now get the oim message ID from the oim_list.
 	 * and append to read list to prepare for deleting the Offline Message when sign out
--- a/libpurple/protocols/msn/servconn.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/servconn.h	Wed Dec 17 18:01:08 2008 +0000
@@ -40,7 +40,7 @@
 	MSN_SERVCONN_ERROR_NONE,
 	MSN_SERVCONN_ERROR_CONNECT,
 	MSN_SERVCONN_ERROR_WRITE,
-	MSN_SERVCONN_ERROR_READ,
+	MSN_SERVCONN_ERROR_READ
 
 } MsnServConnError;
 
--- a/libpurple/protocols/msn/session.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/session.c	Wed Dec 17 18:01:08 2008 +0000
@@ -448,25 +448,23 @@
 	PurpleConnection *gc;
 	PurpleStoredImage *img;
 
-	if (session->logged_in)
-		return;
-
-	account = session->account;
-	gc = purple_account_get_connection(account);
+	if (!session->logged_in) {
+		account = session->account;
+		gc = purple_account_get_connection(account);
 
-	img = purple_buddy_icons_find_account_icon(session->account);
-	/* TODO: Do we really want to call this if img is NULL? */
-	msn_user_set_buddy_icon(session->user, img);
-	if (img != NULL)
-		purple_imgstore_unref(img);
+		img = purple_buddy_icons_find_account_icon(session->account);
+		/* TODO: Do we really want to call this if img is NULL? */
+		msn_user_set_buddy_icon(session->user, img);
+		if (img != NULL)
+			purple_imgstore_unref(img);
 
-	session->logged_in = TRUE;
+		session->logged_in = TRUE;
+		purple_connection_set_state(gc, PURPLE_CONNECTED);
+
+		/* Sync users */
+		msn_session_sync_users(session);
+	}
 
 	msn_change_status(session);
-
-	purple_connection_set_state(gc, PURPLE_CONNECTED);
-
-	/* Sync users */
-	msn_session_sync_users(session);
 }
 
--- a/libpurple/protocols/msn/slpcall.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/slpcall.h	Wed Dec 17 18:01:08 2008 +0000
@@ -37,7 +37,7 @@
 typedef enum
 {
 	MSN_SLPCALL_ANY,
-	MSN_SLPCALL_DC,
+	MSN_SLPCALL_DC
 
 } MsnSlpCallType;
 
--- a/libpurple/protocols/msn/soap.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/soap.c	Wed Dec 17 18:01:08 2008 +0000
@@ -505,7 +505,7 @@
 		purple_debug_info("soap", "read: %s\n", g_strerror(perrno));
 
 #ifndef MSN_UNSAFE_DEBUG
-	if (conn->current_request->secure)
+	if (conn->current_request && conn->current_request->secure)
 		purple_debug_misc("soap", "Received secure request.\n");
 	else
 #endif
--- a/libpurple/protocols/msn/state.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/state.c	Wed Dec 17 18:01:08 2008 +0000
@@ -100,14 +100,15 @@
 	cmedia_array = g_strsplit(cmedia, "\\0", 0);
 
 	/*
-	 * 0: Media Player
-	 * 1: 'Music'
+	 * 0: Application
+	 * 1: 'Music'/'Games'/'Office'
 	 * 2: '1' if enabled, '0' if not
 	 * 3: Format (eg. {0} by {1})
 	 * 4: Title
-	 * 5: Artist
-	 * 6: Album
-	 * 7: ?
+	 * If 'Music':
+	 *  5: Artist
+	 *  6: Album
+	 *  7: ?
 	 */
 #if GLIB_CHECK_VERSION(2,6,0)
 	strings  = g_strv_length(cmedia_array);
@@ -118,6 +119,15 @@
 	if (strings >= 4 && !strcmp(cmedia_array[2], "1")) {
 		parsed = TRUE;
 
+		if (!strcmp(cmedia_array[1], "Music"))
+			media->type = CURRENT_MEDIA_MUSIC;
+		else if (!strcmp(cmedia_array[1], "Games"))
+			media->type = CURRENT_MEDIA_GAMES;
+		else if (!strcmp(cmedia_array[1], "Office"))
+			media->type = CURRENT_MEDIA_OFFICE;
+		else
+			media->type = CURRENT_MEDIA_UNKNOWN;
+
 		g_free(media->title);
 		if (strings == 4) {
 			media->title = g_strdup(cmedia_array[3]);
@@ -199,21 +209,33 @@
 static char *
 create_media_string(PurplePresence *presence)
 {
-	const char *artist, *title, *album;
+	const char *title, *game, *office;
 	char *ret;
 	PurpleStatus *status = purple_presence_get_status(presence, "tune");
 	if (!status || !purple_status_is_active(status))
-		return g_strdup_printf("WMP\\0Music\\00\\0{0} - {1}\\0\\0\\0\\0\\0");
+		return g_strdup_printf("\\0Music\\00\\0\\0");
 
-	artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
 	title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
-	album = purple_status_get_attr_string(status, PURPLE_TUNE_ALBUM);
+	game = purple_status_get_attr_string(status, "game");
+	office = purple_status_get_attr_string(status, "office");
 
-	ret = g_strdup_printf("WMP\\0Music\\0%c\\0{0} - {1}\\0%s\\0%s\\0%s\\0\\0",
-			(title && *title) ? '1' : '0',
-			title ? title : "",
-			artist ? artist : "",
-			album ? album : "");
+	if (title && *title) {
+		const char *artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
+		const char *album = purple_status_get_attr_string(status, PURPLE_TUNE_ALBUM);
+		ret = g_strdup_printf("WMP\\0Music\\01\\0{0}%s%s\\0%s\\0%s\\0%s\\0",
+		                      artist ? " - {1}" : "",
+		                      album ? " ({2})" : "",
+		                      title,
+		                      artist ? artist : "",
+		                      album ? album : "");
+	}
+	else if (game && *game)
+		ret = g_strdup_printf("\\0Games\\01\\0Playing {0}\\0%s\\0", game);
+	else if (office && *office)
+		ret = g_strdup_printf("\\0Office\\01\\0Editing {0}\\0%s\\0", office);
+	else
+		ret = g_strdup_printf("\\0Music\\00\\0\\0");
+
 	return ret;
 }
 
--- a/libpurple/protocols/msn/switchboard.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/switchboard.h	Wed Dec 17 18:01:08 2008 +0000
@@ -57,7 +57,7 @@
 typedef enum
 {
 	MSN_SB_FLAG_IM = 0x01, /**< This switchboard is being used for a conversation. */
-	MSN_SB_FLAG_FT = 0x02, /**< This switchboard is being used for file transfer. */
+	MSN_SB_FLAG_FT = 0x02  /**< This switchboard is being used for file transfer. */
 
 } MsnSBFlag;
 
--- a/libpurple/protocols/msn/user.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/user.c	Wed Dec 17 18:01:08 2008 +0000
@@ -106,12 +106,25 @@
 		purple_prpl_got_user_status_deactive(account, user->passport, "mobile");
 	}
 
-	if (!offline && user->media.title) {
-		purple_prpl_got_user_status(account, user->passport, "tune",
-				PURPLE_TUNE_ARTIST, user->media.artist,
-				PURPLE_TUNE_ALBUM, user->media.album,
-				PURPLE_TUNE_TITLE, user->media.title,
-				NULL);
+	if (!offline && user->media.type != CURRENT_MEDIA_UNKNOWN) {
+		if (user->media.type == CURRENT_MEDIA_MUSIC) {
+			purple_prpl_got_user_status(account, user->passport, "tune",
+			                            PURPLE_TUNE_ARTIST, user->media.artist,
+			                            PURPLE_TUNE_ALBUM, user->media.album,
+			                            PURPLE_TUNE_TITLE, user->media.title,
+			                            NULL);
+		} else if (user->media.type == CURRENT_MEDIA_GAMES) {
+			purple_prpl_got_user_status(account, user->passport, "tune",
+			                            "game", user->media.title,
+			                            NULL);
+		} else if (user->media.type == CURRENT_MEDIA_OFFICE) {
+			purple_prpl_got_user_status(account, user->passport, "tune",
+			                            "office", user->media.title,
+			                            NULL);
+		} else {
+			purple_debug_warning("msn", "Got CurrentMedia with unknown type %d.\n",
+			                     user->media.type);
+		}
 	} else {
 		purple_prpl_got_user_status_deactive(account, user->passport, "tune");
 	}
@@ -191,6 +204,7 @@
 	g_free(user->media.album);
 	g_free(user->media.artist);
 
+	user->media.type   = media ? media->type : CURRENT_MEDIA_UNKNOWN;
 	user->media.title  = media ? g_strdup(media->title) : NULL;
 	user->media.artist = media ? g_strdup(media->artist) : NULL;
 	user->media.album  = media ? g_strdup(media->album) : NULL;
@@ -326,6 +340,20 @@
 }
 
 void
+msn_user_set_pending_group(MsnUser *user, const char *group)
+{
+	user->pending_group = g_strdup(group);
+}
+
+char *
+msn_user_remove_pending_group(MsnUser *user)
+{
+	char *group = user->pending_group;
+	user->pending_group = NULL;
+	return group;
+}
+
+void
 msn_user_set_home_phone(MsnUser *user, const char *number)
 {
 	g_return_if_fail(user != NULL);
--- a/libpurple/protocols/msn/user.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/user.h	Wed Dec 17 18:01:08 2008 +0000
@@ -45,11 +45,20 @@
 /**
  * Current media.
  */
+typedef enum
+{
+	CURRENT_MEDIA_UNKNOWN,
+	CURRENT_MEDIA_MUSIC,
+	CURRENT_MEDIA_GAMES,
+	CURRENT_MEDIA_OFFICE
+} CurrentMediaType;
+
 typedef struct _CurrentMedia
 {
+	CurrentMediaType type;     /**< Type.   */
+	char *title;    /**< Title.  */
 	char *artist;   /**< Artist. */
 	char *album;    /**< Album.  */
-	char *title;    /**< Title.  */
 } CurrentMedia;
 
 /**
@@ -82,6 +91,7 @@
 	gboolean mobile;        /**< Signed up with MSN Mobile.     */
 
 	GList *group_ids;       /**< The group IDs.                 */
+	char *pending_group;    /**< A pending group to add.        */
 
 	MsnObject *msnobj;      /**< The user's MSN Object.         */
 
@@ -204,6 +214,23 @@
 void msn_user_remove_group_id(MsnUser *user, const char * id);
 
 /**
+ * Sets the pending group for a user.
+ *
+ * @param user  The user.
+ * @param group The group name.
+ */
+void msn_user_set_pending_group(MsnUser *user, const char *group);
+
+/**
+ * Removes the pending group from a user.
+ *
+ * @param user The user.
+ *
+ * @return Returns the pending group name.
+ */
+char *msn_user_remove_pending_group(MsnUser *user);
+
+/**
  * Sets the home phone number for a user.
  *
  * @param user   The user.
--- a/libpurple/protocols/msn/userlist.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/userlist.c	Wed Dec 17 18:01:08 2008 +0000
@@ -184,10 +184,6 @@
 		{
 			msn_user_add_group_id(user, group_id);
 		}
-		else
-		{
-			/* session->sync->fl_users_count++; */
-		}
 	}
 	else if (list_id == MSN_LIST_AL)
 	{
@@ -253,10 +249,6 @@
 			msn_user_remove_group_id(user, group_id);
 			return;
 		}
-		else
-		{
-			/* session->sync->fl_users_count--; */
-		}
 	}
 	else if (list_id == MSN_LIST_AL)
 	{
@@ -676,7 +668,7 @@
 
 	msn_user_unset_op(user, list_op);
 
-	msn_notification_rem_buddy_from_list(userlist->session->notification, list_id, who);
+	msn_notification_rem_buddy_from_list(userlist->session->notification, list_id, user);
 }
 
 /*add buddy*/
@@ -756,6 +748,68 @@
 	msn_add_contact_to_group(userlist->session, state, who, group_id);
 }
 
+/*
+ * Save a buddy address/group until we get back response from FQY
+ */
+void
+msn_userlist_save_pending_buddy(MsnUserList *userlist,
+                               const char *who,
+                               const char *group_name)
+{
+	MsnUser *user;
+
+	g_return_if_fail(userlist != NULL);
+
+	user = msn_user_new(userlist, who, NULL);
+	msn_user_set_pending_group(user, group_name);
+	msn_user_set_network(user, MSN_NETWORK_UNKNOWN);
+	userlist->pending = g_list_prepend(userlist->pending, user);
+}
+
+/*
+ * Actually adds a buddy once we have the response from FQY
+ */
+void
+msn_userlist_add_pending_buddy(MsnUserList *userlist,
+                               const char *who,
+                               /*MsnNetwork*/ int network)
+{
+	MsnUser *user = NULL;
+	MsnUser *user2;
+	GList *l;
+	char *group;
+
+	for (l = userlist->pending; l != NULL; l = l->next)
+	{
+		user = (MsnUser *)l->data;
+
+		if (!g_strcasecmp(who, user->passport)) {
+			userlist->pending = g_list_delete_link(userlist->pending, l);
+			break;
+		}
+	}
+
+	if (user == NULL) {
+		purple_debug_error("msn", "Attempting to add a pending user that does not exist.\n");
+		return;
+	}
+
+	group = msn_user_remove_pending_group(user);
+
+	user2 = msn_userlist_find_user(userlist, who);
+	if (user2 != NULL) {
+		/* User already in userlist, so just update it. */
+		msn_user_destroy(user);
+		user = user2;
+	} else {
+		msn_userlist_add_user(userlist, user);
+	}
+
+	msn_user_set_network(user, network);
+	msn_userlist_add_buddy(userlist, who, group);
+	g_free(group);
+}
+
 void
 msn_userlist_add_buddy_to_list(MsnUserList *userlist, const char *who,
 							MsnListId list_id)
@@ -781,7 +835,7 @@
 
 	msn_user_set_op(user, list_op);
 
-	msn_notification_add_buddy_to_list(userlist->session->notification, list_id, who);
+	msn_notification_add_buddy_to_list(userlist->session->notification, list_id, user);
 }
 
 gboolean
--- a/libpurple/protocols/msn/userlist.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/msn/userlist.h	Wed Dec 17 18:01:08 2008 +0000
@@ -47,13 +47,12 @@
 
 	GList *users; /* Contains MsnUsers */
 	GList *groups; /* Contains MsnGroups */
+	GList *pending; /* MsnUsers pending addition (waiting for FQY response) */
 
 	GQueue *buddy_icon_requests;
 	int buddy_icon_window;
 	guint buddy_icon_request_timer;
 
-	int fl_users_count;
-
 };
 
 gboolean msn_userlist_user_is_in_group(MsnUser *user, const char * group_id);
@@ -93,6 +92,12 @@
 void msn_userlist_rem_buddy(MsnUserList *userlist, const char *who);
 void msn_userlist_add_buddy(MsnUserList *userlist,
 			    const char *who, const char *group_name);
+void msn_userlist_save_pending_buddy(MsnUserList *userlist,
+                                     const char *who,
+                                     const char *group_name);
+void msn_userlist_add_pending_buddy(MsnUserList *userlist,
+                                    const char *who,
+                                    /*MsnNetwork*/ int network);
 void msn_userlist_move_buddy(MsnUserList *userlist, const char *who,
 						    const char *old_group_name,
 						    const char *new_group_name);
--- a/libpurple/protocols/myspace/CHANGES	Sun Dec 07 01:42:47 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,156 +0,0 @@
-2007-08-28 Jeff Connelly <pidgin@xyzzy.cjb.net> - 0.17
-* Get server-side contact list from server on sign-on (partly implements
-  server-side contacts, ticket #2658).
-* Set local alias to username on sign-on, if not already set. This fixes
-  #2793, though this may not be the best way, other fixes under consideration.
-* Support myim:sendIM and addContact URLs with cID and uID parameters.
-* Fix #2722, only check for mail if "New mail notifications" is enabled.
-* Modularize msimprpl.
-* Pidgin 2.1.1 only.
-
-2007-08-23 Jeff Connelly <pidgin@xyzzy.cjb.net> - 0.16
-* Add option to add all friends from myspace.com to your buddy list (#2660)
-* If a user doesn't have a picture, don't display an icon (instead of
-  displaying MySpace's "no photo" icon)
-* Fix #2725, a common crash related to buddy icon data
-* Fix #2752, which led to duplicate groups
-* Fix #2720, crash/disconnect when adding a buddy that doesn't exist
-  (You'll now receive an error when looking up invalid usernames).
-* Source-code release only.
-
-2007-08-22 Jeff Connelly <pidgin@xyzzy.cjb.net> - 0.15
-* Incomplete implementation of adding friends from myspace.com.
-* Change msim_msg_get() to start at the given node instead of the beginning.
-* Add msim_msg_get_*_from_element() to access data in MsimMessagElement *'s.
-* Use MsimMessage dictionaries everywhere in incoming messages, instead of
-  the old GHashTable method. Dictionary type is now fully implemented.
-* Add functions to loop over MsimMessages.
-* Link to myspace.com profile in Get Info.
-* Conditionally use my proposed attention API if defined.
-* Propagate to im.pidgin.pidgin branch for 2.1.2.
-* GSoC ended on 2007-08-20. The code in this release hasn't changed since
-  then. I did, however, bump the version number to 0.15 to distinguish this
-  release from the previous one. But there were no code changes. I updated
-  the text files, too.
-* Note: msimprpl will continue to be developed as time permits.
-
-2007-08-12 Jeff Connelly <jeff2@soc.pidgin.im> - 0.14
-* Full emoticon support (except no difference between nerd and geek emoticons),
-  thanks to a number of new icons from Hylke Bons.
-* Package Win32 release archive so that it can easily be extracted directly
-  into the folder Pidgin was installed to.
-* Better password handling, may now support Unicode passwords.
-* Much general clean-up and restructuring of the code.
-* Resolve user ID from buddy list, if it exists. Greatly improves speed of 
-  receiving messages from user IDs.
-* Support sending and receiving hyperlinks.
-* Fix #2521 by reimplementing protocol message escaping to work correctly.
-* Fix #2520 by indicating sign-on at the correct time.
-
-2007-08-04 Jeff Connelly <jeff2@soc.pidgin.im> - 0.13
-* Fix crash when deleting buddies, on Windows.
-* Disable sending client version to oncoming buddies (compile-time option).
-* Updated login process (more closely resembles official client).
-* Zaps, sending and receiving
-* Emoticons, mapped to Pidgin-supported smileys
-* Show official client build in buddy profiles.
-
-2007-07-15 Jeff Connelly <jeff2@soc.pidgin.im> - 0.12
-* Allow logging in with passwords containing uppercase letters (bug #2066)
-* Add /3 -> | translation to escaping.
-* Allow setting status string.
-* Disable keepalive timeout.
-* Remove faking self online, instead show real status (now that it exists).
-* Support font sizes in incoming instant messages.
-* Add support for mail notifications.
-
-2007-07-09 Jeff Connelly <jeff2@soc.pidgin.im> - 0.11
-* Allow going idle (tested with I'dle Ma'ker) and viewing idle status of 
-  buddies (thanks to Scott Ellis, developing a MySpaceIM plugin for Miranda IM,
-  for finding the idle status code.)
-* Time out if no data from server within a certain amount of time 
-  (keep alives).
-* Remove "Sign on as hidden" option, and always set status to current status
-  when signing on.
-* Some support for sending formatted text.
-* Fix build process on Unix, bug #2086.
-
-2007-07-03 Jeff Connelly <jeff2@soc.pidgin.im> - 0.10
-* On incoming instant messages, add support for:
- * Text color
- * Font face
-* Add option to sign on as hidden, default off (previously, always was hidden)
-* Add ability to change status to hidden, available, away
-* Increase password length limit to 10 to match official client (bug #2010)
-
-2007-07-01 Jeff Connelly <jeff2@soc.pidgin.im> - 0.9
-* Fix crash on Windows when logging in (bug #1990)
-* Fix crash on Windows when viewing tooltip text (bug #1999)
-
-2007-06-30 Jeff Connelly <jeff2@soc.pidgin.im> - 0.8
-* Allow "Get Info" on all users, by uid or username
-* Fix crash when re-logging in, if login failed.
-* Show descriptive error message if login password is too long.
-* Fake self from being online, since can't add self to buddy list.
-* Update for Libpurple 2.0.2.
-* Partial support for formatting on incoming instant messages.
-
-2007-06-14 Jeff Connelly <jeff2@soc.pidgin.im> - 0.7
-* Add/delete buddy now functional (required many other code improvements).
-* Show improved buddy information in tooltip text.
-* Show user profile (in "Get Info" option) for buddies on buddy list.
-* Fix crash when re-logging in, if login succeeded.
-
-2007-06-12 Jeff Connelly <jeff2@soc.pidgin.im> - 0.6
-* Use RC4 code from Libpurple 2.0.1
-* Use a new implementation for sending and receiving messages (MsimMessage).
-  This infrastructural change significantly improves extensibility.
-* Show online buddies as online.
-* Send and receive typing notifications (along with other required changes).
-
-2007-05-22 Jeff Connelly <jeff2@soc.pidgin.im> - 0.5
-* Add protocol escaping, so can now send and receive / and \ characters
-* Designed Pidgin 2.0.0beta7
-* Use RC4 code from Samba
-* Use translations (_ macro)
-* No major changes to code, still getting familiar with tools & community
-
-2007-04-29 Jeff Connelly <jeff2@soc.pidgin.im> 
-
-* NOTE: This code is now being developed under Monotone, in the
-  im.pidgin.soc.2007.msimprpl branch on my local computer, which
-  is periodically sync'd with pidgin.im's Monotone database.
-
-  Changes will be logged to Monotone.
-
-2007-04-15 Jeff Connelly <myspaceim@xyzzy.cjb.net> - 0.4
-
-* Gracefully handle a full receive buffer
-* Handle fatal errors
-* Last version for Gaim 2.0.0beta6
-
-2007-04-14 Jeff Connelly <myspaceim@xyzzy.cjb.net> - 0.3
-
-* Win32 support
-* Add a large number of precondition checks and a handful of assertions
-* Add documentation to each function, for doxygen.
-
-2007-04-10 Jeff Connelly <myspaceim@xyzzy.cjb.net> - 0.2
-
-* Add ability to IM by email address.
-* Show usernames on buddy list instead of userids.
-* Show incoming messages as coming from username, instead of userid.
-* Add status messages and tooltip text.
-
-2007-04-09 Jeff Connelly <myspaceim@xyzzy.cjb.net> - 0.1
-
-* Parsing most of the protocol.
-* Logging in using RC4/SHA1-based authentication.
-* Sending messages, by numeric userid or username.
-* Receiving messages, currently only by numeric userid.
-* Some buddy list support (show all users on buddy list as online, by uid).
-
-2007-04-07 Jeff Connelly <myspaceim@xyzzy.cjb.net> - 0.0
-
-* Initial version. Login only. Not publicly released.
-
--- a/libpurple/protocols/myspace/ChangeLog	Sun Dec 07 01:42:47 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-
-2007-04-29 Jeff Connelly <jeff2@soc.pidgin.com> 
-
-* NOTE: This code is now being developed under Monotone, in the
-  im.pidgin.soc.2007.msimprpl branch on my local computer, which
-  is periodically sync'd with pidgin.im's Monotone database.
-
-  Changes will be logged to Monotone.
-
-2007-04-15 Jeff Connelly <myspaceim@xyzzy.cjb.net> - 0.4
-
-* Gracefully handle a full receive buffer
-* Handle fatal errors
-
-2007-04-14 Jeff Connelly <myspaceim@xyzzy.cjb.net> - 0.3
-
-* Win32 support
-* Add a large number of precondition checks and a handful of assertions
-* Add documentation to each function, for doxygen.
-
-2007-04-10 Jeff Connelly <myspaceim@xyzzy.cjb.net> - 0.2
-
-* Add ability to IM by email address.
-* Show usernames on buddy list instead of userids.
-* Show incoming messages as coming from username, instead of userid.
-* Add status messages and tooltip text.
-
-2007-04-09 Jeff Connelly <myspaceim@xyzzy.cjb.net> - 0.1
-
-* Parsing most of the protocol.
-* Logging in using RC4/SHA1-based authentication.
-* Sending messages, by numeric userid or username.
-* Receiving messages, currently only by numeric userid.
-* Some buddy list support (show all users on buddy list as online, by uid).
-
-2007-04-07 Jeff Connelly <myspaceim@xyzzy.cjb.net> - 0.0
-
-* Initial version. Login only. Not publicly released.
-
--- a/libpurple/protocols/myspace/LICENSE	Sun Dec 07 01:42:47 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,339 +0,0 @@
-		    GNU GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-			    Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-		    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-			    NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-
-	    How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License along
-    with this program; if not, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) year name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
--- a/libpurple/protocols/myspace/markup.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/myspace/markup.c	Wed Dec 17 18:01:08 2008 +0000
@@ -21,23 +21,9 @@
 
 typedef int (*MSIM_XMLNODE_CONVERT)(MsimSession *, xmlnode *, gchar **, gchar **);
 
-/* Internal functions */
-
-static guint msim_point_to_purple_size(MsimSession *session, guint point);
-static guint msim_purple_size_to_point(MsimSession *session, guint size);
-static guint msim_height_to_point(MsimSession *session, guint height);
-static guint msim_point_to_height(MsimSession *session, guint point);
-
-static int msim_markup_tag_to_html(MsimSession *, xmlnode *root, gchar **begin, gchar **end);
-static int html_tag_to_msim_markup(MsimSession *, xmlnode *root, gchar **begin, gchar **end);
-static gchar *msim_convert_xml(MsimSession *, const gchar *raw, MSIM_XMLNODE_CONVERT f);
-static gchar *msim_convert_smileys_to_markup(gchar *before);
-static double msim_round(double round);
-
-
 /* Globals */
 
-/* The names in in emoticon_names (for <i n=whatever>) map to corresponding 
+/* The names in in emoticon_names (for <i n=whatever>) map to corresponding
  * entries in emoticon_symbols (for the ASCII representation of the emoticon).
  *
  * Multiple emoticon symbols in Pidgin can map to one name. List the
@@ -90,23 +76,23 @@
 	{ NULL, NULL }
 };
 
-
-
 /* Indexes of this array + 1 map HTML font size to scale of normal font size. *
- * Based on _point_sizes from libpurple/gtkimhtml.c 
+ * Based on _point_sizes from libpurple/gtkimhtml.c
  *                                 1    2  3    4     5      6       7 */
 static gdouble _font_scale[] = { .85, .95, 1, 1.2, 1.44, 1.728, 2.0736 };
 
-#define MAX_FONT_SIZE                   7       /* Purple maximum font size */
+/* Purple maximum font size.  Equivalent to sizeof(_font_scale) / sizeof(_font_scale[0]) */
+#define MAX_FONT_SIZE                   7
+
 #define POINTS_PER_INCH                 72      /* How many pt's in an inch */
 
 /* Text formatting bits for <f s=#> */
 #define MSIM_TEXT_BOLD                  1
-#define MSIM_TEXT_ITALIC                2   
+#define MSIM_TEXT_ITALIC                2
 #define MSIM_TEXT_UNDERLINE             4
 
-/* Default baseline size of purple's fonts, in points. What is size 3 in points. 
- * _font_scale specifies scaling factor relative to this point size. Note this 
+/* Default baseline size of purple's fonts, in points. What is size 3 in points.
+ * _font_scale specifies scaling factor relative to this point size. Note this
  * is only the default; it is configurable in account options. */
 #define MSIM_BASE_FONT_POINT_SIZE       8
 
@@ -114,11 +100,10 @@
  * in account options. */
 #define MSIM_DEFAULT_DPI                96
 
-
 /* round is part of C99, but sometimes is unavailable before then.
  * Based on http://forums.belution.com/en/cpp/000/050/13.shtml
  */
-double msim_round(double value)
+static double msim_round(double value)
 {
 	if (value < 0) {
 		return -(floor(-value + 0.5));
@@ -127,22 +112,17 @@
 	}
 }
 
-
-/** Convert typographical font point size to HTML font size. 
+/** Convert typographical font point size to HTML font size.
  * Based on libpurple/gtkimhtml.c */
 static guint
 msim_point_to_purple_size(MsimSession *session, guint point)
 {
 	guint size, this_point, base;
-	gdouble scale;
-	
+
 	base = purple_account_get_int(session->account, "base_font_size", MSIM_BASE_FONT_POINT_SIZE);
-   
-	for (size = 0; 
-			size < sizeof(_font_scale) / sizeof(_font_scale[0]);
-			++size) {
-		scale = _font_scale[CLAMP(size, 1, MAX_FONT_SIZE) - 1];
-		this_point = (guint)msim_round(scale * base);
+
+	for (size = 0; size < MAX_FONT_SIZE; ++size) {
+		this_point = (guint)msim_round(base * _font_scale[size]);
 
 		if (this_point >= point) {
 			purple_debug_info("msim", "msim_point_to_purple_size: %d pt -> size=%d\n",
@@ -176,7 +156,7 @@
 }
 
 /** Convert a msim markup font pixel height to the more usual point size, for incoming messages. */
-static guint 
+static guint
 msim_height_to_point(MsimSession *session, guint height)
 {
 	guint dpi;
@@ -201,7 +181,7 @@
 }
 
 /** Convert the msim markup <f> (font) tag into HTML. */
-static void 
+static void
 msim_markup_f_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
 {
 	const gchar *face, *height_str, *decor_str;
@@ -212,35 +192,38 @@
 	height_str = xmlnode_get_attrib(root, "h");
 	decor_str = xmlnode_get_attrib(root, "s");
 
-	if (height_str) {
-		height = atol(height_str);
+	/* Validate the font face, to avoid constructing invalid HTML later */
+	if (face != NULL && strchr(face, '\'') != NULL)
+		face = NULL;
+
+	height = height_str != NULL ? atol(height_str) : 12;
+	decor = decor_str != NULL ? atol(decor_str) : 0;
+
+	/*
+	 * The HTML we're constructing here is a bit redudant.  Ideally we
+	 * would use only the font-family and font-size CSS span, but Pidgin
+	 * doesn't support it (it's included for other UIs).  For Pidgin we
+	 * wrap the whole thing in an ugly font tag, and Pidgin will happily
+	 * ignore the <span>.
+	 */
+	gs_begin = g_string_new("");
+	if (height && !face) {
+		guint point_size = msim_height_to_point(session, height);
+		g_string_printf(gs_begin,
+				"<font size='%d'><span style='font-size: %dpt'>",
+				msim_point_to_purple_size(session, point_size),
+				point_size);
+	} else if (height && face) {
+		guint point_size = msim_height_to_point(session, height);
+		g_string_printf(gs_begin,
+				"<font face='%s' size='%d'><span style='font-family: %s; font-size: %dpt'>",
+				face, msim_point_to_purple_size(session, point_size),
+				face, point_size);
 	} else {
-		height = 12;
-	}
-
-	if (decor_str) {
-		decor = atol(decor_str);
-	} else {
-		decor = 0;
+		g_string_printf(gs_begin, "<font><span>");
 	}
 
-	gs_begin = g_string_new("");
-	/* TODO: get font size working */
-	if (height && !face) {
-		g_string_printf(gs_begin, "<font size='%d'>", 
-				msim_point_to_purple_size(session, msim_height_to_point(session, height)));
-	} else if (height && face) {
-		g_string_printf(gs_begin, "<font face='%s' size='%d'>", face,  
-				msim_point_to_purple_size(session, msim_height_to_point(session, height)));
-	} else {
-		g_string_printf(gs_begin, "<font>");
-	}
-
-	/* No support for font-size CSS? */
-	/* g_string_printf(gs_begin, "<span style='font-family: %s; font-size: %dpt'>", face, 
-			msim_height_to_point(height)); */
-
-	gs_end = g_string_new("</font>");
+	gs_end = g_string_new("</span></font>");
 
 	if (decor & MSIM_TEXT_BOLD) {
 		g_string_append(gs_begin, "<b>");
@@ -257,17 +240,16 @@
 		g_string_append(gs_end, "</u>");
 	}
 
-
 	*begin = g_string_free(gs_begin, FALSE);
 	*end = g_string_free(gs_end, FALSE);
 }
 
 /** Convert a msim markup color to a color suitable for libpurple.
-  *
-  * @param msim Either a color name, or an rgb(x,y,z) code.
-  *
-  * @return A new string, either a color name or #rrggbb code. Must g_free(). 
-  */
+ *
+ * @param msim Either a color name, or an rgb(x,y,z) code.
+ *
+ * @return A new string, either a color name or #rrggbb code. Must g_free().
+ */
 static char *
 msim_color_to_purple(const char *msim)
 {
@@ -287,7 +269,7 @@
 }
 
 /** Convert the msim markup <a> (anchor) tag into HTML. */
-static void 
+static void
 msim_markup_a_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
 {
 	const gchar *href;
@@ -302,18 +284,20 @@
 }
 
 /** Convert the msim markup <p> (paragraph) tag into HTML. */
-static void 
+static void
 msim_markup_p_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
 {
-	/* Just pass through unchanged. 
+	/* Just pass through unchanged.
 	 *
 	 * Note: attributes currently aren't passed, if there are any. */
 	*begin = g_strdup("<p>");
 	*end = g_strdup("</p>");
 }
 
-/** Convert the msim markup <c> tag (text color) into HTML. TODO: Test */
-static void 
+/**
+ * Convert the msim markup <c> tag (text color) into HTML.
+ */
+static void
 msim_markup_c_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
 {
 	const gchar *color;
@@ -330,16 +314,21 @@
 
 	purple_color = msim_color_to_purple(color);
 
-	*begin = g_strdup_printf("<font color='%s'>", purple_color); 
+#ifdef USE_CSS_FORMATTING
+	*begin = g_strdup_printf("<span style='color: %s'>", purple_color);
+	*end = g_strdup("</span>");
+#else
+	*begin = g_strdup_printf("<font color='%s'>", purple_color);
+	*end = g_strdup("</font>");
+#endif
 
 	g_free(purple_color);
-
-	/* *begin = g_strdup_printf("<span style='color: %s'>", color); */
-	*end = g_strdup("</font>");
 }
 
-/** Convert the msim markup <b> tag (background color) into HTML. TODO: Test */
-static void 
+/**
+ * Convert the msim markup <b> tag (background color) into HTML.
+ */
+static void
 msim_markup_b_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
 {
 	const gchar *color;
@@ -356,16 +345,19 @@
 
 	purple_color = msim_color_to_purple(color);
 
-	/* TODO: find out how to set background color. */
-	*begin = g_strdup_printf("<span style='background-color: %s'>", 
-			purple_color);
+#ifdef USE_CSS_FORMATTING
+	*begin = g_strdup_printf("<span style='background-color: %s'>", purple_color);
+	*end = g_strdup("</span>");
+#else
+	*begin = g_strdup_printf("<body bgcolor='%s'>", purple_color);
+	*end = g_strdup("</body>");
+#endif
+
 	g_free(purple_color);
-
-	*end = g_strdup("</p>");
 }
 
 /** Convert the msim markup <i> tag (emoticon image) into HTML. */
-static void 
+static void
 msim_markup_i_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
 {
 	const gchar *name;
@@ -396,8 +388,8 @@
 }
 
 /** Convert an individual msim markup tag to HTML. */
-static int 
-msim_markup_tag_to_html(MsimSession *session, xmlnode *root, gchar **begin, 
+static int
+msim_markup_tag_to_html(MsimSession *session, xmlnode *root, gchar **begin,
 		gchar **end)
 {
 	g_return_val_if_fail(root != NULL, 0);
@@ -416,7 +408,7 @@
 		msim_markup_i_to_html(session, root, begin, end);
 	} else {
 		purple_debug_info("msim", "msim_markup_tag_to_html: "
-				"unknown tag name=%s, ignoring", 
+				"unknown tag name=%s, ignoring\n",
 				root->name ? root->name : "(NULL)");
 		*begin = g_strdup("");
 		*end = g_strdup("");
@@ -425,8 +417,8 @@
 }
 
 /** Convert an individual HTML tag to msim markup. */
-static int 
-html_tag_to_msim_markup(MsimSession *session, xmlnode *root, gchar **begin, 
+static int
+html_tag_to_msim_markup(MsimSession *session, xmlnode *root, gchar **begin,
 		gchar **end)
 {
 	int ret = 0;
@@ -437,7 +429,7 @@
 		*end = g_strdup("");
 	/* TODO: Coalesce nested tags into one <f> tag!
 	 * Currently, the 's' value will be overwritten when b/i/u is nested
-	 * within another one, and only the inner-most formatting will be 
+	 * within another one, and only the inner-most formatting will be
 	 * applied to the text. */
 	} else if (!purple_utf8_strcasecmp(root->name, "b")) {
 		if (root->child->type == XMLNODE_TYPE_DATA) {
@@ -515,29 +507,47 @@
 
 		*end = g_strdup("");
 	} else if (!purple_utf8_strcasecmp(root->name, "font")) {
+		GString *tmpbegin, *tmpend;
 		const gchar *size;
 		const gchar *face;
+		const gchar *color;
 
 		size = xmlnode_get_attrib(root, "size");
 		face = xmlnode_get_attrib(root, "face");
+		color = xmlnode_get_attrib(root, "color");
 
-		if (face && size) {
-			*begin = g_strdup_printf("<f f='%s' h='%d'>", face, 
-					msim_point_to_height(session,
-						msim_purple_size_to_point(session, atoi(size))));
-		} else if (face) {
-			*begin = g_strdup_printf("<f f='%s'>", face);
-		} else if (size) {
-			*begin = g_strdup_printf("<f h='%d'>", 
+		tmpbegin = g_string_new("<f");
+		tmpend = g_string_new("</f>");
+
+		if (face != NULL)
+			g_string_append_printf(tmpbegin, "f='%s'", face);
+
+		if (size != NULL)
+			g_string_append_printf(tmpbegin, "h='%d'",
 					 msim_point_to_height(session,
 						 msim_purple_size_to_point(session, atoi(size))));
-		} else {
-			*begin = g_strdup("<f>");
+
+		/* Close the <f> tag */
+		g_string_append(tmpbegin, ">");
+
+		if (color != NULL) {
+			g_string_append_printf(tmpbegin, "<c v='%s'>", color);
+			g_string_prepend(tmpend, "</c>");
 		}
 
-		*end = g_strdup("</f>");
+		*begin = g_string_free(tmpbegin, FALSE);
+		*end = g_string_free(tmpend, FALSE);
+
+	} else if (!purple_utf8_strcasecmp(root->name, "body")) {
+		const gchar *bgcolor;
 
-		/* TODO: color (bg uses <body>), emoticons */
+		bgcolor = xmlnode_get_attrib(root, "bgcolor");
+
+		if (bgcolor != NULL) {
+			*begin = g_strdup_printf("<b v='%s'>", bgcolor);
+			*end = g_strdup("</b>");
+		}
+
 	} else {
 		gchar *err;
 
@@ -550,7 +560,7 @@
 #endif
 
 		err = g_strdup_printf("html_tag_to_msim_markup: unrecognized "
-			"HTML tag %s was sent by the IM client; ignoring", 
+			"HTML tag %s was sent by the IM client; ignoring",
 			root->name ? root->name : "(NULL)");
 		msim_unrecognized(NULL, NULL, err);
 		g_free(err);
@@ -564,29 +574,26 @@
  *
  * @return An HTML string. Caller frees.
  */
-static gchar *
-msim_convert_xmlnode(MsimSession *session, xmlnode *root, MSIM_XMLNODE_CONVERT f, int nodes_processed)
+static void
+msim_convert_xmlnode(MsimSession *session, GString *out, xmlnode *root, MSIM_XMLNODE_CONVERT f, int nodes_processed)
 {
 	xmlnode *node;
-	gchar *begin, *inner, *end;
-	GString *final;
+	gchar *begin, *inner, *end, *tmp;
 	int descended = nodes_processed;
 
-	if (!root || !root->name) {
-		return g_strdup("");
-	}
+	if (!root || !root->name)
+		return;
 
 	purple_debug_info("msim", "msim_convert_xmlnode: got root=%s\n",
 			root->name);
 
 	begin = inner = end = NULL;
 
-	final = g_string_new("");
-
 	if (descended == 0) /* We've not formatted this yet.. :) */
 		descended = f(session, root, &begin, &end); /* Get the value that our format function has already descended for us */
-	
-	g_string_append(final, begin);
+
+	g_string_append(out, begin);
+	g_free(begin);
 
 	/* Loop over all child nodes. */
 	for (node = root->child; node != NULL; node = node->next) {
@@ -597,29 +604,26 @@
 
 			case XMLNODE_TYPE_TAG:
 				/* A tag or tag with attributes. Recursively descend. */
-				inner = msim_convert_xmlnode(session, node, f, descended);
-				g_return_val_if_fail(inner != NULL, NULL);
-		
-				purple_debug_info("msim", " ** node name=%s\n", 
-						(node && node->name) ? node->name : "(NULL)");
+				msim_convert_xmlnode(session, out, node, f, descended);
+
+				purple_debug_info("msim", " ** node name=%s\n",
+						node->name ? node->name : "(NULL)");
 				break;
-		
+
 			case XMLNODE_TYPE_DATA:
 				/* Literal text. */
-				inner = g_strndup(node->data, node->data_sz);
-				purple_debug_info("msim", " ** node data=%s\n", 
-						inner ? inner : "(NULL)");
+				/*
+				 * TODO: Why is it necessary to escape here?  I thought
+				 *       node->data was already escaped?
+				 */
+				tmp = g_markup_escape_text(node->data, node->data_sz);
+				g_string_append(out, tmp);
+				g_free(tmp);
 				break;
-		
+
 			default:
-				purple_debug_info("msim",
-						"msim_convert_xmlnode: strange node\n");
-		}
-
-		if (inner) {
-			g_string_append(final, inner);
-			g_free(inner);
-			inner = NULL;
+				purple_debug_warning("msim",
+						"msim_convert_xmlnode: unknown node type\n");
 		}
 	}
 
@@ -627,15 +631,8 @@
 	 * a paragraph and will display each on its own line. You actually have
 	 * to _nest_ <f> tags to intersperse different text in one paragraph!
 	 * Comment out this line below to see. */
-	g_string_append(final, end);
-
-	g_free(begin);
+	g_string_append(out, end);
 	g_free(end);
-
-	purple_debug_info("msim", "msim_markup_xmlnode_to_gtkhtml: RETURNING %s\n",
-			(final && final->str) ? final->str : "(NULL)");
-
-	return g_string_free(final, FALSE);
 }
 
 /** Convert XML to something based on MSIM_XMLNODE_CONVERT. */
@@ -643,7 +640,7 @@
 msim_convert_xml(MsimSession *session, const gchar *raw, MSIM_XMLNODE_CONVERT f)
 {
 	xmlnode *root;
-	gchar *str;
+	GString *str;
 	gchar *enclosed_raw;
 
 	g_return_val_if_fail(raw != NULL, NULL);
@@ -654,7 +651,7 @@
 	root = xmlnode_from_str(enclosed_raw, -1);
 
 	if (!root) {
-		purple_debug_info("msim", "msim_markup_to_html: couldn't parse "
+		purple_debug_warning("msim", "msim_markup_to_html: couldn't parse "
 				"%s as XML, returning raw: %s\n", enclosed_raw, raw);
 		/* TODO: msim_unrecognized */
 		g_free(enclosed_raw);
@@ -663,13 +660,13 @@
 
 	g_free(enclosed_raw);
 
-	str = msim_convert_xmlnode(session, root, f, 0);
-	g_return_val_if_fail(str != NULL, NULL);
-	purple_debug_info("msim", "msim_markup_to_html: returning %s\n", str);
-
+	str = g_string_new(NULL);
+	msim_convert_xmlnode(session, str, root, f, 0);
 	xmlnode_free(root);
 
-	return str;
+	purple_debug_info("msim", "msim_markup_to_html: returning %s\n", str->str);
+
+	return g_string_free(str, FALSE);
 }
 
 /** Convert plaintext smileys to <i> markup tags.
@@ -696,10 +693,10 @@
 		replacement = g_strdup_printf("<i n=\"%s\"/>", name);
 
 		purple_debug_info("msim", "msim_convert_smileys_to_markup: %s->%s\n",
-				symbol ? symbol : "(NULL)", 
+				symbol ? symbol : "(NULL)",
 				replacement ? replacement : "(NULL)");
 		new = purple_strreplace(old, symbol, replacement);
-		
+
 		g_free(replacement);
 		g_free(old);
 
@@ -708,19 +705,19 @@
 
 	return new;
 }
-	
 
-/** High-level function to convert MySpaceIM markup to Purple (HTML) markup. 
+/**
+ * High-level function to convert MySpaceIM markup to Purple (HTML) markup.
  *
  * @return Purple markup string, must be g_free()'d. */
 gchar *
 msim_markup_to_html(MsimSession *session, const gchar *raw)
 {
-	return msim_convert_xml(session, raw, 
-			(MSIM_XMLNODE_CONVERT)(msim_markup_tag_to_html));
+	return msim_convert_xml(session, raw, msim_markup_tag_to_html);
 }
 
-/** High-level function to convert Purple (HTML) to MySpaceIM markup.
+/**
+ * High-level function to convert Purple (HTML) to MySpaceIM markup.
  *
  * TODO: consider using purple_markup_html_to_xhtml() to make valid XML.
  *
@@ -730,9 +727,8 @@
 {
 	gchar *markup;
 
-	markup = msim_convert_xml(session, raw,
-			(MSIM_XMLNODE_CONVERT)(html_tag_to_msim_markup));
-	
+	markup = msim_convert_xml(session, raw, html_tag_to_msim_markup);
+
 	if (purple_account_get_bool(session->account, "emoticons", TRUE)) {
 		/* Frees markup and allocates a new one. */
 		markup = msim_convert_smileys_to_markup(markup);
@@ -740,5 +736,3 @@
 
 	return markup;
 }
-
-
--- a/libpurple/protocols/myspace/message.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/myspace/message.c	Wed Dec 17 18:01:08 2008 +0000
@@ -19,17 +19,16 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-#include "myspace.h"
+#include "internal.h"
 #include "message.h"
+#include "myspace.h"
 
-static void msim_msg_free_element(gpointer data, gpointer user_data);
 static void msim_msg_debug_string_element(gpointer data, gpointer user_data);
-static gchar *msim_msg_pack_using(MsimMessage *msg, GFunc gf, const gchar *sep, const gchar *begin, const gchar *end);
-static GList *msim_msg_get_node(MsimMessage *msg, const gchar *name);
-static MsimMessage *msim_msg_new_v(gchar *first_key, va_list argp);
 
-/* Escape codes and associated replacement text, used for protocol message
- * escaping and unescaping. */
+/**
+ * Escape codes and associated replacement text, used for protocol message
+ * escaping and unescaping.
+ */
 static struct MSIM_ESCAPE_REPLACEMENT {
 	gchar *code;
 	gchar text;
@@ -53,7 +52,7 @@
 	guint msg_len;
 
 	gs = g_string_new("");
-	msg_len = strlen(msg);	
+	msg_len = strlen(msg);
 
 	for (i = 0; i < msg_len; ++i) {
 		struct MSIM_ESCAPE_REPLACEMENT *replacement;
@@ -97,7 +96,7 @@
 	guint msg_len;
 
 	gs = g_string_new("");
-	msg_len = strlen(msg);	
+	msg_len = strlen(msg);
 
 	for (i = 0; i < msg_len; ++i) {
 		struct MSIM_ESCAPE_REPLACEMENT *replacement;
@@ -126,27 +125,8 @@
 	return g_string_free(gs, FALSE);
 }
 
-/** Create a new MsimMessage. 
- * 
- * @param first_key The first key in the sequence, or NULL for an empty message.
- * @param ... A sequence of gchar* key/type/value triplets, terminated with NULL. 
- *
- * See msim_msg_append() documentation for details on types.
- */
-MsimMessage *
-msim_msg_new(gchar *first_key, ...)
-{
-	va_list argp;
-
-	if (first_key) {
-	va_start(argp, first_key);
-		return msim_msg_new_v(first_key, argp);
-	} else {
-		return NULL;
-	}
-}
-
-/** Create a new message from va_list and its first argument.
+/**
+ * Create a new message from va_list and its first argument.
  *
  * @param first_key The first argument (a key), or NULL to take all arguments
  *    from argp.
@@ -189,11 +169,11 @@
 
 		/* Interpret variadic arguments. */
 		switch (type) {
-			case MSIM_TYPE_INTEGER: 
-			case MSIM_TYPE_BOOLEAN: 
+			case MSIM_TYPE_INTEGER:
+			case MSIM_TYPE_BOOLEAN:
 				msg = msim_msg_append(msg, key, type, GUINT_TO_POINTER(va_arg(argp, int)));
 				break;
-				
+
 			case MSIM_TYPE_STRING:
 				value = va_arg(argp, char *);
 
@@ -210,7 +190,7 @@
 				/* msim_msg_free() will free this GString the caller created. */
 				msg = msim_msg_append(msg, key, type, gs);
 				break;
-			
+
 			case MSIM_TYPE_LIST:
 				gl = va_arg(argp, GList *);
 
@@ -237,9 +217,310 @@
 	return msg;
 }
 
-/** Perform a deep copy on a GList * of gchar * strings. Free with msim_msg_list_free(). */
-GList *
-msim_msg_list_copy(GList *old)
+/**
+ * Create a new MsimMessage.
+ *
+ * @param first_key The first key in the sequence, or NULL for an empty message.
+ * @param ... A sequence of gchar* key/type/value triplets, terminated with NULL.
+ *
+ * See msim_msg_append() documentation for details on types.
+ */
+MsimMessage *
+msim_msg_new(gchar *first_key, ...)
+{
+	va_list argp;
+
+	if (first_key) {
+	va_start(argp, first_key);
+		return msim_msg_new_v(first_key, argp);
+	} else {
+		return NULL;
+	}
+}
+
+/**
+ * Pack a string using the given GFunc and seperator.
+ * Used by msim_msg_dump() and msim_msg_pack().
+ */
+static gchar *
+msim_msg_pack_using(MsimMessage *msg,
+		GFunc gf,
+		const gchar *sep,
+		const gchar *begin, const gchar *end)
+{
+	int num_items;
+	gchar **strings;
+	gchar **strings_tmp;
+	gchar *joined;
+	gchar *final;
+	int i;
+
+	g_return_val_if_fail(msg != NULL, NULL);
+
+	num_items = g_list_length(msg);
+
+	/* Add one for NULL terminator for g_strjoinv(). */
+	strings = (gchar **)g_new0(gchar *, num_items + 1);
+
+	strings_tmp = strings;
+	g_list_foreach(msg, gf, &strings_tmp);
+
+	joined = g_strjoinv(sep, strings);
+	final = g_strconcat(begin, joined, end, NULL);
+	g_free(joined);
+
+	/* Clean up. */
+	for (i = 0; i < num_items; ++i) {
+		g_free(strings[i]);
+	}
+
+	g_free(strings);
+
+	return final;
+}
+
+/**
+ * Return a human-readable string of the message.
+ *
+ * @return A new gchar *, must be g_free()'d.
+ */
+static gchar *
+msim_msg_dump_to_str(MsimMessage *msg)
+{
+	gchar *debug_str;
+
+	if (!msg) {
+		debug_str = g_strdup("<MsimMessage: empty>");
+	} else {
+		debug_str = msim_msg_pack_using(msg, msim_msg_debug_string_element,
+				"\n", "<MsimMessage: \n", "\n/MsimMessage>");
+	}
+
+	return debug_str;
+}
+
+/**
+ * Store a human-readable string describing the element.
+ *
+ * @param data Pointer to an MsimMessageElement.
+ * @param user_data
+ */
+static void
+msim_msg_debug_string_element(gpointer data, gpointer user_data)
+{
+	MsimMessageElement *elem;
+	gchar *string;
+	GString *gs;
+	gchar *binary;
+	gchar ***items;  /* wow, a pointer to a pointer to a pointer */
+
+	gchar *s;
+	GList *gl;
+	guint i;
+
+	elem = (MsimMessageElement *)data;
+	items = user_data;
+
+	switch (elem->type) {
+		case MSIM_TYPE_INTEGER:
+			string = g_strdup_printf("%s(integer): %d", elem->name,
+					GPOINTER_TO_UINT(elem->data));
+			break;
+
+		case MSIM_TYPE_RAW:
+			string = g_strdup_printf("%s(raw): %s", elem->name,
+					elem->data ? (gchar *)elem->data : "(NULL)");
+			break;
+
+		case MSIM_TYPE_STRING:
+			string = g_strdup_printf("%s(string): %s", elem->name,
+					elem->data ? (gchar *)elem->data : "(NULL)");
+			break;
+
+		case MSIM_TYPE_BINARY:
+			gs = (GString *)elem->data;
+			binary = purple_base64_encode((guchar*)gs->str, gs->len);
+			string = g_strdup_printf("%s(binary, %d bytes): %s", elem->name, (int)gs->len, binary);
+			g_free(binary);
+			break;
+
+		case MSIM_TYPE_BOOLEAN:
+			string = g_strdup_printf("%s(boolean): %s", elem->name,
+					elem->data ? "TRUE" : "FALSE");
+			break;
+
+		case MSIM_TYPE_DICTIONARY:
+			if (!elem->data) {
+				s = g_strdup("(NULL)");
+			} else {
+				s = msim_msg_dump_to_str((MsimMessage *)elem->data);
+			}
+
+			if (!s) {
+				s = g_strdup("(NULL, couldn't msim_msg_dump_to_str)");
+			}
+
+			string = g_strdup_printf("%s(dict): %s", elem->name, s);
+
+			g_free(s);
+			break;
+
+		case MSIM_TYPE_LIST:
+			gs = g_string_new("");
+			g_string_append_printf(gs, "%s(list): \n", elem->name);
+
+			i = 0;
+			for (gl = (GList *)elem->data; gl != NULL; gl = g_list_next(gl)) {
+				g_string_append_printf(gs, " %d. %s\n", i, (gchar *)(gl->data));
+				++i;
+			}
+
+			string = g_string_free(gs, FALSE);
+			break;
+
+		default:
+			string = g_strdup_printf("%s(unknown type %d",
+					elem->name ? elem->name : "(NULL)", elem->type);
+			break;
+	}
+
+	**items = string;
+	++(*items);
+}
+
+/**
+ * Search for and return the node in msg, matching name, or NULL.
+ *
+ * @param msg Message to search within.
+ * @param name Field name to search for.
+ *
+ * @return The GList * node for the MsimMessageElement with the given name, or NULL if not found or name is NULL.
+ *
+ * For internal use - users probably want to use msim_msg_get() to
+ * access the MsimMessageElement *, instead of the GList * container.
+ *
+ */
+static GList *
+msim_msg_get_node(MsimMessage *msg, const gchar *name)
+{
+	GList *node;
+
+	if (!name || !msg) {
+		return NULL;
+	}
+
+	/* Linear search for the given name. O(n) but n is small. */
+	for (node = msg; node != NULL; node = g_list_next(node)) {
+		MsimMessageElement *elem;
+
+		elem = (MsimMessageElement *)node->data;
+
+		g_return_val_if_fail(elem != NULL, NULL);
+		g_return_val_if_fail(elem->name != NULL, NULL);
+
+		if (strcmp(elem->name, name) == 0) {
+			return node;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * Create a new MsimMessageElement * - must be g_free()'d.
+ *
+ * For internal use; users probably want msim_msg_append() or msim_msg_insert_before().
+ *
+ * @param dynamic_name Whether 'name' should be freed when the message is destroyed.
+ */
+static MsimMessageElement *
+msim_msg_element_new(const gchar *name, MsimMessageType type, gpointer data, gboolean dynamic_name)
+{
+	MsimMessageElement *elem;
+
+	elem = g_new0(MsimMessageElement, 1);
+
+	elem->name = name;
+	elem->dynamic_name = dynamic_name;
+	elem->type = type;
+	elem->data = data;
+
+	return elem;
+}
+
+/**
+ * Append a new element to a message.
+ *
+ * @param name Textual name of element (static string, neither copied nor freed).
+ * @param type An MSIM_TYPE_* code.
+ * @param data Pointer to data, see below.
+ *
+ * @return The new message - must be assigned to as with GList*. For example:
+ *
+ *     msg = msim_msg_append(msg, ...)
+ *
+ * The data parameter depends on the type given:
+ *
+ * * MSIM_TYPE_INTEGER: Use GUINT_TO_POINTER(x).
+ *
+ * * MSIM_TYPE_BINARY: Same as integer, non-zero is TRUE and zero is FALSE.
+ *
+ * * MSIM_TYPE_STRING: gchar *. The data WILL BE FREED - use g_strdup() if needed.
+ *
+ * * MSIM_TYPE_RAW: gchar *. The data WILL BE FREED - use g_strdup() if needed.
+ *
+ * * MSIM_TYPE_BINARY: g_string_new_len(data, length). The data AND GString will be freed.
+ *
+ * * MSIM_TYPE_DICTIONARY: An MsimMessage *. Freed when message is destroyed.
+ *
+ * * MSIM_TYPE_LIST: GList * of gchar *. Again, everything will be freed.
+ *
+ * */
+MsimMessage *
+msim_msg_append(MsimMessage *msg, const gchar *name,
+		MsimMessageType type, gpointer data)
+{
+	return g_list_append(msg, msim_msg_element_new(name, type, data, FALSE));
+}
+
+/**
+ * Append a new element, but with a dynamically-allocated name.
+ * Exactly the same as msim_msg_append(), except 'name' will be freed when
+ * the message is destroyed. Normally, it isn't, because a static string is given.
+ */
+static MsimMessage *
+msim_msg_append_dynamic_name(MsimMessage *msg, gchar *name,
+		MsimMessageType type, gpointer data)
+{
+	return g_list_append(msg, msim_msg_element_new(name, type, data, TRUE));
+}
+
+/**
+ * Insert a new element into a message, before the given element name.
+ *
+ * @param name_before Name of the element to insert the new element before. If
+ *                    could not be found or NULL, new element will be inserted at end.
+ *
+ * See msim_msg_append() for usage of other parameters, and an important note about return value.
+ */
+MsimMessage *
+msim_msg_insert_before(MsimMessage *msg, const gchar *name_before,
+		const gchar *name, MsimMessageType type, gpointer data)
+{
+	MsimMessageElement *new_elem;
+	GList *node_before;
+
+	new_elem = msim_msg_element_new(name, type, data, FALSE);
+
+	node_before = msim_msg_get_node(msg, name_before);
+
+	return g_list_insert_before(msg, node_before, new_elem);
+}
+
+/**
+ * Perform a deep copy on a GList * of gchar * strings. Free with msim_msg_list_free().
+ */
+static GList *
+msim_msg_list_copy(const GList *old)
 {
 	GList *new_list;
 
@@ -253,65 +534,13 @@
 	return new_list;
 }
 
-/** Free a GList * of MsimMessageElement *'s. */
-void
-msim_msg_list_free(GList *l)
-{
-
-	for (; l != NULL; l = g_list_next(l)) {
-		MsimMessageElement *elem;
-
-		elem = (MsimMessageElement *)l->data;
-
-		/* Note that name is almost never dynamically allocated elsewhere;
-		 * it is usually a static string, but not in lists. So cast it. */
-		g_free((gchar *)elem->name);
-		g_free(elem->data);
-		g_free(elem);
-	}
-	g_list_free(l);
-}
-
-/** Parse a |-separated string into a new GList. Free with msim_msg_list_free(). */
-GList *
-msim_msg_list_parse(const gchar *raw)
-{
-	gchar **array;
-	GList *list;
-	guint i;
-
-	array = g_strsplit(raw, "|", 0);
-	list = NULL;
-
-	/* TODO: escape/unescape /3 <-> | within list elements */
-	
-	for (i = 0; array[i] != NULL; ++i) {
-		MsimMessageElement *elem;
-
-		/* Freed in msim_msg_list_free() */
-		elem = g_new0(MsimMessageElement, 1);
-
-		/* Give the element a name for debugging purposes.
-		 * Not supposed to be looked up by this name; instead,
-		 * lookup the elements by indexing the array. */
-		elem->name = g_strdup_printf("(list item #%d)", i);
-		elem->type = MSIM_TYPE_RAW;
-		elem->data = g_strdup(array[i]);
-
-		list = g_list_append(list, elem);
-	}
-
-	g_strfreev(array);
-
-	return list;
-}
-
-/** Clone an individual element.
+/**
+ * Clone an individual element.
  *
  * @param data MsimMessageElement * to clone.
  * @param user_data Pointer to MsimMessage * to add cloned element to.
  */
-static void 
+static void
 msim_msg_clone_element(gpointer data, gpointer user_data)
 {
 	MsimMessageElement *elem;
@@ -357,10 +586,14 @@
 
 	/* Append cloned data. Note that the 'name' field is a static string, so it
 	 * never needs to be copied nor freed. */
-	*new = msim_msg_append(*new, elem->name, elem->type, new_data);
+	if (elem->dynamic_name)
+		*new = msim_msg_append_dynamic_name(*new, g_strdup(elem->name), elem->type, new_data);
+	else
+		*new = msim_msg_append(*new, elem->name, elem->type, new_data);
 }
 
-/** Clone an existing MsimMessage. 
+/**
+ * Clone an existing MsimMessage.
  *
  * @return Cloned message; caller should free with msim_msg_free().
  */
@@ -380,7 +613,8 @@
 	return new;
 }
 
-/** Free the data of a message element.
+/**
+ * Free the data of a message element.
  *
  * @param elem The MsimMessageElement *
  *
@@ -411,7 +645,7 @@
 		case MSIM_TYPE_DICTIONARY:
 			msim_msg_free((MsimMessage *)elem->data);
 			break;
-			
+
 		case MSIM_TYPE_LIST:
 			g_list_free((GList *)elem->data);
 			break;
@@ -423,7 +657,29 @@
 	}
 }
 
-/** Free an individual message element.
+/**
+ * Free a GList * of MsimMessageElement *'s.
+ */
+void
+msim_msg_list_free(GList *l)
+{
+
+	for (; l != NULL; l = g_list_next(l)) {
+		MsimMessageElement *elem;
+
+		elem = (MsimMessageElement *)l->data;
+
+		/* Note that name is almost never dynamically allocated elsewhere;
+		 * it is usually a static string, but not in lists. So cast it. */
+		g_free((gchar *)elem->name);
+		g_free(elem->data);
+		g_free(elem);
+	}
+	g_list_free(l);
+}
+
+/**
+ * Free an individual message element.
  *
  * @param data MsimMessageElement * to free.
  * @param user_data Not used; required to match g_list_foreach() callback prototype.
@@ -431,7 +687,7 @@
  * Frees both the element data and the element itself.
  * Also frees the name if dynamic_name is TRUE.
  */
-static void 
+static void
 msim_msg_free_element(gpointer data, gpointer user_data)
 {
 	MsimMessageElement *elem;
@@ -449,8 +705,10 @@
 	g_free(elem);
 }
 
-/** Free a complete message. */
-void 
+/**
+ * Free a complete message.
+ */
+void
 msim_msg_free(MsimMessage *msg)
 {
 	if (!msg) {
@@ -458,430 +716,12 @@
 		return;
 	}
 
-#ifdef MSIM_MSG_DEBUG_FREE
-	msim_msg_dump("msim_msg_free: freeing %s", msg);
-#endif
-
 	g_list_foreach(msg, msim_msg_free_element, NULL);
 	g_list_free(msg);
 }
 
-/** Send an existing MsimMessage. */
-gboolean 
-msim_msg_send(MsimSession *session, MsimMessage *msg)
-{
-	gchar *raw;
-	gboolean success;
-	
-	raw = msim_msg_pack(msg);
-	g_return_val_if_fail(raw != NULL, FALSE);
-	success = msim_send_raw(session, raw);
-	g_free(raw);
-
-	msim_msg_dump("msim_msg_send()ing %s\n", msg);
-	
-	return success;
-}
-
 /**
- *
- * Send a message to the server, whose contents is specified using 
- * variable arguments.
- *
- * @param session
- * @param ... A sequence of gchar* key/type/value triplets, terminated with NULL. 
- *
- * This function exists for coding convenience: it allows a message to be created
- * and sent in one line of code. Internally it calls msim_msg_send(). 
- *
- * IMPORTANT: See msim_msg_append() documentation for details on element types.
- *
- */
-gboolean 
-msim_send(MsimSession *session, ...)
-{
-	gboolean success;
-	MsimMessage *msg;
-	va_list argp;
-	
-	va_start(argp, session);
-	msg = msim_msg_new_v(NULL, argp);
-
-	/* Actually send the message. */
-	success = msim_msg_send(session, msg);
-
-	/* Cleanup. */
-	msim_msg_free(msg);
-
-	return success;
-}
-
-/** Create a new MsimMessageElement * - must be g_free()'d. 
- *
- * For internal use; users probably want msim_msg_append() or msim_msg_insert_before(). 
- *
- * @param dynamic_name Whether 'name' should be freed when the message is destroyed.
- */
-static MsimMessageElement *
-msim_msg_element_new(const gchar *name, MsimMessageType type, gpointer data, gboolean dynamic_name)
-{
-	MsimMessageElement *elem;
-
-	elem = g_new0(MsimMessageElement, 1);
-
-	elem->name = name;
-	elem->dynamic_name = dynamic_name;
-	elem->type = type;
-	elem->data = data;
-
-	return elem;
-}
-
-
-/** Append a new element to a message. 
- *
- * @param name Textual name of element (static string, neither copied nor freed).
- * @param type An MSIM_TYPE_* code.
- * @param data Pointer to data, see below.
- *
- * @return The new message - must be assigned to as with GList*. For example:
- *
- *     msg = msim_msg_append(msg, ...)
- *
- * The data parameter depends on the type given:
- *
- * * MSIM_TYPE_INTEGER: Use GUINT_TO_POINTER(x).
- *
- * * MSIM_TYPE_BINARY: Same as integer, non-zero is TRUE and zero is FALSE.
- *
- * * MSIM_TYPE_STRING: gchar *. The data WILL BE FREED - use g_strdup() if needed.
- *
- * * MSIM_TYPE_RAW: gchar *. The data WILL BE FREED - use g_strdup() if needed.
- *
- * * MSIM_TYPE_BINARY: g_string_new_len(data, length). The data AND GString will be freed.
- *
- * * MSIM_TYPE_DICTIONARY: An MsimMessage *. Freed when message is destroyed.
- *
- * * MSIM_TYPE_LIST: GList * of gchar *. Again, everything will be freed.
- *
- * */
-MsimMessage *
-msim_msg_append(MsimMessage *msg, const gchar *name, 
-		MsimMessageType type, gpointer data)
-{
-	return g_list_append(msg, msim_msg_element_new(name, type, data, FALSE));
-}
-
-/** Append a new element, but with a dynamically-allocated name.
- * Exactly the same as msim_msg_append(), except 'name' will be freed when
- * the message is destroyed. Normally, it isn't, because a static string is given.
- */
-static MsimMessage *
-msim_msg_append_dynamic_name(MsimMessage *msg, gchar *name,
-		MsimMessageType type, gpointer data)
-{
-	return g_list_append(msg, msim_msg_element_new(name, type, data, TRUE));
-}
-
-/** Insert a new element into a message, before the given element name.
- *
- * @param name_before Name of the element to insert the new element before. If 
- *                    could not be found or NULL, new element will be inserted at end.
- *
- * See msim_msg_append() for usage of other parameters, and an important note about return value.
- */
-MsimMessage *
-msim_msg_insert_before(MsimMessage *msg, const gchar *name_before, 
-		const gchar *name, MsimMessageType type, gpointer data)
-{
-	MsimMessageElement *new_elem;
-	GList *node_before;
-
-	new_elem = msim_msg_element_new(name, type, data, FALSE);
-
-	node_before = msim_msg_get_node(msg, name_before);
-
-	return g_list_insert_before(msg, node_before, new_elem);
-}
-
-/** Pack a string using the given GFunc and seperator.
- * Used by msim_msg_dump() and msim_msg_pack().
- */
-gchar *
-msim_msg_pack_using(MsimMessage *msg, 
-		GFunc gf, 
-		const gchar *sep, 
-		const gchar *begin, const gchar *end)
-{
-	int num_items;
-	gchar **strings;
-	gchar **strings_tmp;
-	gchar *joined;
-	gchar *final;
-	int i;
-
-	g_return_val_if_fail(msg != NULL, NULL);
-
-	num_items = g_list_length(msg);
-
-	/* Add one for NULL terminator for g_strjoinv(). */
-	strings = (gchar **)g_new0(gchar *, num_items + 1);
-
-	strings_tmp = strings;
-	g_list_foreach(msg, gf, &strings_tmp);
-
-	joined = g_strjoinv(sep, strings);
-	final = g_strconcat(begin, joined, end, NULL);
-	g_free(joined);
-
-	/* Clean up. */
-	for (i = 0; i < num_items; ++i) {
-		g_free(strings[i]);
-	}
-
-	g_free(strings);
-
-	return final;
-}
-/** Store a human-readable string describing the element.
- *
- * @param data Pointer to an MsimMessageElement.
- * @param user_data 
- */
-static void 
-msim_msg_debug_string_element(gpointer data, gpointer user_data)
-{
-	MsimMessageElement *elem;
-	gchar *string;
-	GString *gs;
-	gchar *binary;
-	gchar ***items;  /* wow, a pointer to a pointer to a pointer */
-	
-	gchar *s;
-	GList *gl;
-	guint i;
-
-	elem = (MsimMessageElement *)data;
-	items = user_data;
-
-	switch (elem->type) {
-		case MSIM_TYPE_INTEGER:
-			string = g_strdup_printf("%s(integer): %d", elem->name, 
-					GPOINTER_TO_UINT(elem->data));
-			break;
-
-		case MSIM_TYPE_RAW:
-			string = g_strdup_printf("%s(raw): %s", elem->name, 
-					elem->data ? (gchar *)elem->data : "(NULL)");
-			break;
-
-		case MSIM_TYPE_STRING:
-			string = g_strdup_printf("%s(string): %s", elem->name, 
-					elem->data ? (gchar *)elem->data : "(NULL)");
-			break;
-
-		case MSIM_TYPE_BINARY:
-			gs = (GString *)elem->data;
-			binary = purple_base64_encode((guchar*)gs->str, gs->len);
-			string = g_strdup_printf("%s(binary, %d bytes): %s", elem->name, (int)gs->len, binary);
-			g_free(binary);
-			break;
-
-		case MSIM_TYPE_BOOLEAN:
-			string = g_strdup_printf("%s(boolean): %s", elem->name,
-					elem->data ? "TRUE" : "FALSE");
-			break;
-
-		case MSIM_TYPE_DICTIONARY:
-			if (!elem->data) {
-				s = g_strdup("(NULL)");
-			} else {
-				s = msim_msg_dump_to_str((MsimMessage *)elem->data);
-			}
-
-			if (!s) {
-				s = g_strdup("(NULL, couldn't msim_msg_dump_to_str)");
-			}
-
-			string = g_strdup_printf("%s(dict): %s", elem->name, s);
-
-			g_free(s);
-			break;
-			
-		case MSIM_TYPE_LIST:
-			gs = g_string_new("");
-			g_string_append_printf(gs, "%s(list): \n", elem->name);
-
-			i = 0;
-			for (gl = (GList *)elem->data; gl != NULL; gl = g_list_next(gl)) {
-				g_string_append_printf(gs, " %d. %s\n", i, (gchar *)(gl->data));
-				++i;
-			}
-			
-			string = g_string_free(gs, FALSE);
-			break;
-
-		default:
-			string = g_strdup_printf("%s(unknown type %d", 
-					elem->name ? elem->name : "(NULL)", elem->type);
-			break;
-	}
-
-	**items = string;
-	++(*items);
-}
-
-/** Print a human-readable string of the message to Purple's debug log.
- *
- * @param fmt_string A static string, in which '%s' will be replaced.
- */
-void 
-msim_msg_dump(const gchar *fmt_string, MsimMessage *msg)
-{
-	gchar *debug_str;
-
-	g_return_if_fail(fmt_string != NULL);
-
-	debug_str = msim_msg_dump_to_str(msg);
-	
-	g_return_if_fail(debug_str != NULL);
-
-	purple_debug_info("msim", fmt_string, debug_str);
-
-	g_free(debug_str);
-}
-
-/** Return a human-readable string of the message.
- *
- * @return A new gchar *, must be g_free()'d.
- */
-gchar *
-msim_msg_dump_to_str(MsimMessage *msg)
-{
-	gchar *debug_str;
-
-	if (!msg) {
-		debug_str = g_strdup("<MsimMessage: empty>");
-	} else {
-		debug_str = msim_msg_pack_using(msg, msim_msg_debug_string_element, 
-				"\n", "<MsimMessage: \n", "\n/MsimMessage>");
-	}
-
-	return debug_str;
-}
-
-/** Return a message element data as a new string for a raw protocol message, converting from other types (integer, etc.) if necessary.
- *
- * @return const gchar * The data as a string, or NULL. Caller must g_free().
- *
- * Returns a string suitable for inclusion in a raw protocol message, not necessarily
- * optimal for human consumption. For example, strings are escaped. Use 
- * msim_msg_get_string() if you want a string, which in some cases is same as this.
- */
-gchar *
-msim_msg_pack_element_data(MsimMessageElement *elem)
-{
-	GString *gs;
-	GList *gl;
-
-	g_return_val_if_fail(elem != NULL, NULL);
-
-	switch (elem->type) {
-		case MSIM_TYPE_INTEGER:
-			return g_strdup_printf("%d", GPOINTER_TO_UINT(elem->data));
-
-		case MSIM_TYPE_RAW:
-			/* Not un-escaped - this is a raw element, already escaped if necessary. */
-			return (gchar *)g_strdup((gchar *)elem->data);
-
-		case MSIM_TYPE_STRING:
-			/* Strings get escaped. msim_escape() creates a new string. */
-			g_return_val_if_fail(elem->data != NULL, NULL);
-			return elem->data ? msim_escape((gchar *)elem->data) :
-				g_strdup("(NULL)");
-
-		case MSIM_TYPE_BINARY:
-			gs = (GString *)elem->data;
-			/* Do not escape! */
-			return purple_base64_encode((guchar *)gs->str, gs->len);
-
-		case MSIM_TYPE_BOOLEAN:
-			/* Not used by messages in the wire protocol * -- see msim_msg_pack_element.
-			 * Only used by dictionaries, see msim_msg_pack_element_dict. */
-			return elem->data ? g_strdup("On") : g_strdup("Off");
-
-		case MSIM_TYPE_DICTIONARY:
-			return msim_msg_pack_dict((MsimMessage *)elem->data);
-			
-		case MSIM_TYPE_LIST:
-			/* Pack using a|b|c|d|... */
-			gs = g_string_new("");
-
-			for (gl = (GList *)elem->data; gl != NULL; gl = g_list_next(gl)) {
-				g_string_append_printf(gs, "%s", (gchar*)(gl->data));
-				
-				/* All but last element is separated by a bar. */
-				if (g_list_next(gl)) 
-					g_string_append(gs, "|");
-			}
-			
-			return g_string_free(gs, FALSE);
-
-		default:
-			purple_debug_info("msim", "field %s, unknown type %d\n", 
-					elem->name ? elem->name : "(NULL)", 
-					elem->type);
-			return NULL;
-	}
-}
-
-/** Pack an element into its protcol representation inside a dictionary.
- *
- * See msim_msg_pack_element().
- */
-static void
-msim_msg_pack_element_dict(gpointer data, gpointer user_data)
-{
-	MsimMessageElement *elem;
-	gchar *string, *data_string, ***items;
-
-	elem = (MsimMessageElement *)data;
-	items = (gchar ***)user_data;
-
-	/* Exclude elements beginning with '_' from packed protocol messages. */
-	if (elem->name[0] == '_') {
-		return;
-	}
-
-	data_string = msim_msg_pack_element_data(elem);
-
-	g_return_if_fail(data_string != NULL);
-
-	switch (elem->type) {
-		/* These types are represented by key name/value pairs (converted above). */
-		case MSIM_TYPE_INTEGER:
-		case MSIM_TYPE_RAW:
-		case MSIM_TYPE_STRING:
-		case MSIM_TYPE_BINARY:
-		case MSIM_TYPE_DICTIONARY:
-		case MSIM_TYPE_LIST:
-		case MSIM_TYPE_BOOLEAN: /* Boolean is On or Off */
-			string = g_strconcat(elem->name, "=", data_string, NULL);
-			break;
-
-		default:
-			g_free(data_string);
-			g_return_if_fail(FALSE);
-			break;
-	}
-
-	g_free(data_string);
-
-	**items = string;
-	++(*items);
-}
-
-/** Pack an element into its protocol representation. 
+ * Pack an element into its protocol representation.
  *
  * @param data Pointer to an MsimMessageElement.
  * @param user_data Pointer to a gchar ** array of string items.
@@ -891,7 +731,7 @@
  * is responsible for creating array to correct dimensions, and
  * freeing each string element of the array added by this function.
  */
-static void 
+static void
 msim_msg_pack_element(gpointer data, gpointer user_data)
 {
 	MsimMessageElement *elem;
@@ -942,8 +782,55 @@
 	++(*items);
 }
 
+/**
+ * Pack an element into its protcol representation inside a dictionary.
+ *
+ * See msim_msg_pack_element().
+ */
+static void
+msim_msg_pack_element_dict(gpointer data, gpointer user_data)
+{
+	MsimMessageElement *elem;
+	gchar *string, *data_string, ***items;
 
-/** Return a packed string of a message suitable for sending over the wire.
+	elem = (MsimMessageElement *)data;
+	items = (gchar ***)user_data;
+
+	/* Exclude elements beginning with '_' from packed protocol messages. */
+	if (elem->name[0] == '_') {
+		return;
+	}
+
+	data_string = msim_msg_pack_element_data(elem);
+
+	g_return_if_fail(data_string != NULL);
+
+	switch (elem->type) {
+		/* These types are represented by key name/value pairs (converted above). */
+		case MSIM_TYPE_INTEGER:
+		case MSIM_TYPE_RAW:
+		case MSIM_TYPE_STRING:
+		case MSIM_TYPE_BINARY:
+		case MSIM_TYPE_DICTIONARY:
+		case MSIM_TYPE_LIST:
+		case MSIM_TYPE_BOOLEAN: /* Boolean is On or Off */
+			string = g_strconcat(elem->name, "=", data_string, NULL);
+			break;
+
+		default:
+			g_free(data_string);
+			g_return_if_fail(FALSE);
+			break;
+	}
+
+	g_free(data_string);
+
+	**items = string;
+	++(*items);
+}
+
+/**
+ * Return a packed string of a message suitable for sending over the wire.
  *
  * @return A string. Caller must g_free().
  */
@@ -955,11 +842,12 @@
 	return msim_msg_pack_using(msg, msim_msg_pack_element, "\\", "\\", "\\final\\");
 }
 
-/** Return a packed string of a dictionary, suitable for embedding in MSIM_TYPE_DICTIONARY.
+/**
+ * Return a packed string of a dictionary, suitable for embedding in MSIM_TYPE_DICTIONARY.
  *
  * @return A string; caller must g_free().
  */
-gchar *
+static gchar *
 msim_msg_pack_dict(MsimMessage *msg)
 {
 	g_return_val_if_fail(msg != NULL, NULL);
@@ -967,7 +855,144 @@
 	return msim_msg_pack_using(msg, msim_msg_pack_element_dict, "\034", "", "");
 }
 
-/** 
+/**
+ * Send an existing MsimMessage.
+ */
+gboolean
+msim_msg_send(MsimSession *session, MsimMessage *msg)
+{
+	gchar *raw;
+	gboolean success;
+
+	raw = msim_msg_pack(msg);
+	g_return_val_if_fail(raw != NULL, FALSE);
+	success = msim_send_raw(session, raw);
+	g_free(raw);
+
+	return success;
+}
+
+/**
+ * Return a message element data as a new string for a raw protocol message,
+ * converting from other types (integer, etc.) if necessary.
+ *
+ * @return const gchar * The data as a string, or NULL. Caller must g_free().
+ *
+ * Returns a string suitable for inclusion in a raw protocol message, not necessarily
+ * optimal for human consumption. For example, strings are escaped. Use
+ * msim_msg_get_string() if you want a string, which in some cases is same as this.
+ */
+gchar *
+msim_msg_pack_element_data(MsimMessageElement *elem)
+{
+	GString *gs;
+	GList *gl;
+
+	g_return_val_if_fail(elem != NULL, NULL);
+
+	switch (elem->type) {
+		case MSIM_TYPE_INTEGER:
+			return g_strdup_printf("%d", GPOINTER_TO_UINT(elem->data));
+
+		case MSIM_TYPE_RAW:
+			/* Not un-escaped - this is a raw element, already escaped if necessary. */
+			return (gchar *)g_strdup((gchar *)elem->data);
+
+		case MSIM_TYPE_STRING:
+			/* Strings get escaped. msim_escape() creates a new string. */
+			g_return_val_if_fail(elem->data != NULL, NULL);
+			return elem->data ? msim_escape((gchar *)elem->data) :
+				g_strdup("(NULL)");
+
+		case MSIM_TYPE_BINARY:
+			gs = (GString *)elem->data;
+			/* Do not escape! */
+			return purple_base64_encode((guchar *)gs->str, gs->len);
+
+		case MSIM_TYPE_BOOLEAN:
+			/* Not used by messages in the wire protocol * -- see msim_msg_pack_element.
+			 * Only used by dictionaries, see msim_msg_pack_element_dict. */
+			return elem->data ? g_strdup("On") : g_strdup("Off");
+
+		case MSIM_TYPE_DICTIONARY:
+			return msim_msg_pack_dict((MsimMessage *)elem->data);
+
+		case MSIM_TYPE_LIST:
+			/* Pack using a|b|c|d|... */
+			gs = g_string_new("");
+
+			for (gl = (GList *)elem->data; gl != NULL; gl = g_list_next(gl)) {
+				g_string_append_printf(gs, "%s", (gchar*)(gl->data));
+
+				/* All but last element is separated by a bar. */
+				if (g_list_next(gl))
+					g_string_append(gs, "|");
+			}
+
+			return g_string_free(gs, FALSE);
+
+		default:
+			purple_debug_info("msim", "field %s, unknown type %d\n",
+					elem->name ? elem->name : "(NULL)",
+					elem->type);
+			return NULL;
+	}
+}
+
+/**
+ * Send a message to the server, whose contents is specified using
+ * variable arguments.
+ *
+ * @param session
+ * @param ... A sequence of gchar* key/type/value triplets, terminated with NULL.
+ *
+ * This function exists for coding convenience: it allows a message to be created
+ * and sent in one line of code. Internally it calls msim_msg_send().
+ *
+ * IMPORTANT: See msim_msg_append() documentation for details on element types.
+ *
+ */
+gboolean
+msim_send(MsimSession *session, ...)
+{
+	gboolean success;
+	MsimMessage *msg;
+	va_list argp;
+
+	va_start(argp, session);
+	msg = msim_msg_new_v(NULL, argp);
+
+	/* Actually send the message. */
+	success = msim_msg_send(session, msg);
+
+	/* Cleanup. */
+	msim_msg_free(msg);
+
+	return success;
+}
+
+/**
+ * Print a human-readable string of the message to Purple's debug log.
+ *
+ * @param fmt_string A static string, in which '%s' will be replaced.
+ */
+void
+msim_msg_dump(const gchar *fmt_string, MsimMessage *msg)
+{
+	gchar *debug_str;
+
+	g_return_if_fail(fmt_string != NULL);
+
+	debug_str = msim_msg_dump_to_str(msg);
+
+	g_return_if_fail(debug_str != NULL);
+
+	purple_debug_info("msim", fmt_string, debug_str);
+
+	g_free(debug_str);
+}
+
+/**
  * Parse a raw protocol message string into a MsimMessage *.
  *
  * @param raw The raw message string to parse, will be g_free()'d.
@@ -975,7 +1000,7 @@
  * @return MsimMessage *. Caller should msim_msg_free() when done.
  */
 MsimMessage *
-msim_parse(gchar *raw)
+msim_parse(const gchar *raw)
 {
 	MsimMessage *msg;
 	gchar *token;
@@ -996,13 +1021,12 @@
 				"missing initial backslash: <%s>\n", raw);
 		/* XXX: Should we try to recover, and read to first backslash? */
 
-		g_free(raw);
 		return NULL;
 	}
 
 	msg = msim_msg_new(FALSE);
 
-	for (tokens = g_strsplit(raw + 1, "\\", 0), i = 0; 
+	for (tokens = g_strsplit(raw + 1, "\\", 0), i = 0;
 			(token = tokens[i]);
 			i++) {
 #ifdef MSIM_DEBUG_PARSE
@@ -1012,7 +1036,7 @@
 			/* Odd-numbered ordinal is a value. */
 
 			value = token;
-		
+
 			/* Incoming protocol messages get tagged as MSIM_TYPE_RAW, which
 			 * represents an untyped piece of data. msim_msg_get_* will
 			 * convert to appropriate types for caller, and handle unescaping if needed. */
@@ -1027,49 +1051,11 @@
 	}
 	g_strfreev(tokens);
 
-	/* Can free now since all data was copied to hash key/values */
-	g_free(raw);
-
 	return msg;
 }
 
-/** Search for and return the node in msg, matching name, or NULL. 
- *
- * @param msg Message to search within.
- * @param name Field name to search for.
- *
- * @return The GList * node for the MsimMessageElement with the given name, or NULL if not found or name is NULL.
- *
- * For internal use - users probably want to use msim_msg_get() to
- * access the MsimMessageElement *, instead of the GList * container.
- *
- */
-static GList *
-msim_msg_get_node(MsimMessage *msg, const gchar *name)
-{
-	GList *node;
-
-	if (!name || !msg) {
-		return NULL;
-	}
-
-	/* Linear search for the given name. O(n) but n is small. */
-	for (node = msg; node != NULL; node = g_list_next(node)) {
-		MsimMessageElement *elem;
-
-		elem = (MsimMessageElement *)node->data;
-
-		g_return_val_if_fail(elem != NULL, NULL);
-		g_return_val_if_fail(elem->name != NULL, NULL);
-
-		if (strcmp(elem->name, name) == 0) {
-			return node;
-		}
-	}
-	return NULL;
-}
-
-/** Return the first MsimMessageElement * with given name in the MsimMessage *. 
+/**
+ * Return the first MsimMessageElement * with given name in the MsimMessage *.
  *
  * @param name Name to search for.
  *
@@ -1092,30 +1078,6 @@
 	}
 }
 
-/** Return the data of an element of a given name, as a string.
- *
- * @param name Name of element.
- *
- * @return gchar * The data as a string, or NULL if not found. 
- *     Caller must g_free().
- *
- * Note that msim_msg_pack_element_data() is similar, but returns a string
- * for inclusion into a raw protocol string (escaped and everything).
- * This function unescapes the string for you, if needed.
- */
-gchar *
-msim_msg_get_string(MsimMessage *msg, const gchar *name)
-{
-	MsimMessageElement *elem;
-
-	elem = msim_msg_get(msg, name);
-	if (!elem) {
-		return NULL;
-	}
-
-	return msim_msg_get_string_from_element(elem);
-}
-
 gchar *
 msim_msg_get_string_from_element(MsimMessageElement *elem)
 {
@@ -1140,9 +1102,20 @@
 	}
 }
 
-/** Return an element as a new list. Caller frees with msim_msg_list_free(). */
-GList *
-msim_msg_get_list(MsimMessage *msg, const gchar *name)
+/**
+ * Return the data of an element of a given name, as a string.
+ *
+ * @param name Name of element.
+ *
+ * @return gchar * The data as a string, or NULL if not found.
+ *     Caller must g_free().
+ *
+ * Note that msim_msg_pack_element_data() is similar, but returns a string
+ * for inclusion into a raw protocol string (escaped and everything).
+ * This function unescapes the string for you, if needed.
+ */
+gchar *
+msim_msg_get_string(MsimMessage *msg, const gchar *name)
 {
 	MsimMessageElement *elem;
 
@@ -1151,10 +1124,46 @@
 		return NULL;
 	}
 
-	return msim_msg_get_list_from_element(elem);
+	return msim_msg_get_string_from_element(elem);
 }
 
-GList *
+/**
+ * Parse a |-separated string into a new GList. Free with msim_msg_list_free().
+ */
+static GList *
+msim_msg_list_parse(const gchar *raw)
+{
+	gchar **array;
+	GList *list;
+	guint i;
+
+	array = g_strsplit(raw, "|", 0);
+	list = NULL;
+
+	/* TODO: escape/unescape /3 <-> | within list elements */
+
+	for (i = 0; array[i] != NULL; ++i) {
+		MsimMessageElement *elem;
+
+		/* Freed in msim_msg_list_free() */
+		elem = g_new0(MsimMessageElement, 1);
+
+		/* Give the element a name for debugging purposes.
+		 * Not supposed to be looked up by this name; instead,
+		 * lookup the elements by indexing the array. */
+		elem->name = g_strdup_printf("(list item #%d)", i);
+		elem->type = MSIM_TYPE_RAW;
+		elem->data = g_strdup(array[i]);
+
+		list = g_list_append(list, elem);
+	}
+
+	g_strfreev(array);
+
+	return list;
+}
+
+static GList *
 msim_msg_get_list_from_element(MsimMessageElement *elem)
 {
 	g_return_val_if_fail(elem != NULL, NULL);
@@ -1173,6 +1182,22 @@
 }
 
 /**
+ * Return an element as a new list. Caller frees with msim_msg_list_free().
+ */
+GList *
+msim_msg_get_list(MsimMessage *msg, const gchar *name)
+{
+	MsimMessageElement *elem;
+
+	elem = msim_msg_get(msg, name);
+	if (!elem) {
+		return NULL;
+	}
+
+	return msim_msg_get_list_from_element(elem);
+}
+
+/**
  * Parse a \x1c-separated "dictionary" of key=value pairs into a hash table.
  *
  * @param raw The text of the dictionary to parse. Often the
@@ -1180,8 +1205,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;
@@ -1192,8 +1217,8 @@
 	g_return_val_if_fail(raw != NULL, NULL);
 
 	dict = msim_msg_new(NULL);
- 
-	for (items = g_strsplit(raw, "\x1c", 0), i = 0; 
+
+	for (items = g_strsplit(raw, "\x1c", 0), i = 0;
 		(item = items[i]);
 		i++) {
 		gchar *key, *value;
@@ -1202,7 +1227,7 @@
 
 		key = elements[0];
 		if (!key) {
-			purple_debug_info("msim", "msim_msg_parse_dictionary(%s): null key\n", 
+			purple_debug_info("msim", "msim_msg_dictionary_parse(%s): null key\n",
 					raw);
 			g_strfreev(elements);
 			break;
@@ -1210,14 +1235,14 @@
 
 		value = elements[1];
 		if (!value) {
-			purple_debug_info("msim", "msim_msg_parse_dictionary(%s): null value\n", 
+			purple_debug_info("msim", "msim_msg_dictionary_prase(%s): null value\n",
 					raw);
 			g_strfreev(elements);
 			break;
 		}
 
 #ifdef MSIM_DEBUG_PARSE
-		purple_debug_info("msim_msg_parse_dictionary","-- %s: %s\n", key ? key : "(NULL)", 
+		purple_debug_info("msim_msg_dictionary_parse","-- %s: %s\n", key ? key : "(NULL)",
 				value ? value : "(NULL)");
 #endif
 		/* Append with _dynamic_name since g_strdup(key) is dynamic, and
@@ -1232,7 +1257,27 @@
 	return dict;
 }
 
-/** Return an element as a new dictionary. Caller frees with msim_msg_free(). */
+static MsimMessage *
+msim_msg_get_dictionary_from_element(MsimMessageElement *elem)
+{
+	g_return_val_if_fail(elem != NULL, NULL);
+	switch (elem->type) {
+		case MSIM_TYPE_DICTIONARY:
+			return msim_msg_clone((MsimMessage *)elem->data);
+
+		case MSIM_TYPE_RAW:
+			return msim_msg_dictionary_parse(elem->data);
+
+		default:
+			purple_debug_info("msim_msg_get_dictionary", "type %d unknown, name %s\n",
+					elem->type, elem->name ? elem->name : "(NULL)");
+			return NULL;
+	}
+}
+
+/**
+ * Return an element as a new dictionary. Caller frees with msim_msg_free().
+ */
 MsimMessage *
 msim_msg_get_dictionary(MsimMessage *msg, const gchar *name)
 {
@@ -1246,49 +1291,6 @@
 	return msim_msg_get_dictionary_from_element(elem);
 }
 
-MsimMessage *
-msim_msg_get_dictionary_from_element(MsimMessageElement *elem)
-{
-	g_return_val_if_fail(elem != NULL, NULL);
-	switch (elem->type) {
-		case MSIM_TYPE_DICTIONARY:
-			return msim_msg_clone((MsimMessage *)elem->data);
-		
-		case MSIM_TYPE_RAW:
-			return msim_msg_dictionary_parse((gchar *)elem->data);
-
-		default:
-			purple_debug_info("msim_msg_get_dictionary", "type %d unknown, name %s\n",
-					elem->type, elem->name ? elem->name : "(NULL)");
-			return NULL;
-	}
-}
-
-/** Return the data of an element of a given name, as an unsigned integer.
- *
- * @param name Name of element.
- *
- * @return guint Numeric representation of data, or 0 if could not be converted / not found.
- *
- * Useful to obtain an element's data if you know it should be an integer,
- * even if it is not stored as an MSIM_TYPE_INTEGER. MSIM_TYPE_STRING will
- * be converted handled correctly, for example.
- */
-guint 
-msim_msg_get_integer(MsimMessage *msg, const gchar *name)
-{
-	MsimMessageElement *elem;
-
-	elem = msim_msg_get(msg, name);
-
-	if (!elem) {
-		return 0;
-	}
-
-	return msim_msg_get_integer_from_element(elem);
-}
-
-
 guint
 msim_msg_get_integer_from_element(MsimMessageElement *elem)
 {
@@ -1307,29 +1309,32 @@
 	}
 }
 
-/** Return the data of an element of a given name, as a binary GString.
+/**
+ * Return the data of an element of a given name, as an unsigned integer.
  *
- * @param binary_data A pointer to a new pointer, which will be filled in with the binary data. CALLER MUST g_free().
+ * @param name Name of element.
  *
- * @param binary_length A pointer to an integer, which will be set to the binary data length.
+ * @return guint Numeric representation of data, or 0 if could not be converted / not found.
  *
- * @return TRUE if successful, FALSE if not.
+ * Useful to obtain an element's data if you know it should be an integer,
+ * even if it is not stored as an MSIM_TYPE_INTEGER. MSIM_TYPE_STRING will
+ * be converted handled correctly, for example.
  */
-gboolean 
-msim_msg_get_binary(MsimMessage *msg, const gchar *name, 
-		gchar **binary_data, gsize *binary_length)
+guint
+msim_msg_get_integer(MsimMessage *msg, const gchar *name)
 {
 	MsimMessageElement *elem;
-				
+
 	elem = msim_msg_get(msg, name);
+
 	if (!elem) {
-		return FALSE;
+		return 0;
 	}
 
-	return msim_msg_get_binary_from_element(elem, binary_data, binary_length);
+	return msim_msg_get_integer_from_element(elem);
 }
 
-gboolean
+static gboolean
 msim_msg_get_binary_from_element(MsimMessageElement *elem, gchar **binary_data, gsize *binary_length)
 {
 	GString *gs;
@@ -1344,7 +1349,7 @@
 			 * by msimprpl code for things like instant messages - stuff that should be
 			 * escaped if needed). DWIM.
 			 */
-	
+
 			/* Previously, incoming messages were stored as MSIM_TYPE_STRING.
 			 * This was fine for integers and strings, since they can easily be
 			 * converted in msim_get_*, as desirable. However, it does not work
@@ -1372,7 +1377,7 @@
 
 
 			/* Rejected because if it isn't already a GString, have to g_new0 it and
-			 * then caller has to ALSO free the GString! 
+			 * then caller has to ALSO free the GString!
 			 *
 			 * return (GString *)elem->data; */
 
@@ -1382,3 +1387,26 @@
 			return FALSE;
 	}
 }
+
+/**
+ * Return the data of an element of a given name, as a binary GString.
+ *
+ * @param binary_data A pointer to a new pointer, which will be filled in with the binary data. CALLER MUST g_free().
+ *
+ * @param binary_length A pointer to an integer, which will be set to the binary data length.
+ *
+ * @return TRUE if successful, FALSE if not.
+ */
+gboolean
+msim_msg_get_binary(MsimMessage *msg, const gchar *name,
+		gchar **binary_data, gsize *binary_length)
+{
+	MsimMessageElement *elem;
+
+	elem = msim_msg_get(msg, name);
+	if (!elem) {
+		return FALSE;
+	}
+
+	return msim_msg_get_binary_from_element(elem, binary_data, binary_length);
+}
--- a/libpurple/protocols/myspace/message.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/myspace/message.h	Wed Dec 17 18:01:08 2008 +0000
@@ -24,17 +24,20 @@
 
 #include <glib.h>
 
+#define MsimMessage GList               /* #define instead of typedef to avoid casting */
+typedef gchar MsimMessageType;
+typedef struct _MsimMessageElement MsimMessageElement;
+
+#include "session.h"
+
 /* Types */
-#define MsimMessage GList               /* #define instead of typedef to avoid casting */
-typedef struct _MsimMessageElement
+struct _MsimMessageElement
 {
 	const gchar *name;              /**< Textual name of element. */
 	gboolean dynamic_name;          /**< TRUE if 'name' is a dynamic string to be freed, not static. */
 	guint type;                     /**< MSIM_TYPE_* code. */
 	gpointer data;                  /**< Pointer to data, or GUINT_TO_POINTER for int/bool. */
-} MsimMessageElement;
-
-typedef gchar MsimMessageType;
+};
 
 #define msim_msg_get_next_element_node(msg)    ((MsimMessage *)(msg->next))
 
@@ -58,20 +61,13 @@
 void msim_msg_free(MsimMessage *msg);
 MsimMessage *msim_msg_append(MsimMessage *msg, const gchar *name, MsimMessageType type, gpointer data);
 MsimMessage *msim_msg_insert_before(MsimMessage *msg, const gchar *name_before, const gchar *name, MsimMessageType type, gpointer data);
-gchar *msim_msg_dump_to_str(MsimMessage *msg);
 gchar *msim_msg_pack_element_data(MsimMessageElement *elem);
 void msim_msg_dump(const char *fmt_string, MsimMessage *msg);
 gchar *msim_msg_pack(MsimMessage *msg);
-gchar *msim_msg_pack_dict(MsimMessage *msg);
 
-GList *msim_msg_list_copy(GList *old);
 void msim_msg_list_free(GList *l);
-GList *msim_msg_list_parse(const gchar *raw);
 
-/* Defined in myspace.h */
-struct _MsimSession;
-
-/* Based on http://permalink.gmane.org/gmane.comp.parsers.sparse/695 
+/* Based on http://permalink.gmane.org/gmane.comp.parsers.sparse/695
  * Define macros for useful gcc attributes. */
 #ifdef __GNUC__
 #define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
@@ -87,7 +83,7 @@
 	#define FORMAT_ATTR(pos)
 	#define NORETURN_ATTR
 	#define SENTINEL_ATTR
-#endif 
+#endif
 
 /* Cause gcc to emit "a missing sentinel in function call" if forgot
  * to write NULL as last, terminating parameter. */
@@ -95,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);
 
@@ -109,10 +104,6 @@
 
 /* Retrieve data by element (MsimMessageElement *), returned from msim_msg_get() */
 gchar *msim_msg_get_string_from_element(MsimMessageElement *elem);
-GList *msim_msg_get_list_from_element(MsimMessageElement *elem);
-MsimMessage *msim_msg_get_dictionary_from_element(MsimMessageElement *elem);
 guint msim_msg_get_integer_from_element(MsimMessageElement *elem);
-gboolean msim_msg_get_binary_from_element(MsimMessageElement *elem, 
-		gchar **binary_data, gsize *binary_length);
 
 #endif /* _MYSPACE_MESSAGE_H */
--- a/libpurple/protocols/myspace/myspace.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Wed Dec 17 18:01:08 2008 +0000
@@ -1,4 +1,5 @@
-/* MySpaceIM Protocol Plugin
+/**
+ * MySpaceIM Protocol Plugin
  *
  * \author Jeff Connelly
  *
@@ -35,87 +36,423 @@
 
 #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.
+#include "privacy.h"
+
+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;
+
+	/* 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));
+	}
+
+	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;
+
+	/* 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.
+ */
+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(). */
+	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)");
+			/* 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);
+
+	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_load(PurplePlugin *plugin)
+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)
+{
+	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;
+}
+
+/**
+ * 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)
 {
-	/* 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;
+	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;
 	}
-	return TRUE;
+
+	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 +460,7 @@
  *
  * @return GList of status types.
  */
-GList *
+static GList *
 msim_status_types(PurpleAccount *acct)
 {
 	GList *types;
@@ -177,154 +514,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,230 +707,552 @@
 }
 
 /**
- * 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.
+ * Process unrecognized information.
  *
- * @return Binary login challenge response, ready to send to the server. 
- * Must be g_free()'d when finished. NULL if error.
+ * @param session
+ * @param msg An MsimMessage that was unrecognized, or NULL.
+ * @param note Information on what was unrecognized, or NULL.
  */
-static gchar *
-msim_compute_login_response(const gchar nonce[2 * NONCE_SIZE], 
-		const gchar *email, const gchar *password, guint *response_len)
+void
+msim_unrecognized(MsimSession *session, MsimMessage *msg, gchar *note)
+{
+	/* 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.
+	 */
+
+	/* 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).
+	 *
+	 * Filed enhancement ticket for libpurple as #4688.
+	 */
+
+	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);
+	}
+
+	if (msg) {
+		msim_msg_dump("Unrecognized message dump: %s\n", msg);
+	}
+}
+
+/** 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)
 {
-	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;
+	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;
+}
+
+#ifdef MSIM_USE_KEEPALIVE
+/**
+ * Check if the connection is still alive, based on last communication.
+ */
+static gboolean
+msim_check_alive(gpointer data)
+{
+	MsimSession *session;
+	time_t delta;
+
+	session = (MsimSession *)data;
+
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+
+	delta = time(NULL) - session->last_comm;
+
+	/* purple_debug_info("msim", "msim_check_alive: delta=%d\n", delta); */
+	if (delta >= MSIM_KEEPALIVE_INTERVAL) {
+		purple_debug_info("msim",
+				"msim_check_alive: %zu > interval of %d, presumed dead\n",
+				delta, MSIM_KEEPALIVE_INTERVAL);
+		purple_connection_error_reason(session->gc,
+				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+				_("Lost connection with server"));
+
+		return FALSE;
 	}
 
-	/* 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");
+	return TRUE;
+}
 #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);
+/**
+ * Handle mail reply checks.
+ */
+static void
+msim_check_inbox_cb(MsimSession *session, MsimMessage *reply, gpointer data)
+{
+	MsimMessage *body;
+	guint old_inbox_status;
+	guint i, n;
+	const gchar *froms[5], *tos[5], *urls[5], *subjects[5];
+
+	/* Information for each new inbox message type. */
+	static struct
+	{
+		const gchar *key;
+		guint bit;
+		const gchar *url;
+		const gchar *text;
+	} message_types[] = {
+		{ "Mail", MSIM_INBOX_MAIL, "http://messaging.myspace.com/index.cfm?fuseaction=mail.inbox", NULL },
+		{ "BlogComment", MSIM_INBOX_BLOG_COMMENT, "http://blog.myspace.com/index.cfm?fuseaction=blog", NULL },
+		{ "ProfileComment", MSIM_INBOX_PROFILE_COMMENT, "http://home.myspace.com/index.cfm?fuseaction=user", NULL },
+		{ "FriendRequest", MSIM_INBOX_FRIEND_REQUEST, "http://messaging.myspace.com/index.cfm?fuseaction=mail.friendRequests", NULL },
+		{ "PictureComment", MSIM_INBOX_PICTURE_COMMENT, "http://home.myspace.com/index.cfm?fuseaction=user", NULL }
+	};
+
+	/* Can't write _()'d strings in array initializers. Workaround. */
+	message_types[0].text = _("New mail messages");
+	message_types[1].text = _("New blog comments");
+	message_types[2].text = _("New profile comments");
+	message_types[3].text = _("New friend requests!");
+	message_types[4].text = _("New picture comments");
+
+	g_return_if_fail(reply != NULL);
+
+	body = msim_msg_get_dictionary(reply, "body");
+
+	if (body == NULL)
+		return;
+
+	old_inbox_status = session->inbox_status;
+
+	n = 0;
+
+	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;
+
+		if (msim_msg_get(body, key)) {
+			/* Notify only on when _changes_ from no mail -> has mail
+			 * (edge triggered) */
+			if (!(session->inbox_status & bit)) {
+				purple_debug_info("msim", "msim_check_inbox_cb: got %s, at %d\n",
+						key ? key : "(NULL)", n);
+
+				subjects[n] = message_types[i].text;
+				froms[n] = _("MySpace");
+				tos[n] = session->username;
+				/* TODO: append token, web challenge, so automatically logs in.
+				 * Would also need to free strings because they won't be static
+				 */
+				urls[n] = message_types[i].url;
+
+				++n;
+			} else {
+				purple_debug_info("msim",
+						"msim_check_inbox_cb: already notified of %s\n",
+						key ? key : "(NULL)");
+			}
+
+			session->inbox_status |= bit;
+		}
 	}
 
-#ifdef MSIM_DEBUG_LOGIN_CHALLENGE
-	purple_debug_info("msim", "response=<%s>\n", data_out);
-#endif
-
-	*response_len = data_out_len;
-
-	return (gchar *)data_out;
+	if (n) {
+		purple_debug_info("msim",
+				"msim_check_inbox_cb: notifying of %d\n", n);
+
+		/* TODO: free strings with callback _if_ change to dynamic (w/ token) */
+		purple_notify_emails(session->gc,         /* handle */
+				n,                        /* count */
+				TRUE,                     /* detailed */
+				subjects, froms, tos, urls,
+				NULL,                     /* PurpleNotifyCloseCallback cb */
+				NULL);                    /* gpointer user_data */
+
+	}
+
+	msim_msg_free(body);
+}
+
+/**
+ * Send request to check if there is new mail.
+ */
+static gboolean
+msim_check_inbox(gpointer data)
+{
+	MsimSession *session;
+
+	session = (MsimSession *)data;
+
+	if (!MSIM_SESSION_VALID(session)) {
+		purple_debug_info("msim", "msim_check_inbox: session invalid, stopping the mail check.\n");
+		return FALSE;
+	}
+
+	purple_debug_info("msim", "msim_check_inbox: checking mail\n");
+	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,
+				msim_new_reply_callback(session, msim_check_inbox_cb, NULL),
+			"body", MSIM_TYPE_STRING, g_strdup(""),
+			NULL), TRUE);
+
+	/* Always return true, so that we keep checking for mail. */
+	return TRUE;
 }
 
 /**
- * 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.
+ * Add contact from server to buddy list, after looking up username.
+ * Callback from msim_add_contact_from_server().
  *
- * @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().
+ * @param data An MsimMessage * of the contact information. Will be freed.
  */
-int 
-msim_send_im(PurpleConnection *gc, const gchar *who, const gchar *message, 
-		PurpleMessageFlags flags)
+static void
+msim_add_contact_from_server_cb(MsimSession *session, MsimMessage *user_lookup_info, gpointer data)
 {
-	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;
+	MsimMessage *contact_info, *user_lookup_info_body;
+	PurpleGroup *group;
+	PurpleBuddy *buddy;
+	MsimUser *user;
+	gchar *username, *group_name, *display_name;
+	guint uid, visibility;
+
+	contact_info = (MsimMessage *)data;
+	purple_debug_info("msim_add_contact_from_server_cb", "contact_info addr=%p\n", contact_info);
+	uid = msim_msg_get_integer(contact_info, "ContactID");
+
+	if (!user_lookup_info) {
+		username = g_strdup(msim_uid2username_from_blist(session->account, uid));
+		display_name = NULL;
+		g_return_if_fail(username != NULL);
 	} else {
-		rc = -1;
+		user_lookup_info_body = msim_msg_get_dictionary(user_lookup_info, "body");
+		username = msim_msg_get_string(user_lookup_info_body, "UserName");
+		display_name = msim_msg_get_string(user_lookup_info_body, "DisplayName");
+		msim_msg_free(user_lookup_info_body);
+		g_return_if_fail(username != NULL);
+	}
+
+	purple_debug_info("msim_add_contact_from_server_cb",
+			"*** about to add/update username=%s\n", username);
+
+	/* 1. Creates a new group, or gets existing group if it exists (or so
+	 * the documentation claims). */
+	group_name = msim_msg_get_string(contact_info, "GroupName");
+	if (!group_name || (*group_name == '\0')) {
+		g_free(group_name);
+		group_name = g_strdup(_("IM Friends"));
+		purple_debug_info("myspace", "No GroupName specified, defaulting to '%s'.\n", group_name);
+	}
+	group = purple_find_group(group_name);
+	if (!group) {
+		group = purple_group_new(group_name);
+		/* Add group to beginning. See #2752. */
+		purple_blist_add_group(group, NULL);
+	}
+	g_free(group_name);
+
+	visibility = msim_msg_get_integer(contact_info, "Visibility");
+	if (visibility == 2) {
+		/* This buddy is blocked (and therefore not on our buddy list */
+		purple_privacy_deny_add(session->account, username, TRUE);
+		msim_msg_free(contact_info);
+		g_free(username);
+		g_free(display_name);
+		return;
 	}
 
-	g_free(message_msim);
-
-	return rc;
+	/* 2. Get or create buddy */
+	buddy = purple_find_buddy(session->account, username);
+	if (!buddy) {
+		purple_debug_info("msim_add_contact_from_server_cb",
+				"creating new buddy: %s\n", username);
+		buddy = purple_buddy_new(session->account, username, NULL);
+	}
+
+	/* TODO: use 'Position' in contact_info to take into account where buddy is */
+	purple_blist_add_buddy(buddy, NULL, group, NULL /* insertion point */);
+
+	if (strtol(username, NULL, 10) == uid) {
+		/*
+		 * This user has not set their username!  Set their server
+		 * alias to their display name so that we don't see a bunch
+		 * of numbers in the buddy list.
+		 */
+		if (display_name != NULL) {
+			purple_blist_node_set_string(&buddy->node, "DisplayName", display_name);
+			serv_got_alias(session->gc, username, display_name);
+		} else {
+			serv_got_alias(session->gc, username,
+					purple_blist_node_get_string(&buddy->node, "DisplayName"));
+		}
+	}
+	g_free(display_name);
+
+	/* 3. Update buddy information */
+	user = msim_get_user_from_buddy(buddy);
+
+	user->id = uid;
+	/* Keep track of the user ID across sessions */
+	purple_blist_node_set_int(&buddy->node, "UserID", uid);
+
+	/* Stores a few fields in the MsimUser, relevant to the buddy itself.
+	 * AvatarURL, Headline, ContactID. */
+	msim_store_user_info(session, contact_info, NULL);
+
+	/* TODO: other fields, store in 'user' */
+	msim_msg_free(contact_info);
+
+	g_free(username);
 }
 
-/** Send a buddy message of a given type.
+/**
+ * Add first ContactID in contact_info to buddy's list. Used to add
+ * server-side buddies to client-side list.
  *
- * @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.
+ * @return TRUE if added.
+ */
+static gboolean
+msim_add_contact_from_server(MsimSession *session, MsimMessage *contact_info)
+{
+	guint uid;
+	const gchar *username;
+
+	uid = msim_msg_get_integer(contact_info, "ContactID");
+	g_return_val_if_fail(uid != 0, FALSE);
+
+	/* Lookup the username, since NickName and IMName is unreliable */
+	username = msim_uid2username_from_blist(session->account, uid);
+	if (!username) {
+		gchar *uid_str;
+
+		uid_str = g_strdup_printf("%d", uid);
+		purple_debug_info("msim_add_contact_from_server",
+				"contact_info addr=%p\n", contact_info);
+		msim_lookup_user(session, uid_str, msim_add_contact_from_server_cb, (gpointer)msim_msg_clone(contact_info));
+		g_free(uid_str);
+	} else {
+		msim_add_contact_from_server_cb(session, NULL, (gpointer)msim_msg_clone(contact_info));
+	}
+
+	/* Say that the contact was added, even if we're still looking up
+	 * their username. */
+	return TRUE;
+}
+
+/**
+ * Called when contact list is received from server.
+ */
+static void
+msim_got_contact_list(MsimSession *session, MsimMessage *reply, gpointer user_data)
+{
+	MsimMessage *body, *body_node;
+	gchar *msg;
+	guint buddy_count;
+
+	body = msim_msg_get_dictionary(reply, "body");
+	if (!body) {
+		/* No friends. Not an error. */
+		return;
+	}
+
+	buddy_count = 0;
+
+	for (body_node = body;
+		body_node != NULL;
+		body_node = msim_msg_get_next_element_node(body_node))
+	{
+		MsimMessageElement *elem;
+
+		elem = (MsimMessageElement *)body_node->data;
+
+		if (g_str_equal(elem->name, "ContactID"))
+		{
+			/* Will look for first contact in body_node */
+			if (msim_add_contact_from_server(session, body_node)) {
+				++buddy_count;
+			}
+		}
+	}
+
+	switch (GPOINTER_TO_UINT(user_data)) {
+		case MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS:
+		        msg = g_strdup_printf(ngettext("%d buddy was added or updated from the server (including buddies already on the server-side list)",
+						       "%d buddies were added or updated from the server (including buddies already on the server-side list)",
+						       buddy_count),
+					      buddy_count);
+			purple_notify_info(session->account, _("Add contacts from server"), msg, NULL);
+			g_free(msg);
+			break;
+
+		case MSIM_CONTACT_LIST_IMPORT_TOP_FRIENDS:
+			/* TODO */
+			break;
+
+		case MSIM_CONTACT_LIST_INITIAL_FRIENDS:
+			/* Nothing */
+			break;
+	}
+
+	msim_msg_free(body);
+}
+
+/**
+ * Get contact list, calling msim_got_contact_list() with
+ * what_to_do_after as user_data gpointer.
  *
+ * @param what_to_do_after should be one of the MSIM_CONTACT_LIST_* #defines.
  */
-gboolean 
-msim_send_bm(MsimSession *session, const gchar *who, const gchar *text, 
-		int type)
+static gboolean
+msim_get_contact_list(MsimSession *session, int what_to_do_after)
 {
-	gboolean rc;
-	MsimMessage *msg;
-	const gchar *from_username;
+	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)),
+			"body", MSIM_TYPE_STRING, g_strdup(""),
+			NULL);
+}
+
+/** 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);
-	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),
+
+	/* 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_INTEGER, 1,
+			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+			"cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
+			"dsn", MSIM_TYPE_INTEGER, MG_OWN_MYSPACE_INFO_DSN,
+			"lid", MSIM_TYPE_INTEGER, MG_OWN_MYSPACE_INFO_LID,
+			"rid", MSIM_TYPE_INTEGER, session->next_rid++,
+			"UserID", MSIM_TYPE_INTEGER, session->userid,
+			"body", MSIM_TYPE_DICTIONARY, body,
+			NULL);
+
+	/* Request MySpace info about ourself. */
+	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_OWN_IM_INFO_DSN,
+			"lid", MSIM_TYPE_INTEGER, MG_OWN_IM_INFO_LID,
+			"rid", MSIM_TYPE_INTEGER, session->next_rid++,
+			"body", MSIM_TYPE_STRING, g_strdup(""),
 			NULL);
 
-	rc = msim_postprocess_outgoing(session, msg, who, "t", "cv");
-
-	msim_msg_free(msg);
-
-	return rc;
+	/* 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. */
+/**
+ * Record the client version in the buddy list, from an incoming message.
+ */
 static gboolean
 msim_incoming_bm_record_cv(MsimSession *session, MsimMessage *msg)
 {
@@ -639,44 +1285,186 @@
 	return ret;
 }
 
-/** Handle an incoming buddy message. */
+#ifdef MSIM_SEND_CLIENT_VERSION
+/**
+ * Send our client version to another unofficial client that understands it.
+ */
 static gboolean
-msim_incoming_bm(MsimSession *session, MsimMessage *msg)
+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)
 {
-	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);
+	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);
+
+	/* 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:
-			/* Not really an IM, but show it for informational 
-			 * purposes during development. */
-			return msim_incoming_im(session, msg);
+			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'. 
+ * @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 
+static gboolean
 msim_incoming_im(MsimSession *session, MsimMessage *msg)
 {
 	gchar *username, *msg_msim_markup, *msg_purple_markup;
@@ -701,7 +1489,7 @@
 		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) {
@@ -730,50 +1518,14 @@
 }
 
 /**
- * Process unrecognized information.
- *
- * @param session
- * @param msg An MsimMessage that was unrecognized, or NULL.
- * @param note Information on what was unrecognized, or NULL.
- */
-void 
-msim_unrecognized(MsimSession *session, MsimMessage *msg, gchar *note)
-{
-	/* 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.
-	 */
-
-	/* 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). 
-	 *
-	 * Filed enhancement ticket for libpurple as #4688.
-	 */
-
-	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);
-	}
-
-	if (msg) {
-		msim_msg_dump("Unrecognized message dump: %s\n", msg);
-	}
-}
-
-/**
  * Handle an incoming action message.
  *
  * @param session
  * @param msg
  *
  * @return TRUE if successful.
- *
  */
-static gboolean 
+static gboolean
 msim_incoming_action(MsimSession *session, MsimMessage *msg)
 {
 	gchar *msg_text, *username;
@@ -819,7 +1571,7 @@
 
 		rc = TRUE;
 	} else {
-		msim_unrecognized(session, msg, 
+		msim_unrecognized(session, msg,
 				"got to msim_incoming_action but unrecognized value for 'msg'");
 		rc = FALSE;
 	}
@@ -830,7 +1582,9 @@
 	return rc;
 }
 
-/* Process an incoming media (message background?) message. */
+/**
+ * Process an incoming media (message background?) message.
+ */
 static gboolean
 msim_incoming_media(MsimSession *session, MsimMessage *msg)
 {
@@ -855,8 +1609,10 @@
 	return TRUE;
 }
 
-/* Process an incoming "unofficial client" message. The plugin for
- * Miranda IM sends this message with the plugin information. */
+/**
+ * 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)
 {
@@ -873,7 +1629,7 @@
 		username, client_info);
 
 	user = msim_find_user(session, username);
-	
+
 	g_return_val_if_fail(user != NULL, FALSE);
 
 	if (user->client_info) {
@@ -887,28 +1643,660 @@
 	return TRUE;
 }
 
-
-#ifdef MSIM_SEND_CLIENT_VERSION
-/** Send our client version to another unofficial client that understands it. */
+/**
+ * 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");
+		/* 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_send_unofficial_client(MsimSession *session, gchar *username)
+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);
+
+	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);
+}
+
+/**
+ * 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)
 {
-	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;
+	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_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));
+		 */
+	}
+}
+
+/**
+ * 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);
+}
+
+/**
+ * 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;
+
+	/*
+	 * Lets wipe out our local list of blocked buddies.  We'll get a
+	 * list of all blocked buddies from the server, and we shouldn't
+	 * have stuff in the local list that isn't on the server list.
+	 */
+	while (acct->deny != NULL)
+		purple_privacy_deny_remove(acct, acct->deny->data, TRUE);
+
+	/* 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
@@ -917,8 +2305,8 @@
  *
  * @return 0
  */
-unsigned int 
-msim_send_typing(PurpleConnection *gc, const gchar *name, 
+static unsigned int
+msim_send_typing(PurpleConnection *gc, const gchar *name,
 		PurpleTypingState state)
 {
 	const gchar *typing_str;
@@ -932,8 +2320,8 @@
 	g_return_val_if_fail(MSIM_SESSION_VALID(session), 0);
 
 	switch (state) {
-		case PURPLE_TYPING: 
-			typing_str = "%typing%"; 
+		case PURPLE_TYPING:
+			typing_str = "%typing%";
 			break;
 
 		case PURPLE_TYPED:
@@ -948,11 +2336,11 @@
 	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, 
+/**
+ * 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;
@@ -962,7 +2350,7 @@
 
 	g_return_if_fail(MSIM_SESSION_VALID(session));
 
-	/* Get user{name,id} from msim_get_info, passed as an MsimMessage for 
+	/* Get user{name,id} from msim_get_info, passed as an MsimMessage for
 	   orthogonality. */
 	msg = (MsimMessage *)data;
 	g_return_if_fail(msg != NULL);
@@ -980,15 +2368,8 @@
 
 	if (!user) {
 		/* User isn't on blist, create a temporary user to store info. */
-		/* TODO: is this legit, or is it somehow responsible for #3444? */
-		PurpleBuddy *buddy;
-
 		user = g_new0(MsimUser, 1);
 		user->temporary_user = TRUE;
-
-		buddy = purple_buddy_new(session->account, username, NULL);
-		user->buddy = buddy;
-		buddy->proto_data = (gpointer)user;
 	}
 
 	/* Update user structure with new information */
@@ -1005,7 +2386,6 @@
 	purple_notify_user_info_destroy(user_info);
 
 	if (user->temporary_user) {
-		purple_blist_remove_buddy(user->buddy);
 		g_free(user->client_info);
 		g_free(user->gender);
 		g_free(user->location);
@@ -1018,15 +2398,15 @@
 	g_free(username);
 }
 
-/** Retrieve a user's profile. 
+/**
+ * Retrieve a user's profile.
  * @param username Username, user ID, or email address to lookup.
  */
-void 
+static void
 msim_get_info(PurpleConnection *gc, const gchar *username)
 {
 	MsimSession *session;
 	MsimUser *user;
-	guint uid;
 	gchar *user_to_lookup;
 	MsimMessage *user_msg;
 
@@ -1041,15 +2421,15 @@
 	user = msim_find_user(session, username);
 
 	/* If is on buddy list, lookup by uid since it is faster. */
-	if (user && (uid = purple_blist_node_get_int(&user->buddy->node, "UserID"))) {
-		user_to_lookup = g_strdup_printf("%d", uid);
+	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 
+	 * 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(
@@ -1059,11 +2439,38 @@
 
 	msim_lookup_user(session, user_to_lookup, msim_get_info_cb, user_msg);
 
-	g_free(user_to_lookup); 
+	g_free(user_to_lookup);
 }
 
-/** Set your status - callback for when user manually sets it.  */
-void
+/**
+ * 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;
@@ -1105,7 +2512,7 @@
 					"status interpreting as online");
 			status_code = MSIM_STATUS_CODE_ONLINE;
 
-			unrecognized_msg = g_strdup_printf("msim_set_status, unrecognized status type: %d\n", 
+			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);
@@ -1126,11 +2533,12 @@
 	/* 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
+/**
+ * Go idle.
+ */
+static void
 msim_set_idle(PurpleConnection *gc, int time)
 {
 	MsimSession *session;
@@ -1145,7 +2553,7 @@
 	status = purple_account_get_active_status(session->account);
 
 	if (time == 0) {
-		/* Going back from idle. In msim, idle is mutually exclusive 
+		/* 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.
@@ -1169,911 +2577,47 @@
 	}
 }
 
-/** 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. 
+/**
+ * @return TRUE if everything was ok, FALSE if something went awry.
  */
-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)
+static gboolean
+msim_update_blocklist_for_buddy(MsimSession *session, const char *name, gboolean allow, gboolean block)
 {
-	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)
-{
-	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);
-	}
-}
-
-#ifdef MSIM_USE_KEEPALIVE
-/** Check if the connection is still alive, based on last communication. */
-static gboolean
-msim_check_alive(gpointer data)
-{
-	MsimSession *session;
-	time_t delta;
-	gchar *errmsg;
-
-	session = (MsimSession *)data;
-
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
-
-	delta = time(NULL) - session->last_comm;
-	/* purple_debug_info("msim", "msim_check_alive: delta=%d\n", delta); */
-	if (delta >= MSIM_KEEPALIVE_INTERVAL) {
-	        errmsg = g_strdup_printf(ngettext("Connection to server lost (no data received within %d second)",
-						  "Connection to server lost (no data received within %d seconds)",
-						  (int)delta),
-					 (int)delta);
-
-		purple_debug_info("msim", "msim_check_alive: %s > interval of %d, presumed dead\n",
-				errmsg, MSIM_KEEPALIVE_INTERVAL);
-		purple_connection_error_reason(session->gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, errmsg);
-
-		purple_notify_error(session->gc, NULL, errmsg, NULL);
-
-		g_free(errmsg);
-
+	MsimMessage *msg;
+	GList *list;
+
+	list = NULL;
+	list = g_list_prepend(list, allow ? "a+" : "a-");
+	list = g_list_prepend(list, "<uid>");
+	list = g_list_prepend(list, block ? "b+" : "b-");
+	list = g_list_prepend(list, "<uid>");
+	list = g_list_reverse(list);
+
+	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, list,
+			NULL);
+
+	if (!msim_postprocess_outgoing(session, msg, name, "idlist", NULL)) {
+		purple_debug_error("myspace",
+				"blocklist command failed for %s, allow=%d, block=%d\n",
+				name, allow, block);
+		msim_msg_free(msg);
 		return FALSE;
 	}
 
-	return TRUE;
-}
-#endif
-
-/** Handle mail reply checks. */
-static void
-msim_check_inbox_cb(MsimSession *session, MsimMessage *reply, gpointer data)
-{
-	MsimMessage *body;
-	guint old_inbox_status;
-	guint i, n;
-	const gchar *froms[5], *tos[5], *urls[5], *subjects[5];
-
-	/* Information for each new inbox message type. */
-	static struct 
-	{
-		const gchar *key;
-		guint bit;
-		const gchar *url;
-		const gchar *text;
-	} message_types[] = {
-		{ "Mail", MSIM_INBOX_MAIL, "http://messaging.myspace.com/index.cfm?fuseaction=mail.inbox", NULL },
-		{ "BlogComment", MSIM_INBOX_BLOG_COMMENT, "http://blog.myspace.com/index.cfm?fuseaction=blog", NULL },
-		{ "ProfileComment", MSIM_INBOX_PROFILE_COMMENT, "http://home.myspace.com/index.cfm?fuseaction=user", NULL },
-		{ "FriendRequest", MSIM_INBOX_FRIEND_REQUEST, "http://messaging.myspace.com/index.cfm?fuseaction=mail.friendRequests", NULL },
-		{ "PictureComment", MSIM_INBOX_PICTURE_COMMENT, "http://home.myspace.com/index.cfm?fuseaction=user", NULL }
-	};
-
-	/* Can't write _()'d strings in array initializers. Workaround. */
-	message_types[0].text = _("New mail messages");
-	message_types[1].text = _("New blog comments");
-	message_types[2].text = _("New profile comments");
-	message_types[3].text = _("New friend requests!");
-	message_types[4].text = _("New picture comments");
-
-	g_return_if_fail(reply != NULL);
-
-	msim_msg_dump("msim_check_inbox_cb: reply=%s\n", reply);
-
-	body = msim_msg_get_dictionary(reply, "body");
-
-	if (body == NULL)
-		return;
-
-	old_inbox_status = session->inbox_status;
-
-	n = 0;
-
-	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;
-
-		if (msim_msg_get(body, key)) {
-			/* Notify only on when _changes_ from no mail -> has mail
-			 * (edge triggered) */
-			if (!(session->inbox_status & bit)) {
-				purple_debug_info("msim", "msim_check_inbox_cb: got %s, at %d\n",
-						key ? key : "(NULL)", n);
-
-				subjects[n] = message_types[i].text;
-				froms[n] = _("MySpace");
-				tos[n] = session->username;
-				/* TODO: append token, web challenge, so automatically logs in.
-				 * Would also need to free strings because they won't be static
-				 */
-				urls[n] = message_types[i].url;
-
-				++n;
-			} else {
-				purple_debug_info("msim",
-						"msim_check_inbox_cb: already notified of %s\n",
-						key ? key : "(NULL)");
-			}
-
-			session->inbox_status |= bit;
-		}
-	}
-
-	if (n) {
-		purple_debug_info("msim",
-				"msim_check_inbox_cb: notifying of %d\n", n);
-
-		/* TODO: free strings with callback _if_ change to dynamic (w/ token) */
-		purple_notify_emails(session->gc,         /* handle */
-				n,                        /* count */
-				TRUE,                     /* detailed */
-				subjects, froms, tos, urls, 
-				NULL,                     /* PurpleNotifyCloseCallback cb */
-				NULL);                    /* gpointer user_data */
-
-	}
-
-	msim_msg_free(body);
-}
-
-/* Send request to check if there is new mail. */
-static gboolean
-msim_check_inbox(gpointer data)
-{
-	MsimSession *session;
-
-	session = (MsimSession *)data;
-
-	if (!MSIM_SESSION_VALID(session)) {
-		purple_debug_info("msim", "msim_check_inbox: session invalid, stopping the mail check.\n");
-		return FALSE;
-	}
-
-	purple_debug_info("msim", "msim_check_inbox: checking mail\n");
-	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, 
-				msim_new_reply_callback(session, msim_check_inbox_cb, NULL),
-			"body", MSIM_TYPE_STRING, g_strdup(""),
-			NULL), TRUE);
-
-	/* Always return true, so that we keep checking for mail. */
-	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);
+	msim_msg_free(msg);
 
 	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.
+ * Add a buddy to user's buddy list.
  */
-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);
-
-		/* All buddies on list should have a UserID integer associated with them. */
-		purple_blist_node_set_int(&buddy->node, "UserID", msim_msg_get_integer(msg, "f"));
-		
-		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 
+static void
 msim_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
 {
 	MsimSession *session;
@@ -2082,7 +2626,7 @@
 	MsimMessage *body;
 
 	session = (MsimSession *)gc->proto_data;
-	purple_debug_info("msim", "msim_add_buddy: want to add %s to %s\n", 
+	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(
@@ -2098,7 +2642,7 @@
 		return;
 	}
 	msim_msg_free(msg);
-	
+
 	/* TODO: if addbuddy fails ('error' message is returned), delete added buddy from
 	 * buddy list since Purple adds it locally. */
 
@@ -2133,216 +2677,19 @@
 	}
 	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;
+	/* Add to allow list, remove from block list */
+	msim_update_blocklist_for_buddy(session, buddy->name, TRUE, FALSE);
 }
 
-/** 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.
+/**
+ * Remove a buddy from the user's buddy list.
  */
-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 
+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;
 
@@ -2378,27 +2725,101 @@
 	}
 	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,
+	/*
+	 * Remove from our approve list and from our block list (this
+	 * doesn't seem like it would be necessary, but the official client
+	 * does it)
+	 */
+	if (!msim_update_blocklist_for_buddy(session, buddy->name, FALSE, FALSE))
+		purple_notify_error(NULL, NULL,
+				_("Failed to remove buddy"), _("blocklist command failed"));
+}
+
+/**
+ * Remove a buddy from the user's buddy list and add them to the block list.
+ */
+static void
+msim_add_deny(PurpleConnection *gc, const char *name)
+{
+	MsimSession *session;
+	MsimMessage *msg, *body;
+
+	session = (MsimSession *)gc->proto_data;
+
+	/* Remove from buddy list */
+	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, msg, name, "delprofileid", NULL))
+		purple_debug_error("myspace", "delbuddy command failed\n");
+	msim_msg_free(msg);
+
+	/* Remove from our approve list and add to our block list */
+	msim_update_blocklist_for_buddy(session, name, FALSE, TRUE);
+
+	/*
+	 * Add the buddy to our list of blocked contacts, so we know they
+	 * are blocked if we log in with another client
+	 */
+	body = msim_msg_new(
+			"ContactID", MSIM_TYPE_STRING, g_strdup("<uid>"),
+			"Visibility", MSIM_TYPE_INTEGER, 2,
+			NULL);
+	msg = msim_msg_new(
+			"persist", MSIM_TYPE_INTEGER, 1,
 			"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,
+			"cmd", MSIM_TYPE_INTEGER, MSIM_CMD_BIT_ACTION | MSIM_CMD_PUT,
+			"dsn", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_DSN,
+			"lid", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_LID,
+			"rid", MSIM_TYPE_INTEGER, session->next_rid++,
+			"body", MSIM_TYPE_DICTIONARY, body,
 			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);
+	if (!msim_postprocess_outgoing(session, msg, name, "body", NULL))
+		purple_debug_error("myspace", "add to block list command failed\n");
+	msim_msg_free(msg);
+
+	/*
+	 * TODO: MySpace doesn't allow blocked buddies on our buddy list,
+	 *       do they?  If not then we need to remove the buddy from
+	 *       libpurple's buddy list.
+	 */
+}
+
+/**
+ * Remove a buddy from the user's block list.
+ */
+static void
+msim_rem_deny(PurpleConnection *gc, const char *name)
+{
+	MsimSession *session;
+	MsimMessage *msg, *body;
+
+	session = (MsimSession *)gc->proto_data;
+
+	/*
+	 * Remove from our list of blocked contacts, so we know they
+	 * are no longer blocked if we log in with another client
+	 */
+	body = msim_msg_new(
+			"ContactID", MSIM_TYPE_STRING, g_strdup("<uid>"),
+			NULL);
+	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, MC_DELETE_CONTACT_INFO_DSN,
+			"lid", MSIM_TYPE_INTEGER, MC_DELETE_CONTACT_INFO_LID,
+			"rid", MSIM_TYPE_INTEGER, session->next_rid++,
+			"body", MSIM_TYPE_DICTIONARY, body,
+			NULL);
+	if (!msim_postprocess_outgoing(session, msg, name, "body", NULL))
+		purple_debug_error("myspace", "remove from block list command failed\n");
+	msim_msg_free(msg);
+
+	/* Remove from our approve list and our block list */
+	msim_update_blocklist_for_buddy(session, name, FALSE, FALSE);
 }
 
 /**
@@ -2406,10 +2827,10 @@
  * 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 
+ * 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 const char *msim_normalize(const PurpleAccount *account, const char *str) {
 	static char normalized[BUF_LEN];
 	char *tmp1, *tmp2;
 	int i, j;
@@ -2429,7 +2850,7 @@
 		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 
+			/* 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. */
@@ -2467,6 +2888,92 @@
 	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)
+{
+	return TRUE;
+}
+
+/**
+ * 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.
+ */
+/*
+ * TODO: This needs to do non-blocking writes and use a watcher to check
+  *      when the fd is available to be written to.
+ */
+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)
 {
@@ -2479,624 +2986,15 @@
 	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.
- *
+ * Callbacks called by Purple, to access this plugin.
  */
-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(). 
- *
- * @param data An MsimMessage * of the contact information. Will be freed.
- */
-static void
-msim_add_contact_from_server_cb(MsimSession *session, MsimMessage *user_lookup_info, gpointer data)
-{
-	MsimMessage *contact_info, *user_lookup_info_body;
-	PurpleGroup *group;
-	PurpleBuddy *buddy;
-	MsimUser *user;
-	gchar *username, *group_name;
-	guint uid;
-
-	contact_info = (MsimMessage *)data;
-	purple_debug_info("msim_add_contact_from_server_cb", "contact_info addr=%p\n", contact_info);
-	uid = msim_msg_get_integer(contact_info, "ContactID");
-
-	if (!user_lookup_info) {
-		username = g_strdup(msim_uid2username_from_blist(session->account, uid));
-		g_return_if_fail(username != NULL);
-	} else {
-		user_lookup_info_body = msim_msg_get_dictionary(user_lookup_info, "body");
-		username = msim_msg_get_string(user_lookup_info_body, "UserName");
-		msim_msg_free(user_lookup_info_body);
-		g_return_if_fail(username != NULL);
-	}
-
-	purple_debug_info("msim_add_contact_from_server_cb",
-			"*** about to add/update username=%s\n", username);
-
-	/* 1. Creates a new group, or gets existing group if it exists (or so
-	 * the documentation claims). */
-	group_name = msim_msg_get_string(contact_info, "GroupName");
-	if (!group_name || (*group_name == '\0')) {
-		g_free(group_name);
-		group_name = g_strdup(_("IM Friends"));
-		purple_debug_info("myspace", "No GroupName specified, defaulting to '%s'.\n", group_name);
-	}
-	group = purple_find_group(group_name);
-	if (!group) {
-		group = purple_group_new(group_name);
-		/* Add group to beginning. See #2752. */
-		purple_blist_add_group(group, NULL);
-	}
-	g_free(group_name);
-
-	/* 2. Get or create buddy */
-	buddy = purple_find_buddy(session->account, username);
-	if (!buddy) {
-		purple_debug_info("msim_add_contact_from_server_cb",
-				"creating new buddy: %s\n", username);
-		buddy = purple_buddy_new(session->account, username, NULL);
-	}
-
-	/* TODO: use 'Position' in contact_info to take into account where buddy is */
-	purple_blist_add_buddy(buddy, NULL, group, NULL /* insertion point */);
-
-	/* 3. Update buddy information */
-	user = msim_get_user_from_buddy(buddy);
-
-	/* All buddies on list should have 'uid' integer associated with them. */
-	purple_blist_node_set_int(&buddy->node, "UserID", uid);
-
-	/* Stores a few fields in the MsimUser, relevant to the buddy itself.
-	 * AvatarURL, Headline, ContactID. */
-	msim_store_user_info(session, contact_info, NULL);
-
-	/* TODO: other fields, store in 'user' */
-	msim_msg_free(contact_info);
-
-	g_free(username);
-}
-
-/** 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)
-{
-	guint uid;
-	const gchar *username;
-
-	uid = msim_msg_get_integer(contact_info, "ContactID");
-	g_return_val_if_fail(uid != 0, FALSE);
-
-	/* Lookup the username, since NickName and IMName is unreliable */
-	username = msim_uid2username_from_blist(session->account, uid);
-	if (!username) {
-		gchar *uid_str;
-
-		uid_str = g_strdup_printf("%d", uid);
-		purple_debug_info("msim_add_contact_from_server",
-				"contact_info addr=%p\n", contact_info);
-		msim_lookup_user(session, uid_str, msim_add_contact_from_server_cb, (gpointer)msim_msg_clone(contact_info));
-		g_free(uid_str);
-	} else {
-		msim_add_contact_from_server_cb(session, NULL, (gpointer)msim_msg_clone(contact_info));
-	}
-
-	/* Say that the contact was added, even if we're still looking up
-	 * their username. */
-	return TRUE;
-}
-
-/** Called when contact list is received from server. */
-static void
-msim_got_contact_list(MsimSession *session, MsimMessage *reply, gpointer user_data)
-{
-	MsimMessage *body, *body_node;
-	gchar *msg;
-	guint buddy_count;
-
-	msim_msg_dump("msim_got_contact_list: reply=%s", reply);
-
-	body = msim_msg_get_dictionary(reply, "body");
-	if (!body) {
-		/* No friends. Not an error. */
-		return;
-	}
-
-	buddy_count = 0;
-
-	for (body_node = body;
-		body_node != NULL;
-		body_node = msim_msg_get_next_element_node(body_node))
-	{
-		MsimMessageElement *elem;
-
-		elem = (MsimMessageElement *)body_node->data;
-
-		if (g_str_equal(elem->name, "ContactID"))
-		{
-			/* Will look for first contact in body_node */
-			if (msim_add_contact_from_server(session, body_node)) {
-				++buddy_count;
-			}
-		}
-	}
-
-	switch (GPOINTER_TO_UINT(user_data)) {
-		case MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS:
-		        msg = g_strdup_printf(ngettext("%d buddy was added or updated from the server (including buddies already on the server-side list)",
-						       "%d buddies were added or updated from the server (including buddies already on the server-side list)",
-						       buddy_count),
-					      buddy_count);
-			purple_notify_info(session->account, _("Add contacts from server"), msg, NULL);
-			g_free(msg);
-			break;
-
-		case MSIM_CONTACT_LIST_IMPORT_TOP_FRIENDS:
-			/* TODO */
-			break;
-		
-		case MSIM_CONTACT_LIST_INITIAL_FRIENDS:
-			/* Nothing */
-			break;
-	}
-
-	msim_msg_free(body);
-}
-
-/* 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, 
-			"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)), 
-			"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)
-{
-	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. */
-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;
-}
-
-/** 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 */
@@ -3122,9 +3020,9 @@
 	msim_remove_buddy, /* remove_buddy */
 	NULL,              /* remove_buddies */
 	NULL,              /* add_permit */
-	NULL,              /* add_deny */
+	msim_add_deny,     /* add_deny */
 	NULL,              /* rem_permit */
-	NULL,              /* rem_deny */
+	msim_rem_deny,     /* rem_deny */
 	NULL,              /* set_permit_deny */
 	NULL,              /* join_chat */
 	NULL,              /* reject chat invite */
@@ -3166,9 +3064,119 @@
 	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;
+
+	/* 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,
@@ -3202,32 +3210,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;
@@ -3304,8 +3298,10 @@
 	return failures;
 }
 
-/** Test protocol-level escaping/unescaping. */
-int 
+/**
+ * Test protocol-level escaping/unescaping.
+ */
+static int
 msim_test_escaping(void)
 {
 	guint failures;
@@ -3336,87 +3332,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)
 {
@@ -3450,35 +3505,85 @@
 	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) 
+/**
+ * Initialize plugin.
+ */
+static void
+init_plugin(PurplePlugin *plugin)
 {
 #ifdef MSIM_SELF_TEST
 	msim_test_all();
@@ -3529,7 +3634,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	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/myspace/myspace.h	Wed Dec 17 18:01:08 2008 +0000
@@ -63,18 +63,17 @@
 /*#define MSIM_SEND_CLIENT_VERSION              */
 
 /* Debugging options */
-/*#define MSIM_DEBUG_MSG                */
 /* Low-level and rarely needed */
 /*#define MSIM_DEBUG_PARSE             */
 /*#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 +118,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 +141,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 +171,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 +188,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	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/myspace/persist.h	Wed Dec 17 18:01:08 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
@@ -72,6 +72,7 @@
 
 /** Messages to Change/send information */
 MSIM_PERSIST_DSN_LID(MC_USER_PREFERENCES,          1, 10)
+MSIM_PERSIST_DSN_LID(MC_DELETE_CONTACT_INFO,       0, 8)
 MSIM_PERSIST_DSN_LID(MC_CONTACT_INFO,              0, 9)
 MSIM_PERSIST_DSN_LID(MC_SET_USERNAME,              9, 14)
 MSIM_PERSIST_DSN_LID(MC_IMPORT_ALL_FRIENDS,       14, 21)
--- a/libpurple/protocols/myspace/release.sh	Sun Dec 07 01:42:47 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-#!/bin/bash
-# Created:20070618
-# By Jeff Connelly
-
-# Package a new msimprpl for release. Must be run with bash.
-
-VERSION=0.18
-make
-# Include 'myspace' directory in archive, so it can easily be unextracted
-# into ~/pidgin/libpurple/protocols at the correct location.
-# (if this command fails, run it manually).
-# This convenient command requires bash.
-cd ../../..
-tar -cf libpurple/protocols/msimprpl-$VERSION.tar libpurple/protocols/myspace/{CHANGES,ChangeLog,LICENSE,Makefile.*,*.c,*.h,README,release.sh,.deps/*} autogen.sh configure.ac
-cd libpurple/protocols/myspace
-gzip ../msimprpl-$VERSION.tar
-
-mv ~/pidgin/config.h ~/pidgin/config.h-
-make -f Makefile.mingw
-mv ~/pidgin/config.h- ~/pidgin/config.h
-cp ~/pidgin/win32-install-dir/plugins/libmyspace.dll .
-# Zip is more common with Win32 users. Just include a few files in this archive,
-# but (importantly) preserve the install directory structure!
-mkdir -p win32-archive/plugins
-cp libmyspace.dll win32-archive/plugins
-mkdir -p win32-archive/pixmaps/pidgin/protocols/{48,22,16}
-cp ~/pidgin/win32-install-dir/pixmaps/pidgin/protocols/48/myspace.png \
-                win32-archive/pixmaps/pidgin/protocols/48/
-cp ~/pidgin/win32-install-dir/pixmaps/pidgin/protocols/22/myspace.png \
-                win32-archive/pixmaps/pidgin/protocols/22/
-cp ~/pidgin/win32-install-dir/pixmaps/pidgin/protocols/16/myspace.png \
-                win32-archive/pixmaps/pidgin/protocols/16/
-mkdir -p win32-archive/pixmaps/pidgin/emotes/default
-cp ~/pidgin/win32-install-dir/pixmaps/pidgin/emotes/default/theme \
-        win32-archive/pixmaps/pidgin/emotes/default/theme
-# Emoticons in MySpaceIM but not Pidgin 2.1.0
-cp ~/pidgin/win32-install-dir/pixmaps/pidgin/emotes/default/{sinister,sidefrown,pirate,mohawk,messed,bulgy-eyes}.png \
-	win32-archive/pixmaps/pidgin/emotes/default/
-
-# Use DOS line endings and .txt file extension for convenience
-u2d < README > win32-archive/msimprpl-README.txt
-u2d < LICENSE > win32-archive/msimprpl-LICENSE.txt
-u2d < CHANGES > win32-archive/msimprpl-CHANGES.txt
-cd win32-archive
-zip -r ../../msimprpl-$VERSION-win32.zip *
-cd ..
-rm -rf win32-archive
-ls -l ../msimprpl-$VERSION*
--- a/libpurple/protocols/myspace/session.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/myspace/session.c	Wed Dec 17 18:01:08 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	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/myspace/session.h	Wed Dec 17 18:01:08 2008 +0000
@@ -20,6 +20,8 @@
 #ifndef _MYSPACE_SESSION_H
 #define _MYSPACE_SESSION_H
 
+#include "account.h"
+
 /* Random number in every MsimSession, to ensure it is valid. */
 #define MSIM_SESSION_STRUCT_MAGIC       0xe4a6752b
 
@@ -32,6 +34,9 @@
 	guint sesskey;                      /**< Session key from server */
 	guint userid;                       /**< This user's numeric user ID */
 	gchar *username;                    /**< This user's unique username */
+	gboolean show_only_to_list;
+	int privacy_mode;
+	int offline_message_mode;
 	gint fd;                            /**< File descriptor to/from server */
 
 	/* TODO: Remove. */
@@ -52,7 +57,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	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/myspace/user.c	Wed Dec 17 18:01:08 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)
 {
@@ -63,15 +58,18 @@
 		/* TODO: where is this freed? */
 		user = g_new0(MsimUser, 1);
 		user->buddy = buddy;
+		user->id = purple_blist_node_get_int(&buddy->node, "UserID");
 		buddy->proto_data = (gpointer)user;
-	} 
+	}
 
 	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)
 {
@@ -88,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
@@ -96,28 +95,14 @@
 {
 	PurplePresence *presence;
 	gchar *str;
-	guint uid;
 	guint cv;
 
-	/* Useful to identify the account the tooltip refers to. 
+	/* Useful to identify the account the tooltip refers to.
 	 *  Other prpls show this. */
 	if (user->username) {
 		purple_notify_user_info_add_pair(user_info, _("User"), user->username);
 	}
 
-	uid = purple_blist_node_get_int(&user->buddy->node, "UserID");
-
-	if (full) {
-		/* TODO: link to username, if available */
-		if (uid) {
-			char *profile = g_strdup_printf("<a href=\"http://myspace.com/%d\">http://myspace.com/%d</a>",
-											uid, uid);
-			purple_notify_user_info_add_pair(user_info, _("Profile"), profile);
-			g_free(profile);
-		}
-	}
-
-
 	/* a/s/l...the vitals */
 	if (user->age) {
 		char age[16];
@@ -138,21 +123,23 @@
 		purple_notify_user_info_add_pair(user_info, _("Headline"), user->headline);
 	}
 
-	presence = purple_buddy_get_presence(user->buddy);
+	if (user->buddy != NULL) {
+		presence = purple_buddy_get_presence(user->buddy);
+
+		if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
+			PurpleStatus *status;
+			const char *artist, *title;
 
-	if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
-		PurpleStatus *status;
-		const char *artist, *title;
-		
-		status = purple_presence_get_status(presence, "tune");
-		title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
-		artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
+			status = purple_presence_get_status(presence, "tune");
+			title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
+			artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
 
-		str = msim_format_now_playing(artist, title);
-		if (str && *str) {
-			purple_notify_user_info_add_pair(user_info, _("Song"), str);
+			str = msim_format_now_playing(artist, title);
+			if (str && *str) {
+				purple_notify_user_info_add_pair(user_info, _("Song"), str);
+			}
+			g_free(str);
 		}
-		g_free(str);
 	}
 
 	/* Note: total friends only available if looked up by uid, not username. */
@@ -180,9 +167,55 @@
 			purple_notify_user_info_add_pair(user_info, _("Client Version"), client);
 		g_free(client);
 	}
+
+	if (full && user->id) {
+		/* TODO: link to username, if available */
+		char *profile;
+		purple_notify_user_info_add_section_break(user_info);
+		if (user->buddy != NULL)
+			profile = g_strdup_printf("<a href=\"http://myspace.com/%s\">%s</a>",
+					purple_buddy_get_name(user->buddy), _("View web profile"));
+		else
+			profile = g_strdup_printf("<a href=\"http://myspace.com/%d\">%s</a>",
+					user->id, _("View web profile"));
+		purple_notify_user_info_add_pair(user_info, NULL, profile);
+		g_free(profile);
+	}
 }
 
-/** Set the currently playing song artist and or title.
+/**
+ * Callback for when a buddy icon finished being downloaded.
+ */
+static void
+msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data,
+		gpointer user_data,
+		const gchar *url_text,
+		gsize len,
+		const gchar *error_message)
+{
+	MsimUser *user;
+
+	user = (MsimUser *)user_data;
+
+	purple_debug_info("msim_downloaded_buddy_icon",
+			"Downloaded %" G_GSIZE_FORMAT " bytes\n", len);
+
+	if (!url_text) {
+		purple_debug_info("msim_downloaded_buddy_icon",
+				"failed to download icon for %s",
+				user->buddy->name);
+		return;
+	}
+
+	purple_buddy_icons_set_for_user(user->buddy->account,
+			user->buddy->name,
+			g_memdup((gchar *)url_text, len), len,
+			/* Use URL itself as buddy icon "checksum" (TODO: ETag) */
+			user->image_url);		/* checksum */
+}
+
+/**
+ * Set the currently playing song artist and or title.
  *
  * @param user User associated with the now playing information.
  *
@@ -200,12 +233,16 @@
 	PurplePresence *presence;
 	const char *prev_artist, *prev_title;
 
+	if (user->buddy == NULL)
+		/* User not on buddy list so nothing to do */
+		return;
+
 	prev_artist = NULL;
 	prev_title = NULL;
 
-	if (new_artist && !strlen(new_artist))
+	if (new_artist && !*new_artist)
 		new_artist = NULL;
-	if (new_title && !strlen(new_title))
+	if (new_title && !*new_title)
 		new_title = NULL;
 
 	if (!new_artist && !new_title) {
@@ -217,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;
 
@@ -235,22 +272,24 @@
 			NULL);
 }
 
-/** Store a field of information about a buddy. 
+/**
+ * Store a field of information about a buddy.
  *
  * @param key_str Key to store.
  * @param value_str Value string, either user takes ownership of this string
  *                  or it is freed if MsimUser doesn't store the string.
  * @param user User to store data in. Existing data will be replaced.
- * */
-void 
+ */
+static void
 msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user)
 {
 	if (g_str_equal(key_str, "UserID") || g_str_equal(key_str, "ContactID")) {
 		/* Save to buddy list, if it exists, for quick cached uid lookup with msim_uid2username_from_blist(). */
+		user->id = atol(value_str);
 		if (user->buddy)
 		{
 			purple_debug_info("msim", "associating uid %s with username %s\n", key_str, user->buddy->name);
-			purple_blist_node_set_int(&user->buddy->node, "UserID", atol(value_str));
+			purple_blist_node_set_int(&user->buddy->node, "UserID", user->id);
 		}
 		/* Need to store in MsimUser, too? What if not on blist? */
 	} else if (g_str_equal(key_str, "Age")) {
@@ -278,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);
@@ -286,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);
@@ -334,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.
@@ -346,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;
@@ -362,16 +401,49 @@
 		return FALSE;
 	}
 
+	if (msim_msg_get_integer(msg, "dsn") == MG_OWN_IM_INFO_DSN &&
+		msim_msg_get_integer(msg, "lid") == MG_OWN_IM_INFO_LID) {
+		/*
+		 * Some of this info will be available on the buddy list if the
+		 * has themselves as their own buddy.
+		 *
+		 * Much of the info is already available in MsimSession,
+		 * stored in msim_we_are_logged_on().
+		 */
+		gchar *tmpstr;
+
+		tmpstr = msim_msg_get_string(body, "ShowOnlyToList");
+		if (tmpstr != NULL) {
+			session->show_only_to_list = g_str_equal(tmpstr, "True");
+			g_free(tmpstr);
+		}
+
+		session->privacy_mode = msim_msg_get_integer(body, "PrivacyMode");
+		session->offline_message_mode = msim_msg_get_integer(body, "OfflineMessageMode");
+
+		msim_send(session,
+				"blocklist", MSIM_TYPE_BOOLEAN, TRUE,
+				"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+				"idlist", MSIM_TYPE_STRING,
+						g_strdup_printf("w%d|c%d",
+								session->show_only_to_list ? 1 : 0,
+								session->privacy_mode),
+				NULL);
+	} else if (msim_msg_get_integer(msg, "dsn") == MG_OWN_MYSPACE_INFO_DSN &&
+			msim_msg_get_integer(msg, "lid") == MG_OWN_MYSPACE_INFO_LID) {
+		/* TODO: same as above, but for MySpace info. */
+	}
+
 	username = msim_msg_get_string(body, "UserName");
 
 	if (!username) {
-		purple_debug_info("msim", 
+		purple_debug_info("msim",
 			"msim_process_reply: not caching body, no UserName\n");
 		msim_msg_free(body);
 		g_free(username);
 		return FALSE;
 	}
-	
+
 	/* Null user = find and store in PurpleBuddy's proto_data */
 	if (!user) {
 		user = msim_find_user(session, username);
@@ -383,8 +455,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;
@@ -398,25 +470,64 @@
 		msim_store_user_info_each(key_str, value_str, user);
 	}
 
-	if (msim_msg_get_integer(msg, "dsn") == MG_OWN_IM_INFO_DSN &&
-		msim_msg_get_integer(msg, "lid") == MG_OWN_IM_INFO_LID) {
-		/* TODO: do something with our own IM info, if we need it for some
-		 * specific purpose. Otherwise it is available on the buddy list,
-		 * if the user has themselves as their own buddy. 
-		 *
-		 * However, much of the info is already available in MsimSession,
-		 * stored in msim_we_are_logged_on(). */
-	} else if (msim_msg_get_integer(msg, "dsn") == MG_OWN_MYSPACE_INFO_DSN &&
-			msim_msg_get_integer(msg, "lid") == MG_OWN_MYSPACE_INFO_LID) {
-		/* TODO: same as above, but for MySpace info. */
-	}
-
 	msim_msg_free(body);
 	g_free(username);
 
 	return TRUE;
 }
 
+#if 0
+/**
+ * Return whether a given username is syntactically valid.
+ * Note: does not actually check that the user exists.
+ */
+static gboolean
+msim_is_valid_username(const gchar *user)
+{
+	return !msim_is_userid(user) &&  /* Not all numeric */
+		strlen(user) <= MSIM_MAX_USERNAME_LENGTH
+		&& strspn(user, "0123456789"
+			"abcdefghijklmnopqrstuvwxyz"
+			"_"
+			"ABCDEFGHIJKLMNOPQRSTUVWXYZ") == strlen(user);
+}
+#endif
+
+/**
+ * Check if a string is a userid (all numeric).
+ *
+ * @param user The user id, email, or name.
+ *
+ * @return TRUE if is userid, FALSE if not.
+ */
+gboolean
+msim_is_userid(const gchar *user)
+{
+	g_return_val_if_fail(user != NULL, FALSE);
+
+	return strspn(user, "0123456789") == strlen(user);
+}
+
+/**
+ * Check if a string is an email address (contains an @).
+ *
+ * @param user The user id, email, or name.
+ *
+ * @return TRUE if is an email, FALSE if not.
+ *
+ * This function is not intended to be used as a generic
+ * means of validating email addresses, but to distinguish
+ * between a user represented by an email address from
+ * other forms of identification.
+ */
+static gboolean
+msim_is_email(const gchar *user)
+{
+	g_return_val_if_fail(user != NULL, FALSE);
+
+	return strchr(user, '@') != NULL;
+}
+
 /**
  * Asynchronously lookup user information, calling callback when receive result.
  *
@@ -426,7 +537,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;
@@ -441,8 +552,6 @@
 	purple_debug_info("msim", "msim_lookup_userid: "
 			"asynchronously looking up <%s>\n", user);
 
-	msim_msg_dump("msim_lookup_user: data=%s\n", (MsimMessage *)data);
-
 	/* Setup callback. Response will be associated with request using 'rid'. */
 	rid = msim_new_reply_callback(session, cb, data);
 
@@ -452,8 +561,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;
@@ -478,231 +587,87 @@
 			"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");
+	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);
 }
 
 /**
@@ -713,7 +678,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)
 {
@@ -727,8 +692,6 @@
 	purple_debug_info("msim", "msim_set_username: "
 			"Setting username %s\n", username);
 
-	msim_msg_dump("msim_set_username: data=%s\n", (MsimMessage *)data);
-
 	/* Setup callback. Response will be associated with request using 'rid'. */
 	rid = msim_new_reply_callback(session, cb, data);
 
@@ -757,82 +720,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	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/myspace/user.h	Wed Dec 17 18:01:08 2008 +0000
@@ -25,6 +25,8 @@
 typedef struct _MsimUser
 {
 	PurpleBuddy *buddy;
+	/* Note: id is also &buddy->node (set_blist_node_int), when buddy is non-NULL */
+	int id;
 	guint client_cv;
 	gchar *client_info;
 	guint age;
@@ -33,7 +35,6 @@
 	guint total_friends;
 	gchar *headline;
 	gchar *display_name;
-	/* Note: uid is in &buddy->node (set_blist_node_int), since it never changes */
 	gchar *username;
 	gchar *band_name, *song_name;
 	gchar *image_url;
@@ -41,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);
 
@@ -50,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	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/myspace/zap.c	Wed Dec 17 18:01:08 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/oscar/bstream.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/oscar/bstream.c	Wed Dec 17 18:01:08 2008 +0000
@@ -302,3 +302,12 @@
 
 	return len;
 }
+
+int byte_stream_putuid(ByteStream *bs, OscarData *od)
+{
+	PurpleAccount *account;
+
+	account = purple_connection_get_account(od->gc);
+
+	return byte_stream_putle32(bs, atoi(purple_account_get_username(account)));
+}
--- a/libpurple/protocols/oscar/family_auth.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/oscar/family_auth.c	Wed Dec 17 18:01:08 2008 +0000
@@ -295,10 +295,9 @@
 	/*
 	 * No matter what, we should have a screen name.
 	 */
-	memset(od->sn, 0, sizeof(od->sn));
 	if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) {
 		info->sn = aim_tlv_getstr(tlvlist, 0x0001, 1);
-		strncpy(od->sn, info->sn, sizeof(od->sn));
+		purple_connection_set_display_name(od->gc, info->sn);
 	}
 
 	/*
@@ -598,18 +597,18 @@
 {
 	if (od->authinfo != NULL)
 	{
-		free(od->authinfo->sn);
-		free(od->authinfo->bosip);
-		free(od->authinfo->errorurl);
-		free(od->authinfo->email);
-		free(od->authinfo->chpassurl);
-		free(od->authinfo->latestrelease.name);
-		free(od->authinfo->latestrelease.url);
-		free(od->authinfo->latestrelease.info);
-		free(od->authinfo->latestbeta.name);
-		free(od->authinfo->latestbeta.url);
-		free(od->authinfo->latestbeta.info);
-		free(od->authinfo);
+		g_free(od->authinfo->sn);
+		g_free(od->authinfo->bosip);
+		g_free(od->authinfo->errorurl);
+		g_free(od->authinfo->email);
+		g_free(od->authinfo->chpassurl);
+		g_free(od->authinfo->latestrelease.name);
+		g_free(od->authinfo->latestrelease.url);
+		g_free(od->authinfo->latestrelease.info);
+		g_free(od->authinfo->latestbeta.name);
+		g_free(od->authinfo->latestbeta.url);
+		g_free(od->authinfo->latestbeta.info);
+		g_free(od->authinfo);
 	}
 }
 
--- a/libpurple/protocols/oscar/family_icbm.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/oscar/family_icbm.c	Wed Dec 17 18:01:08 2008 +0000
@@ -1214,7 +1214,7 @@
 	/*
 	 * Your UIN
 	 */
-	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putuid(&bs, od);
 
 	/*
 	 * TLV t(type) l(strlen(message)+1) v(message+NULL)
--- a/libpurple/protocols/oscar/family_icq.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/oscar/family_icq.c	Wed Dec 17 18:01:08 2008 +0000
@@ -36,7 +36,7 @@
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
 		return -EINVAL;
 
-	purple_debug_info("oscar", "Requesting offline messages from %s", od->sn);
+	purple_debug_info("oscar", "Requesting offline messages\n");
 
 	bslen = 2 + 4 + 2 + 2;
 
@@ -49,7 +49,7 @@
 	byte_stream_put16(&bs, bslen);
 
 	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x003c); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
 
@@ -70,7 +70,7 @@
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
 		return -EINVAL;
 
-	purple_debug_info("oscar", "Acknowledged receipt of offline messages from %s", od->sn);
+	purple_debug_info("oscar", "Acknowledged receipt of offline messages\n");
 
 	bslen = 2 + 4 + 2 + 2;
 
@@ -83,7 +83,7 @@
 	byte_stream_put16(&bs, bslen);
 
 	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x003e); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
 
@@ -117,7 +117,7 @@
 	byte_stream_put16(&bs, bslen);
 
 	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
 	byte_stream_putle16(&bs, 0x0c3a); /* shrug. */
@@ -172,7 +172,7 @@
 	byte_stream_put16(&bs, bslen);
 
 	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
 	byte_stream_putle16(&bs, 0x042e); /* shrug. */
@@ -212,7 +212,7 @@
 	byte_stream_put16(&bs, bslen);
 
 	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
 	byte_stream_putle16(&bs, 0x04b2); /* shrug. */
@@ -259,7 +259,7 @@
 	byte_stream_put16(&bs, bslen);
 
 	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
 	byte_stream_putle16(&bs, 0x04ba); /* shrug. */
@@ -303,7 +303,7 @@
 	byte_stream_put16(&bs, bslen);
 
 	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
 	byte_stream_putle16(&bs, 0x051f); /* shrug. */
@@ -341,7 +341,7 @@
 	byte_stream_put16(&bs, bslen);
 
 	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
 	byte_stream_putle16(&bs, 0x0998); /* shrug. */
@@ -377,11 +377,12 @@
 int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char *alias)
 {
 	FlapConnection *conn;
+	PurpleAccount *account;
 	ByteStream bs;
 	aim_snacid_t snacid;
 	int bslen, xmllen;
 	char *xml;
-	const char *timestr;
+	const char *timestr, *username;
 	time_t t;
 	struct tm *tm;
 	gchar *stripped;
@@ -392,6 +393,9 @@
 	if (!name || !msg || !alias)
 		return -EINVAL;
 
+	account = purple_connection_get_account(od->gc);
+	username = purple_account_get_username(account);
+
 	time(&t);
 	tm = gmtime(&t);
 	timestr = purple_utf8_strftime("%a, %d %b %Y %T %Z", tm);
@@ -399,7 +403,7 @@
 	stripped = purple_markup_strip_html(msg);
 
 	/* The length of xml included the null terminating character */
-	xmllen = 209 + strlen(name) + strlen(stripped) + strlen(od->sn) + strlen(alias) + strlen(timestr) + 1;
+	xmllen = 209 + strlen(name) + strlen(stripped) + strlen(username) + strlen(alias) + strlen(timestr) + 1;
 
 	xml = g_new(char, xmllen);
 	snprintf(xml, xmllen, "<icq_sms_message>"
@@ -411,7 +415,7 @@
 		"<delivery_receipt>Yes</delivery_receipt>"
 		"<time>%s</time>"
 		"</icq_sms_message>",
-		name, stripped, od->sn, alias, timestr);
+		name, stripped, username, alias, timestr);
 
 	bslen = 36 + xmllen;
 
@@ -424,7 +428,7 @@
 	byte_stream_put16(&bs, bslen);
 
 	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
 
@@ -481,7 +485,7 @@
 	byte_stream_put16(&bs, bslen);
 
 	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
 	byte_stream_putle16(&bs, 0x0fa0); /* shrug. */
--- a/libpurple/protocols/oscar/family_locate.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/oscar/family_locate.c	Wed Dec 17 18:01:08 2008 +0000
@@ -203,11 +203,9 @@
 	 {0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8,
 	  0x88, 0x6f, 0xea, 0x35, 0x95, 0xfd, 0xb6, 0xdf}},
 
-	/*
-	{OSCAR_CAPABILITY_ICQ2GO,
+	{OSCAR_CAPABILITY_TYPING,
 	 {0x56, 0x3f, 0xc8, 0x09, 0x0b, 0x6f, 0x41, 0xbd,
 	  0x9f, 0x79, 0x42, 0x26, 0x09, 0xdf, 0xa2, 0xf3}},
-	*/
 
 	/*
 	 * Chat is oddball.
--- a/libpurple/protocols/oscar/oscar.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Wed Dec 17 18:01:08 2008 +0000
@@ -68,7 +68,7 @@
 
 static OscarCapability purple_caps = (OSCAR_CAPABILITY_CHAT | OSCAR_CAPABILITY_BUDDYICON | OSCAR_CAPABILITY_DIRECTIM |
 									  OSCAR_CAPABILITY_SENDFILE | OSCAR_CAPABILITY_UNICODE | OSCAR_CAPABILITY_INTEROPERATE |
-									  OSCAR_CAPABILITY_SHORTCAPS);
+									  OSCAR_CAPABILITY_SHORTCAPS | OSCAR_CAPABILITY_TYPING);
 
 static guint8 features_aim[] = {0x01, 0x01, 0x01, 0x02};
 static guint8 features_icq[] = {0x01, 0x06};
@@ -3187,6 +3187,12 @@
 		}
 	}
 
+	purple_notify_user_info_add_section_break(user_info);
+	tmp = g_strdup_printf("<a href=\"http://profiles.aim.com/%s\">%s</a>",
+			purple_normalize(account, userinfo->sn), _("View web profile"));
+	purple_notify_user_info_add_pair(user_info, NULL, tmp);
+	g_free(tmp);
+
 	purple_notify_userinfo(gc, userinfo->sn, user_info, NULL, NULL);
 	purple_notify_user_info_destroy(user_info);
 
--- a/libpurple/protocols/oscar/oscar.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.h	Wed Dec 17 18:01:08 2008 +0000
@@ -362,8 +362,9 @@
 	OSCAR_CAPABILITY_LIVEVIDEO            = 0x02000000,
 	OSCAR_CAPABILITY_CAMERA               = 0x04000000,
 	OSCAR_CAPABILITY_ICHAT_SCREENSHARE    = 0x08000000,
-	OSCAR_CAPABILITY_GENERICUNKNOWN       = 0x10000000,
-	OSCAR_CAPABILITY_LAST                 = 0x20000000
+	OSCAR_CAPABILITY_TYPING               = 0x10000000,
+	OSCAR_CAPABILITY_GENERICUNKNOWN       = 0x20000000,
+	OSCAR_CAPABILITY_LAST                 = 0x40000000
 } OscarCapability;
 
 /*
@@ -488,16 +489,8 @@
 		guint maxawaymsglen; /* max size (bytes) of posted away message */
 	} rights;
 
-	/* ---- Client Accessible ------------------------ */
-
-	/* Our screen name. */
-	/* TODO: Get rid of this and use purple_account_get_username() everywhere? */
-	char sn[MAXSNLEN+1];
-
 	PurpleConnection *gc;
 
-	/* ---- Internal Use Only ------------------------ */
-
 	void *modlistv;
 
 	/*
@@ -1587,6 +1580,7 @@
 int byte_stream_putraw(ByteStream *bs, const guint8 *v, int len);
 int byte_stream_putstr(ByteStream *bs, const char *str);
 int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, int len);
+int byte_stream_putuid(ByteStream *bs, OscarData *od);
 int byte_stream_putcaps(ByteStream *bs, guint32 caps);
 
 /*
--- a/libpurple/protocols/qq/buddy_info.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/buddy_info.c	Wed Dec 17 18:01:08 2008 +0000
@@ -58,7 +58,7 @@
 
 #define QQ_PUBLISH_SIZE 3
 static const gchar *publish_types[] = {
-	N_("Visible"), N_("Firend Only"), N_("Private")
+	N_("Visible"), N_("Friend Only"), N_("Private")
 };
 
 #define QQ_GENDER_SIZE 3
@@ -87,7 +87,7 @@
 	QQ_INFO_UNKNOW3, QQ_INFO_UNKNOW4, QQ_INFO_UNKNOW5,
 	QQ_INFO_IS_PUB_MOBILE, QQ_INFO_IS_PUB_CONTACT, QQ_INFO_COLLEGE, QQ_INFO_HOROSCOPE,
 	QQ_INFO_ZODIAC, QQ_INFO_BLOOD, QQ_INFO_SHOW, QQ_INFO_UNKNOW6,
-	QQ_INFO_LAST_2007, QQ_INFO_LAST,
+	QQ_INFO_LAST_2007, QQ_INFO_LAST
 };
 
 enum {
@@ -95,7 +95,7 @@
 };
 
 enum {
-	QQ_FIELD_LABEL = 0, QQ_FIELD_STRING, QQ_FIELD_MULTI, QQ_FIELD_BOOL, QQ_FIELD_CHOICE,
+	QQ_FIELD_LABEL = 0, QQ_FIELD_STRING, QQ_FIELD_MULTI, QQ_FIELD_BOOL, QQ_FIELD_CHOICE
 };
 
 typedef struct {
@@ -504,8 +504,6 @@
 {
 	PurpleAccount *account = purple_connection_get_account(gc);
 	const gchar *icon_path = purple_account_get_buddy_icon_path(account);
-	gchar **segments;
-	gint index;
 
 	g_return_if_fail(icon_path != NULL);
 
@@ -514,12 +512,6 @@
 	 *  purple_imgstore_get_filename is always new file
 	 *  QQ buddy may set custom icon if level is over 16 */
 	purple_debug_info("QQ", "Change my icon to %s\n", icon_path);
-	segments = g_strsplit_set(icon_path, G_DIR_SEPARATOR_S, 0);
-	for (index = 0; segments[index] != NULL; index++) {
-		purple_debug_info("QQ", "Split to %s\n", segments[index]);
-	}
-
-	g_strfreev(segments);
 }
 
 gchar *qq_get_icon_name(gint face)
--- a/libpurple/protocols/qq/buddy_info.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/buddy_info.h	Wed Dec 17 18:01:08 2008 +0000
@@ -71,7 +71,7 @@
 	QQ_BUDDY_INFO_MODIFY_BASE,
 	QQ_BUDDY_INFO_MODIFY_EXT,
 	QQ_BUDDY_INFO_MODIFY_ADDR,
-	QQ_BUDDY_INFO_MODIFY_CONTACT,
+	QQ_BUDDY_INFO_MODIFY_CONTACT
 };
 
 gchar *qq_get_icon_name(gint face);
--- a/libpurple/protocols/qq/buddy_opt.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/buddy_opt.c	Wed Dec 17 18:01:08 2008 +0000
@@ -46,7 +46,7 @@
 enum {
 	QQ_MY_AUTH_APPROVE = 0x30,	/* ASCII value of "0" */
 	QQ_MY_AUTH_REJECT = 0x31,	/* ASCII value of "1" */
-	QQ_MY_AUTH_REQUEST = 0x32,	/* ASCII value of "2" */
+	QQ_MY_AUTH_REQUEST = 0x32	/* ASCII value of "2" */
 };
 
 typedef struct _qq_buddy_req {
@@ -317,9 +317,9 @@
 	add_req->auth_len = 0;
 
 	who = uid_to_purple_name(uid);
-	msg = g_strdup_printf(_("%u needs Q&A"), uid);
-	purple_request_input(gc, _("Add buddy Q&A"), msg,
-			_("Input answer here"),
+	msg = g_strdup_printf(_("%u requires verification"), uid);
+	purple_request_input(gc, _("Add buddy question"), msg,
+			_("Enter answer here"),
 			NULL,
 			TRUE, FALSE, NULL,
 			_("Send"), G_CALLBACK(add_buddy_question_cb),
@@ -616,7 +616,7 @@
 	qq_buddy_req *add_req = (qq_buddy_req *)data;
 	gchar *who = uid_to_purple_name(add_req->uid);
 	purple_request_input(add_req->gc, NULL, _("Authorization denied message:"),
-			NULL, _("Sorry, You are not my style."), TRUE, FALSE, NULL,
+			NULL, _("Sorry, you're not my style."), TRUE, FALSE, NULL,
 			_("OK"), G_CALLBACK(buddy_add_deny_reason_cb),
 			_("Cancel"), G_CALLBACK(buddy_add_deny_noreason_cb),
 			purple_connection_get_account(add_req->gc), who, NULL,
@@ -661,9 +661,9 @@
 	}
 
 	who = uid_to_purple_name(uid);
-	msg = g_strdup_printf(_("%u needs authentication"), uid);
+	msg = g_strdup_printf(_("%u needs authorization"), uid);
 	purple_request_input(gc, _("Add buddy authorize"), msg,
-			_("Input request here"),
+			_("Enter request here"),
 			_("Would you be my friend?"),
 			TRUE, FALSE, NULL,
 			_("Send"), G_CALLBACK(add_buddy_auth_cb),
--- a/libpurple/protocols/qq/buddy_opt.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/buddy_opt.h	Wed Dec 17 18:01:08 2008 +0000
@@ -38,14 +38,14 @@
 	QQ_AUTH_INFO_TEMP_SESSION = 0x0003,
 	QQ_AUTH_INFO_CLUSTER = 0x0002,
 	QQ_AUTH_INFO_REMOVE_BUDDY = 0x0006,
-	QQ_AUTH_INFO_UPDATE_BUDDY_INFO = 0x0007,
+	QQ_AUTH_INFO_UPDATE_BUDDY_INFO = 0x0007
 };
 
 enum {
 	QQ_QUESTION_GET = 0x01,
 	QQ_QUESTION_SET = 0x02,
 	QQ_QUESTION_REQUEST = 0x03,		/* get question only*/
-	QQ_QUESTION_ANSWER = 0x04,
+	QQ_QUESTION_ANSWER = 0x04
 };
 
 void qq_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
--- a/libpurple/protocols/qq/group.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/group.c	Wed Dec 17 18:01:08 2008 +0000
@@ -116,7 +116,7 @@
 	return qd->roomlist;
 }
 
-/* free roomlist space, I have no idea when this one is called ... */
+/* free roomlist space, I have no idea when this one is called... */
 void qq_roomlist_cancel(PurpleRoomlist *list)
 {
 	qq_data *qd;
--- a/libpurple/protocols/qq/group.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/group.h	Wed Dec 17 18:01:08 2008 +0000
@@ -37,7 +37,7 @@
 	QQ_ROOM_ROLE_NO = 0x00,	/* default 0x00 means not member */
 	QQ_ROOM_ROLE_YES,
 	QQ_ROOM_ROLE_REQUESTING,
-	QQ_ROOM_ROLE_ADMIN,
+	QQ_ROOM_ROLE_ADMIN
 } qq_room_role;
 
 typedef struct _qq_room_data qq_room_data;
--- a/libpurple/protocols/qq/group_im.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/group_im.c	Wed Dec 17 18:01:08 2008 +0000
@@ -329,6 +329,7 @@
 	return;
 }
 
+#if 0
 static void request_room_send_im_ex(PurpleConnection *gc, guint32 room_id,
 	qq_im_format *fmt, gchar *msg, guint16 msg_id, guint8 frag_count, guint8 frag_index)
 {
@@ -358,6 +359,7 @@
 	/*qq_show_packet("QQ_ROOM_CMD_SEND_IM_EX", raw_data, bytes); */
 	qq_send_room_cmd(gc, QQ_ROOM_CMD_SEND_IM_EX, room_id, raw_data, bytes);
 }
+#endif
 
 /* send a chat msg to a QQ Qun
  * called by purple */
@@ -376,7 +378,7 @@
 	g_return_val_if_fail(id != 0 && what != NULL, -1);
 
 	qd = (qq_data *) gc->proto_data;
-	purple_debug_info("QQ", "Send chat IM to %u, len %d:\n%s\n", id, strlen(what), what);
+	purple_debug_info("QQ", "Send chat IM to %u, len %" G_GSIZE_FORMAT ":\n%s\n", id, strlen(what), what);
 
 	/* qq_show_packet("chat IM UTF8", (guint8 *)what, strlen(what)); */
 
--- a/libpurple/protocols/qq/group_info.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/group_info.h	Wed Dec 17 18:01:08 2008 +0000
@@ -31,7 +31,7 @@
 
 enum {
 	QQ_ROOM_INFO_UPDATE_ONLY = 0,
-	QQ_ROOM_INFO_DISPLAY,
+	QQ_ROOM_INFO_DISPLAY
 };
 
 gint qq_request_room_get_buddies(PurpleConnection *gc, guint32 room_id, gint update_class);
--- a/libpurple/protocols/qq/group_join.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/group_join.c	Wed Dec 17 18:01:08 2008 +0000
@@ -44,7 +44,7 @@
 enum {
 	QQ_ROOM_JOIN_OK = 0x01,
 	QQ_ROOM_JOIN_NEED_AUTH = 0x02,
-	QQ_ROOM_JOIN_DENIED = 0x03,
+	QQ_ROOM_JOIN_DENIED = 0x03
 };
 
 enum {
@@ -219,11 +219,11 @@
 
 	rmd = qq_room_data_find(gc, id);
 	if (rmd != NULL) {
-		msg = g_strdup_printf(_("Successed join to Qun %s (%u)"), rmd->title_utf8, rmd->ext_id);
+		msg = g_strdup_printf(_("Successfully joined Qun %s (%u)"), rmd->title_utf8, rmd->ext_id);
 		qq_got_message(gc, msg);
 		g_free(msg);
 	} else {
-		qq_got_message(gc, _("Successed join to Qun"));
+		qq_got_message(gc, _("Successfully joined Qun"));
 	}
 }
 
@@ -254,7 +254,7 @@
 	g_return_if_fail(rmd != NULL);
 	switch (reply) {
 	case QQ_ROOM_JOIN_OK:
-		purple_debug_info("QQ", "Successed in joining group \"%s\"\n", rmd->title_utf8);
+		purple_debug_info("QQ", "Succeeded in joining group \"%s\"\n", rmd->title_utf8);
 		rmd->my_role = QQ_ROOM_ROLE_YES;
 		/* this must be shown before getting online members */
 		qq_room_conv_open(gc, rmd);
@@ -267,7 +267,7 @@
 		do_room_join_request(gc, rmd);
 		break;
 	case QQ_ROOM_JOIN_DENIED:
-		msg = g_strdup_printf(_("Qun %u denied to join"), rmd->ext_id);
+		msg = g_strdup_printf(_("Qun %u denied from joining"), rmd->ext_id);
 		purple_notify_info(gc, _("QQ Qun Operation"), _("Failed:"), msg);
 		g_free(msg);
 		break;
@@ -276,7 +276,7 @@
 			   "Failed to join room ext id %u %s, unknown reply: 0x%02x\n",
 			   rmd->ext_id, rmd->title_utf8, reply);
 
-		purple_notify_info(gc, _("QQ Qun Operation"), _("Failed:"), _("Join Qun, Unknow Reply"));
+		purple_notify_info(gc, _("QQ Qun Operation"), _("Failed:"), _("Join Qun, Unknown Reply"));
 	}
 }
 
--- a/libpurple/protocols/qq/group_opt.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/group_opt.c	Wed Dec 17 18:01:08 2008 +0000
@@ -122,7 +122,7 @@
 
 	who = uid_to_purple_name(add_req->member);
 	purple_request_input(add_req->gc, NULL, _("Authorization denied message:"),
-			NULL, _("Sorry, you are not our style ..."), TRUE, FALSE, NULL,
+			NULL, _("Sorry, you are not our style"), TRUE, FALSE, NULL,
 			_("OK"), G_CALLBACK(member_join_deny_reason_cb),
 			_("Cancel"), G_CALLBACK(member_join_deny_noreason_cb),
 			purple_connection_get_account(add_req->gc), who, NULL,
@@ -204,7 +204,7 @@
 
 	purple_debug_info("QQ", "Succeed in modify members for room %u\n", rmd->ext_id);
 
-	qq_room_got_chat_in(gc, id, 0, _("Successfully changed Qun member"), now);
+	qq_room_got_chat_in(gc, id, 0, _("Successfully changed Qun members"), now);
 }
 
 void qq_room_change_info(PurpleConnection *gc, qq_room_data *rmd)
@@ -347,7 +347,7 @@
 
 	purple_request_action(gc, _("QQ Qun Operation"),
 			    _("You have successfully created a Qun"),
-			    _("Would you like to set up the detail information now?"),
+			    _("Would you like to set up detailed information now?"),
 			    1,
 				purple_connection_get_account(gc), NULL, NULL,
 				add_req, 2,
@@ -519,7 +519,7 @@
 		rmd->my_role = QQ_ROOM_ROLE_YES;
 	}
 
-	msg = g_strdup_printf(_("<b>Joinning Qun %u is approved by admin %u for %s</b>"),
+	msg = g_strdup_printf(_("<b>Joining Qun %u is approved by admin %u for %s</b>"),
 			ext_id, admin_uid, reason);
 	now = time(NULL);
 	qq_room_got_chat_in(gc, id, 0, msg, now);
--- a/libpurple/protocols/qq/im.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/im.c	Wed Dec 17 18:01:08 2008 +0000
@@ -1258,7 +1258,7 @@
 	g_return_val_if_fail(who != NULL && what != NULL, -1);
 
 	qd = (qq_data *) gc->proto_data;
-	purple_debug_info("QQ", "Send IM to %s, len %d:\n%s\n", who, strlen(what), what);
+	purple_debug_info("QQ", "Send IM to %s, len %" G_GSIZE_FORMAT ":\n%s\n", who, strlen(what), what);
 
 	uid_to = purple_name_to_uid(who);
 	if (uid_to == qd->uid) {
--- a/libpurple/protocols/qq/im.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/im.h	Wed Dec 17 18:01:08 2008 +0000
@@ -45,7 +45,7 @@
 	QQ_MSG_SYS_30 = 0x0030,
 	QQ_MSG_SYS_4C = 0x004C,
 	QQ_MSG_EXTEND = 0x0084,
-	QQ_MSG_EXTEND_85 = 0x0085,
+	QQ_MSG_EXTEND_85 = 0x0085
 };
 
 typedef struct {
--- a/libpurple/protocols/qq/packet_parse.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/packet_parse.c	Wed Dec 17 18:01:08 2008 +0000
@@ -32,11 +32,9 @@
 /* note:
  * 1, in these functions, 'b' stands for byte, 'w' stands for word, 'dw' stands for double word.
  * 2, we use '*cursor' and 'buf' as two addresses to calculate the length.
- * 3, change '0' to '1', if want to get more info about the packet parsing. */
+ * 3, change 'undef' to 'define' to get more info about the packet parsing. */
 
-#if 0
-#define PARSER_DEBUG
-#endif
+#undef PARSER_DEBUG
 
 /* read one byte from buf,
  * return the number of bytes read if succeeds, otherwise return -1 */
--- a/libpurple/protocols/qq/qq.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/qq.c	Wed Dec 17 18:01:08 2008 +0000
@@ -100,10 +100,13 @@
 	qd->use_tcp = purple_account_get_bool(account, "use_tcp", TRUE);
 
 	custom_server = purple_account_get_string(account, "server", NULL);
-	purple_debug_info("QQ", "Select server '%s'\n", custom_server);
-	if ( (custom_server != NULL && strlen(custom_server) > 0) && strcasecmp(custom_server, "auto") != 0) {
-		qd->servers = g_list_append(qd->servers, g_strdup(custom_server));
-		return;
+
+	if (custom_server != NULL) {
+		purple_debug_info("QQ", "Select server '%s'\n", custom_server);
+		if (*custom_server != '\0' && g_ascii_strcasecmp(custom_server, "auto") != 0) {
+			qd->servers = g_list_append(qd->servers, g_strdup(custom_server));
+			return;
+		}
 	}
 
 	if (qd->use_tcp) {
@@ -493,7 +496,7 @@
 	icon_path = qq_get_icon_path(icon_name);
 	g_free(icon_name);
 
-	purple_debug_info("QQ", "Change prev icon %s to ...\n", icon_path);
+	purple_debug_info("QQ", "Change prev icon %s to...\n", icon_path);
 	purple_request_file(action, _("Select icon..."), icon_path,
 			FALSE,
 			G_CALLBACK(qq_change_icon_cb), NULL,
--- a/libpurple/protocols/qq/qq_base.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/qq_base.c	Wed Dec 17 18:01:08 2008 +0000
@@ -72,7 +72,7 @@
 		qq_show_packet("Login reply OK, but length < 139", data, len);
 		purple_connection_error_reason(gc,
 				PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
-				_("Can not decrypt server reply"));
+				_("Cannot decrypt server reply"));
 		return QQ_LOGIN_REPLY_ERR;
 	}
 
@@ -160,7 +160,7 @@
 	if (len < 11) {
 		purple_connection_error_reason(gc,
 				PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
-				_("Can not decrypt get server reply"));
+				_("Cannot decrypt server reply"));
 		return QQ_LOGIN_REPLY_ERR;
 	}
 
@@ -424,7 +424,7 @@
 			qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len,
 					">>> [default] decrypt and dump");
 			error = g_strdup_printf(
-						_("Unknow reply code when login (0x%02X)"),
+						_("Unknown reply code when logging in (0x%02X)"),
 						ret );
 			reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
 			break;
@@ -464,14 +464,16 @@
 	qq_data *qd;
 	gchar **segments;
 
-	g_return_val_if_fail(data != NULL && data_len != 0, FALSE);
+	g_return_val_if_fail(data != NULL, FALSE);
+	g_return_val_if_fail(data_len != 0, FALSE);
 
 	qd = (qq_data *) gc->proto_data;
 
 	/* qq_show_packet("Keep alive reply packet", data, len); */
 
 	/* the last one is 60, don't know what it is */
-	if (NULL == (segments = split_data(data, data_len, "\x1f", 6)))
+	segments = split_data(data, data_len, "\x1f", 6);
+	if (segments == NULL)
 			return TRUE;
 
 	/* segments[0] and segment[1] are all 0x30 ("0") */
@@ -479,7 +481,7 @@
 	if(0 == qd->online_total) {
 		purple_connection_error_reason(gc,
 				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				_("Keep alive error"));
+				_("Lost connection with server"));
 	}
 	qd->my_ip.s_addr = inet_addr(segments[3]);
 	qd->my_port = strtol(segments[4], NULL, 10);
@@ -528,7 +530,7 @@
 	if(0 == qd->online_total) {
 		purple_connection_error_reason(gc,
 				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				_("Keep alive error"));
+				_("Lost connection with server"));
 	}
 
 	bytes += qq_getIP(&qd->my_ip, data + bytes);
@@ -572,7 +574,7 @@
 	if(0 == qd->online_total) {
 		purple_connection_error_reason(gc,
 				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				_("Keep alive error"));
+				_("Lost connection with server"));
 	}
 
 	bytes += qq_getIP(&qd->my_ip, data + bytes);
@@ -653,7 +655,7 @@
 	if (data_len < 15) {
 		purple_connection_error_reason(gc,
 				PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
-				_("Can not decrypt get server reply"));
+				_("Could not decrypt server reply"));
 		return QQ_LOGIN_REPLY_ERR;
 	}
 
@@ -745,7 +747,7 @@
 	qd->send_seq++;
 	qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN_EX, qd->send_seq, buf, bytes, TRUE);
 
-	purple_connection_update_progress(gc, _("Requesting captcha ..."), 3, QQ_CONNECT_STEPS);
+	purple_connection_update_progress(gc, _("Requesting captcha"), 3, QQ_CONNECT_STEPS);
 }
 
 static void request_token_ex_code(PurpleConnection *gc,
@@ -790,7 +792,7 @@
 	qd->send_seq++;
 	qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN_EX, qd->send_seq, buf, bytes, TRUE);
 
-	purple_connection_update_progress(gc, _("Checking code of captcha ..."), 3, QQ_CONNECT_STEPS);
+	purple_connection_update_progress(gc, _("Checking captcha"), 3, QQ_CONNECT_STEPS);
 }
 
 typedef struct {
@@ -813,7 +815,7 @@
 
 	purple_connection_error_reason(captcha_req->gc,
 			PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
-			_("Failed captcha verify"));
+			_("Failed captcha verification"));
 }
 
 static void captcha_input_ok_cb(qq_captcha_request *captcha_req,
@@ -872,8 +874,8 @@
 	purple_request_field_group_add_field(group, field);
 
 	purple_request_fields(account,
-		_("QQ Captcha Verifing"),
-		_("QQ Captcha Verifing"),
+		_("QQ Captcha Verification"),
+		_("QQ Captcha Verification"),
 		_("Enter the text from the image"),
 		fields,
 		_("OK"), G_CALLBACK(captcha_input_ok_cb),
@@ -1111,7 +1113,7 @@
 			qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len,
 					">>> [default] decrypt and dump");
 			error = g_strdup_printf(
-						_("Unknow reply code when checking password (0x%02X)"),
+						_("Unknown reply when checking password (0x%02X)"),
 						ret );
 			reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
 			break;
@@ -1257,7 +1259,7 @@
 				/* Missing get server before login*/
 			default:
 				error = g_strdup_printf(
-						_("Unknow reply code when login (0x%02X):\n%s"),
+						_("Unknown reply code when logging in (0x%02X):\n%s"),
 						ret, msg_utf8);
 				break;
 		}
@@ -1446,7 +1448,7 @@
 				break;
 			default:
 				error = g_strdup_printf(
-						_("Unknow reply code when login (0x%02X):\n%s"),
+						_("Unknown reply code when logging in (0x%02X):\n%s"),
 						ret, msg_utf8);
 				break;
 		}
--- a/libpurple/protocols/qq/qq_define.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/qq_define.h	Wed Dec 17 18:01:08 2008 +0000
@@ -74,7 +74,7 @@
 	QQ_CMD_ADD_BUDDY_NO_AUTH_EX = 0x00A7,			/* add friend without auth */
 	QQ_CMD_ADD_BUDDY_AUTH_EX = 0x00A8, 				/* add buddy with auth */
 	QQ_CMD_BUDDY_CHECK_CODE =  0x00B5,
-	QQ_CMD_BUDDY_QUESTION =  0x00B7,
+	QQ_CMD_BUDDY_QUESTION =  0x00B7
 };
 
 const gchar *qq_get_cmd_desc(gint type);
@@ -104,7 +104,7 @@
 	QQ_ROOM_CMD_TEMP_QUIT = 0x32,
 	QQ_ROOM_CMD_TEMP_GET_INFO = 0x33,
 	QQ_ROOM_CMD_TEMP_SEND_IM = 0x35,
-	QQ_ROOM_CMD_TEMP_GET_MEMBERS = 0x37,
+	QQ_ROOM_CMD_TEMP_GET_MEMBERS = 0x37
 };
 
 const gchar *qq_get_room_cmd_desc(gint room_cmd);
@@ -119,7 +119,7 @@
 	QQ_SERVER_BUDDY_ADDING_EX = 40,
 	QQ_SERVER_BUDDY_ADD_REQUEST_EX = 41,
 	QQ_SERVER_BUDDY_ADDED_ANSWER = 42,
-	QQ_SERVER_BUDDY_ADDED_EX = 43,
+	QQ_SERVER_BUDDY_ADDED_EX = 43
 };
 
 enum {
@@ -128,7 +128,7 @@
 	QQ_BUDDY_CHANGE_TO_OFFLINE = 20,
 	QQ_BUDDY_ONLINE_AWAY = 30,
 	QQ_BUDDY_ONLINE_INVISIBLE = 40,
-	QQ_BUDDY_ONLINE_BUSY = 50,
+	QQ_BUDDY_ONLINE_BUSY = 50
 };
 
 gboolean is_online(guint8 status);
--- a/libpurple/protocols/qq/qq_network.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/qq_network.c	Wed Dec 17 18:01:08 2008 +0000
@@ -376,7 +376,7 @@
 			/* No worries */
 			return;
 
-		error_msg = g_strdup_printf(_("Lost connection with server:\n%d, %s"), errno, g_strerror(errno));
+		error_msg = g_strdup_printf(_("Lost connection with server:\n%s"), g_strerror(errno));
 		purple_connection_error_reason(gc,
 				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 				error_msg);
@@ -773,12 +773,12 @@
 	set_all_keys( gc );
 
 	if (qd->client_version >= 2007) {
-		purple_connection_update_progress(gc, _("Get server ..."), 2, QQ_CONNECT_STEPS);
+		purple_connection_update_progress(gc, _("Getting server"), 2, QQ_CONNECT_STEPS);
 		qq_request_get_server(gc);
 		return;
 	}
 
-	purple_connection_update_progress(gc, _("Request token"), 2, QQ_CONNECT_STEPS);
+	purple_connection_update_progress(gc, _("Requesting token"), 2, QQ_CONNECT_STEPS);
 	qq_request_token(gc);
 }
 
@@ -935,7 +935,7 @@
 		return FALSE;
 	}
 
-	purple_connection_update_progress(gc, _("Connecting server ..."), 1, QQ_CONNECT_STEPS);
+	purple_connection_update_progress(gc, _("Connecting to server"), 1, QQ_CONNECT_STEPS);
 
 	purple_debug_info("QQ", "Connect to %s:%d\n", server, port);
 
@@ -951,7 +951,7 @@
 		qd->conn_data = purple_proxy_connect_udp(gc, account, server, port, connect_cb, gc);
 	}
 	if ( qd->conn_data == NULL ) {
-		purple_debug_error("QQ", _("Couldn't create socket"));
+		purple_debug_error("QQ", "Couldn't create socket");
 		return FALSE;
 	}
 #else
@@ -986,7 +986,7 @@
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
 	qd = (qq_data *) gc->proto_data;
 
-	purple_debug_info("QQ", "Disconnecting ...\n");
+	purple_debug_info("QQ", "Disconnecting...\n");
 
 	if (qd->network_watcher > 0) {
 		purple_debug_info("QQ", "Remove network watcher\n");
--- a/libpurple/protocols/qq/qq_process.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/qq_process.c	Wed Dec 17 18:01:08 2008 +0000
@@ -87,7 +87,7 @@
 
 	if (data[0] != 0) {
 		purple_debug_warning("QQ", "Failed sent IM\n");
-		purple_notify_error(gc, _("Error"), _("Failed to send IM."), NULL);
+		purple_notify_error(gc, _("Error"), _("Unable to send message."), NULL);
 		return;
 	}
 
@@ -538,7 +538,7 @@
 			qq_process_buddy_change_status(data, data_len, gc);
 			break;
 		default:
-			process_unknow_cmd(gc, _("Unknow SERVER CMD"), data, data_len, cmd, seq);
+			process_unknow_cmd(gc, _("Unknown SERVER CMD"), data, data_len, cmd, seq);
 			break;
 	}
 }
@@ -796,7 +796,7 @@
 						seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len);
 			} else {
 				purple_debug_warning("QQ",
-					   _("Not a member of room \"%s\"\n"), rmd->title_utf8);
+					   "Not a member of room \"%s\"\n", rmd->title_utf8);
 				rmd->my_role = QQ_ROOM_ROLE_NO;
 			}
 			break;
@@ -948,7 +948,7 @@
 		qq_show_packet("Can not decrypted", rcved, rcved_len);
 		purple_connection_error_reason(gc,
 				PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
-				_("Can not decrypt login reply"));
+				_("Could not decrypt login reply"));
 		return QQ_LOGIN_REPLY_ERR;
 	}
 
@@ -1019,7 +1019,7 @@
 			qq_update_all(gc, 0);
 			break;
 		default:
-			process_unknow_cmd(gc, _("Unknow LOGIN CMD"), data, data_len, cmd, seq);
+			process_unknow_cmd(gc, _("Unknown LOGIN CMD"), data, data_len, cmd, seq);
 			return QQ_LOGIN_REPLY_ERR;
 	}
 	return QQ_LOGIN_REPLY_OK;
@@ -1141,7 +1141,7 @@
 			qq_process_buddy_check_code(gc, data, data_len);
 			break;
 		default:
-			process_unknow_cmd(gc, _("Unknow CLIENT CMD"), data, data_len, cmd, seq);
+			process_unknow_cmd(gc, _("Unknown CLIENT CMD"), data, data_len, cmd, seq);
 			is_unknow = TRUE;
 			break;
 	}
--- a/libpurple/protocols/qq/qq_process.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/qq_process.h	Wed Dec 17 18:01:08 2008 +0000
@@ -35,7 +35,7 @@
 	QQ_CMD_CLASS_UPDATE_ALL,
 	QQ_CMD_CLASS_UPDATE_ONLINE,
 	QQ_CMD_CLASS_UPDATE_BUDDY,
-	QQ_CMD_CLASS_UPDATE_ROOM,
+	QQ_CMD_CLASS_UPDATE_ROOM
 };
 
 guint8 qq_proc_login_cmds(PurpleConnection *gc,  guint16 cmd, guint16 seq,
--- a/libpurple/protocols/qq/qq_trans.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/qq_trans.c	Wed Dec 17 18:01:08 2008 +0000
@@ -39,7 +39,7 @@
 	QQ_TRANS_IS_SERVER = 0x01,			/* Is server command or client command */
 	QQ_TRANS_IS_IMPORT = 0x02,			/* Only notice if not get reply; or resend, disconn if reties get 0*/
 	QQ_TRANS_REMAINED = 0x04,				/* server command before login*/
-	QQ_TRANS_IS_REPLY = 0x08,				/* server command before login*/
+	QQ_TRANS_IS_REPLY = 0x08				/* server command before login*/
 };
 
 struct _qq_transaction {
--- a/libpurple/protocols/qq/send_file.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/qq/send_file.c	Wed Dec 17 18:01:08 2008 +0000
@@ -612,7 +612,8 @@
 	PurpleConnection *gc;
 	PurpleAccount *account;
 	guint32 to_uid;
-	gchar *filename, *filename_without_path;
+	const gchar *filename;
+	gchar *base_filename;
 
 	g_return_if_fail (xfer != NULL);
 	account = purple_xfer_get_account(xfer);
@@ -621,13 +622,14 @@
 	to_uid = purple_name_to_uid (xfer->who);
 	g_return_if_fail (to_uid != 0);
 
-	filename = (gchar *) purple_xfer_get_local_filename (xfer);
+	filename = purple_xfer_get_local_filename (xfer);
 	g_return_if_fail (filename != NULL);
 
-	filename_without_path = strrchr (filename, '/') + 1;
+	base_filename = g_path_get_basename(filename);
 
-	_qq_send_packet_file_request (gc, to_uid, filename_without_path,
+	_qq_send_packet_file_request (gc, to_uid, base_filename,
 			purple_xfer_get_size(xfer));
+	g_free(base_filename);
 }
 
 /* cancel the transfer of receiving files */
@@ -696,7 +698,7 @@
 		return;
 	}
 	*/
-	filename = strrchr(purple_xfer_get_local_filename(qd->xfer), '/') + 1;
+	filename = g_path_get_basename(purple_xfer_get_local_filename(qd->xfer));
 	msg = g_strdup_printf(_("%d has declined the file %s"),
 		 sender_uid, filename);
 
@@ -704,7 +706,8 @@
 	purple_xfer_request_denied(qd->xfer);
 	qd->xfer = NULL;
 
-	g_free (msg);
+	g_free(filename);
+	g_free(msg);
 }
 
 /* process cancel im for file transfer request */
@@ -725,7 +728,7 @@
 		return;
 	}
 	*/
-	filename = strrchr(purple_xfer_get_local_filename(qd->xfer), '/') + 1;
+	filename = g_path_get_basename(purple_xfer_get_local_filename(qd->xfer));
 	msg = g_strdup_printf
 		(_("%d canceled the transfer of %s"),
 		 sender_uid, filename);
@@ -734,7 +737,8 @@
 	purple_xfer_cancel_remote(qd->xfer);
 	qd->xfer = NULL;
 
-	g_free (msg);
+	g_free(filename);
+	g_free(msg);
 }
 
 /* process accept im for file transfer request */
--- a/libpurple/protocols/sametime/sametime.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/sametime/sametime.c	Wed Dec 17 18:01:08 2008 +0000
@@ -158,7 +158,7 @@
   blist_choice_LOCAL = 1, /**< local only */
   blist_choice_MERGE = 2, /**< merge from server */
   blist_choice_STORE = 3, /**< merge from and save to server */
-  blist_choice_SYNCH = 4, /**< sync with server */
+  blist_choice_SYNCH = 4  /**< sync with server */
 };
 
 
@@ -514,6 +514,11 @@
     idle_len = time(NULL) - idle;
     ugly_idle_len = ((time(NULL) * 1000) - idle) / 1000;
 
+	if(idle > ugly_idle_len)
+		ugly_idle_len = 0;
+	else
+		ugly_idle_len = (ugly_idle_len - idle) / 1000;
+
     /* 
        what's the deal here? Well, good clients are smart enough to
        publish their idle time by using an attribute to indicate that
--- a/libpurple/protocols/silc10/wb.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/silc10/wb.c	Wed Dec 17 18:01:08 2008 +0000
@@ -61,14 +61,14 @@
 /* Commands */
 typedef enum {
 	SILCPURPLE_WB_DRAW 	= 0x01,
-	SILCPURPLE_WB_CLEAR	= 0x02,
+	SILCPURPLE_WB_CLEAR	= 0x02
 } SilcPurpleWbCommand;
 
 /* Brush size */
 typedef enum {
 	SILCPURPLE_WB_BRUSH_SMALL = 2,
 	SILCPURPLE_WB_BRUSH_MEDIUM = 5,
-	SILCPURPLE_WB_BRUSH_LARGE = 10,
+	SILCPURPLE_WB_BRUSH_LARGE = 10
 } SilcPurpleWbBrushSize;
 
 /* Brush color (XXX Purple should provide default colors) */
@@ -85,7 +85,7 @@
 	SILCPURPLE_WB_COLOR_TAN		= 12093547,
 	SILCPURPLE_WB_COLOR_BROWN		= 5256485,
 	SILCPURPLE_WB_COLOR_GREY		= 11184810,
-	SILCPURPLE_WB_COLOR_WHITE		= 16777215,
+	SILCPURPLE_WB_COLOR_WHITE		= 16777215
 } SilcPurpleWbColor;
 
 typedef struct {
--- a/libpurple/protocols/simple/simple.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/simple/simple.c	Wed Dec 17 18:01:08 2008 +0000
@@ -1939,6 +1939,14 @@
 		sip->txbuf = purple_circ_buffer_new(0);
 
 	userserver = g_strsplit(username, "@", 2);
+	if (userserver[1] == NULL || userserver[1][0] == '\0') {
+		purple_connection_error_reason(gc,
+			PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
+			_("Unable to connect to server. Please enter the "
+			  "address of the server you wish to connect to."));
+		return;
+	}
+
 	purple_connection_set_display_name(gc, userserver[0]);
 	sip->username = g_strdup(userserver[0]);
 	sip->servername = g_strdup(userserver[1]);
--- a/libpurple/protocols/yahoo/yahoo_aliases.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_aliases.c	Wed Dec 17 18:01:08 2008 +0000
@@ -301,7 +301,7 @@
 						  "<ct a=\"1\" yi='%s' nn='%s' />\n</ab>\r\n",
 						  purple_account_get_username(gc->account),
 						  who, converted_alias_jp);
-			free(converted_alias_jp);
+			g_free(converted_alias_jp);
 			g_free(alias_jp);
 		} else {
 			gchar *escaped_alias = g_markup_escape_text(alias, -1);
@@ -321,7 +321,7 @@
 						  "<ct e=\"1\"  yi='%s' id='%s' nn='%s' pr='0' />\n</ab>\r\n",
 						  purple_account_get_username(gc->account),
 						  who, cb->id, converted_alias_jp);
-			free(converted_alias_jp);
+			g_free(converted_alias_jp);
 			g_free(alias_jp);
 		} else {
 			gchar *escaped_alias = g_markup_escape_text(alias, -1);
--- a/libpurple/protocols/yahoo/yahoo_picture.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_picture.c	Wed Dec 17 18:01:08 2008 +0000
@@ -408,8 +408,10 @@
 	if (ret < 0 && errno == EAGAIN)
 		return;
 	else if (ret <= 0) {
-		purple_debug_info("yahoo", "Buddy icon upload response (%d) bytes (> ~400 indicates failure):\n%.*s\n",
-			d->str->len, d->str->len, d->str->str);
+		/* There are other problems if d->str->len overflows, so shut up the
+		 * warning on 64-bit. */
+		purple_debug_info("yahoo", "Buddy icon upload response (%" G_GSIZE_FORMAT ") bytes (> ~400 indicates failure):\n%.*s\n",
+			d->str->len, (guint)d->str->len, d->str->str);
 
 		yahoo_buddy_icon_upload_data_free(d);
 		return;
@@ -517,7 +519,8 @@
 	g_string_prepend(d->str, header);
 	g_free(header);
 
-	purple_debug_info("yahoo", "Buddy icon upload data:\n%.*s\n", d->str->len, d->str->str);
+	/* There are other problems if we're uploading over 4GB of data */
+	purple_debug_info("yahoo", "Buddy icon upload data:\n%.*s\n", (guint)d->str->len, d->str->str);
 
 	d->fd = source;
 	d->watcher = purple_input_add(d->fd, PURPLE_INPUT_WRITE, yahoo_buddy_icon_upload_pending, d);
--- a/libpurple/protocols/yahoo/yahoo_profile.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_profile.c	Wed Dec 17 18:01:08 2008 +0000
@@ -807,7 +807,7 @@
 	 */
 	if (error_message != NULL || url_text == NULL || strcmp(url_text, "") == 0) {
 		purple_notify_user_info_add_pair(user_info, _("Error retrieving profile"), NULL);
-		purple_notify_userinfo(info_data->gc, info_data->name, 
+		purple_notify_userinfo(info_data->gc, info_data->name,
 			user_info, NULL, NULL);
 		purple_notify_user_info_destroy(user_info);
 		g_free(profile_url_text);
@@ -841,10 +841,10 @@
 						 _("If you wish to view this profile, "
 						"you will need to visit this link in your web browser:"),
 						 profile_url_text, profile_url_text);
-		purple_notify_user_info_add_pair(user_info, NULL, tmp);		
+		purple_notify_user_info_add_pair(user_info, NULL, tmp);
 		g_free(tmp);
 
-		purple_notify_userinfo(info_data->gc, info_data->name, 
+		purple_notify_userinfo(info_data->gc, info_data->name,
 				user_info, NULL, NULL);
 
 		g_free(profile_url_text);
@@ -1193,17 +1193,15 @@
 
 	if(!found)
 	{
-		GString *str = g_string_new("");
+		const gchar *str;
 
-		g_string_append_printf(str, "<br><b>");
-		g_string_append_printf(str, _("User information for %s unavailable"),
-				info_data->name);
-		g_string_append_printf(str, "</b><br>");
+		purple_notify_user_info_add_section_break(user_info);
+		purple_notify_user_info_add_pair(user_info,
+				_("Error retrieving profile"), NULL);
 
 		if (profile_state == PROFILE_STATE_UNKNOWN_LANGUAGE) {
-			g_string_append_printf(str, "%s<br><br>",
-					_("Sorry, this profile seems to be in a language "
-					  "or format that is not supported at this time."));
+			str = _("This profile is in a language "
+					  "or format that is not supported at this time.");
 
 		} else if (profile_state == PROFILE_STATE_NOT_FOUND) {
 			PurpleBuddy *b = purple_find_buddy
@@ -1217,27 +1215,26 @@
 				 */
 				f = yahoo_friend_find(b->account->gc, b->name);
 			}
-			g_string_append_printf(str, "%s<br><br>",
-				f?  _("Could not retrieve the user's profile. "
+			str = f ? _("Could not retrieve the user's profile. "
 					  "This most likely is a temporary server-side problem. "
-					  "Please try again later."):
+					  "Please try again later.") :
 					_("Could not retrieve the user's profile. "
 					  "This most likely means that the user does not exist; "
 					  "however, Yahoo! sometimes does fail to find a user's "
 					  "profile. If you know that the user exists, "
-					  "please try again later."));
+					  "please try again later.");
 		} else {
-			g_string_append_printf(str, "%s<br><br>",
-					_("The user's profile is empty."));
+			str = _("The user's profile is empty.");
 		}
-		
-		purple_notify_user_info_add_pair(user_info, NULL, str->str);
-		g_string_free(str, TRUE);
+
+		purple_notify_user_info_add_pair(user_info, NULL, str);
 	}
 
 	/* put a link to the actual profile URL */
-	tmp = g_strdup_printf("<a href=\"%s\">%s</a>", profile_url_text, profile_url_text);
-	purple_notify_user_info_add_pair(user_info, _("Profile URL"), tmp);
+	purple_notify_user_info_add_section_break(user_info);
+	tmp = g_strdup_printf("<a href=\"%s\">%s</a>",
+			profile_url_text, _("View web profile"));
+	purple_notify_user_info_add_pair(user_info, NULL, tmp);
 	g_free(tmp);
 
 	g_free(stripped);
--- a/libpurple/protocols/yahoo/yahoochat.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoochat.c	Wed Dec 17 18:01:08 2008 +0000
@@ -1180,7 +1180,7 @@
 
 enum yahoo_room_type {
 	yrt_yahoo,
-	yrt_user,
+	yrt_user
 };
 
 struct yahoo_chatxml_state {
--- a/libpurple/protocols/yahoo/ycht.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/yahoo/ycht.h	Wed Dec 17 18:01:08 2008 +0000
@@ -43,7 +43,7 @@
 	YCHT_SERVICE_CHATMSG = 0x41,
 	YCHT_SERVICE_CHATMSG_EMOTE = 0x43,
 	YCHT_SERVICE_PING = 0x62,
-	YCHT_SERVICE_ONLINE_FRIENDS = 0x68,
+	YCHT_SERVICE_ONLINE_FRIENDS = 0x68
 } ycht_service;
 /*
 yahoo: YCHT Service: 0x11 Version: 0x100
--- a/libpurple/protocols/zephyr/zephyr.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/protocols/zephyr/zephyr.c	Wed Dec 17 18:01:08 2008 +0000
@@ -64,7 +64,7 @@
 	PURPLE_ZEPHYR_NONE, /* Non-kerberized ZEPH0.2 */
 	PURPLE_ZEPHYR_KRB4, /* ZEPH0.2 w/ KRB4 support */
 	PURPLE_ZEPHYR_TZC,  /* tzc executable proxy */
-	PURPLE_ZEPHYR_INTERGALACTIC_KRB4, /* Kerberized ZEPH0.3 */
+	PURPLE_ZEPHYR_INTERGALACTIC_KRB4 /* Kerberized ZEPH0.3 */
 } zephyr_connection_type;
 
 struct _zephyr_account {
@@ -1673,7 +1673,7 @@
 
 			purple_debug_info("zephyr", "about to read from tzc\n");
 
-			if (waitpid(pid, NULL, WNOHANG) == 0) { // Only select if tzc is still running
+			if (waitpid(pid, NULL, WNOHANG) == 0) { /* Only select if tzc is still running */
 				purple_debug_info("zephyr", "about to read from tzc\n");
 				select_status = select(zephyr->fromtzc[ZEPHYR_FD_READ] + 1, &rfds, NULL, NULL, NULL);
 			}
--- a/libpurple/prpl.h	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/prpl.h	Wed Dec 17 18:01:08 2008 +0000
@@ -189,7 +189,7 @@
 	 * Used as a hint that unknown commands should not be sent as messages.
 	 * @since 2.1.0
 	 */
-	OPT_PROTO_SLASH_COMMANDS_NATIVE = 0x00000400,
+	OPT_PROTO_SLASH_COMMANDS_NATIVE = 0x00000400
 
 } PurpleProtocolOptions;
 
--- a/libpurple/smiley.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/smiley.c	Wed Dec 17 18:01:08 2008 +0000
@@ -288,7 +288,7 @@
 {
 	PROP_0,
 	PROP_SHORTCUT,
-	PROP_IMGSTORE,
+	PROP_IMGSTORE
 };
 
 #define PROP_SHORTCUT_S "shortcut"
--- a/libpurple/sslconn.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/sslconn.c	Wed Dec 17 18:01:08 2008 +0000
@@ -57,7 +57,7 @@
 		return FALSE;
 	}
 
-	return ops->init();
+	return (_ssl_initialized = ops->init());
 }
 
 gboolean
--- a/libpurple/win32/global.mak	Sun Dec 07 01:42:47 2008 +0000
+++ b/libpurple/win32/global.mak	Wed Dec 17 18:01:08 2008 +0000
@@ -16,11 +16,11 @@
 GTK_BIN ?= $(GTK_TOP)/bin
 BONJOUR_TOP ?= $(WIN32_DEV_TOP)/Bonjour_SDK
 LIBXML2_TOP ?= $(WIN32_DEV_TOP)/libxml2-2.6.30
-MEANWHILE_TOP ?= $(WIN32_DEV_TOP)/meanwhile-1.0.2_daa1
+MEANWHILE_TOP ?= $(WIN32_DEV_TOP)/meanwhile-1.0.2_daa2
 NSPR_TOP ?= $(WIN32_DEV_TOP)/nspr-4.6.4
 NSS_TOP ?= $(WIN32_DEV_TOP)/nss-3.11.4
 PERL_LIB_TOP ?= $(WIN32_DEV_TOP)/perl-5.10.0
-SILC_TOOLKIT ?= $(WIN32_DEV_TOP)/silc-toolkit-1.1.7
+SILC_TOOLKIT ?= $(WIN32_DEV_TOP)/silc-toolkit-1.1.8
 TCL_LIB_TOP ?= $(WIN32_DEV_TOP)/tcl-8.4.5
 GSTREAMER_TOP ?= $(WIN32_DEV_TOP)/gstreamer-0.10.13
 
--- a/pidgin/gtkblist.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/pidgin/gtkblist.c	Wed Dec 17 18:01:08 2008 +0000
@@ -3630,6 +3630,7 @@
 	const char *name = NULL;
 	char *filename, *path;
 	PurplePresence *p;
+	PurpleStatus *tune;
 
 	if(PURPLE_BLIST_NODE_IS_CONTACT(node)) {
 		if(!gtknode->contact_expanded) {
@@ -3668,7 +3669,21 @@
 		return _pidgin_blist_get_cached_emblem(path);
 	}
 
-	if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_TUNE)) {
+	tune = purple_presence_get_status(p, "tune");
+	if (tune && purple_status_is_active(tune)) {
+		/* Only in MSN.
+		 * TODO: Replace "Tune" with generalized "Media" in 3.0. */
+		if (purple_status_get_attr_string(tune, "game") != NULL) {
+			path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "game.png", NULL);
+			return _pidgin_blist_get_cached_emblem(path);
+		}
+		/* Only in MSN.
+		 * TODO: Replace "Tune" with generalized "Media" in 3.0. */
+		if (purple_status_get_attr_string(tune, "office") != NULL) {
+			path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "office.png", NULL);
+			return _pidgin_blist_get_cached_emblem(path);
+		}
+		/* Regular old "tune" is the only one in all protocols. */
 		path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "music.png", NULL);
 		return _pidgin_blist_get_cached_emblem(path);
 	}
--- a/pidgin/gtkimhtml.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/pidgin/gtkimhtml.c	Wed Dec 17 18:01:08 2008 +0000
@@ -3126,9 +3126,15 @@
 								font->size = 6;
 							else if (g_ascii_strcasecmp(size, "xx-large") == 0)
 								font->size = 7;
-							else
-								font->size = 3;
-						    gtk_imhtml_font_set_size(imhtml, font->size);
+
+							/*
+							 * TODO: Handle other values, like percentages, or
+							 * lengths specified as em, ex, px, in, cm, mm, pt
+							 * or pc.  Or even better, use an actual HTML
+							 * renderer like webkit.
+							 */
+							if (font->size > 0)
+							    gtk_imhtml_font_set_size(imhtml, font->size);
 						}
 						else if (oldfont)
 						{
--- a/pidgin/gtkutils.c	Sun Dec 07 01:42:47 2008 +0000
+++ b/pidgin/gtkutils.c	Wed Dec 17 18:01:08 2008 +0000
@@ -1502,16 +1502,16 @@
 
 		break;
 	}
-	free(data->filename);
-	free(data->who);
-	free(data);
+	g_free(data->filename);
+	g_free(data->who);
+	g_free(data);
 }
 
 static void dnd_image_cancel_callback(_DndData *data, int choice)
 {
-	free(data->filename);
-	free(data->who);
-	free(data);
+	g_free(data->filename);
+	g_free(data->who);
+	g_free(data);
 }
 
 static void dnd_set_icon_ok_cb(_DndData *data)
@@ -1521,9 +1521,9 @@
 
 static void dnd_set_icon_cancel_cb(_DndData *data)
 {
-	free(data->filename);
-	free(data->who);
-	free(data);
+	g_free(data->filename);
+	g_free(data->who);
+	g_free(data);
 }
 
 void
@@ -3276,13 +3276,7 @@
 static void
 combo_box_changed_cb(GtkComboBox *combo_box, GtkEntry *entry)
 {
-#if GTK_CHECK_VERSION(2, 6, 0)
 	char *text = gtk_combo_box_get_active_text(combo_box);
-#else
-	GtkWidget *widget = gtk_bin_get_child(GTK_BIN(combo_box));
-	char *text = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
-#endif
-
 	gtk_entry_set_text(entry, text ? text : "");
 	g_free(text);
 }
--- a/pidgin/plugins/perl/common/GtkIMHtml.xs	Sun Dec 07 01:42:47 2008 +0000
+++ b/pidgin/plugins/perl/common/GtkIMHtml.xs	Wed Dec 17 18:01:08 2008 +0000
@@ -173,7 +173,7 @@
 	t_GL = NULL;
 	t_len = av_len((AV *)SvRV(unused));
 
-	for (i = 0; i < t_len; i++) {
+	for (i = 0; i <= t_len; i++) {
 		STRLEN t_sl;
 		t_GL = g_slist_append(t_GL, SvPV(*av_fetch((AV *)SvRV(unused), i, 0), t_sl));
 	}
--- a/po/ca.po	Sun Dec 07 01:42:47 2008 +0000
+++ b/po/ca.po	Wed Dec 17 18:01:08 2008 +0000
@@ -3,7 +3,7 @@
 # Copyright (C) unknown, Robert Millan <zeratul2@wanadoo.es>
 # Copyright (C) December 2003 (from 2003-12-12 until 2003-12-18),
 #               January (2004-01-07,12), Xan <dxpublica@telefonica.net>
-# Copyright (c) 2004, 2005, 2006, 2007
+# Copyright (c) 2004, 2005, 2006, 2007, 2008
 #               Josep Puigdemont i Casamajó <josep.puigdemont@gmail.com>
 #
 # This file is distributed under the same license as the Pidgin package.
@@ -27,14 +27,14 @@
 #
 # NOTE: adjectives in catalan go [almost] always to the end, for instance:
 # NOTA: els adjectius en català acostumen a anar al final, per exemple:
-#   "New file" --> "Fitxer nou"
+#  "New file" --> "Fitxer nou"
 #
 msgid ""
 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-05-11 13:00+0200\n"
+"POT-Creation-Date: 2008-12-14 17:46+0100\n"
+"PO-Revision-Date: 2008-12-15 00:07+0100\n"
 "Last-Translator: Josep Puigdemont i Casamajó <josep.puigdemont@gmail.com>\n"
 "Language-Team: Catalan <tradgnome@softcatala.net>\n"
 "MIME-Version: 1.0\n"
@@ -96,7 +96,6 @@
 msgid "Remember password"
 msgstr "Recorda la contrasenya"
 
-#, fuzzy
 msgid "There are no protocol plugins installed."
 msgstr "No hi ha connectors de protocol instal·lats."
 
@@ -122,9 +121,8 @@
 msgstr "Àlies:"
 
 #. Register checkbox
-#, fuzzy
 msgid "Create this account on the server"
-msgstr "Crea aquest compte nou al servidor"
+msgstr "Crea aquest compte al servidor"
 
 #. Cancel button
 #. Cancel
@@ -434,9 +432,8 @@
 msgid "View Log..."
 msgstr "Mostra el registre..."
 
-#, fuzzy
 msgid "View All Logs"
-msgstr "Visualitza el registre"
+msgstr "Visualitza tots els registres"
 
 msgid "Show"
 msgstr "Mostra"
@@ -641,21 +638,18 @@
 msgid "Send To"
 msgstr "Envia a"
 
-# FIXME
-#, fuzzy
 msgid "Invite message"
-msgstr "Missatge de sortida"
+msgstr "Missatge d'invitació"
 
 msgid "Invite"
 msgstr "Convida"
 
-#, fuzzy
 msgid ""
 "Please enter the name of the user you wish to invite,\n"
 "along with an optional invite message."
 msgstr ""
-"Introduïu el nom de l'usuari que vulgueu convidar, així com un missatge "
-"d'invitació opcional."
+"Introduïu el nom de l'usuari que vulgueu convidar,\n"
+"així com un missatge d'invitació opcional."
 
 msgid "Conversation"
 msgstr "Conversa"
@@ -670,9 +664,8 @@
 msgid "Add Buddy Pounce..."
 msgstr "Afegeix un avís per a l'amic..."
 
-#, fuzzy
 msgid "Invite..."
-msgstr "Convida"
+msgstr "Convida..."
 
 msgid "Enable Logging"
 msgstr "Habilita el registre"
@@ -683,11 +676,11 @@
 msgid "<AUTO-REPLY> "
 msgstr "<RESPOSTA-AUTOMÀTICA> "
 
-#, fuzzy, c-format
+#, c-format
 msgid "List of %d user:\n"
 msgid_plural "List of %d users:\n"
-msgstr[0] "Llista d'usuaris:\n"
-msgstr[1] "Llista d'usuaris:\n"
+msgstr[0] "Llista d'%d usuari:\n"
+msgstr[1] "Llista de %d usuaris:\n"
 
 msgid "Supported debug options are:  version"
 msgstr "Les opcions de depuració disponibles són:  version"
@@ -707,10 +700,14 @@
 "%s is not a valid message class. See '/help msgcolor' for valid message "
 "classes."
 msgstr ""
+"%s no és una classe de missatge vàlida. Vegeu '/help msgcolor' per a llistar "
+"les classes de missatge vàlides."
 
 #, c-format
 msgid "%s is not a valid color. See '/help msgcolor' for valid colors."
 msgstr ""
+"%s no és un color vàlid. Vegei '/help msgcolor' per a llistar els colors "
+"vàlids."
 
 msgid ""
 "say &lt;message&gt;:  Send a message normally as if you weren't using a "
@@ -763,6 +760,13 @@
 "background&gt;: black, red, green, blue, white, gray, darkgray, magenta, "
 "cyan, default<br><br>EXAMPLE:<br>    msgcolor send cyan default"
 msgstr ""
+"msgcolor &lt;classe&gt; &lt;primer pla&gt; &lt;fons&gt;: estableix el color "
+"de les diferents classes de missatge en les finestres de conversa.<br>    "
+"&lt;classe&gt;: receive (rep), send (envia), highlight (ressalta), action "
+"(acció), timestamp (marca de temps)<br>    &lt;primer pla/fons&gt;: black "
+"(negre), red (vermell), green (verd), blue (blau), white (blanc), gray "
+"(gris), darkgray (gris fosc), magenta, cyan (cian), default (per defecte)"
+"<br><br>EXEMPLE:<br>    msgcolor send cyan default"
 
 msgid "Unable to open file."
 msgstr "No s'ha pogut obrir el fitxer."
@@ -783,10 +787,10 @@
 msgid "Pause"
 msgstr "Fes una pausa"
 
-#, fuzzy, c-format
+#, c-format
 msgid "File Transfers - %d%% of %d file"
 msgid_plural "File Transfers - %d%% of %d files"
-msgstr[0] "Transferència de fitxers - %d%% de %d fitxers"
+msgstr[0] "Transferència de fitxers - %d%% de %d fitxer"
 msgstr[1] "Transferència de fitxers - %d%% de %d fitxers"
 
 #. Create the window.
@@ -904,9 +908,8 @@
 msgid "Conversations with %s"
 msgstr "Converses amb %s"
 
-#, fuzzy
 msgid "All Conversations"
-msgstr "Converses"
+msgstr "Totes les converses"
 
 msgid "System Log"
 msgstr "Registre del sistema"
@@ -1542,10 +1545,10 @@
 msgstr "Sense agrupament"
 
 msgid "Nested Subgroup"
-msgstr ""
+msgstr "Subgrup imbricat"
 
 msgid "Nested Grouping (experimental)"
-msgstr ""
+msgstr "Subgrup imbricat (experimental)"
 
 msgid "Provides alternate buddylist grouping options."
 msgstr "Proporciona opcions alternatives per a l'agrupament d'amics."
@@ -1868,7 +1871,7 @@
 
 #, c-format
 msgid "Resolver process exited without answering our request"
-msgstr ""
+msgstr "El procés resoledor ha acabat sense respondre la nostra sol·licitud"
 
 #, c-format
 msgid "Thread creation failure: %s"
@@ -2177,10 +2180,11 @@
 msgid "ABI version mismatch %d.%d.x (need %d.%d.x)"
 msgstr "Hi ha un error de coincidència de l'ABI %d.%d.x (cal %d.%d.x)"
 
-#, fuzzy
 msgid ""
 "Plugin does not implement all required functions (list_icon, login and close)"
-msgstr "El connector no implementa totes les funcions requerides"
+msgstr ""
+"El connector no implementa totes les funcions requerides (list_icon, login i "
+"close)"
 
 #, c-format
 msgid ""
@@ -2266,9 +2270,8 @@
 "s'hagi transferit completament (només quan no hi ha conversa amb qui\n"
 "l'envia)"
 
-#, fuzzy
 msgid "Create a new directory for each user"
-msgstr "Seleccioneu quin directori d'usuari cercar"
+msgstr "Crea un directori nou per a cada usuari"
 
 msgid "Notes"
 msgstr "Notes"
@@ -2433,7 +2436,7 @@
 msgstr "Temps d'espera d'inactivitat del usuaris (en minuts)"
 
 msgid "Apply hiding rules to buddies"
-msgstr ""
+msgstr "Aplica les normes d'ocultació als amics"
 
 #. *< type
 #. *< ui_requirement
@@ -2846,14 +2849,13 @@
 "No s'ha pogut detectar la instal·lació d'ActiveTCL. Si voleu emprar "
 "connectors TCL, instal·leu l'ActiveTCL de http://www.activestate.com\n"
 
-#, fuzzy
 msgid ""
 "The Apple Bonjour For Windows toolkit wasn't found, see the FAQ at: http://d."
 "pidgin.im/BonjourWindows for more information."
 msgstr ""
 "No s'ha pogut trobar el joc d'eines per a Windows de l'Apple Bonjour, "
-"consulteu les preguntes més freqüents a http://developer.pidgin.im/wiki/Using"
-"%20Pidgin#CanIusePidginforBonjourLink-LocalMessaging per a més informació."
+"consulteu les preguntes més freqüents a http://developer.pidgin.im/"
+"BonjourWindows per a més informació."
 
 msgid "Unable to listen for incoming IM connections\n"
 msgstr "No es poden escoltar connexions entrants de MI\n"
@@ -3257,7 +3259,7 @@
 msgstr "Codificacions"
 
 msgid "Auto-detect incoming UTF-8"
-msgstr ""
+msgstr "Detecta UTF-8 entrant automàticament"
 
 msgid "Real name"
 msgstr "Nom real"
@@ -3272,9 +3274,9 @@
 msgid "Bad mode"
 msgstr "Mode dolent"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Ban on %s by %s, set %s ago"
-msgstr "Bandejament a %s de %s, establert fa %ld segons"
+msgstr "Bandejament a %s de %s, establert fa %s"
 
 #, c-format
 msgid "Ban on %s"
@@ -3445,7 +3447,7 @@
 "missatge el treu."
 
 msgid "ctcp <nick> <msg>: sends ctcp msg to nick."
-msgstr ""
+msgstr "ctcp <sobrenom> <msg>: envia un missatge ctcp a sobrenom"
 
 msgid "chanserv: Send a command to chanserv"
 msgstr "chanserv: envia una ordre al chanserv"
@@ -3750,9 +3752,9 @@
 msgid "Service Discovery Items"
 msgstr "Elements del servei de descoberta"
 
-#, fuzzy
+# http://xmpp.org/extensions/xep-0033.html
 msgid "Extended Stanza Addressing"
-msgstr "Adreça (cont.)"
+msgstr "Bloc d'adressament estès"
 
 msgid "Multi-User Chat"
 msgstr "Xat multi-usuari"
@@ -3812,17 +3814,18 @@
 msgstr "Negociacions de la sessió xifrada"
 
 # Pot ser també música, cançó... (josep)
-#, fuzzy
+# Vegeu: http://xmpp.org/extensions/xep-0118.html
 msgid "User Tune"
 msgstr "Melodia de l'usuari"
 
-#, fuzzy
+# Nota: "Roster" en XMPP és la llista de contactes (josep)
 msgid "Roster Item Exchange"
-msgstr "MI amb intercanvi de clau"
-
-#, fuzzy
+msgstr "Intercanvi d'element de la llista de contactes"
+
+# Vegeu: http://xmpp.org/extensions/xep-0152.html (josep)
+# Nota: codi mort
 msgid "Reachability Address"
-msgstr "Adreça de correu"
+msgstr "Adreça de localització"
 
 msgid "User Profile"
 msgstr "Perfil de l'usuari"
@@ -3875,8 +3878,11 @@
 msgid "Ping"
 msgstr "Ping"
 
+# Vegeu: http://xmpp.org/extensions/xep-0200.html
+# Nota: Això es refereix a les capabilitats de l'altre interlocutor
+# No apareix a l'aplicació final, és codi mort dins un #if 0 ... #endif (josep)
 msgid "Stanza Encryption"
-msgstr "Xifratge de paràgrafs"
+msgstr "Blocs xifrats"
 
 msgid "Entity Time"
 msgstr "Hora de l'entitat"
@@ -3909,9 +3915,9 @@
 msgid "Resource"
 msgstr "Recurs"
 
-# FIXME
+# Segons la viquipèdia
 msgid "Middle Name"
-msgstr "Primer cognom"
+msgstr "Nom del mig"
 
 msgid "Address"
 msgstr "Adreça"
@@ -4421,8 +4427,9 @@
 msgid "Unsupported Encoding"
 msgstr "La codificació no està implementada"
 
+# FIXME
 msgid "Unsupported Stanza Type"
-msgstr "El tipus de permanència no està implementada"
+msgstr "Aquest tipus de bloc no està implementat"
 
 msgid "Unsupported Version"
 msgstr "Aquesta versió no està implementada"
@@ -4580,7 +4587,6 @@
 
 #. this should probably be part of global smiley theme settings later on,
 #. shared with MSN
-#, fuzzy
 msgid "Show Custom Smileys"
 msgstr "Mostra emoticones personalitzades"
 
@@ -4607,9 +4613,9 @@
 msgid "XMPP Message Error"
 msgstr "Missatge d'error de l'XMPP"
 
-#, fuzzy, c-format
+#, c-format
 msgid "(Code %s)"
-msgstr " (Codi %s)"
+msgstr "(Codi %s)"
 
 msgid "XML Parse error"
 msgstr "Error en l'anàlisi de l'XML"
@@ -4709,6 +4715,19 @@
 msgid "Unable to retrieve MSN Address Book"
 msgstr "No s'ha pogut obtenir la llibreta d'adreces 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 "No s'ha pogut afegir «%s»."
+
+msgid "Buddy Add error"
+msgstr "Error en afegir un amic"
+
+msgid "The username specified does not exist."
+msgstr "El nom d'usuari especificat no existeix."
+
 #, c-format
 msgid "Buddy list synchronization issue in %s (%s)"
 msgstr "Problema de sincronització de la llista d'amics a %s (%s)"
@@ -4936,9 +4955,9 @@
 msgid "Passport account not yet verified"
 msgstr "El compte de passaport encara no està verificat"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Passport account suspended"
-msgstr "El compte de passaport encara no està verificat"
+msgstr "El compte de passaport s'ha suspès"
 
 #, c-format
 msgid "Bad ticket"
@@ -4952,13 +4971,11 @@
 msgid "MSN Error: %s\n"
 msgstr "Error d'MSN: %s\n"
 
-#, fuzzy
 msgid "Other Contacts"
-msgstr "Contacte preferit"
-
-#, fuzzy
+msgstr "Altres contactes"
+
 msgid "Non-IM Contacts"
-msgstr "Suprimeix el contacte"
+msgstr "Contactes que no són de MI"
 
 msgid "Nudge"
 msgstr "Donar un cop de colze"
@@ -4971,9 +4988,8 @@
 msgid "Nudging %s..."
 msgstr "S'està donant un cop de colze a %s..."
 
-#, fuzzy
 msgid "Email Address..."
-msgstr "Adreça de correu electrònic"
+msgstr "Correu electrònic..."
 
 msgid "Your new MSN friendly name is too long."
 msgstr "El vostre nom amistós nou d'MSN és massa llarg."
@@ -5009,22 +5025,20 @@
 msgid "Disallow"
 msgstr "Denega"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Blocked Text for %s"
-msgstr "Comentari sobre l'amic %s"
-
-#, fuzzy
+msgstr "Text blocat de %s"
+
 msgid "No text is blocked for this account."
-msgstr "Utilitza aquesta _icona d'amic per a aquest compte:"
+msgstr "No hi ha text blocat per aquest compte."
 
 #, c-format
 msgid ""
 "MSN servers are currently blocking the following regular expressions:<br/>%s"
-msgstr ""
-
-#, fuzzy
+msgstr "Actualment, sevidors MSN bloquen aquestes expressions regulars:<br/>%s"
+
 msgid "This account does not have email enabled."
-msgstr "Pot ser que aquest compte Hotmail no sigui actiu."
+msgstr "Aquest compte no té el correu habilitat."
 
 msgid "Send a mobile message."
 msgstr "Envia un missatge de mòbil."
@@ -5032,6 +5046,12 @@
 msgid "Page"
 msgstr "Pàgina"
 
+msgid "Playing a game"
+msgstr "Jugant a un joc"
+
+msgid "Working"
+msgstr "Treballant"
+
 msgid "Has you"
 msgstr "Us té"
 
@@ -5068,6 +5088,12 @@
 msgid "Album"
 msgstr "Àlbum"
 
+msgid "Game Title"
+msgstr "Títol del joc"
+
+msgid "Office Title"
+msgstr "Títol oficial"
+
 msgid "Set Friendly Name..."
 msgstr "Estableix el nom amistós..."
 
@@ -5087,7 +5113,7 @@
 msgstr "Permet/denega pàgines de mòbil..."
 
 msgid "View Blocked Text..."
-msgstr ""
+msgstr "Mostra el text blocat..."
 
 msgid "Open Hotmail Inbox"
 msgstr "Obre la safata d'entrada de Hotmail"
@@ -5259,8 +5285,8 @@
 "No s'ha pogut trobar informació del perfil de l'usuari. El més segur és que "
 "l'usuari no existeixi."
 
-msgid "Profile URL"
-msgstr "URL del perfil"
+msgid "View web profile"
+msgstr "Mostra el perfil web"
 
 #. *< type
 #. *< ui_requirement
@@ -5289,9 +5315,8 @@
 msgid "Windows Live ID authentication:Unable to connect"
 msgstr "Autenticació amb el Windows Live ID: no s'ha pogut connectar"
 
-#, fuzzy
 msgid "Windows Live ID authentication:Invalid response"
-msgstr "Autenticació amb el Windows Live ID: no s'ha pogut connectar"
+msgstr "Autenticació amb el Windows Live ID: la resposta no és vàlida"
 
 #, c-format
 msgid "%s is not a valid group."
@@ -5316,9 +5341,8 @@
 msgid "Unable to add user"
 msgstr "No s'ha pogut afegir l'usuari"
 
-#, fuzzy
 msgid "The following users are missing from your addressbook"
-msgstr "El que segueix són els resultats de la vostra cerca"
+msgstr "Manquen aquests usuaris a la vostra llista d'amics"
 
 #, c-format
 msgid "Unable to add user on %s (%s)"
@@ -5343,9 +5367,8 @@
 msgid "Service Temporarily Unavailable."
 msgstr "El servei no està disponible temporalment."
 
-#, fuzzy
 msgid "Mobile message was not sent because it was too long."
-msgstr "El missatge no s'ha enviat perquè no esteu connectat."
+msgstr "No s'ha enviat el missatge al mòbil perquè era massa llarg."
 
 msgid "Unable to rename group"
 msgstr "No s'ha pogut canviar el nom del grup"
@@ -5385,21 +5408,21 @@
 "Message was not sent because the system is unavailable. This normally "
 "happens when the user is blocked or does not exist."
 msgstr ""
-
-#, fuzzy
+"No s'ha pogut enviar el missatge perquè el sistema no està disponible. Això "
+"normalment passa quan l'usuari està blocat o no existeix."
+
 msgid "Message was not sent because messages are being sent too quickly."
 msgstr ""
-"El missatge no s'ha pogut enviar perquè s'està enviant massa de pressa:"
-
-#, fuzzy
+"No s'ha pogut enviar el missatge perquè se n'estan enviant massa depressa."
+
 msgid "Message was not sent because an unknown encoding error occurred."
 msgstr ""
-"No s'ha pogut enviar el missatge perquè s'ha produït un error desconegut:"
-
-#, fuzzy
+"No s'ha pogut enviar el missatge perquè s'ha produït un error desconegut en "
+"la codificació."
+
 msgid "Message was not sent because an unknown error occurred."
 msgstr ""
-"No s'ha pogut enviar el missatge perquè s'ha produït un error desconegut:"
+"No s'ha pogut enviar el missatge perquè s'ha produït un error desconegut."
 
 msgid "Unable to connect"
 msgstr "No s'ha pogut connectar"
@@ -5518,20 +5541,11 @@
 msgid "%s has removed you from his or her buddy list."
 msgstr "%s us ha suprimit de la seva llista d'amics."
 
-#, fuzzy
 msgid "Delete Buddy from Address Book?"
-msgstr "Afegeix a la llibreta d'adreces"
-
-#, fuzzy
+msgstr "Voleu suprimir l'amic de la llibreta d'adreces?"
+
 msgid "Do you want to delete this buddy from your address book as well?"
-msgstr "Voleu afegir aquest amic a la vostra llista d'amics?"
-
-#. 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 "No s'ha pogut afegir «%s»."
+msgstr "Voleu suprimir aquest amic de la vostra llista d'amics també?"
 
 msgid "The username specified is invalid."
 msgstr "El nom d'usuari especificat no és vàlid."
@@ -5539,6 +5553,9 @@
 msgid "This Hotmail account may not be active."
 msgstr "Pot ser que aquest compte Hotmail no sigui actiu."
 
+msgid "Profile URL"
+msgstr "URL del perfil"
+
 #. *< type
 #. *< ui_requirement
 #. *< flags
@@ -5575,13 +5592,8 @@
 msgid "Logging in"
 msgstr "S'està entrant"
 
-#, fuzzy, 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] ""
-"S'ha perdut la connexió al servidor (fa %d segons que no s'hi reben dades)"
-msgstr[1] ""
-"S'ha perdut la connexió al servidor (fa %d segons que no s'hi reben dades)"
+msgid "Lost connection with server"
+msgstr "S'ha perdut la connexió amb el servidor"
 
 #. Can't write _()'d strings in array initializers. Workaround.
 msgid "New mail messages"
@@ -5676,7 +5688,7 @@
 msgid "IM Friends"
 msgstr "Amics de MI"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "%d buddy was added or updated from the server (including buddies already on "
 "the server-side list)"
@@ -5684,8 +5696,8 @@
 "%d buddies were added or updated from the server (including buddies already "
 "on the server-side list)"
 msgstr[0] ""
-"S'han afegit o actualitzat %d amics al servidor (incloent els amics que ja "
-"són a la llista del servidor)"
+"S'ha afegit o actualitzat %d amic al servidor (incloent els amics que ja són "
+"a la llista del servidor)"
 msgstr[1] ""
 "S'han afegit o actualitzat %d amics al servidor (incloent els amics que ja "
 "són a la llista del servidor)"
@@ -5740,9 +5752,6 @@
 msgid "User"
 msgstr "Usuari"
 
-msgid "Profile"
-msgstr "Perfil"
-
 msgid "Headline"
 msgstr "Titular"
 
@@ -6237,9 +6246,8 @@
 msgid "AIM Protocol Plugin"
 msgstr "Connector per al protocol AIM"
 
-#, fuzzy
 msgid "ICQ UIN..."
-msgstr "ICQ UIN"
+msgstr "ICQ UIN..."
 
 #. *< type
 #. *< ui_requirement
@@ -6339,10 +6347,10 @@
 msgstr "En la llista de permès/denegat local"
 
 msgid "Warning level too high (sender)"
-msgstr ""
+msgstr "Nivell d'avís massa alt (remitent)"
 
 msgid "Warning level too high (receiver)"
-msgstr ""
+msgstr "Nivell d'avís massa alt (receptor)"
 
 msgid "User temporarily unavailable"
 msgstr "Usuari no disponible temporalment"
@@ -6446,9 +6454,8 @@
 msgid "Camera"
 msgstr "Càmera"
 
-#, fuzzy
 msgid "Screen Sharing"
-msgstr "Nom d'usuari"
+msgstr "Compartició de pantalla"
 
 #, c-format
 msgid "Free For Chat"
@@ -6697,27 +6704,30 @@
 msgstr[0] "S'ha perdut %hu missatge de %s perquè no era vàlid."
 msgstr[1] "S'han perdut %hu missatges de %s perquè no eren vàlids."
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "You missed %hu message from %s because his/her warning level is too high."
 msgid_plural ""
 "You missed %hu messages from %s because his/her warning level is too high."
-msgstr[0] "S'ha perdut %hu missatge de %s perquè ell/ella era massa dolent/a."
+msgstr[0] ""
+"Heu perdut %hu missatge de %s perquè el seu nivell d'avís és massa alt."
 msgstr[1] ""
-"S'han perdut %hu missatges de %s perquè ell/ella era massa dolent/a."
-
-#, fuzzy, c-format
+"Heu perdut %hu missatges de %s perquè el seu nivell d'avís és massa alt."
+
+#, c-format
 msgid "You missed %hu message from %s because your warning level is too high."
 msgid_plural ""
 "You missed %hu messages from %s because your warning level is too high."
-msgstr[0] "S'ha perdut %hu missatge de %s perquè sou massa dolent."
-msgstr[1] "S'han perdut %hu missatges de %s perquè sou massa dolent."
+msgstr[0] ""
+"Heu perdut %hu missatge de %s perquè el vostre nivell d'avís és massa alt."
+msgstr[1] ""
+"Heu perdut %hu missatges de %s perquè el vostre nivell d'avís és massa alt."
 
 #, c-format
 msgid "You missed %hu message from %s for an unknown reason."
 msgid_plural "You missed %hu messages from %s for an unknown reason."
-msgstr[0] "S'ha perdut %hu missatge de %s per motius desconeguts."
-msgstr[1] "S'han perdut %hu missatges de %s per motius desconeguts."
+msgstr[0] "Heu perdut %hu missatge de %s per motius desconeguts."
+msgstr[1] "Heu perdut %hu missatges de %s per motius desconeguts."
 
 #. Data is assumed to be the destination sn
 #, c-format
@@ -6741,6 +6751,9 @@
 msgid "Member Since"
 msgstr "Membre des de"
 
+msgid "Profile"
+msgstr "Perfil"
+
 msgid "Your AIM connection may be lost."
 msgstr "La vostra connexió d'AIM es pot perdre."
 
@@ -6928,11 +6941,9 @@
 "d'usuari han de ser adreces de correu vàlides, o començar amb una lletra i "
 "contenir només lletres, nombres i espais, o només nombres."
 
-#, fuzzy
 msgid "Unable to Add"
 msgstr "No s'ha pogut afegir"
 
-#, fuzzy
 msgid "Unable to Retrieve Buddy List"
 msgstr "No s'ha pogut obtenir la llista d'amics"
 
@@ -7126,8 +7137,9 @@
 "per a la transferència de fitxers\n"
 "(és més lent, però acostuma a funcionar)"
 
+# FIXME: entrades/registres?
 msgid "Allow multiple simultaneous logins"
-msgstr ""
+msgstr "Permet diverses entrades simultànies"
 
 #, c-format
 msgid "Asking %s to connect to us at %s:%hu for Direct IM."
@@ -7230,16 +7242,14 @@
 msgid "Other"
 msgstr "Altres"
 
-#, fuzzy
 msgid "Visible"
-msgstr "Invisible"
-
-msgid "Firend Only"
-msgstr ""
-
-#, fuzzy
+msgstr "Visible"
+
+msgid "Friend Only"
+msgstr "Només amic"
+
 msgid "Private"
-msgstr "Privadesa"
+msgstr "Privat"
 
 msgid "QQ Number"
 msgstr "Número QQ"
@@ -7256,9 +7266,8 @@
 msgid "Phone Number"
 msgstr "Número de telèfon"
 
-#, fuzzy
 msgid "Authorize adding"
-msgstr "Voleu autoritzar l'amic?"
+msgstr "Autoritzar que us afegeixin"
 
 msgid "Cellphone Number"
 msgstr "Número de mòbil"
@@ -7266,131 +7275,110 @@
 msgid "Personal Introduction"
 msgstr "Introducció personal"
 
-#, fuzzy
 msgid "City/Area"
-msgstr "Ciutat"
-
-#, fuzzy
+msgstr "Ciutat/Àrea"
+
 msgid "Publish Mobile"
-msgstr "Mòbil personal"
-
-#, fuzzy
+msgstr "Publica el mòbil"
+
 msgid "Publish Contact"
-msgstr "Posa un àlies al contacte"
+msgstr "Publica el contacte"
 
 msgid "College"
 msgstr "Col·legi"
 
-#, fuzzy
 msgid "Horoscope"
-msgstr "Signe de l'horòscop"
-
-#, fuzzy
+msgstr "Horòscop"
+
 msgid "Zodiac"
-msgstr "Signe del zodíac"
-
-#, fuzzy
+msgstr "Zodíac"
+
 msgid "Blood"
-msgstr "Blocat"
-
-#, fuzzy
+msgstr "Sang"
+
 msgid "True"
-msgstr "Taure"
-
-#, fuzzy
+msgstr "Cert"
+
 msgid "False"
-msgstr "Ha fallat"
-
-#, fuzzy
+msgstr "Fals"
+
 msgid "Modify Contact"
-msgstr "Modifica el compte"
-
-#, fuzzy
+msgstr "Modifica el contacte"
+
 msgid "Modify Address"
-msgstr "Adreça de casa"
-
-#, fuzzy
+msgstr "Modifica l'adreça"
+
 msgid "Modify Extended Information"
-msgstr "Modifica la meva informació"
-
-#, fuzzy
+msgstr "Modifica la informació estesa"
+
 msgid "Modify Information"
-msgstr "Modifica la meva informació"
+msgstr "Modifica la informació"
 
 msgid "Update"
 msgstr "Actualitza"
 
-#, fuzzy
 msgid "Could not change buddy information."
-msgstr "Introduïu informació sobre l'amic."
-
-#, c-format
-msgid "%d needs Q&A"
-msgstr ""
-
-#, fuzzy
-msgid "Add buddy Q&A"
-msgstr "Afegeix un amic"
-
-#, fuzzy
-msgid "Input answer here"
-msgstr "Introduïu la sol·licitud aquí"
+msgstr "No s'ha pogut canviar la informació l'amic."
+
+#, c-format
+msgid "%u requires verification"
+msgstr "Cal verificació per a %u"
+
+# Nota: títol de finestra
+msgid "Add buddy question"
+msgstr "Afegir una pregunta"
+
+msgid "Enter answer here"
+msgstr "Introduïu la resposta aquí"
 
 msgid "Send"
 msgstr "Envia"
 
-#, fuzzy
 msgid "Invalid answer."
-msgstr "La contrasenya no és vàlida"
+msgstr "La resposta no és vàlida"
 
 msgid "Authorization denied message:"
 msgstr "Missatge de denegació de l'autorització:"
 
-#, fuzzy
-msgid "Sorry, You are not my style."
-msgstr "Em sap greu, no sou el meu tipus..."
-
-#, fuzzy, c-format
-msgid "%d needs authentication"
-msgstr "L'usuari %d necessita autenticació"
-
-#, fuzzy
+msgid "Sorry, you're not my style."
+msgstr "Em sap greu, no sou el meu tipus."
+
+#, c-format
+msgid "%u needs authorization"
+msgstr "Cal autorització per a %u"
+
+# Nota: títol de finestra (josep)
 msgid "Add buddy authorize"
-msgstr "Voleu afegir l'amic a la llista?"
-
-msgid "Input request here"
+msgstr "Autorització per a afegir un amic"
+
+msgid "Enter request here"
 msgstr "Introduïu la sol·licitud aquí"
 
 msgid "Would you be my friend?"
 msgstr "Voleu ser el meu amic?"
 
-#, fuzzy
 msgid "QQ Buddy"
-msgstr "Amic"
-
-#, fuzzy
+msgstr "Amic QQ"
+
 msgid "Add buddy"
 msgstr "Afegeix un amic"
 
-#, fuzzy
 msgid "Invalid QQ Number"
-msgstr "El nom de la cara QQ no és vàlida"
-
-#, fuzzy
+msgstr "El nombre QQ no és vàlid"
+
 msgid "Failed sending authorize"
-msgstr "Autoritzeu-me, si us plau."
-
-#, fuzzy, c-format
-msgid "Failed removing buddy %d"
-msgstr "No s'ha pogut suprimir l'amic"
-
-#, fuzzy, c-format
+msgstr "No s'ha pogut enviar l'autorizació"
+
+#, c-format
+msgid "Failed removing buddy %u"
+msgstr "No s'ha pogut suprimir l'amic %u"
+
+#, c-format
 msgid "Failed removing me from %d's buddy list"
-msgstr "Suprimeix l'usuari de la llista d'amics"
-
-#, fuzzy
+msgstr "No us heu pogut suprimir de la llista d'amics de %d"
+
 msgid "No reason given"
-msgstr "No s'ha indicat cap motiu."
+msgstr "No s'ha indicat cap motiu"
 
 #. only need to get value
 #, c-format
@@ -7400,9 +7388,9 @@
 msgid "Would you like to add him?"
 msgstr "Voleu afegir-lo?"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Rejected by %s"
-msgstr "S'ha connectat a %s"
+msgstr "Rebutjat per %s"
 
 #, c-format
 msgid "Message: %s"
@@ -7417,82 +7405,73 @@
 msgid "QQ Qun"
 msgstr "QQ Qun"
 
-#, fuzzy
 msgid "Please enter Qun number"
-msgstr "Introduïu un nou nom per a %s"
-
-#, fuzzy
+msgstr "Introduïu el número Qun"
+
 msgid "You can only search for permanent Qun\n"
-msgstr "Només podeu cercar grups QQ permanents\n"
-
-#, fuzzy
+msgstr "Només podeu cercar Quns permanents\n"
+
+msgid "(Invalid UTF-8 string)"
+msgstr "(No és una cadena UTF-8 vàlida)"
+
 msgid "Not member"
 msgstr "No en sóc membre"
 
-#, fuzzy
 msgid "Member"
-msgstr "Membre des de"
-
-#, fuzzy
+msgstr "Membre"
+
 msgid "Requesting"
-msgstr "Diàleg de sol·licitud"
-
-#, fuzzy
+msgstr "Demanant"
+
 msgid "Admin"
-msgstr "Alerta d'administració"
-
-#, fuzzy
+msgstr "Administrador"
+
 msgid "Notice"
-msgstr "Nota"
-
-#, fuzzy
+msgstr "Avís"
+
 msgid "Detail"
 msgstr "Detalls"
 
 msgid "Creator"
 msgstr "Creador"
 
-#, fuzzy
 msgid "About me"
-msgstr "Quant al %s"
-
-#, fuzzy
+msgstr "Quant a mi"
+
 msgid "Category"
-msgstr "Error en el xat"
-
-#, fuzzy
+msgstr "Categoria"
+
 msgid "The Qun does not allow others to join"
-msgstr "Aquest grup no permet que s'hi afegeixi ningú"
-
-#, fuzzy
+msgstr "Aquest Qun no permet que s'hi afegeixi ningú"
+
 msgid "Join QQ Qun"
-msgstr "Entra a un xat"
-
-#, c-format
-msgid "Successfully joined Qun %s (%d)"
-msgstr ""
-
-#, fuzzy
+msgstr "Entra al Qun QQ"
+
+msgid "Input request here"
+msgstr "Introduïu la sol·licitud aquí"
+
+#, c-format
+msgid "Successfully joined Qun %s (%u)"
+msgstr "S'ha entrat al Qun %s (%u)"
+
 msgid "Successfully joined Qun"
-msgstr "Heu modificat amb èxit el membre del Qun"
-
-#, c-format
-msgid "Qun %d denied to join"
-msgstr ""
+msgstr "S'ha entrat al Qun"
+
+#, c-format
+msgid "Qun %u denied from joining"
+msgstr "No se us ha permès entrar al Qun %u"
 
 msgid "QQ Qun Operation"
 msgstr "Operació Qun QQ"
 
-#, fuzzy
 msgid "Failed:"
-msgstr "Ha fallat"
-
-msgid "Join Qun, Unknow Reply"
-msgstr ""
-
-#, fuzzy
+msgstr "Ha fallat:"
+
+msgid "Join Qun, Unknown Reply"
+msgstr "Resposta desconeguda en entrar al Qun"
+
 msgid "Quit Qun"
-msgstr "QQ Qun"
+msgstr "Surt del Qun"
 
 msgid ""
 "Note, if you are the creator, \n"
@@ -7501,51 +7480,47 @@
 "Nota, si en sou el creador, \n"
 "aquesta operació suprimirà aquest Qun."
 
-#, fuzzy
-msgid "Sorry, you are not our style ..."
-msgstr "Em sap greu, no sou el meu tipus..."
-
-#, fuzzy
-msgid "Successfully changed Qun member"
-msgstr "Heu modificat amb èxit el membre del Qun"
-
-#, fuzzy
+msgid "Sorry, you are not our style"
+msgstr "Em sap greu, no sou el meu tipus"
+
+msgid "Successfully changed Qun members"
+msgstr "S'ha canviat els membres del Qun"
+
 msgid "Successfully changed Qun information"
-msgstr "Heu modificat amb èxit la informació del Qun"
+msgstr "S'ha canviat la iformació del Qun correctament"
 
 msgid "You have successfully created a Qun"
 msgstr "Heu creat un Qun"
 
-#, fuzzy
-msgid "Would you like to set detailed information now?"
-msgstr "Voleu establir-la els detalls del Qun ara?"
+msgid "Would you like to set up detailed information now?"
+msgstr "Voleu establir informació detallada ara?"
 
 msgid "Setup"
-msgstr "Instal·lació"
-
-#, fuzzy, c-format
-msgid "%d requested to join Qun %d for %s"
-msgstr "L'usuari %d ha sol·licitat unir-se al grup %d"
-
-#, fuzzy, c-format
-msgid "%d request to join Qun %d"
-msgstr "L'usuari %d ha sol·licitat unir-se al grup %d"
-
-#, fuzzy, c-format
-msgid "Failed to join Qun %d, operated by admin %d"
-msgstr "No s'ha pogut entrar al xat de l'amic."
-
-#, 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 "Suprimeix l'amic"
-
-#, c-format
-msgid "<b>New buddy %d joined.</b>"
-msgstr ""
+msgstr "Configuració"
+
+#, c-format
+msgid "%u requested to join Qun %u for %s"
+msgstr "%u ha sol·licitat unir-se al Qun %u per %s"
+
+#, c-format
+msgid "%u request to join Qun %u"
+msgstr "%u ha sol·licitat unir-se al Qun %u"
+
+#, c-format
+msgid "Failed to join Qun %u, operated by admin %u"
+msgstr "No s'ha pogut entrar al Qun %u, administrat per %u"
+
+#, c-format
+msgid "<b>Joining Qun %u is approved by admin %u for %s</b>"
+msgstr "<b>L'administrador %2$u us ha permès unir-vos al Qun %1$u per %3$s</b>"
+
+#, c-format
+msgid "<b>Removed buddy %u.</b>"
+msgstr "<b>S'ha suprimit l'amic %u.</b>"
+
+#, c-format
+msgid "<b>New buddy %u joined.</b>"
+msgstr "<b>El nou amic %u ha entrat.</b>"
 
 #, c-format
 msgid "Unknown-%d"
@@ -7555,10 +7530,10 @@
 msgstr "Nivell"
 
 msgid " VIP"
-msgstr ""
+msgstr " VIP"
 
 msgid " TCP"
-msgstr ""
+msgstr " TCP"
 
 #, fuzzy
 msgid " FromMobile"
@@ -7568,128 +7543,122 @@
 msgid " BindMobile"
 msgstr "Mòbil"
 
-#, fuzzy
 msgid " Video"
-msgstr "Vídeo en directe"
-
-#, fuzzy
+msgstr " Vídeo"
+
 msgid " Zone"
-msgstr "Cap"
-
+msgstr " Zona"
+
+# Nota: només apareix si es defineix DEBUG
 msgid "Flag"
-msgstr ""
-
+msgstr "Bandera"
+
+# Nota: només apareix si es defineix DEBUG
 msgid "Ver"
-msgstr ""
+msgstr "Ver"
 
 msgid "Invalid name"
 msgstr "QQ: El nom d'usuari no és vàlid"
 
-#, fuzzy
 msgid "Select icon..."
-msgstr "Selecciona una carpeta..."
-
-#, fuzzy, c-format
+msgstr "Selecciona una icona..."
+
+#, c-format
 msgid "<b>Login time</b>: %d-%d-%d, %d:%d:%d<br>\n"
-msgstr "<b>Temps de connexió</b>: %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Temps d'entrada</b>: %d-%d-%d, %d:%d:%d<br>\n"
+
+#, c-format
 msgid "<b>Total Online Buddies</b>: %d<br>\n"
-msgstr "<b>En línia ara</b>: %d<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Amic en línia</b>: %d<br>\n"
+
+#, c-format
 msgid "<b>Last Refresh</b>: %d-%d-%d, %d:%d:%d<br>\n"
-msgstr "<b>Actualitzat per darrer cop</b>: %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Actualitzat per darrer cop</b>: %d-%d-%d, %d:%d:%d<br>\n"
+
+#, c-format
 msgid "<b>Server</b>: %s<br>\n"
-msgstr "<b>ID del servidor:</b> %s: %d<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Servidor</b>: %s<br>\n"
+
+#, c-format
 msgid "<b>Client Tag</b>: %s<br>\n"
-msgstr "<b>Temps de connexió</b>: %s<br>\n"
+msgstr "<b>Etiqueta del client</b>: %s<br>\n"
 
 #, c-format
 msgid "<b>Connection Mode</b>: %s<br>\n"
 msgstr "<b>Mode de connexió</b>: %s<br>\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "<b>My Internet IP</b>: %s:%d<br>\n"
-msgstr "<b>Adreça IP:</b> %s<br>"
-
-#, fuzzy, c-format
+msgstr "<b>La meva adreça IP</b>: %s:%d<br>\n"
+
+#, c-format
 msgid "<b>Sent</b>: %lu<br>\n"
-msgstr "<b>En línia ara</b>: %d<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Enviats</b>: %lu<br>\n"
+
+#, c-format
 msgid "<b>Resend</b>: %lu<br>\n"
-msgstr "<b>Usuari:</b> %s<br>"
-
-#, fuzzy, c-format
+msgstr "<b>Reenviats</b>: %lu<br>\n"
+
+#, c-format
 msgid "<b>Lost</b>: %lu<br>\n"
-msgstr "<b>%s:</b> %s<br>"
-
-#, fuzzy, c-format
+msgstr "<b>Perduts</b>: %lu<br>\n"
+
+#, c-format
 msgid "<b>Received</b>: %lu<br>\n"
-msgstr "<b>Actualitzat per darrer cop</b>: %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Rebuta</b>: %lu<br>\n"
+
+#, c-format
 msgid "<b>Received Duplicate</b>: %lu<br>\n"
-msgstr "<b>La meva IP pública:</b> %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Rebuts duplicats</b>: %lu<br>\n"
+
+#, c-format
 msgid "<b>Time</b>: %d-%d-%d, %d:%d:%d<br>\n"
-msgstr "<b>Temps de connexió</b>: %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Temps</b>: %d-%d-%d, %d:%d:%d<br>\n"
+
+#, c-format
 msgid "<b>IP</b>: %s<br>\n"
-msgstr "<b>ID del servidor:</b> %s: %d<br>\n"
+msgstr "<b>IP</b>: %s<br>\n"
 
 msgid "Login Information"
 msgstr "Informació de la connexió"
 
-#, fuzzy
 msgid "<p><b>Original Author</b>:<br>\n"
-msgstr "<b>Usuari extern</b><br>"
+msgstr "<p><b>Autor original</b>:<br>\n"
 
 msgid "<p><b>Code Contributors</b>:<br>\n"
-msgstr ""
-
-#, fuzzy
+msgstr "<p><b>Col·laboradors del codi</b>:<br>\n"
+
 msgid "<p><b>Lovely Patch Writers</b>:<br>\n"
-msgstr "<b>Actualitzat per darrer cop</b>: %s<br>\n"
-
-#, fuzzy
+msgstr "<p><b>Encantadors apedaçadors (de codi)</b>:<br>\n"
+
 msgid "<p><b>Acknowledgement</b>:<br>\n"
-msgstr "<b>En línia ara</b>: %d<br>\n"
-
+msgstr "<p><b>Reconeixement</b>:<br>\n"
+
+# FIXME: ush... traducció lliure... 
 msgid "<p><i>And, all the boys in the backroom...</i><br>\n"
-msgstr ""
+msgstr "<p><i>I tothom que ho ha fet possible...<i><br>\n"
 
 msgid "<i>Feel free to join us!</i> :)"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "About OpenQ r%s"
-msgstr "Quant al %s"
-
-#, fuzzy
+msgstr "<i>No dubteu a col·laborar amb nosaltres!</i> :)"
+
+#, c-format
+msgid "About OpenQ %s"
+msgstr "Quant a l'OpenQ %s"
+
 msgid "Change Icon"
-msgstr "Desa la icona"
+msgstr "Canvia la icona"
 
 msgid "Change Password"
 msgstr "Canvia la contrasenya"
 
-#, fuzzy
 msgid "Account Information"
-msgstr "Informació de la connexió"
+msgstr "Informació del compte"
 
 msgid "Update all QQ Quns"
-msgstr ""
-
-#, fuzzy
+msgstr "Actualitza tots els Quns QQ"
+
 msgid "About OpenQ"
-msgstr "Quant al %s"
+msgstr "Quant a l'OpenQ"
 
 #. *< type
 #. *< ui_requirement
@@ -7701,116 +7670,102 @@
 #. *< version
 #. *  summary
 #. *  description
-#, fuzzy
 msgid "QQ Protocol Plugin"
 msgstr "Connector per al protocol QQ"
 
-#, fuzzy
 msgid "Auto"
-msgstr "Autor"
-
-#, fuzzy
+msgstr "Auto"
+
 msgid "Select Server"
-msgstr "Seleccioneu un usuari"
+msgstr "Seleccioneu un servidor"
 
 msgid "QQ2005"
-msgstr ""
+msgstr "QQ2005"
 
 msgid "QQ2007"
-msgstr ""
+msgstr "QQ2007"
 
 msgid "QQ2008"
-msgstr ""
-
-#. #endif
-#, fuzzy
+msgstr "QQ2008"
+
 msgid "Connect by TCP"
 msgstr "Connecta amb TCP"
 
-#, fuzzy
 msgid "Show server notice"
-msgstr "Mostra menys opcions"
-
-#, fuzzy
+msgstr "Mostra els avisos del servidor"
+
 msgid "Show server news"
-msgstr "Mostra menys opcions"
-
-#, fuzzy
+msgstr "Mostra les notícies del servidor"
+
+# FIXME: keep alive -> permanència
 msgid "Keep alive interval (seconds)"
-msgstr "Error de permanència"
-
-#, fuzzy
+msgstr "Interval de permanència (en segons)"
+
 msgid "Update interval (seconds)"
-msgstr "Error de permanència"
-
-#, fuzzy
-msgid "Can not decrypt server reply"
-msgstr "No s'ha pogut obtenir informació del servidor"
-
-#, fuzzy
-msgid "Can not decrypt get server reply"
-msgstr "No s'ha pogut obtenir informació del servidor"
+msgstr "Interval d'actualització (en segons)"
+
+msgid "Cannot decrypt server reply"
+msgstr "No es pot desxifrar la resposta del servidor"
 
 #, c-format
 msgid "Failed requesting token, 0x%02X"
-msgstr ""
-
-#, fuzzy, c-format
+msgstr "S'ha produït un error en sol·licitar el testimoni, 0x%02X"
+
+#, c-format
 msgid "Invalid token len, %d"
-msgstr "El títol no és vàlid"
+msgstr "La longiud del testimoni no és vàlida, %d"
 
 #. extend redirect used in QQ2006
 msgid "Redirect_EX is not currently supported"
-msgstr ""
+msgstr "Redirect_EX no està implementat"
 
 #. need activation
 #. need activation
 #. need activation
-#, fuzzy
 msgid "Activation required"
-msgstr "Cal registre"
-
-#, c-format
-msgid "Unknow reply code when login (0x%02X)"
-msgstr ""
-
-msgid "Keep alive error"
-msgstr "Error de permanència"
-
-#, fuzzy
-msgid "Requesting captcha ..."
-msgstr "S'està cridant l'atenció de %s..."
-
-msgid "Checking code of captcha ..."
-msgstr ""
-
-msgid "Failed captcha verify"
-msgstr ""
-
-#, fuzzy
+msgstr "Cal activació"
+
+#, c-format
+msgid "Unknown reply code when logging in (0x%02X)"
+msgstr "No s'ha reconegut el codi de resposta en entrar (0x%02X)"
+
+msgid "Could not decrypt server reply"
+msgstr "No s'ha pogut desxifrar la resposta del servidor"
+
+# FIXME: captcha
+msgid "Requesting captcha"
+msgstr "S'està sol·licitant un capcha"
+
+msgid "Checking captcha"
+msgstr "S'està comprovant el captcha"
+
+msgid "Failed captcha verification"
+msgstr "Ha fallat la verificació del captcha"
+
 msgid "Captcha Image"
-msgstr "Desa imatge"
-
-#, fuzzy
+msgstr "Imatge captcha"
+
 msgid "Enter code"
-msgstr "Introduïu la contrasenya"
-
-msgid "QQ Captcha Verifing"
-msgstr ""
-
-#, fuzzy
+msgstr "Introduïu el codi"
+
+msgid "QQ Captcha Verification"
+msgstr "Verificació del captcha QQ"
+
 msgid "Enter the text from the image"
-msgstr "Introduïu el nom del grup"
-
-#, c-format
-msgid "Unknow reply code when checking password (0x%02X)"
-msgstr ""
-
-#, c-format
-msgid ""
-"Unknow reply code when login (0x%02X):\n"
+msgstr "Introduïu el text de la imatge"
+
+#, c-format
+msgid "Unknown reply when checking password (0x%02X)"
+msgstr ""
+"No s'ha reconegut el codi de resposta en comprovar la contrasenya (0x%02X)"
+
+#, c-format
+msgid ""
+"Unknown reply code when logging in (0x%02X):\n"
 "%s"
 msgstr ""
+"No s'ha reconegut el codi de resposta en entrar (0x%02X):\n"
+"%s"
 
 #. we didn't successfully connect. tdt->toc_fd is valid here
 msgid "Unable to connect."
@@ -7819,14 +7774,6 @@
 msgid "Socket error"
 msgstr "Error del sòcol"
 
-#, fuzzy, c-format
-msgid ""
-"Lost connection with server:\n"
-"%d, %s"
-msgstr ""
-"S'ha perdut la connexió amb el servidor:\n"
-"%s"
-
 msgid "Unable to read from socket"
 msgstr "No s'ha pogut llegir el sòcol"
 
@@ -7836,77 +7783,74 @@
 msgid "Connection lost"
 msgstr "S'ha perdut la connexió"
 
-#, fuzzy
-msgid "Get server ..."
-msgstr "Estableix informació d'usuari..."
-
-#, fuzzy
-msgid "Request token"
-msgstr "Petició denegada"
+msgid "Getting server"
+msgstr "S'està obtenint el servidor"
+
+msgid "Requesting token"
+msgstr "S'està sol·licitant un testimoni"
 
 msgid "Couldn't resolve host"
 msgstr "No s'ha pogut obtenir l'adreça de l'ordinador"
 
-#, fuzzy
 msgid "Invalid server or port"
-msgstr "El nom d'usuari o la contrasenya no són vàlides"
-
-#, fuzzy
-msgid "Connecting server ..."
-msgstr "Servidor al qual connectar-se"
-
-#, fuzzy
+msgstr "El servidor o el port no són vàlids"
+
+msgid "Connecting to server"
+msgstr "S'està connectant al servidor"
+
 msgid "QQ Error"
-msgstr "Error del QQid"
-
-msgid "Failed to send IM."
-msgstr "No s'ha pogut enviar la MI."
-
-#, fuzzy, c-format
+msgstr "Error del QQ"
+
+#, c-format
 msgid ""
 "Server News:\n"
 "%s\n"
 "%s\n"
 "%s"
-msgstr "Servidor repetidor d'ICQ"
-
-#, fuzzy, c-format
+msgstr ""
+"Notícies del servidor:\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 "Instruccions del servidor: %s"
-
-msgid "Unknow SERVER CMD"
-msgstr ""
+msgstr ""
+"Avís del servidor de %s: \n"
+"%s"
+
+msgid "Unknown SERVER CMD"
+msgstr "Ordre del servidor desconeguda"
 
 #, c-format
 msgid ""
 "Error reply of %s(0x%02X)\n"
-"Room %d, reply 0x%02X"
-msgstr ""
-
-#, fuzzy
+"Room %u, reply 0x%02X"
+msgstr ""
+"Resposta d'error de %s(0x%02X)\n"
+"Sala %u, resposta 0x%02X"
+
 msgid "QQ Qun Command"
-msgstr "Ordre"
-
-#, c-format
-msgid "Not a member of room \"%s\"\n"
-msgstr ""
-
-msgid "Can not decrypt login reply"
-msgstr ""
-
-#, fuzzy
-msgid "Unknow LOGIN CMD"
-msgstr "Motiu desconegut"
-
-#, fuzzy
-msgid "Unknow CLIENT CMD"
-msgstr "Motiu desconegut"
+msgstr "Ordre QQ Qun"
+
+msgid "Could not decrypt login reply"
+msgstr "No s'ha pogut desxifrar la resposta d'entrada"
+
+msgid "Unknown LOGIN CMD"
+msgstr "Ordre d'entrada desconeguda"
+
+msgid "Unknown CLIENT CMD"
+msgstr "Ordre de client desconeguda"
 
 #, c-format
 msgid "%d has declined the file %s"
@@ -8931,9 +8875,9 @@
 msgid "Error loading SILC key pair"
 msgstr "S'ha produït un error en carregar el parell de claus claus SILC"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Download %s: %s"
-msgstr "Usuaris a %s: %s"
+msgstr "Baixada %s: %s"
 
 msgid "Your Current Mood"
 msgstr "El vostre estat d'ànim actual"
@@ -9195,7 +9139,8 @@
 msgid "Private Key file"
 msgstr "Fitxer de la clau privada"
 
-# FIXME
+# El recull diu "xifra", però aquí no es refereix a una xifra sinó a un
+# mètode de xifratge
 msgid "Cipher"
 msgstr "Codi"
 
@@ -9779,9 +9724,8 @@
 msgid "doodle: Request user to start a Doodle session"
 msgstr "doodle: fa una petició a l'usuari per iniciar una sessió Doodle"
 
-#, fuzzy
 msgid "Yahoo ID..."
-msgstr "ID de Yahoo!"
+msgstr "ID de Yahoo..."
 
 #. *< type
 #. *< ui_requirement
@@ -9891,16 +9835,9 @@
 msgid "Last Update"
 msgstr "Darrera actualització"
 
-#, c-format
-msgid "User information for %s unavailable"
-msgstr "Dades de l'usuari %s no disponibles"
-
-msgid ""
-"Sorry, this profile seems to be in a language or format that is not "
-"supported at this time."
-msgstr ""
-"Disculpeu, aquest perfil deu estar en una llengua que actualment no està "
-"implementada."
+msgid ""
+"This profile is in a language or format that is not supported at this time."
+msgstr "Aquest perfil és en una llengua que actualment no està implementada."
 
 msgid ""
 "Could not retrieve the user's profile. This most likely is a temporary "
@@ -10153,11 +10090,11 @@
 
 #, c-format
 msgid "Requesting %s's attention..."
-msgstr "S'està cridant l'atenció de %s..."
+msgstr "S'està reclamant l'atenció de %s..."
 
 #, c-format
 msgid "%s has requested your attention!"
-msgstr "%s us ha cridat l'atenció!"
+msgstr "%s us ha demanat l'atenció!"
 
 #. *
 #. * A wrapper for purple_request_action() that uses @c Yes and @c No buttons.
@@ -10203,21 +10140,18 @@
 msgstr "Voleu acceptar la invitació al xat?"
 
 #. Shortcut
-#, fuzzy
 msgid "Shortcut"
-msgstr "Ordena"
-
-#, fuzzy
+msgstr "Drecera"
+
 msgid "The text-shortcut for the smiley"
-msgstr "Tema de la drecera de text de GTK+"
+msgstr "La drecera de text per a l'emoticona"
 
 #. Stored Image
-#, fuzzy
 msgid "Stored Image"
-msgstr "Desa imatge"
+msgstr "Imatge desada"
 
 msgid "Stored Image. (that'll have to do for now)"
-msgstr ""
+msgstr "Imatge desada. (de moment hem de passar amb això)"
 
 msgid "SSL Connection Failed"
 msgstr "No s'ha pogut connectar amb SSL"
@@ -10347,9 +10281,11 @@
 msgid "Unable to connect to %s"
 msgstr "No s'ha pogut connectar a %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Error reading from %s: response too long (%d bytes limit)"
-msgstr "S'ha produït un error en llegir de %s: %s"
+msgstr ""
+"S'ha produït un error en llegir de %s: la resposta és massa llarga (%d bytes "
+"de límit)"
 
 #, c-format
 msgid ""
@@ -10400,9 +10336,9 @@
 msgstr "S'ha refusat la connexió."
 
 #. 10048
-#, fuzzy, c-format
+#, c-format
 msgid "Address already in use."
-msgstr "Aquest nom de xat ja existeix"
+msgstr "Aquesta adreça ja s'està fent servir"
 
 msgid "Internet Messenger"
 msgstr "Missatger d'Internet"
@@ -10511,9 +10447,8 @@
 msgid "_Basic"
 msgstr "_Bàsic"
 
-#, fuzzy
 msgid "Create _this new account on the server"
-msgstr "Crea aquest compte nou al servidor"
+msgstr "Crea _aquest compte nou al servidor"
 
 msgid "_Advanced"
 msgstr "_Avançat"
@@ -10524,7 +10459,7 @@
 msgid "Protocol"
 msgstr "Protocol"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "<span size='larger' weight='bold'>Welcome to %s!</span>\n"
 "\n"
@@ -10539,12 +10474,12 @@
 "<span size='larger' weight='bold'>Benvingut al %s!</span>\n"
 "\n"
 "No teniu cap compte de MI configurat. Per a connectar-vos amb el %s premeu "
-"el botó <b>Afegeix</b> de sota, i configureu el vostre primer compte. Si "
-"voleu que el %s es connecti amb més comptes de MI, torneu a prémer "
-"<b>Afegeix</b> fins a configurar-los tots.\n"
+"el botó <b>Afegeix</b> d'aquí sota, i configureu el vostre primer compte. Si "
+"voleu que el %s es connecti amb més comptes de missatgeria instantània (MI), "
+"torneu a prémer <b>Afegeix</b> fins a configurar-los tots.\n"
 "\n"
 "Podeu tornar a aquesta finestra per afegir, editar o suprimir comptes, a "
-"partir del menú <b>Comptes->Afegeix/Edita</b> de la finestra de la llista "
+"partir del menú <b>Comptes->Gestiona els comptes</b> a finestra de la llista "
 "d'amics."
 
 #, c-format
@@ -10613,9 +10548,8 @@
 msgid "_Remove"
 msgstr "Sup_rimeix"
 
-#, fuzzy
 msgid "Set Custom Icon"
-msgstr "Estableix una icona personalitzada..."
+msgstr "Estableix una icona personalitzada"
 
 msgid "Remove Custom Icon"
 msgstr "Suprimeix la icona personalitzada"
@@ -10717,9 +10651,8 @@
 msgid "/_Accounts"
 msgstr "/_Comptes"
 
-#, fuzzy
 msgid "/Accounts/Manage Accounts"
-msgstr "/Comptes/Gestió"
+msgstr "/Comptes/Gestió de comptes"
 
 # Accelerador a la "n" com en la resta de programes
 #. Tools
@@ -10736,14 +10669,13 @@
 msgstr "/Eines/_Connectors"
 
 msgid "/Tools/Pr_eferences"
-msgstr "/Eines/Pr_eferències"
+msgstr "/Eines/Preferè_ncies"
 
 msgid "/Tools/Pr_ivacy"
 msgstr "/Eines/_Privadesa"
 
-#, fuzzy
 msgid "/Tools/Smile_y"
-msgstr "/Eines/_Absent"
+msgstr "/Eines/Em_oticona"
 
 msgid "/Tools/_File Transfers"
 msgstr "/Eines/Transferència de _fitxers"
@@ -10904,7 +10836,7 @@
 msgstr "/Comptes"
 
 #. Translators: Please maintain the use of -> and <- to refer to menu heirarchy
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "<span weight='bold' size='larger'>Welcome to %s!</span>\n"
 "\n"
@@ -10915,9 +10847,9 @@
 "<span weight='bold' size='larger'>Benvingut al %s!</span>\n"
 "\n"
 "No teniu cap compte habilitat. Podeu habilitar comptes de MI des del menú "
-"<b>Comptes->Gestió</b> de la finestra de <b>Comptes</b>. Quan hagueu "
-"habilitat algun compte, podreu connectar-vos, establir el vostre estat, i "
-"parlar amb amics."
+"<b>Comptes->Gestió de comptes</b> de la finestra de <b>Comptes</b>. Quan "
+"hagueu habilitat algun compte podreu connectar-vos-hi, establir el vostre "
+"estat, i parlar amb amics."
 
 #. set the Show Offline Buddies option. must be done
 #. * after the treeview or faceprint gets mad. -Robot101
@@ -10970,9 +10902,8 @@
 msgid "Auto_join when account becomes online."
 msgstr "Entra _automàticament quant el compte estigui connectat."
 
-#, fuzzy
 msgid "_Remain in chat after window is closed."
-msgstr "_Oculta el xat quan la finestra es tanqui."
+msgstr "_Continua al xat quan la finestra es tanqui."
 
 msgid "Please enter the name of the group to be added."
 msgstr "Introduïu el nom del grup que vulgueu afegir."
@@ -11348,23 +11279,22 @@
 msgid "Fatal Error"
 msgstr "Error fatal"
 
+# Fixme
 msgid "bug master"
-msgstr ""
-
-#, fuzzy
+msgstr "bug master"
+
 msgid "artist"
-msgstr "Artista"
+msgstr "artista"
 
 #. feel free to not translate this
 msgid "Ka-Hing Cheung"
-msgstr ""
+msgstr "Ka-Hing Cheung"
 
 msgid "support"
 msgstr "suport"
 
-#, fuzzy
 msgid "webmaster"
-msgstr "desenvolupador i mantenidor de la pàgina web"
+msgstr "administrador del web"
 
 msgid "Senior Contributor/QA"
 msgstr "Col·laborador veterà/CQ"
@@ -11387,7 +11317,7 @@
 msgstr "suport/CQ"
 
 msgid "XMPP"
-msgstr ""
+msgstr "XMPP"
 
 msgid "original author"
 msgstr "autor original"
@@ -11466,9 +11396,8 @@
 msgid "French"
 msgstr "Francès"
 
-#, fuzzy
 msgid "Irish"
-msgstr "Kurd"
+msgstr "Irlandès"
 
 msgid "Galician"
 msgstr "Gallec"
@@ -11537,7 +11466,7 @@
 msgstr "Noruec (Nynorsk)"
 
 msgid "Occitan"
-msgstr ""
+msgstr "Occità"
 
 msgid "Punjabi"
 msgstr "Punjabi"
@@ -11779,45 +11708,35 @@
 msgid "Right-click for more unread messages...\n"
 msgstr "Feu clic amb el botó principal per a més missatges per llegir...\n"
 
-#, fuzzy
 msgid "_Change Status"
-msgstr "Canvia d'estat"
-
-#, fuzzy
+msgstr "_Canvia d'estat"
+
 msgid "Show Buddy _List"
-msgstr "Mostra la llista d'amics"
-
-#, fuzzy
+msgstr "Mostra la _llista d'amics"
+
 msgid "_Unread Messages"
-msgstr "Missatges sense llegir"
-
-#, fuzzy
+msgstr "Missatges _sense llegir"
+
 msgid "New _Message..."
-msgstr "Missatge nou..."
-
-#, fuzzy
+msgstr "_Missatge nou..."
+
 msgid "_Accounts"
-msgstr "/_Comptes"
-
-#, fuzzy
+msgstr "_Comptes"
+
 msgid "Plu_gins"
-msgstr "Connectors"
-
-#, fuzzy
+msgstr "Co_nnectors"
+
 msgid "Pr_eferences"
-msgstr "Preferències"
-
-#, fuzzy
+msgstr "Pr_eferències"
+
 msgid "Mute _Sounds"
-msgstr "Inhabilita els sons"
-
-#, fuzzy
+msgstr "Inhabilita els _sons"
+
 msgid "_Blink on New Message"
-msgstr "Parpelleja si hi ha missatges nous"
-
-#, fuzzy
+msgstr "_Parpelleja si hi ha missatges nous"
+
 msgid "_Quit"
-msgstr "Surt"
+msgstr "_Surt"
 
 msgid "Not started"
 msgstr "No s'ha iniciat"
@@ -11900,14 +11819,13 @@
 msgid "Color to draw hyperlinks."
 msgstr "El color amb què pintar els enllaços."
 
-#, fuzzy
 msgid "Hyperlink visited color"
-msgstr "Color dels enllaços"
-
-#, fuzzy
+msgstr "Color dels enllaços visitats"
+
 msgid "Color to draw hyperlinks after it has been visited (or activated)."
 msgstr ""
-"El color amb què es pintaran els enllaços quan el ratolí hi estigui a sobre."
+"El color amb el qual es pintaran els enllaços que ja s'hagin visitat (o "
+"activat)."
 
 # FIXME: prelight? (josep)
 msgid "Hyperlink prelight color"
@@ -11943,13 +11861,11 @@
 msgid "Color to draw the name of an action message."
 msgstr "Color amb el qual es pintaran els missatges d'acció."
 
-#, fuzzy
 msgid "Action Message Name Color for Whispered Message"
-msgstr "Nom del color dels missatges d'acció"
-
-#, fuzzy
+msgstr "Color del nom del missatge d'acció per a missatges xiuxiuejats"
+
 msgid "Whisper Message Name Color"
-msgstr "Nom del color per als missatges enviats"
+msgstr "Color dels missatges xiuxiuejats enviats"
 
 msgid "Typing notification color"
 msgstr "Color per a les notificacions de quan s'escriu"
@@ -12025,9 +11941,9 @@
 msgid "_Save Image..."
 msgstr "_Desa la imatge..."
 
-#, fuzzy, c-format
+#, c-format
 msgid "_Add Custom Smiley..."
-msgstr "Mostra emoticones personalitzades"
+msgstr "_Afegeix una emoticones personalitzada..."
 
 msgid "Select Font"
 msgstr "Selecciona el tipus de lletra"
@@ -12072,13 +11988,15 @@
 "This smiley is disabled because a custom smiley exists for this shortcut:\n"
 " %s"
 msgstr ""
+"Aquesta emoticona està inhabilitada perquè hi ha una emoticona "
+"personalitzada per aquesta drecera:\n"
+" %s"
 
 msgid "Smile!"
 msgstr "Somrieu!"
 
-#, fuzzy
 msgid "_Manage custom smileys"
-msgstr "Mostra emoticones personalitzades"
+msgstr "_Gestiona les emoticones personalitzades"
 
 msgid "This theme has no available smileys."
 msgstr "Aquest tema no disposa d'emoticones."
@@ -12290,7 +12208,7 @@
 "  -v, --version       mostra la versió actual i surt\n"
 
 # FIXME: backtrace -> traça (bug-buddy) ?
-#, 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"
@@ -12311,17 +12229,12 @@
 "\n"
 "Si podeu reproduir aquest error, feu-ho saber als desenvolupadors,\n"
 "enviant-los un error de programació a:\n"
-"%ssimpleticket\n"
+"%ssimpleticket/\n"
 "\n"
 "Assegureu-vos que indiqueu el que estàveu fent, i envieu una traça\n"
 "(backtrace) del fitxer core. Si no sabeu com obtenir una traça,\n"
 "llegiu les instruccions que hi ha a:\n"
 "%swiki/GetABacktrace\n"
-"\n"
-"Si necessiteu ajuda, envieu un missatge instantani a SeanEgn o\n"
-"bé a LSchiere (per AIM). La informació per a contactar en Sean o\n"
-"en Luke a través d'altres protocols és aquí:\n"
-"%swiki/DeveloperPages\n"
 
 #. Translators may want to transliterate the name.
 #. It is not to be translated.
@@ -12329,7 +12242,7 @@
 msgstr "Pidgin"
 
 msgid "Open All Messages"
-msgstr "Obre els _missatges"
+msgstr "Obre tots els missatges"
 
 msgid "<span weight=\"bold\" size=\"larger\">You have mail!</span>"
 msgstr "<span weight=\"bold\" size=\"larger\">Teniu correu electrònic.</span>"
@@ -12360,8 +12273,7 @@
 msgid ""
 "The 'Manual' browser command has been chosen, but no command has been set."
 msgstr ""
-"S'ha triat l'ordre per al navegador 'manualment', però no se n'ha indicat "
-"cap."
+"S'ha triat l'ordre per al navegador «manualment», però no se n'ha indicat cap."
 
 msgid "The following plugins will be unloaded."
 msgstr "Es descarregaran els connectors següents."
@@ -12794,31 +12706,26 @@
 "Ordre per al so\n"
 "(%s per al nom de fitxer)"
 
-#, fuzzy
 msgid "M_ute sounds"
-msgstr "Inhabilita els sons"
+msgstr "In_habilita els sons"
 
 msgid "Sounds when conversation has _focus"
 msgstr "Sons quan la conversa tingui el _focus"
 
-#, fuzzy
 msgid "_Enable sounds:"
-msgstr "Habilita els sons:"
-
-#, fuzzy
+msgstr "_Habilita els sons:"
+
 msgid "V_olume:"
-msgstr "Volum:"
+msgstr "V_olum:"
 
 msgid "Play"
 msgstr "Reprodueix"
 
-#, fuzzy
 msgid "_Browse..."
 msgstr "Nav_ega..."
 
-#, fuzzy
 msgid "_Reset"
-msgstr "Reinicia"
+msgstr "_Reinicia"
 
 msgid "_Report idle time:"
 msgstr "Informa del _temps d'inactivitat:"
@@ -12990,61 +12897,52 @@
 msgid "Status for %s"
 msgstr "Estat per a %s"
 
-#, fuzzy
 msgid "Custom Smiley"
-msgstr "Insereix una emoticona"
+msgstr "Emoticona personalitzada"
 
 msgid "More Data needed"
-msgstr ""
+msgstr "Calen més dades"
 
 msgid "Please provide a shortcut to associate with the smiley."
-msgstr ""
-
-#, fuzzy
+msgstr "Especifiqueu una drecera associada a l'emoticona."
+
 msgid "Duplicate Shortcut"
-msgstr "Duplicació de la correcció"
+msgstr "Drecera duplicada"
 
 msgid ""
 "A custom smiley for the selected shortcut already exists. Please specify a "
 "different shortcut."
 msgstr ""
-
-#, fuzzy
+"Hi ha una emoticona personalitzada per la drecera que heu seleccionat. "
+"Indiqueu-ne una de diferent."
+
 msgid "Please select an image for the smiley."
-msgstr "Seleccioneu l'estat d'ànim de la llista."
-
-#, fuzzy
+msgstr "Seleccioneu una imatge per a l'emoticona."
+
 msgid "Edit Smiley"
-msgstr "Insereix una emoticona"
-
-#, fuzzy
+msgstr "Edita l'emoticona"
+
 msgid "Add Smiley"
-msgstr "_Emoticona"
-
-#, fuzzy
+msgstr "Afegeix una emoticona"
+
 msgid "Smiley _Image"
-msgstr "Desa imatge"
+msgstr "_Imatge de l'emoticona"
 
 #. Smiley shortcut
-#, fuzzy
 msgid "Smiley S_hortcut"
-msgstr "Dreceres de teclat"
-
-#, fuzzy
+msgstr "_Dreceres de l'emoticona"
+
 msgid "Smiley"
-msgstr "_Emoticona"
-
-#, fuzzy
+msgstr "Emoticona"
+
 msgid "Custom Smiley Manager"
-msgstr "Gestor de certificats"
-
-#, fuzzy
+msgstr "Gestor d'emoticones personalitzades"
+
 msgid "Click to change your buddyicon for this account."
-msgstr "Utilitza aquesta _icona d'amic per a aquest compte:"
-
-#, fuzzy
+msgstr "Feu clic per canviar la icona d'amic d'aquest compte."
+
 msgid "Click to change your buddyicon for all accounts."
-msgstr "Utilitza aquesta _icona d'amic per a aquest compte:"
+msgstr "Feu clic per canviar la icona d'amic de tots els comptes."
 
 msgid "Waiting for network connection"
 msgstr "S'està esperant la connexió de xarxa"
@@ -13182,20 +13080,17 @@
 msgid "_Invite"
 msgstr "Conv_ida"
 
-#, fuzzy
 msgid "_Modify..."
-msgstr "_Modifica"
-
-#, fuzzy
+msgstr "_Modifica..."
+
 msgid "_Add..."
-msgstr "_Afegeix"
+msgstr "_Afegeix..."
 
 msgid "_Open Mail"
 msgstr "_Obre el correu"
 
-#, fuzzy
 msgid "_Edit"
-msgstr "Edita"
+msgstr "_Edita"
 
 msgid "Pidgin Tooltip"
 msgstr "Indicador de funció del Pidgin"
@@ -13214,12 +13109,11 @@
 msgid "none"
 msgstr "cap"
 
-#, fuzzy
 msgid "Small"
-msgstr "Correu electrònic"
+msgstr "Petites"
 
 msgid "Smaller versions of the default smilies"
-msgstr ""
+msgstr "Versions més petites de les emoticones per defecte"
 
 msgid "Response Probability:"
 msgstr "Probabilitat de resposta:"
@@ -13693,9 +13587,9 @@
 msgid "Set window manager \"_URGENT\" hint"
 msgstr "Aplica l'opció «_URGENT» del gestor de finestres"
 
-#, fuzzy
+# (gnome)
 msgid "_Flash window"
-msgstr "Finestres de _xat"
+msgstr "Finestres _flash"
 
 #. Raise window method button
 msgid "R_aise conversation window"
@@ -13783,9 +13677,8 @@
 msgid "Hyperlink Color"
 msgstr "Color dels hiperenllaços"
 
-#, fuzzy
 msgid "Visited Hyperlink Color"
-msgstr "Color dels hiperenllaços"
+msgstr "Color dels enllaços visitats"
 
 msgid "Highlighted Message Name Color"
 msgstr "Nom del color per als missatges ressaltats"
@@ -13880,18 +13773,16 @@
 
 #, c-format
 msgid "You can upgrade to %s %s today."
-msgstr ""
+msgstr "Podeu actualitzar-vos a %s %s avui."
 
 msgid "New Version Available"
 msgstr "Nova versió disponible"
 
-#, fuzzy
 msgid "Later"
-msgstr "Data"
-
-#, fuzzy
+msgstr "Més tard"
+
 msgid "Download Now"
-msgstr "Usuaris a %s: %s"
+msgstr "Baixa-la ara"
 
 #. *< type
 #. *< ui_requirement
@@ -14190,24 +14081,64 @@
 
 # FIXME: stanza -> estrofa (literal) (Josep)
 msgid "Insert an <iq/> stanza."
-msgstr "Insereix una estrofa <iq/>"
+msgstr "Insereix un bloc <iq/>."
 
 msgid "Insert a <presence/> stanza."
-msgstr "Insereix una estrofa <presence/>"
+msgstr "Insereix un bloc <presence/>."
 
 msgid "Insert a <message/> stanza."
-msgstr "Insereix una estrofa <message/>"
+msgstr "Insereix un bloc <message/>."
 
 #. *< name
 #. *< version
 #. *  summary
 msgid "Send and receive raw XMPP stanzas."
-msgstr "Envia i rep estrofes XMPP en brut."
+msgstr "Envia i rep blocs XMPP en brut."
 
 #. *  description
 msgid "This plugin is useful for debbuging XMPP servers or clients."
 msgstr "Aquest connector és útil per a depurar servidors i clients XMPP."
 
+#~ 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] ""
+#~ "S'ha perdut la connexió al servidor (fa %d segon que no s'hi reben dades)"
+#~ msgstr[1] ""
+#~ "S'ha perdut la connexió al servidor (fa %d segons que no s'hi reben dades)"
+
+#~ msgid "Keep alive error"
+#~ msgstr "Error de permanència"
+
+#~ msgid ""
+#~ "Lost connection with server:\n"
+#~ "%d, %s"
+#~ msgstr ""
+#~ "S'ha perdut la connexió amb el servidor:\n"
+#~ "%d, %s"
+
+#~ msgid "Connecting server ..."
+#~ msgstr "S'està connectant al servidor..."
+
+#~ msgid "Failed to send IM."
+#~ msgstr "No s'ha pogut enviar la MI."
+
+#~ msgid "Not a member of room \"%s\"\n"
+#~ msgstr "No sou un membre de la sala «%s»\n"
+
+#~ msgid "User information for %s unavailable"
+#~ msgstr "Dades de l'usuari %s no disponibles"
+
+#~ msgid ""
+#~ "You are using %s version %s.  The current version is %s.  You can get it "
+#~ "from <a href=\"%s\">%s</a><hr>"
+#~ msgstr ""
+#~ "Esteu emprant la versió %s del %s. La versió actual és %s, la podeu "
+#~ "obtenir de <a href=\"%s\">%s</a><hr>"
+
+#~ msgid "<b>ChangeLog:</b><br>%s"
+#~ msgstr "<b>Registre de canvis:</b><br>%s"
+
 #~ msgid "A group with the name already exists."
 #~ msgstr "Ja existeix un grup amb aquest nom."
 
@@ -14217,13 +14148,8 @@
 #~ msgid "Blood Type"
 #~ msgstr "Tipus de sang"
 
-#, fuzzy
 #~ msgid "Update information"
-#~ msgstr "Actualitza la meva informació"
-
-#, fuzzy
-#~ msgid "Successed:"
-#~ msgstr "Velocitat:"
+#~ msgstr "Actualitza la informació"
 
 #~ msgid ""
 #~ "Setting custom faces is not currently supported. Please choose an image "
@@ -14244,14 +14170,6 @@
 #~ msgid "Add buddy with auth request failed"
 #~ msgstr "Ha fallat la sol·licitut per afegir un amic amb autorització"
 
-#, fuzzy
-#~ msgid "Add into %d's buddy list"
-#~ msgstr "No s'ha pogut carregar la llista d'amics"
-
-#, fuzzy
-#~ msgid "QQ Number Error"
-#~ msgstr "Número QQ"
-
 #~ msgid "Group Description"
 #~ msgstr "Descripció del grup"
 
@@ -14261,26 +14179,12 @@
 #~ msgid "Approve"
 #~ msgstr "Aprova"
 
-#, fuzzy
-#~ msgid "Successed to join Qun %d, operated by admin %d"
-#~ msgstr ""
-#~ "L'administrador %2$d ha rebutjat la vostra sol·liciut per entrar al grup %"
-#~ "1$d"
-
-#, fuzzy
-#~ msgid "[%d] removed from Qun \"%d\""
-#~ msgstr "Vós [%d] heu sortit del grup «%d»"
-
-#, fuzzy
-#~ msgid "[%d] added to Qun \"%d\""
-#~ msgstr "Vós [%d] heu estat afegit al grup «%d»"
-
 #~ msgid "I am a member"
 #~ msgstr "En sóc membre"
 
-#, fuzzy
+# FIXME? (hi demano [entrar]?)
 #~ msgid "I am requesting"
-#~ msgstr "Sol·licitud incorrecta"
+#~ msgstr "Demano"
 
 #~ msgid "I am the admin"
 #~ msgstr "En sóc l'administrador"
@@ -14288,10 +14192,6 @@
 #~ msgid "Unknown status"
 #~ msgstr "Estat desconegut"
 
-#, fuzzy
-#~ msgid "Remove from Qun"
-#~ msgstr "Suprimeix el grup"
-
 #~ msgid "You entered a group ID outside the acceptable range"
 #~ msgstr "Heu entrat un identificador de grup fora del rang"
 
@@ -14301,24 +14201,6 @@
 #~ msgid "Do you want to approve the request?"
 #~ msgstr "Voleu aprovar aquesta sol·licitud?"
 
-#, fuzzy
-#~ msgid "Change Qun member"
-#~ msgstr "Número de telèfon"
-
-#, fuzzy
-#~ msgid "Change Qun information"
-#~ msgstr "Informació del canal"
-
-# Gnome_2.6_Extras [rhythmbox.HEAD.ca.po]
-#, fuzzy
-#~ msgid ""
-#~ "%s\n"
-#~ "\n"
-#~ "%s"
-#~ msgstr ""
-#~ "%s:\n"
-#~ "%s"
-
 #~ msgid "System Message"
 #~ msgstr "Missatge del sistema"
 
@@ -14331,64 +14213,47 @@
 #~ msgid "Set My Information"
 #~ msgstr "Estableix la meva informació"
 
-#, fuzzy
-#~ msgid "Leave the QQ Qun"
-#~ msgstr "Surt d'aquest Qun QQ"
-
 #~ msgid "Block this buddy"
 #~ msgstr "Bloca aquest usuari"
 
-#, fuzzy
 #~ msgid "Error password: %s"
-#~ msgstr "S'ha produït un error en canviar la contrasenya"
-
-#, fuzzy
+#~ msgstr "Error en la contrasenya: %s"
+
 #~ msgid "Failed to connect all servers"
-#~ msgstr "No s'ha pogut connectar al servidor."
-
-#, fuzzy
+#~ msgstr "No s'han pogut connectar tots els servidors"
+
 #~ msgid "Connecting server %s, retries %d"
-#~ msgstr ""
-#~ "S'ha produït un error de connexió del servidor %s:\n"
-#~ "%s"
-
-#, fuzzy
+#~ msgstr "S'està connectant al servidor %s, %d reintents"
+
 #~ msgid "Do you approve the requestion?"
 #~ msgstr "Voleu aprovar aquesta sol·licitud?"
 
-#, fuzzy
 #~ msgid "Do you add the buddy?"
 #~ msgstr "Voleu afegir aquest amic?"
 
-#, fuzzy
 #~ msgid "%s added you [%s] to buddy list"
 #~ msgstr "%s us ha afegit [%s] a la seva llista d'amics"
 
-#, fuzzy
 #~ msgid "QQ Budy"
-#~ msgstr "Amic"
+#~ msgstr "Amic QQ"
+
+#~ msgid "Requestion approved by %s"
+#~ msgstr "%s ha aprovat la sol.licitud"
 
 #~ msgid "%s wants to add you [%s] as a friend"
 #~ msgstr "%s us vol afegir [%s] com a amic"
 
-#, fuzzy
 #~ msgid "%s is not in buddy list"
 #~ msgstr "%s no és a la vostra llista d'amics"
 
-#, fuzzy
 #~ msgid "Would you add?"
 #~ msgstr "Voleu afegir-lo?"
 
 #~ msgid "%s"
 #~ msgstr "%s"
 
-#, fuzzy
-#~ msgid "QQ Server Notice"
-#~ msgstr "Port en el servidor"
-
-#, fuzzy
 #~ msgid "Network disconnected"
-#~ msgstr "El remot s'ha desconnectat"
+#~ msgstr "La xarxa s'ha desconnectat"
 
 #~ msgid "developer"
 #~ msgstr "desenvolupador"
@@ -14399,33 +14264,6 @@
 #~ 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 ""
-#~ "Esteu emprant la versió %s del %s. La versió actual és %s, la podeu "
-#~ "obtenir de <a href=\"%s\">%s</a><hr>"
-
-#~ msgid "<b>ChangeLog:</b><br>%s"
-#~ msgstr "<b>Registre de canvis:</b><br>%s"
-
-#~ msgid "EOF while reading from resolver process"
-#~ msgstr ""
-#~ "S'ha arribat al final del fitxer (EOF) en llegir del procés resoledor"
-
-#~ msgid "Error setting socket options"
-#~ msgstr "S'ha produït un error en establir les opcions del sòcol"
-
-#~ msgid ""
-#~ "Windows Live ID authentication: cannot find authenticate token in server "
-#~ "response"
-#~ msgstr ""
-#~ "Autenticació amb el Windows Live ID: no s'ha pogut trobar el testimoni "
-#~ "d'autenticació al servidor"
-
-#~ msgid "Windows Live ID authentication Failed"
-#~ msgstr "No s'ha pogut autenticar amb el Windows Live ID"
-
 #~ msgid "Too evil (sender)"
 #~ msgstr "Massa malvat (remitent)"
 
@@ -14441,86 +14279,6 @@
 #~ msgid "<i>(retrieving)</i>"
 #~ msgstr "<i>(s'està recuperant)</i>"
 
-#~ msgid "Your information has been updated"
-#~ msgstr "S'ha actualitzat la vostra informació"
-
-#~ msgid "Input your reason:"
-#~ msgstr "Indiqueu-ne el motiu:"
-
-#~ msgid "You have successfully removed a buddy"
-#~ msgstr "Heu suprimit amb èxit un amic"
-
-#~ msgid "You have successfully removed yourself from your friend's buddy list"
-#~ msgstr "Us heu suprimit amb èxit de la llista d'amics del vostre amic"
-
-#~ msgid "You have added %d to buddy list"
-#~ msgstr "Heu afegit %d a la llista d'amics"
-
-#~ msgid "Invalid QQid"
-#~ msgstr "QQid invàlid"
-
-#~ msgid "Please enter external group ID"
-#~ msgstr "Introduïu l'ID del grup extern"
-
-#~ msgid "Reason: %s"
-#~ msgstr "Motiu: %s"
-
-#~ msgid "Your request to join group %d has been approved by admin %d"
-#~ msgstr ""
-#~ "L'administrador %2$d ha aprovat la vostra sol·liciud per entrar al grup %1"
-#~ "$d"
-
-#~ msgid "This group has been added to your buddy list"
-#~ msgstr "S'ha afegit aquest grup a la vostra llista d'amics"
-
-#~ msgid "I am applying to join"
-#~ msgstr "Estic sol·licitant entrar-hi"
-
-#~ msgid "You have successfully left the group"
-#~ msgstr "Heu sortit del grup correctament"
-
-#~ msgid "QQ Group Auth"
-#~ msgstr "Autorització de grup QQ"
-
-#~ msgid "Your authorization request has been accepted by the QQ server"
-#~ msgstr "El servidor QQ ha acceptat la sol·licitud d'autorització"
-
-#~ msgid "Code [0x%02X]: %s"
-#~ msgstr "Codi [0x%02X]: %s"
-
-#~ msgid "Group Operation Error"
-#~ msgstr "S'ha produït un error d'orientació del grup"
-
-#~ msgid "Enter your reason:"
-#~ msgstr "Indiqueu-ne el motiu:"
-
-#~ msgid "Error requesting login token"
-#~ msgstr "S'ha produït un error en sol·licitar un testimoni d'entrada"
-
-#~ msgid "Unable to login. Check debug log."
-#~ msgstr "No s'ha pogut connectar, comproveu el registre de depuració."
-
-#~ msgid "Unable to login"
-#~ msgstr "No s'ha connectar"
-
-#~ msgid "TCP Address"
-#~ msgstr "Adreça TCP"
-
-#~ msgid "UDP Address"
-#~ msgstr "Adreça UDP"
-
-#~ msgid "Show Login Information"
-#~ msgstr "Mostra informació de la connexió"
-
-#~ msgid "Login failed, no reply"
-#~ msgstr "Ha fallat l'entrada, no s'ha obtingut resposta"
-
-#~ msgid "User %s rejected your request"
-#~ msgstr "L'usuari %s ha declinat la vostra sol·licitud"
-
-#~ msgid "User %s approved your request"
-#~ msgstr "L'usuari %s ha acceptat la vostra sol·licitud"
-
 #~ msgid "Screen name:"
 #~ msgstr "Nom d'usuari:"
 
@@ -15521,6 +15279,9 @@
 #~ msgid "Reject Call"
 #~ msgstr "Rebutja la trucada"
 
+#~ msgid "Connected to %s"
+#~ msgstr "S'ha connectat a %s"
+
 #~ msgid "_Mute"
 #~ msgstr "_Silencia"
 
@@ -15941,9 +15702,6 @@
 #~ msgid "Away title: "
 #~ msgstr "Motiu de l'absència: "
 
-#~ msgid "Buddy List Error"
-#~ msgstr "Error en la llista d'amics"
-
 #~ msgid ""
 #~ "\n"
 #~ "Mark all accounts as \"away\" with the default message.\n"
--- a/po/de.po	Sun Dec 07 01:42:47 2008 +0000
+++ b/po/de.po	Wed Dec 17 18:01:08 2008 +0000
@@ -7,14 +7,15 @@
 #
 # This file is distributed under the same license as the Pidgin package.
 #
+# Jochen Kemnade <jochenkemnade@web.de>, 2008.
 msgid ""
 msgstr ""
 "Project-Id-Version: de\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-12-01 15:52-0800\n"
-"PO-Revision-Date: 2008-10-28 17:46+0100\n"
+"POT-Creation-Date: 2008-12-15 10:46+0100\n"
+"PO-Revision-Date: 2008-12-15 10:46+0100\n"
 "Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n"
-"Language-Team: Deutsch <de@li.org>\n"
+"Language-Team: German <de@li.org>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
@@ -1127,7 +1128,6 @@
 msgid "%s has sent you a message. (%s)"
 msgstr "%s hat Ihnen eine Nachricht gesendet. (%s)"
 
-#, c-format
 msgid "Unknown pounce event. Please report this!"
 msgstr "Unbekanntes Alarm-Ereignis. Bitte berichten Sie dieses Problem!"
 
@@ -1497,7 +1497,6 @@
 "Wenn eine neue Unterhaltung eröffnet wird, fügt dieses Plugin die letzte "
 "Unterhaltung in die aktuelle Unterhaltung ein."
 
-#, c-format
 msgid "Online"
 msgstr "Online"
 
@@ -1840,7 +1839,6 @@
 "Fehler beim Lesen vom Auflösungsprozess:\n"
 "%s"
 
-#, c-format
 msgid "Resolver process exited without answering our request"
 msgstr "Auflösungsprozess hat sich beendet ohne die Anfrage zu beantworten"
 
@@ -1931,7 +1929,6 @@
 msgid "Transfer of file %s complete"
 msgstr "Übertragung der Datei %s ist komplett"
 
-#, c-format
 msgid "File transfer complete"
 msgstr "Dateiübertragung ist komplett"
 
@@ -1939,7 +1936,6 @@
 msgid "You canceled the transfer of %s"
 msgstr "Sie haben die Dateiübertragung von %s abgebrochen"
 
-#, c-format
 msgid "File transfer cancelled"
 msgstr "Dateiübertragung wurde abgebrochen"
 
@@ -2147,7 +2143,6 @@
 msgid "You are using %s, but this plugin requires %s."
 msgstr "Sie benutzen %s, aber dieses Plugin benötigt %s."
 
-#, c-format
 msgid "This plugin has not defined an ID."
 msgstr "Dieses Plugin hat keine ID definiert."
 
@@ -2912,10 +2907,10 @@
 msgstr "Hostname oder Portnummer ihres Proxys sind falsch angegeben."
 
 msgid "Token Error"
-msgstr "Kürzel-Fehler"
+msgstr "Token-Fehler"
 
 msgid "Unable to fetch the token.\n"
-msgstr "Kann das Kürzel nicht abholen.\n"
+msgstr "Kann das Token nicht abholen.\n"
 
 msgid "Save Buddylist..."
 msgstr "Buddy-Liste speichern..."
@@ -2967,10 +2962,10 @@
 msgstr "Passwort (nochmal)"
 
 msgid "Enter current token"
-msgstr "Geben Sie das aktuelle Kürzel ein"
+msgstr "Geben Sie das aktuelle Token ein"
 
 msgid "Current token"
-msgstr "Aktuelles Kürzel"
+msgstr "Aktuelles Token"
 
 msgid "Register New Gadu-Gadu Account"
 msgstr "Registrierung eines neuen Gadu-Gadu-Kontos"
@@ -3043,7 +3038,6 @@
 #. get_yahoo_status_from_purple_status() returns YAHOO_STATUS_CUSTOM for
 #. * the generic away state (YAHOO_STATUS_TYPE_AWAY) with no message
 #. Away stuff
-#, c-format
 msgid "Away"
 msgstr "Abwesend"
 
@@ -3935,7 +3929,6 @@
 msgid "Extended Away"
 msgstr "Abwesend (erweitert)"
 
-#, c-format
 msgid "Do Not Disturb"
 msgstr "Nicht stören"
 
@@ -4318,7 +4311,7 @@
 msgstr "Server überlastet"
 
 msgid "Service Unavailable"
-msgstr "Dienst nicht erreichbar"
+msgstr "Dienst nicht verfügbar"
 
 msgid "Subscription Required"
 msgstr "Abonnement erforderlich"
@@ -4690,6 +4683,19 @@
 msgid "Unable to retrieve MSN Address Book"
 msgstr "Konnte das MSN-Adressbuch nicht abrufen"
 
+#. 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 "Kann „%s“ nicht hinzufügen."
+
+msgid "Buddy Add error"
+msgstr "Fehler beim Hinzufügen des Buddys"
+
+msgid "The username specified does not exist."
+msgstr "Der angegebene Benutzername existiert nicht."
+
 #, c-format
 msgid "Buddy list synchronization issue in %s (%s)"
 msgstr "Fehler bei der Buddy-Listen-Synchronisation bei %s (%s)"
@@ -4710,220 +4716,166 @@
 "%s ist auf der lokalen Liste, aber nicht auf der Serverliste. Möchten Sie, "
 "dass der Buddy hinzugefügt wird?"
 
-#, c-format
 msgid "Unable to parse message"
 msgstr "Kann die Nachricht nicht parsen"
 
-#, c-format
 msgid "Syntax Error (probably a client bug)"
 msgstr "Syntaxfehler (wahrscheinlich ein Client-Bug)"
 
-#, c-format
 msgid "Invalid email address"
 msgstr "Ungültige E-Mail-Adresse"
 
-#, c-format
 msgid "User does not exist"
 msgstr "Benutzer existiert nicht"
 
-#, c-format
 msgid "Fully qualified domain name missing"
 msgstr "Der Fully Qualified Domain Name fehlt"
 
-#, c-format
 msgid "Already logged in"
 msgstr "Schon angemeldet"
 
-#, c-format
 msgid "Invalid username"
 msgstr "Ungültiger Benutzername"
 
-#, c-format
 msgid "Invalid friendly name"
 msgstr "Ungültiger Freundesname"
 
-#, c-format
 msgid "List full"
 msgstr "Liste voll"
 
-#, c-format
 msgid "Already there"
 msgstr "Schon da"
 
-#, c-format
 msgid "Not on list"
 msgstr "Nicht auf der Liste"
 
-#, c-format
 msgid "User is offline"
 msgstr "Benutzer ist offline"
 
-#, c-format
 msgid "Already in the mode"
 msgstr "Bereits in diesem Modus"
 
-#, c-format
 msgid "Already in opposite list"
 msgstr "Bereits in der „Gegenteil-Liste“"
 
-#, c-format
 msgid "Too many groups"
 msgstr "Zu viele Gruppen"
 
-#, c-format
 msgid "Invalid group"
 msgstr "Ungültige Gruppe"
 
-#, c-format
 msgid "User not in group"
 msgstr "Benutzer ist nicht in der Gruppe"
 
-#, c-format
 msgid "Group name too long"
 msgstr "Name der Gruppe ist zu lang"
 
-#, c-format
 msgid "Cannot remove group zero"
 msgstr "Kann die Gruppe „Null“ nicht entfernen"
 
-#, c-format
 msgid "Tried to add a user to a group that doesn't exist"
 msgstr ""
 "Versuchte einen Benutzer zu einer nichtexistierenden Gruppe hinzuzufügen"
 
-#, c-format
 msgid "Switchboard failed"
 msgstr "Vermittlung gescheitert"
 
-#, c-format
 msgid "Notify transfer failed"
 msgstr "Übertragung der Benachrichtigung gescheitert"
 
-#, c-format
 msgid "Required fields missing"
 msgstr "Notwendige Felder fehlen"
 
-#, c-format
 msgid "Too many hits to a FND"
 msgstr "Zu viele Treffer zu einem FND"
 
-#, c-format
 msgid "Not logged in"
 msgstr "Nicht angemeldet"
 
-#, c-format
 msgid "Service temporarily unavailable"
 msgstr "Dienst momentan nicht verfügbar"
 
-#, c-format
 msgid "Database server error"
 msgstr "Fehler des Datenbank-Servers"
 
-#, c-format
 msgid "Command disabled"
 msgstr "Kommando abgeschaltet"
 
-#, c-format
 msgid "File operation error"
 msgstr "Dateiverarbeitungsfehler"
 
-#, c-format
 msgid "Memory allocation error"
 msgstr "Fehler bei der Speicheranforderung"
 
-#, c-format
 msgid "Wrong CHL value sent to server"
 msgstr "Falscher CHL-Wert zum Server gesendet"
 
-#, c-format
 msgid "Server busy"
 msgstr "Server beschäftigt"
 
-#, c-format
 msgid "Server unavailable"
 msgstr "Server unerreichbar"
 
-#, c-format
 msgid "Peer notification server down"
 msgstr "Peer-Benachrichtigungsserver nicht erreichbar"
 
-#, c-format
 msgid "Database connect error"
 msgstr "Datenbank-Verbindungsfehler"
 
-#, c-format
 msgid "Server is going down (abandon ship)"
 msgstr "Server fährt runter (melden Sie sich ab)"
 
-#, c-format
 msgid "Error creating connection"
 msgstr "Fehler beim Herstellen der Verbindung"
 
-#, c-format
 msgid "CVR parameters are either unknown or not allowed"
 msgstr "CVR-Parameter sind entweder unbekannt oder nicht erlaubt"
 
-#, c-format
 msgid "Unable to write"
 msgstr "Schreiben nicht möglich"
 
-#, c-format
 msgid "Session overload"
 msgstr "Sitzung überlastet"
 
-#, c-format
 msgid "User is too active"
 msgstr "Benutzer ist zu aktiv"
 
-#, c-format
 msgid "Too many sessions"
 msgstr "Zu viele Sitzungen"
 
-#, c-format
 msgid "Passport not verified"
 msgstr "Passport (MSN Benutzerausweis) wurde nicht überprüft"
 
-#, c-format
 msgid "Bad friend file"
 msgstr "Falsche Friends-Datei"
 
-#, c-format
 msgid "Not expected"
 msgstr "Nicht erwartet"
 
-#, c-format
 msgid "Friendly name changes too rapidly"
 msgstr "Benutzernamen werden zu oft geändert"
 
-#, c-format
 msgid "Server too busy"
 msgstr "Server ist zu beschäftigt"
 
-#, c-format
 msgid "Authentication failed"
 msgstr "Authentifizierung fehlgeschlagen"
 
-#, c-format
 msgid "Not allowed when offline"
 msgstr "Nicht erlaubt im Offline-Modus"
 
-#, c-format
 msgid "Not accepting new users"
 msgstr "Akzeptiert keine neuen Benutzer"
 
-#, c-format
 msgid "Kids Passport without parental consent"
 msgstr "Kinder-Passwort ohne die Zustimmung der Eltern"
 
-#, c-format
 msgid "Passport account not yet verified"
 msgstr "Passport-Konto wurde noch nicht überprüft"
 
-#, c-format
 msgid "Passport account suspended"
 msgstr "Passport-Konto gesperrt"
 
-#, c-format
 msgid "Bad ticket"
 msgstr "Falsches Ticket"
 
@@ -5011,6 +4963,12 @@
 msgid "Page"
 msgstr "Nachricht"
 
+msgid "Playing a game"
+msgstr "Spielt ein Spiel"
+
+msgid "Working"
+msgstr "Arbeitet"
+
 msgid "Has you"
 msgstr "Hat Sie"
 
@@ -5047,6 +5005,12 @@
 msgid "Album"
 msgstr "Album"
 
+msgid "Game Title"
+msgstr "Spieltitel"
+
+msgid "Office Title"
+msgstr "Dienststellenbezeichnung"
+
 msgid "Set Friendly Name..."
 msgstr "Setze Spitzname..."
 
@@ -5240,8 +5204,8 @@
 "Konnte keinerlei Information im Profil des Benutzers finden. Der Benutzer "
 "existiert wahrscheinlich nicht."
 
-msgid "Profile URL"
-msgstr "URL des Profils"
+msgid "View web profile"
+msgstr "Web-Profil ansehen"
 
 #. *< type
 #. *< ui_requirement
@@ -5508,19 +5472,15 @@
 msgid "Do you want to delete this buddy from your address book as well?"
 msgstr "Möchten Sie diesen Buddy außerdem aus Ihrem Adressbuch löschen?"
 
-#. 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 "Kann „%s“ nicht hinzufügen."
-
 msgid "The username specified is invalid."
 msgstr "Der angegebene Benutzername ist ungültig."
 
 msgid "This Hotmail account may not be active."
 msgstr "Dieses Hotmail-Konto ist vielleicht nicht aktiv."
 
+msgid "Profile URL"
+msgstr "URL des Profils"
+
 #. *< type
 #. *< ui_requirement
 #. *< flags
@@ -5556,13 +5516,8 @@
 msgid "Logging in"
 msgstr "Logge ein"
 
-#, 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] ""
-"Verbindung zum Server verloren (seit %d Sekunde keine Daten empfangen)"
-msgstr[1] ""
-"Verbindung zum Server verloren (seit %d Sekunden keine Daten empfangen)"
+msgid "Lost connection with server"
+msgstr "Verbindung zum Server verloren"
 
 #. Can't write _()'d strings in array initializers. Workaround.
 msgid "New mail messages"
@@ -5719,9 +5674,6 @@
 msgid "User"
 msgstr "Benutzer"
 
-msgid "Profile"
-msgstr "Profil"
-
 msgid "Headline"
 msgstr "Überschrift"
 
@@ -6154,7 +6106,6 @@
 msgid "Error. SSL support is not installed."
 msgstr "Fehler. SSL ist nicht installiert."
 
-#, c-format
 msgid "This conference has been closed. No more messages can be sent."
 msgstr ""
 "Diese Konferenz wurde geschlossen. Es können keine Nachrichten mehr gesendet "
@@ -6424,23 +6375,18 @@
 msgid "Screen Sharing"
 msgstr "Gemeinsamer Bildschirm"
 
-#, c-format
 msgid "Free For Chat"
 msgstr "Bereit zum Chatten"
 
-#, c-format
 msgid "Not Available"
 msgstr "Nicht verfügbar"
 
-#, c-format
 msgid "Occupied"
 msgstr "Beschäftigt"
 
-#, c-format
 msgid "Web Aware"
 msgstr "In Web"
 
-#, c-format
 msgid "Invisible"
 msgstr "Unsichtbar"
 
@@ -6731,6 +6677,9 @@
 msgid "Member Since"
 msgstr "Mitglied seit"
 
+msgid "Profile"
+msgstr "Profil"
+
 msgid "Your AIM connection may be lost."
 msgstr "Ihre AIM-Verbindung könnte unterbrochen sein."
 
@@ -6925,11 +6874,9 @@
 "beginnen und nur Buchstaben, Ziffern und Leerzeichen enthalten oder nur aus "
 "Ziffern bestehen."
 
-#, fuzzy
 msgid "Unable to Add"
 msgstr "Kann nicht hinzufügen"
 
-#, fuzzy
 msgid "Unable to Retrieve Buddy List"
 msgstr "Konnte Buddy-Liste nicht laden"
 
@@ -7139,7 +7086,6 @@
 msgid "Attempting to connect to %s:%hu."
 msgstr "Verbindungsversuch mit %s:%hu."
 
-#, c-format
 msgid "Attempting to connect via proxy server."
 msgstr "Verbindungsversuch über einen Proxyserver."
 
@@ -7231,16 +7177,14 @@
 msgid "Other"
 msgstr "Andere"
 
-#, fuzzy
 msgid "Visible"
-msgstr "Unsichtbar"
-
-msgid "Firend Only"
-msgstr ""
-
-#, fuzzy
+msgstr "Sichtbar"
+
+msgid "Friend Only"
+msgstr "Nur Freund"
+
 msgid "Private"
-msgstr "Privatsphäre"
+msgstr "Privat"
 
 msgid "QQ Number"
 msgstr "QQ-Nummer"
@@ -7257,9 +7201,8 @@
 msgid "Phone Number"
 msgstr "Telefonnummer"
 
-#, fuzzy
 msgid "Authorize adding"
-msgstr "Buddy autorisieren?"
+msgstr "Hinzufügen autorisieren?"
 
 msgid "Cellphone Number"
 msgstr "Handy-Telefonnummer"
@@ -7267,100 +7210,82 @@
 msgid "Personal Introduction"
 msgstr "Persönliche Vorstellung"
 
-#, fuzzy
 msgid "City/Area"
-msgstr "Stadt"
+msgstr "Stadt/Gegend"
 
 #, fuzzy
 msgid "Publish Mobile"
 msgstr "Handy (privat)"
 
-#, fuzzy
 msgid "Publish Contact"
-msgstr "Kontakt-Alias"
+msgstr "Kontakt veröffentlichen"
 
 msgid "College"
 msgstr "College"
 
-#, fuzzy
 msgid "Horoscope"
-msgstr "Horoskopsymbol"
-
-#, fuzzy
+msgstr "Horoskop"
+
 msgid "Zodiac"
 msgstr "Sternzeichen"
 
-#, fuzzy
 msgid "Blood"
-msgstr "Blockiert"
-
-#, fuzzy
+msgstr "Blutgruppe"
+
 msgid "True"
-msgstr "Stier"
-
-#, fuzzy
+msgstr "Wahr"
+
 msgid "False"
-msgstr "Gescheitert"
-
-#, fuzzy
+msgstr "Falsch"
+
 msgid "Modify Contact"
-msgstr "Konto bearbeiten"
-
-#, fuzzy
+msgstr "Kontakt bearbeiten"
+
 msgid "Modify Address"
-msgstr "Privatadresse"
-
-#, fuzzy
+msgstr "Adresse bearbeiten"
+
 msgid "Modify Extended Information"
-msgstr "Informationen bearbeiten"
-
-#, fuzzy
+msgstr "Erweiterte Informationen bearbeiten"
+
 msgid "Modify Information"
 msgstr "Informationen bearbeiten"
 
-#, fuzzy
 msgid "Update"
-msgstr "Letzte Aktualisierung"
-
-#, fuzzy
+msgstr "Aktualisieren"
+
 msgid "Could not change buddy information."
-msgstr "Buddy-Informationen bearbeiten"
-
-#, c-format
-msgid "%d needs Q&A"
-msgstr ""
-
-#, fuzzy
-msgid "Add buddy Q&A"
-msgstr "Buddy hinzufügen"
-
-#, fuzzy
-msgid "Input answer here"
-msgstr "Anfrage hier eingeben"
+msgstr "Konnte Buddy-Informationen nicht bearbeiten."
+
+#, c-format
+msgid "%u requires verification"
+msgstr "%u erfordert Autorisierung"
+
+msgid "Add buddy question"
+msgstr "Buddy-Frage hinzufügen"
+
+msgid "Enter answer here"
+msgstr "Antwort hier eingeben"
 
 msgid "Send"
 msgstr "Senden"
 
-#, fuzzy
 msgid "Invalid answer."
-msgstr "Ungültiger Benutzername."
+msgstr "Ungültige Antwort."
 
 msgid "Authorization denied message:"
 msgstr "Nachricht für die Ablehnung der Autorisierung:"
 
-#, fuzzy
-msgid "Sorry, You are not my style."
-msgstr "Tut mir Leid, du bist nicht mein Typ..."
-
-#, c-format
-msgid "%d needs authentication"
-msgstr "%d benötigt Authentifizierung"
-
-#, fuzzy
+msgid "Sorry, you're not my style."
+msgstr "Tut mir Leid, du bist nicht mein Typ."
+
+#, c-format
+msgid "%u needs authorization"
+msgstr "%u benötigt Authorisierung"
+
 msgid "Add buddy authorize"
-msgstr "Benutzer zu Ihrer Buddy-Liste hinzufügen?"
-
-msgid "Input request here"
+msgstr "Buddy-Autorisierung hinzufügen"
+
+msgid "Enter request here"
 msgstr "Anfrage hier eingeben"
 
 msgid "Would you be my friend?"
@@ -7369,28 +7294,25 @@
 msgid "QQ Buddy"
 msgstr "QQ-Buddy"
 
-#, fuzzy
 msgid "Add buddy"
 msgstr "Buddy hinzufügen"
 
 msgid "Invalid QQ Number"
 msgstr "Ungültige QQ-Nummer"
 
-#, fuzzy
 msgid "Failed sending authorize"
-msgstr "Bitte autorisiere mich!"
-
-#, fuzzy, c-format
-msgid "Failed removing buddy %d"
-msgstr "Kontakt konnte nicht entfernt werden"
-
-#, fuzzy, c-format
+msgstr "Senden der Autorisierung fehlgeschlagen"
+
+#, c-format
+msgid "Failed removing buddy %u"
+msgstr "Kontakt %u konnte nicht entfernt werden"
+
+#, c-format
 msgid "Failed removing me from %d's buddy list"
-msgstr "Von der Liste des Buddys entfernen"
-
-#, fuzzy
+msgstr "Entfernen von %ds Buddy-Liste fehlgeschlagen"
+
 msgid "No reason given"
-msgstr "Kein Grund angegeben."
+msgstr "Kein Grund angegeben"
 
 #. only need to get value
 #, c-format
@@ -7400,9 +7322,9 @@
 msgid "Would you like to add him?"
 msgstr "Möchten Sie ihn hinzufügen?"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Rejected by %s"
-msgstr "Anfrage abgelehnt von %s"
+msgstr "Abgelehnt von %s"
 
 #, c-format
 msgid "Message: %s"
@@ -7423,58 +7345,55 @@
 msgid "You can only search for permanent Qun\n"
 msgstr "Sie können nur nach permanenten Qun suchen\n"
 
-#, fuzzy
+msgid "(Invalid UTF-8 string)"
+msgstr "(Ungültige UTF8-Zeichenkette)"
+
 msgid "Not member"
-msgstr "Ich bin kein Mitglied"
+msgstr "Kein Mitglied"
 
 msgid "Member"
 msgstr "Mitglied"
 
-#, fuzzy
 msgid "Requesting"
-msgstr "Anfrage-Dialog"
-
-#, fuzzy
+msgstr "Frage an"
+
 msgid "Admin"
-msgstr "Adium"
-
-#, fuzzy
+msgstr "Admin"
+
 msgid "Notice"
-msgstr "Bemerkung:"
-
-#, fuzzy
+msgstr "Bemerkung"
+
 msgid "Detail"
-msgstr "Standard"
+msgstr "Detail"
 
 msgid "Creator"
 msgstr "Ersteller"
 
-#, fuzzy
 msgid "About me"
-msgstr "Über %s"
-
-#, fuzzy
+msgstr "Über mich"
+
 msgid "Category"
-msgstr "Chatfehler"
+msgstr "Kategorie"
 
 msgid "The Qun does not allow others to join"
 msgstr "Diesen Qun können andere nicht beitreten"
 
-#, fuzzy
 msgid "Join QQ Qun"
-msgstr "Qun betreten"
-
-#, c-format
-msgid "Successfully joined Qun %s (%d)"
-msgstr ""
-
-#, fuzzy
+msgstr "QQ-Qun betreten"
+
+msgid "Input request here"
+msgstr "Anfrage hier eingeben"
+
+#, c-format
+msgid "Successfully joined Qun %s (%u)"
+msgstr "Qun %s (%u) erfolgreich betreten"
+
 msgid "Successfully joined Qun"
-msgstr "Sie haben einen Qun angelegt"
-
-#, c-format
-msgid "Qun %d denied to join"
-msgstr "Qun %d hat Ihren Beitritt abgelehnt"
+msgstr "Qun erfolgreich betreten"
+
+#, c-format
+msgid "Qun %u denied from joining"
+msgstr "Qun %u hat Ihren Beitritt abgelehnt"
 
 msgid "QQ Qun Operation"
 msgstr "QQ-Qun-Operation"
@@ -7482,12 +7401,11 @@
 msgid "Failed:"
 msgstr "Gescheitert:"
 
-msgid "Join Qun, Unknow Reply"
+msgid "Join Qun, Unknown Reply"
 msgstr "Qun-Beitritt, Unbekannte Antwort"
 
-#, fuzzy
 msgid "Quit Qun"
-msgstr "QQ-Qun"
+msgstr "Qun verlassen"
 
 msgid ""
 "Note, if you are the creator, \n"
@@ -7496,51 +7414,47 @@
 "Beachten Sie, dass diese Operation den Qun entfernen könnte, \n"
 "wenn Sie der Ersteller sind."
 
-#, fuzzy
-msgid "Sorry, you are not our style ..."
-msgstr "Tut mir Leid, du bist nicht mein Typ..."
-
-#, fuzzy
-msgid "Successfully changed Qun member"
-msgstr "Qun-Mitglied ändern"
-
-#, fuzzy
+msgid "Sorry, you are not our style"
+msgstr "Tut mir Leid, du bist nicht unser Typ"
+
+msgid "Successfully changed Qun members"
+msgstr "Qun-Mitglieder erfolgreich geändert"
+
 msgid "Successfully changed Qun information"
-msgstr "Qun-Informationen bearbeiten"
+msgstr "Qun-Informationen erfolgreich bearbeitet"
 
 msgid "You have successfully created a Qun"
 msgstr "Sie haben einen Qun angelegt"
 
-#, fuzzy
-msgid "Would you like to set detailed information now?"
+msgid "Would you like to set up detailed information now?"
 msgstr "Möchten Sie jetzt Detail-Informationen einstellen?"
 
 msgid "Setup"
 msgstr "Setup"
 
 #, fuzzy, c-format
-msgid "%d requested to join Qun %d for %s"
-msgstr "%d möchte dem Qun %d beitreten"
-
-#, c-format
-msgid "%d request to join Qun %d"
+msgid "%u requested to join Qun %u for %s"
 msgstr "%d möchte dem Qun %d beitreten"
 
 #, c-format
-msgid "Failed to join Qun %d, operated by admin %d"
-msgstr "Dem Qun %d, moderiert von admin %d, konnte nicht beigetreten werden"
-
-#, 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 "Buddy entfernen"
-
-#, c-format
-msgid "<b>New buddy %d joined.</b>"
-msgstr ""
+msgid "%u request to join Qun %u"
+msgstr "%u möchte dem Qun %u beitreten"
+
+#, c-format
+msgid "Failed to join Qun %u, operated by admin %u"
+msgstr "Dem Qun %u, moderiert von admin %u, konnte nicht beigetreten werden"
+
+#, c-format
+msgid "<b>Joining Qun %u is approved by admin %u for %s</b>"
+msgstr ""
+
+#, c-format
+msgid "<b>Removed buddy %u.</b>"
+msgstr "<b>Buddy %u entfernt</b>"
+
+#, c-format
+msgid "<b>New buddy %u joined.</b>"
+msgstr "<b>Neuer Buddy %u ist beigetreten.</b>"
 
 #, c-format
 msgid "Unknown-%d"
@@ -7576,21 +7490,20 @@
 msgid "Invalid name"
 msgstr "QQ: Ungültiger Name"
 
-#, fuzzy
 msgid "Select icon..."
-msgstr "Ordner auswählen..."
-
-#, fuzzy, c-format
+msgstr "Icon wählen..."
+
+#, c-format
 msgid "<b>Login time</b>: %d-%d-%d, %d:%d:%d<br>\n"
-msgstr "<b>Anmeldezeit</b>: %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Anmeldezeit</b>: %d-%d-%d, %d:%d:%d<br>\n"
+
+#, c-format
 msgid "<b>Total Online Buddies</b>: %d<br>\n"
-msgstr "<b>Aktuell online:</b> %d<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Insgesamt online</b>: %d<br>\n"
+
+#, c-format
 msgid "<b>Last Refresh</b>: %d-%d-%d, %d:%d:%d<br>\n"
-msgstr "<b>Letzte Aktualisierung</b>: %s<br>\n"
+msgstr "<b>Letzte Aktualisierung</b>: %d-%d-%d, %d:%d:%d<br>\n"
 
 #, c-format
 msgid "<b>Server</b>: %s<br>\n"
@@ -7604,9 +7517,9 @@
 msgid "<b>Connection Mode</b>: %s<br>\n"
 msgstr "<b>Verbindungsmodus</b>: %s<br>\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "<b>My Internet IP</b>: %s:%d<br>\n"
-msgstr "<b>Meine Internet-Adresse</b>: %s<br>\n"
+msgstr "<b>Meine Internet-IP</b>: %s:%d<br>\n"
 
 #, c-format
 msgid "<b>Sent</b>: %lu<br>\n"
@@ -7628,44 +7541,41 @@
 msgid "<b>Received Duplicate</b>: %lu<br>\n"
 msgstr "<b>Duplikat empfangen</b>: %lu<br>\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "<b>Time</b>: %d-%d-%d, %d:%d:%d<br>\n"
-msgstr "<b>Anmeldezeit</b>: %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Zeit</b>: %d-%d-%d, %d:%d:%d<br>\n"
+
+#, c-format
 msgid "<b>IP</b>: %s<br>\n"
-msgstr "<b>Server</b>: %s<br>\n"
+msgstr "<b>IP</b>: %s<br>\n"
 
 msgid "Login Information"
 msgstr "Login-Informationen"
 
 msgid "<p><b>Original Author</b>:<br>\n"
-msgstr ""
+msgstr "<p><b>Original-Autor</b>:<br>\n"
 
 msgid "<p><b>Code Contributors</b>:<br>\n"
-msgstr ""
-
-#, fuzzy
+msgstr "<p><b>Code-Mitwirkende</b>:<br>\n"
+
 msgid "<p><b>Lovely Patch Writers</b>:<br>\n"
-msgstr "<b>Letzte Aktualisierung</b>: %s<br>\n"
-
-#, fuzzy
+msgstr "<p><b>Wunderbare Patch-Schreiber</b>:<br>\n"
+
 msgid "<p><b>Acknowledgement</b>:<br>\n"
-msgstr "<b>Gesendet</b>: %lu<br>\n"
+msgstr "<p><b>Bestätigung</b>:<br>\n"
 
 msgid "<p><i>And, all the boys in the backroom...</i><br>\n"
-msgstr ""
+msgstr "<p><i>Und all die Jungs im Hinterzimmer...</i><br>\n"
 
 msgid "<i>Feel free to join us!</i> :)"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "About OpenQ r%s"
-msgstr "Über %s"
-
-#, fuzzy
+msgstr "<i>Treten Sie uns bei, wenn Sie mögen!</i> :)"
+
+#, c-format
+msgid "About OpenQ %s"
+msgstr "Über OpenQ %s"
+
 msgid "Change Icon"
-msgstr "Icon speichern"
+msgstr "Icon ändern"
 
 msgid "Change Password"
 msgstr "Passwort ändern"
@@ -7674,11 +7584,10 @@
 msgstr "Kontoinformationen"
 
 msgid "Update all QQ Quns"
-msgstr ""
-
-#, fuzzy
+msgstr "Alle QQ-Quns aktualisieren"
+
 msgid "About OpenQ"
-msgstr "Über %s"
+msgstr "Über OpenQ"
 
 #. *< type
 #. *< ui_requirement
@@ -7690,27 +7599,24 @@
 #. *< version
 #. *  summary
 #. *  description
-#, fuzzy
 msgid "QQ Protocol Plugin"
 msgstr "QQ-Protokoll-Plugin"
 
 msgid "Auto"
 msgstr "Auto"
 
-#, fuzzy
 msgid "Select Server"
-msgstr "Benutzer wählen"
+msgstr "Server wählen"
 
 msgid "QQ2005"
-msgstr ""
+msgstr "QQ2005"
 
 msgid "QQ2007"
-msgstr ""
+msgstr "QQ2007"
 
 msgid "QQ2008"
-msgstr ""
-
-#. #endif
+msgstr "QQ2008"
+
 msgid "Connect by TCP"
 msgstr "Über TCP verbinden"
 
@@ -7720,25 +7626,18 @@
 msgid "Show server news"
 msgstr "Server-News anzeigen"
 
-#, fuzzy
 msgid "Keep alive interval (seconds)"
-msgstr "Intervall(e) zum Aufrechterhalten der Verbindung (Keep alive)"
-
-#, fuzzy
+msgstr "Intervall zum Aufrechterhalten der Verbindung (Sekunden)"
+
 msgid "Update interval (seconds)"
-msgstr "Aktualisierungsintervall(e)"
-
-#, fuzzy
-msgid "Can not decrypt server reply"
-msgstr "Kann die Antwort der Anmeldung nicht entschlüsseln"
-
-#, fuzzy
-msgid "Can not decrypt get server reply"
-msgstr "Kann die Antwort der Anmeldung nicht entschlüsseln"
+msgstr "Aktualisierungsintervall (Sekunden)"
+
+msgid "Cannot decrypt server reply"
+msgstr "Kann die Antwort des Servers nicht entschlüsseln"
 
 #, c-format
 msgid "Failed requesting token, 0x%02X"
-msgstr ""
+msgstr "Fehler beim Anfordern des Tokens, 0x%02X"
 
 #, c-format
 msgid "Invalid token len, %d"
@@ -7746,56 +7645,53 @@
 
 #. extend redirect used in QQ2006
 msgid "Redirect_EX is not currently supported"
-msgstr ""
+msgstr "Redirect_EX wird im Moment nicht unterstützt"
 
 #. need activation
 #. need activation
 #. need activation
-#, fuzzy
 msgid "Activation required"
-msgstr "Registrierung erforderlich"
-
-#, fuzzy, c-format
-msgid "Unknow reply code when login (0x%02X)"
-msgstr "Anmeldung nicht möglich, unbekannter Antwort-Code 0x%02X"
-
-msgid "Keep alive error"
-msgstr "Fehler beim Aufrechterhalten der Verbindung (Keep alive)"
-
-#, fuzzy
-msgid "Requesting captcha ..."
-msgstr "Bitte um %ss Aufmerksamkeit..."
-
-msgid "Checking code of captcha ..."
-msgstr ""
-
-msgid "Failed captcha verify"
-msgstr ""
-
-#, fuzzy
+msgstr "Aktivierung erforderlich"
+
+#, c-format
+msgid "Unknown reply code when logging in (0x%02X)"
+msgstr "Unbekannte Antwort bei der Anmeldung (0x%02X)"
+
+msgid "Could not decrypt server reply"
+msgstr "Konnte die Antwort des Servers nicht entschlüsseln"
+
+msgid "Requesting captcha"
+msgstr "Captcha anfordern"
+
+msgid "Checking captcha"
+msgstr "Captcha überprüfen"
+
+msgid "Failed captcha verification"
+msgstr "Captcha-Überprüfung fehlgeschlagen"
+
 msgid "Captcha Image"
-msgstr "Bild speichern"
-
-#, fuzzy
+msgstr "Captcha-Bild"
+
 msgid "Enter code"
-msgstr "Geben Sie ein Passwort ein"
-
-msgid "QQ Captcha Verifing"
-msgstr ""
-
-#, fuzzy
+msgstr "Geben Sie den Code ein"
+
+msgid "QQ Captcha Verification"
+msgstr "QQ-Captcha-Überprüfung"
+
 msgid "Enter the text from the image"
-msgstr "Bitte geben Sie den Namen der Gruppe ein"
-
-#, c-format
-msgid "Unknow reply code when checking password (0x%02X)"
-msgstr ""
-
-#, c-format
-msgid ""
-"Unknow reply code when login (0x%02X):\n"
+msgstr "Bitte geben Sie den Text aus dem Bild ein"
+
+#, c-format
+msgid "Unknown reply when checking password (0x%02X)"
+msgstr "Unbekannte Antwort bei Überprüfungen des Passwortes (0x%02X)"
+
+#, c-format
+msgid ""
+"Unknown reply code when logging in (0x%02X):\n"
 "%s"
 msgstr ""
+"Unbekannte Antwort bei der Anmeldung (0x%02X):\n"
+"%s"
 
 #. we didn't successfully connect. tdt->toc_fd is valid here
 msgid "Unable to connect."
@@ -7804,14 +7700,6 @@
 msgid "Socket error"
 msgstr "Socket-Fehler"
 
-#, c-format
-msgid ""
-"Lost connection with server:\n"
-"%d, %s"
-msgstr ""
-"Verbindung zum Server verloren:\n"
-"%d, %s"
-
 msgid "Unable to read from socket"
 msgstr "Socket kann nicht gelesen werden"
 
@@ -7821,12 +7709,11 @@
 msgid "Connection lost"
 msgstr "Verbindung verloren"
 
-#, fuzzy
-msgid "Get server ..."
-msgstr "Benutzer-Info setzen..."
-
-msgid "Request token"
-msgstr "Anfragekürzel"
+msgid "Getting server"
+msgstr "Hole server"
+
+msgid "Requesting token"
+msgstr "Fordere Token an"
 
 msgid "Couldn't resolve host"
 msgstr "Kann den Hostnamen nicht auflösen"
@@ -7834,62 +7721,62 @@
 msgid "Invalid server or port"
 msgstr "Ungültiger Server oder Port"
 
-#, fuzzy
-msgid "Connecting server ..."
-msgstr "Verbindungsserver"
+msgid "Connecting to server"
+msgstr "Verbinde mit Server"
 
 msgid "QQ Error"
 msgstr "QQ-Fehler"
 
-msgid "Failed to send IM."
-msgstr "Senden der Nachricht fehlgeschlagen."
-
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Server News:\n"
 "%s\n"
 "%s\n"
 "%s"
-msgstr "QQ-Server-News"
+msgstr ""
+"Server-News:\n"
+"%s\n"
+"%s\n"
+"%s"
+
+#, c-format
+msgid "%s:%s"
+msgstr "%s:%s"
 
 #, c-format
 msgid "From %s:"
 msgstr "Von %s:"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Server notice From %s: \n"
 "%s"
-msgstr "Anleitung vom Server: %s"
-
-msgid "Unknow SERVER CMD"
+msgstr ""
+"Servernotiz von %s: \n"
+"%s"
+
+msgid "Unknown SERVER CMD"
 msgstr "Unbekanntes SERVER-CMD"
 
 #, c-format
 msgid ""
 "Error reply of %s(0x%02X)\n"
-"Room %d, reply 0x%02X"
-msgstr ""
-"Fehlerantwort %s(0x%02X)\n"
-"Raum %d, Antwort 0x%02X"
+"Room %u, reply 0x%02X"
+msgstr ""
+"Fehlerantwort von %s(0x%02X)\n"
+"Raum %u, Antwort 0x%02X"
 
 msgid "QQ Qun Command"
 msgstr "QQ-Qun-Kommando"
 
-#, fuzzy, c-format
-msgid "Not a member of room \"%s\"\n"
-msgstr "Sie sind kein Mitglied des Qun „%s“\n"
-
-msgid "Can not decrypt login reply"
-msgstr "Kann die Antwort der Anmeldung nicht entschlüsseln"
-
-#, fuzzy
-msgid "Unknow LOGIN CMD"
-msgstr "Unbekanntes Antwort-CMD"
-
-#, fuzzy
-msgid "Unknow CLIENT CMD"
-msgstr "Unbekanntes SERVER-CMD"
+msgid "Could not decrypt login reply"
+msgstr "Konnte die Antwort der Anmeldung nicht entschlüsseln"
+
+msgid "Unknown LOGIN CMD"
+msgstr "Unbekanntes LOGIN-CMD"
+
+msgid "Unknown CLIENT CMD"
+msgstr "Unbekanntes CLIENT-CMD"
 
 #, c-format
 msgid "%d has declined the file %s"
@@ -8502,7 +8389,6 @@
 msgid "<br><b>Channel Topic:</b><br>%s"
 msgstr "<br><b>Thema des Kanals:</b><br>%s"
 
-#, c-format
 msgid "<br><b>Channel Modes:</b> "
 msgstr "<br><b>Kanal-Modi:</b> "
 
@@ -8527,7 +8413,6 @@
 msgid "Channel Public Keys List"
 msgstr "Liste der öffentlichen Schlüssel des Kanals"
 
-#, c-format
 msgid ""
 "Channel authentication is used to secure the channel from unauthorized "
 "access. The authentication may be based on passphrase and digital "
@@ -8932,7 +8817,6 @@
 msgid "Your Current Mood"
 msgstr "Ihre momentane Stimmung"
 
-#, c-format
 msgid "Normal"
 msgstr "Normal"
 
@@ -9318,47 +9202,37 @@
 msgid "No server statistics available"
 msgstr "Keine Serverstatistik verfügbar"
 
-#, c-format
 msgid "Failure: Version mismatch, upgrade your client"
 msgstr "Fehler: Unterschiedliche Version, aktualisieren Sie Ihren Client"
 
-#, c-format
 msgid "Failure: Remote does not trust/support your public key"
 msgstr ""
 "Fehler: Die entfernte Seite vertraut Ihrem öffentlichen Schlüssel nicht"
 
-#, c-format
 msgid "Failure: Remote does not support proposed KE group"
 msgstr ""
 "Fehler: Entferntes Programm unterstützt nicht die vorgeschlagen KE-Gruppe"
 
-#, c-format
 msgid "Failure: Remote does not support proposed cipher"
 msgstr ""
 "Fehler: Entferntes Programm unterstützt die vorgeschlagene Cipher nicht"
 
-#, c-format
 msgid "Failure: Remote does not support proposed PKCS"
 msgstr "Fehler: Entferntes Programm unterstützt die vorgeschlagene PKCS nicht"
 
-#, c-format
 msgid "Failure: Remote does not support proposed hash function"
 msgstr ""
 "Fehler: Entferntes Programm unterstützt die vorgeschlagen Hashfunktion nicht"
 
-#, c-format
 msgid "Failure: Remote does not support proposed HMAC"
 msgstr "Fehler: Entferntes Programm unterstützt das vorgeschlagene HMAC nicht"
 
-#, c-format
 msgid "Failure: Incorrect signature"
 msgstr "Fehler: Falsche Signatur"
 
-#, c-format
 msgid "Failure: Invalid cookie"
 msgstr "Fehler: Ungültiger Cookie"
 
-#, c-format
 msgid "Failure: Authentication failed"
 msgstr "Fehler: Authentifizierung fehlgeschlagen"
 
@@ -9390,6 +9264,9 @@
 msgid "SIP usernames may not contain whitespaces or @ symbols"
 msgstr "SIP-Benutzernamen dürfen keine Leerzeichen oder @-Symbole enthalten"
 
+msgid "SIP connect server not specified"
+msgstr "SIP-Verbindungsserver nicht angegeben"
+
 #. *< type
 #. *< ui_requirement
 #. *< flags
@@ -9455,7 +9332,6 @@
 msgid "Warning of %s not allowed."
 msgstr "Verwarnung von %s nicht erlaubt."
 
-#, c-format
 msgid "A message has been dropped, you are exceeding the server speed limit."
 msgstr ""
 "Eine Nachricht ging verloren. Sie überschreiten die Geschwindigkeitsgrenze "
@@ -9479,39 +9355,30 @@
 "Eine Nachricht von %s hat Sie nicht erreicht, da sie zu schnell gesendet "
 "wurde."
 
-#, c-format
 msgid "Failure."
 msgstr "Fehler."
 
-#, c-format
 msgid "Too many matches."
 msgstr "Zu viele Übereinstimmungen."
 
-#, c-format
 msgid "Need more qualifiers."
 msgstr "Benötige mehr Angaben."
 
-#, c-format
 msgid "Dir service temporarily unavailable."
 msgstr "Verzeichnis-Dienst ist zur Zeit nicht verfügbar."
 
-#, c-format
 msgid "Email lookup restricted."
 msgstr "E-Mail-Suche eingeschränkt."
 
-#, c-format
 msgid "Keyword ignored."
 msgstr "Stichwort ignoriert."
 
-#, c-format
 msgid "No keywords."
 msgstr "Keine Stichwörter."
 
-#, c-format
 msgid "User has no directory information."
 msgstr "Der Benutzer hat kein Profil."
 
-#, c-format
 msgid "Country not supported."
 msgstr "Land nicht unterstützt."
 
@@ -9519,19 +9386,15 @@
 msgid "Failure unknown: %s."
 msgstr "Unbekannter Fehler: %s."
 
-#, c-format
 msgid "Incorrect username or password."
 msgstr "Ungültiger Benutzername oder Passwort."
 
-#, c-format
 msgid "The service is temporarily unavailable."
 msgstr "Der Dienst ist zur Zeit nicht verfügbar."
 
-#, c-format
 msgid "Your warning level is currently too high to log in."
 msgstr "Ihre Warnstufe ist zur Zeit zu hoch, um sich anzumelden."
 
-#, c-format
 msgid ""
 "You have been connecting and disconnecting too frequently.  Wait ten minutes "
 "and try again.  If you continue to try, you will need to wait even longer."
@@ -9891,13 +9754,9 @@
 msgid "Last Update"
 msgstr "Letzte Aktualisierung"
 
-#, c-format
-msgid "User information for %s unavailable"
-msgstr "Benutzerinformation für %s nicht verfügbar"
-
-msgid ""
-"Sorry, this profile seems to be in a language or format that is not "
-"supported at this time."
+#, fuzzy
+msgid ""
+"This profile is in a language or format that is not supported at this time."
 msgstr ""
 "Entschuldigung, das Profil enthält eine Sprache, die zur Zeit nicht "
 "unterstützt wird."
@@ -10372,29 +10231,24 @@
 msgstr " (%s)"
 
 #. 10053
-#, c-format
 msgid "Connection interrupted by other software on your computer."
 msgstr ""
 "Die Verbindung wurde von einer anderen Software auf ihrem Computer "
 "unterbrochen."
 
 #. 10054
-#, c-format
 msgid "Remote host closed connection."
 msgstr "Der entfernte Host hat die Verbindung beendet."
 
 #. 10060
-#, c-format
 msgid "Connection timed out."
 msgstr "Verbindungsabbruch wegen Zeitüberschreitung."
 
 #. 10061
-#, c-format
 msgid "Connection refused."
 msgstr "Verbindung abgelehnt."
 
 #. 10048
-#, c-format
 msgid "Address already in use."
 msgstr "Adresse wird bereits benutzt."
 
@@ -10518,7 +10372,7 @@
 msgid "Protocol"
 msgstr "Protokoll"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "<span size='larger' weight='bold'>Welcome to %s!</span>\n"
 "\n"
@@ -10533,9 +10387,9 @@
 "<span size='larger' weight='bold'>Willkommen bei %s!</span>\n"
 "\n"
 "Sie haben keine IM-Konten konfiguriert. Um sich mit %s zu verbinden, drücken "
-"Sie unten auf den <b>Hinzufügen</b>-Button und konfigurieren Sie Ihr erstes "
-"Konto. Wenn Sie mehrere IM-Konten mit %s benutzen wollen, drücken Sie erneut "
-"auf <b>Hinzufügen</b> um sie einzurichten.\n"
+"Sie unten auf den <b>Hinzufügen...</b>-Button und konfigurieren Sie Ihr "
+"erstes Konto. Wenn Sie mehrere IM-Konten mit %s benutzen wollen, drücken Sie "
+"erneut auf <b>Hinzufügen...</b> um sie einzurichten.\n"
 "\n"
 "Sie können später über <b>Konten->Konten verwalten</b> im Buddy-"
 "Listenfenster zu diesem Dialog zurückkehren und Konten hinzufügen, "
@@ -10966,9 +10820,8 @@
 msgid "Auto_join when account becomes online."
 msgstr "Automatisch _beitreten, wenn das Konto online geht."
 
-#, fuzzy
 msgid "_Remain in chat after window is closed."
-msgstr "_Chat verstecken, wenn das Fenster geschlossen wird."
+msgstr "In _Chat bleiben, nachdem das Fenster geschlossen wird."
 
 msgid "Please enter the name of the group to be added."
 msgstr "Bitte geben Sie den Namen der Gruppe ein, die hinzugefügt werden soll."
@@ -11626,7 +11479,6 @@
 "geschützt.  Die Datei 'COPYRIGHT' enthält die komplette Liste der "
 "Mitwirkenden.  Wir übernehmen keine Haftung für dieses Programm.<BR><BR>"
 
-#, c-format
 msgid "<FONT SIZE=\"4\">IRC:</FONT> #pidgin on irc.freenode.net<BR><BR>"
 msgstr "<FONT SIZE=\"4\">IRC:</FONT> #pidgin auf irc.freenode.net<BR><BR>"
 
@@ -11994,11 +11846,9 @@
 msgid "Save Image"
 msgstr "Bild speichern"
 
-#, c-format
 msgid "_Save Image..."
 msgstr "Bild _speichern..."
 
-#, c-format
 msgid "_Add Custom Smiley..."
 msgstr "Benutzerdefinierten Smiley _hinzufügen..."
 
@@ -12260,7 +12110,7 @@
 "                      nur das erste Konto aktiviert).\n"
 "  -v, --version       zeigt aktuelle Version und beendet das Programm\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"
@@ -12288,11 +12138,6 @@
 "der Core-Datei. Falls Sie nicht wissen, wie man einen \n"
 "Backtrace erstellt, lesen Sie bitte die Informationen auf \n"
 "%swiki/GetABacktrace\n"
-"\n"
-"Wenn Sie weitere Hilfe benötigen, kontaktieren sie bitte \n"
-"SeanEgn oder LSchiere (über AIM).  Kontaktinformationen \n"
-"für Sean und Luke über andere Protokolle finden Sie unter \n"
-"%swiki/DeveloperPages\n"
 
 #. Translators may want to transliterate the name.
 #. It is not to be translated.
@@ -12718,27 +12563,21 @@
 msgid "Sound Selection"
 msgstr "Klang-Auswahl"
 
-#, c-format
 msgid "Quietest"
 msgstr "Am leisesten"
 
-#, c-format
 msgid "Quieter"
 msgstr "Leiser"
 
-#, c-format
 msgid "Quiet"
 msgstr "Leise"
 
-#, c-format
 msgid "Loud"
 msgstr "Laut"
 
-#, c-format
 msgid "Louder"
 msgstr "Lauter"
 
-#, c-format
 msgid "Loudest"
 msgstr "Am lautesten"
 
@@ -13139,13 +12978,11 @@
 msgid "_Invite"
 msgstr "_Einladen"
 
-#, fuzzy
 msgid "_Modify..."
-msgstr "_Bearbeiten"
-
-#, fuzzy
+msgstr "_Bearbeiten..."
+
 msgid "_Add..."
-msgstr "_Hinzufügen"
+msgstr "_Hinzufügen..."
 
 msgid "_Open Mail"
 msgstr "Mail ö_ffnen"
@@ -13168,12 +13005,11 @@
 msgid "none"
 msgstr "keine"
 
-#, fuzzy
 msgid "Small"
-msgstr "E-Mail"
+msgstr "Klein"
 
 msgid "Smaller versions of the default smilies"
-msgstr ""
+msgstr "Kleinere Versionen der Default-Smileys"
 
 msgid "Response Probability:"
 msgstr "Antwortwahrscheinlichkeit:"
@@ -13760,7 +13596,6 @@
 msgid "Select Color"
 msgstr "Farbe auswählen"
 
-#, c-format
 msgid "Select Interface Font"
 msgstr "Schriftart wählen"
 
@@ -13835,18 +13670,16 @@
 
 #, c-format
 msgid "You can upgrade to %s %s today."
-msgstr ""
+msgstr "Sie können heute auf %s %s aktualisieren."
 
 msgid "New Version Available"
 msgstr "Neue Version verfügbar"
 
-#, fuzzy
 msgid "Later"
-msgstr "Datum"
-
-#, fuzzy
+msgstr "Später"
+
 msgid "Download Now"
-msgstr "Download %s: %s"
+msgstr "Jetzt herunterladen"
 
 #. *< type
 #. *< ui_requirement
@@ -13987,7 +13820,6 @@
 msgid "Timestamp Format Options"
 msgstr "Zeitstempelformat-Optionen"
 
-#, c-format
 msgid "_Force 24-hour time format"
 msgstr "_Erzwinge 24-Stunden Zeitformat"
 
@@ -14158,169 +13990,3 @@
 msgid "This plugin is useful for debbuging XMPP servers or clients."
 msgstr ""
 "Dieses Plugin ist nützlich zur Fehlersuche in XMPP-Servern oder -Clients."
-
-#~ msgid "Primary Information"
-#~ msgstr "Primäre Informationen"
-
-#~ msgid "Blood Type"
-#~ msgstr "Blutgruppe"
-
-#~ msgid "Update information"
-#~ msgstr "Informationen aktualisieren"
-
-#~ msgid "Successed:"
-#~ msgstr "Erfolgreich:"
-
-#~ msgid ""
-#~ "Setting custom faces is not currently supported. Please choose an image "
-#~ "from %s."
-#~ msgstr ""
-#~ "Das Setzen von benutzerdefinierten Gesichtern wird momentan nicht "
-#~ "unterstützt. Bitte wählen Sie ein Bild von %s."
-
-#~ msgid "Invalid QQ Face"
-#~ msgstr "Ungültiges QQ-Gesicht"
-
-# c-format
-#~ msgid "You rejected %d's request"
-#~ msgstr "Sie haben die Anfrage von %d abgelehnt"
-
-#~ msgid "Reject request"
-#~ msgstr "Anfrage ablehnen"
-
-#~ msgid "Add buddy with auth request failed"
-#~ msgstr "Benutzer hinzufügen, wenn Autorisierungsanfrage fehlschlug"
-
-#~ msgid "Add into %d's buddy list"
-#~ msgstr "Zu %ds Buddy-Liste hinzufügen"
-
-#~ msgid "QQ Number Error"
-#~ msgstr "Fehler in QQ-Nummer"
-
-#~ msgid "Group Description"
-#~ msgstr "Gruppenbeschreibung"
-
-#~ msgid "Auth"
-#~ msgstr "Autorisieren"
-
-#~ msgid "Approve"
-#~ msgstr "Akzeptieren"
-
-#~ msgid "Successed to join Qun %d, operated by admin %d"
-#~ msgstr "Erfolgreicher Beitritt in den Qun %d, moderiert vom Admin %d"
-
-#~ msgid "[%d] removed from Qun \"%d\""
-#~ msgstr "[%d] vom Qun „%d“ entfernt"
-
-#~ msgid "[%d] added to Qun \"%d\""
-#~ msgstr "[%d] zum Qun „%d“ hinzugefügt"
-
-#~ msgid "I am a member"
-#~ msgstr "Ich bin Mitglied"
-
-#~ msgid "I am requesting"
-#~ msgstr "Ich frage an"
-
-#~ msgid "I am the admin"
-#~ msgstr "Ich bin der Admin"
-
-#~ msgid "Unknown status"
-#~ msgstr "Unbekannter Status"
-
-#~ msgid "Remove from Qun"
-#~ msgstr "vom Qun entfernen"
-
-#~ msgid "You entered a group ID outside the acceptable range"
-#~ msgstr ""
-#~ "Sie haben eine Gruppen-ID außerhalb des erlaubten Bereichs angegeben"
-
-#~ msgid "Are you sure you want to leave this Qun?"
-#~ msgstr "Wollen Sie dieses Qun wirklich verlassen?"
-
-#~ msgid "Do you want to approve the request?"
-#~ msgstr "Wollen sie die Anfrage akzeptieren?"
-
-#~ msgid ""
-#~ "%s\n"
-#~ "\n"
-#~ "%s"
-#~ msgstr ""
-#~ "%s\n"
-#~ "\n"
-#~ "%s"
-
-#~ msgid "System Message"
-#~ msgstr "Systemnachricht"
-
-#~ msgid "<b>Last Login IP</b>: %s<br>\n"
-#~ msgstr "<b>Letzte Anmelde-IP</b>: %s<br>\n"
-
-#~ msgid "<b>Last Login Time</b>: %s\n"
-#~ msgstr "<b>Letzte Anmeldezeit</b>: %s\n"
-
-#~ msgid "Set My Information"
-#~ msgstr "Meine Informationen festlegen"
-
-#~ msgid "Leave the QQ Qun"
-#~ msgstr "Diesen QQ-Qun verlassen"
-
-#~ msgid "Block this buddy"
-#~ msgstr "Diesen Buddy blockieren"
-
-#~ msgid "Invalid token reply code, 0x%02X"
-#~ msgstr "Ungültiger Token-Antwort-Code, 0x%02X"
-
-#~ msgid "Unable login for not support Redirect_EX now"
-#~ msgstr "Anmeldung nicht möglich, Redirect_EX wird noch nicht unterstützt"
-
-#~ msgid "Error password: %s"
-#~ msgstr "Passwort-Fehler: %s"
-
-#~ msgid "Need active: %s"
-#~ msgstr "Brauche aktiv: %s"
-
-#~ msgid "Failed to connect all servers"
-#~ msgstr "Konnte nicht alle Server verbinden"
-
-#~ msgid "Connecting server %s, retries %d"
-#~ msgstr "Verbinde zu Server %s, %d Wiederholungen"
-
-#~ msgid "Do you approve the requestion?"
-#~ msgstr "Wollen sie die Anfrage akzeptieren?"
-
-#~ msgid "Do you add the buddy?"
-#~ msgstr "Möchten Sie diesen Buddy hinzufügen?"
-
-#~ msgid "%s added you [%s] to buddy list"
-#~ msgstr "%s hat Sie [%s] zur Buddy-Liste hinzugefügt"
-
-#~ msgid "QQ Budy"
-#~ msgstr "QQ-Buddy"
-
-#~ msgid "Requestion approved by %s"
-#~ msgstr "Anfrage akzeptiert von %s"
-
-#~ msgid "%s wants to add you [%s] as a friend"
-#~ msgstr "%s möchte Sie [%s] als Freund hinzufügen"
-
-#~ msgid "%s is not in buddy list"
-#~ msgstr "%s ist nicht in der Buddy-Liste"
-
-#~ msgid "Would you add?"
-#~ msgstr "Möchten Sie ihn hinzufügen?"
-
-#~ msgid "%s"
-#~ msgstr "%s"
-
-#~ msgid "QQ Server Notice"
-#~ msgstr "QQ-Server-Nachricht"
-
-#~ msgid ""
-#~ "You are using %s version %s.  The current version is %s.  You can get it "
-#~ "from <a href=\"%s\">%s</a><hr>"
-#~ msgstr ""
-#~ "Sie verwenden gerade %s Version %s.  Die aktuelle Version ist %s.  Sie "
-#~ "können Pidgin von <a href=\"%s\">%s</a> herunterladen.<hr>"
-
-#~ msgid "<b>ChangeLog:</b><br>%s"
-#~ msgstr "<b>Änderungen:</b><br>%s"
--- a/po/fi.po	Sun Dec 07 01:42:47 2008 +0000
+++ b/po/fi.po	Wed Dec 17 18:01:08 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	Sun Dec 07 01:42:47 2008 +0000
+++ b/po/fr.po	Wed Dec 17 18:01:08 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 :"
 
--- a/share/ca-certs/Makefile.am	Sun Dec 07 01:42:47 2008 +0000
+++ b/share/ca-certs/Makefile.am	Wed Dec 17 18:01:08 2008 +0000
@@ -3,19 +3,27 @@
 		CAcert_Class3.pem \
 		Equifax_Secure_CA.pem \
 		GTE_CyberTrust_Global_Root.pem \
-		Microsoft_Internet_Authority.pem \
-		Microsoft_Secure_Server_Authority.pem \
 		StartCom_Free_SSL_CA.pem \
 		Verisign_RSA_Secure_Server_CA.pem \
 		Verisign_Class3_Primary_CA.pem \
 		VeriSign_Class_3_Public_Primary_Certification_Authority_-_G5.pem
 
-if INSTALL_SSL_CERTIFICATES
+EXTRA_CERTS = \
+		Microsoft_Internet_Authority.pem \
+		Microsoft_Secure_Server_Authority.pem
+
+
 cacertsdir =	$(datadir)/purple/ca-certs
-cacerts_DATA =	$(CERTIFICATES)
+
+if INSTALL_SSL_CERTIFICATES
+cacerts_DATA = \
+	$(CERTIFICATES) \
+	$(EXTRA_CERTS)
+else
+cacerts_DATA = $(EXTRA_CERTS)
 endif
 
 EXTRA_DIST =	\
 		Makefile.mingw \
-		$(CERTIFICATES)
-
+		$(CERTIFICATES) \
+		$(EXTRA_CERTS)
--- a/share/ca-certs/Microsoft_Internet_Authority.pem	Sun Dec 07 01:42:47 2008 +0000
+++ b/share/ca-certs/Microsoft_Internet_Authority.pem	Wed Dec 17 18:01:08 2008 +0000
@@ -1,24 +1,29 @@
------BEGIN CERTIFICATE-----
-MIIECzCCA3SgAwIBAgIEBAAD/jANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJV
-UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
-cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
-b2JhbCBSb290MB4XDTA2MDQxOTE0MzUwMFoXDTA5MDQxOTIzNTkwMFowJzElMCMG
-A1UEAxMcTWljcm9zb2Z0IEludGVybmV0IEF1dGhvcml0eTCCASIwDQYJKoZIhvcN
-AQEBBQADggEPADCCAQoCggEBALUIbk0YdsTXnGPswqx8d/Ntrsjy8Wau8cKHBGBu
-KZwAZe5qW+QOU4gRxiKbM/trspEu1lObU77PVtiZSqFQMkXOYNLhlq1a/eqh68RJ
-Jxxev9KWmfppQ388ONqhi8wziHoXc66RUCiqabp751dbmwnnTN6GfIR952Zg+ab1
-wmGL3o7B1efCMCI9LIMKsId16yHiXKbTBHuWnkAe4Qx2BMAgoJQQ21EbTBhyvCfd
-EiRdOdYo1OTe2xih4JUPmXf7xPNDjMCrpjEJ8woxgCnH12z7PNPqwrhnFe/6808t
-axy4iNgObXcZS3ERcZBA9RFT1z3onQ2E2plkaBPmZQPiZu0CAwEAAaOCAXAwggFs
-MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly93d3cucHVibGljLXRydXN0LmNvbS9j
-Z2ktYmluL0NSTC8yMDE4L2NkcC5jcmwwHQYDVR0OBBYEFDNf3Q+3nFzO7ofdcHCL
-X33PIry5MFQGA1UdIARNMEswSQYKKoZIhvhjAQIBBTA7MDkGCCsGAQUFBwIBFi1o
-dHRwOi8vd3d3LnB1YmxpYy10cnVzdC5jb20vQ1BTL09tbmlSb290Lmh0bWwwgYkG
-A1UdIwSBgTB/oXmkdzB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBv
-cmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4x
-IzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290ggIBpTAOBgNVHQ8B
-Af8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBAjANBgkqhkiG9w0BAQUFAAOBgQBj
-SQlU7cXbnngZAIOa4zci+1Z2XFTTyOFc/Tfc0qU/xVWPZPBJdx2UVk2yCwmIHFBY
-OJSQC+7Kn7GE5nE3rBAyBrnB0oymBcBeD8tT3B4B31jHfnFgsC9UYin9uJN144+e
-tbzOegUg4qaNApAaWGre3YY7ALn1y/6XgqIEIEZcCQ==
------END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFCjCCBHOgAwIBAgIEBycWdTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
+cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
+b2JhbCBSb290MB4XDTA4MDIxOTE4MjcwMloXDTExMDIxOTE4MjQ1M1owJzElMCMG
+A1UEAxMcTWljcm9zb2Z0IEludGVybmV0IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcN
+AQEBBQADggIPADCCAgoCggIBAKiloatvDehDG/rQriel2AC9qmSJdvjKb2fmJf30
+K7SaC3zQu8kGQxENUEFsHsH0jmBejJ9vvn9tHZ8hGL+kORvWUVBskdMzP65rC0V0
+VeVgUYzPZ7MvrLfhh9+v3yJ7qRuf1aNgmzJg5t1AA91X+aRrFT4lRzl9BFWhQ1VS
+XaD7l6qoiyhD8FbrdLRAe61swsRmzWeXoy6NJpOBsGXaCSG1Jooylro+zkWxt97c
+NkNf/wYqoYcIXo02YpFbwreveejW9a0Lh/1z9+e9aiMtC5QnPT57GTqNINt5R0rp
+Iz4g3GJhmjXVoVF/tev5DMJuhRgPoz0W0aA3UnSmTWh2RFvgqawLqSRrKUhVjySi
+/m5s62uG5xxIftO7/6ljzS061CFoV/RBl/I3WghYp04sr4cSXWa/rL449YhBT8BJ
+jltefWCYAOcT1nA4oFXwXbl1qCUIkZ0bqwju2FGW5vl2qh6vmzcQjc3XxD0m2UqC
+yJNFa9SUgVXtUCqeOI+KqgLW01tpqZteG10byWKmppTVAvdPwHoGE0bl6wBwXldE
+f7Pn4lqu6Yp4bedP3Qv1sfp2H7D98cxSwYRt3UcXN2kjTPv+pby2fEHm9GWf3iE/
+7OtzUI7LYhP7+rGyuCYTtZKH1jDWHrTZBpnAPmrAQQHCI8/4TjF9ZQ1mqRi6x9I9
+9XGfAgMBAAGjggFvMIIBazASBgNVHRMBAf8ECDAGAQH/AgEBMFMGA1UdIARMMEow
+SAYJKwYBBAGxPgEAMDswOQYIKwYBBQUHAgEWLWh0dHA6Ly9jeWJlcnRydXN0Lm9t
+bmlyb290LmNvbS9yZXBvc2l0b3J5LmNmbTAOBgNVHQ8BAf8EBAMCAYYwgYkGA1Ud
+IwSBgTB/oXmkdzB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0
+aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAh
+BgNVBAMTGkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290ggIBpTBFBgNVHR8EPjA8
+MDqgOKA2hjRodHRwOi8vd3d3LnB1YmxpYy10cnVzdC5jb20vY2dpLWJpbi9DUkwv
+MjAxOC9jZHAuY3JsMB0GA1UdDgQWBBTG27vA2CAZkvFg/IjxWH+8G06PGjANBgkq
+hkiG9w0BAQUFAAOBgQBnSDXCyiqGmHTAEJOtZYVm/IbzGtzCY423NF6/yuccYZkm
+spJnDoh8nq3nx3P2KBEyPAqoQ1MEFC+ByQjV4AAQ9dMQALUGNRfHhFUhBeeIybYd
+bzvKOxSlIYSwO2T56+oXyDlkbQWKmHec5qzCE0lwGHslsRU/CHwhuFu2nH+CxQ==
+-----END CERTIFICATE-----
--- a/share/ca-certs/Microsoft_Secure_Server_Authority.pem	Sun Dec 07 01:42:47 2008 +0000
+++ b/share/ca-certs/Microsoft_Secure_Server_Authority.pem	Wed Dec 17 18:01:08 2008 +0000
@@ -1,30 +1,35 @@
 -----BEGIN CERTIFICATE-----
-MIIFEzCCA/ugAwIBAgIKYQVOAQADAAAAHDANBgkqhkiG9w0BAQUFADAnMSUwIwYD
-VQQDExxNaWNyb3NvZnQgSW50ZXJuZXQgQXV0aG9yaXR5MB4XDTA3MDkyODIyMDYz
-N1oXDTA5MDQxOTIzNTkwMFowgYsxEzARBgoJkiaJk/IsZAEZFgNjb20xGTAXBgoJ
+MIIGEzCCA/ugAwIBAgIKYRZtLwAEAAAAIDANBgkqhkiG9w0BAQUFADAnMSUwIwYD
+VQQDExxNaWNyb3NvZnQgSW50ZXJuZXQgQXV0aG9yaXR5MB4XDTA4MDQwOTIxMzc1
+NFoXDTExMDIxOTE4MjQ1M1owgYsxEzARBgoJkiaJk/IsZAEZFgNjb20xGTAXBgoJ
 kiaJk/IsZAEZFgltaWNyb3NvZnQxFDASBgoJkiaJk/IsZAEZFgRjb3JwMRcwFQYK
 CZImiZPyLGQBGRYHcmVkbW9uZDEqMCgGA1UEAxMhTWljcm9zb2Z0IFNlY3VyZSBT
 ZXJ2ZXIgQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
-xcCphW3RnMyuq1EAwlSsUghQUuCSQAaeFBTro1qbeCJEALHQGrXg8SMnY9Om64WG
-PnB9HhOb1LTOdkMVx6a3GU0mcv+LkefcW/CewIMfDXPoeGA4ULmY9wbraPwJY8Ba
-H3PAvOVSTJ0k9ZX6tXjE0D/214kn0+ZN+Y+ZwoqFC5/lgQyUxxgfVA0FsR/NDNF6
-keBsoNz2vPghAsruLhkON+5KGQo0o+T+XcJ7xNs7eJR7MWZn2rNCM1J+qrR0o2vG
-vz8QBSKogUXiPRXYVkNSkBEFZqGvEob1pDwC5fJEP71J6xEJHsSe0pcaa637RU04
-4BsjRHqJE3Rrlurb6Fc8vQIDAQABo4IB2jCCAdYwEgYDVR0TAQH/BAgwBgEB/wIB
-ATAdBgNVHQ4EFgQUmY+l9x6Bb/p5wvAWP7JUsQhoR1UwCwYDVR0PBAQDAgGGMBIG
-CSsGAQQBgjcVAQQFAgMEAAQwIwYJKwYBBAGCNxUCBBYEFBOB4Tms57aqAqhuDUms
-pmqjrALsMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMB8GA1UdIwQYMBaAFDNf
-3Q+3nFzO7ofdcHCLX33PIry5MIGjBgNVHR8EgZswgZgwgZWggZKggY+GNmh0dHA6
-Ly9tc2NybC5taWNyb3NvZnQuY29tL3BraS9tc2NvcnAvY3JsL21zd3d3KDMpLmNy
+kYTz6fKXvrdfIr5o3Ue4CRIzhTE+8JE4hrLTQki3emjYn/CfHRPb7hmMiOZmWBdE
+DUEymyXOyZ7Sy2tC6WaBC4onVYotPoSsaOZJv6EJeHPk64RiWTfX+XqufRndYOEC
+DUmotYQNPV/8InioIBf9+gOSsAMdmyGZF6C1PkJqvPZTRxNv6hxuMMb6uOQIPoFX
+/ceQvAOZcJx2qGsAVKsJHylYkC0GgVyFVhOI0vcZZBcP5T+NtOmyjVBWdxS413HL
+D+8w+3wG0bOP8EyOeRnuf0KLXGBangte0ZFIRd28GXpo5UrcA/r5000e2RTHmhC4
+8YPMIoi+q9XZoF5R0Z069QIDAQABo4IB2jCCAdYwEgYDVR0TAQH/BAgwBgEB/wIB
+ADAdBgNVHQ4EFgQUFFXEOeA9LtFVLkiWsNh+FCIGk7wwCwYDVR0PBAQDAgGGMBIG
+CSsGAQQBgjcVAQQFAgMFAAUwIwYJKwYBBAGCNxUCBBYEFM7FoL4P/nlmdZEP8PeS
+WzWYqBWzMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMB8GA1UdIwQYMBaAFMbb
+u8DYIBmS8WD8iPFYf7wbTo8aMIGjBgNVHR8EgZswgZgwgZWggZKggY+GNmh0dHA6
+Ly9tc2NybC5taWNyb3NvZnQuY29tL3BraS9tc2NvcnAvY3JsL21zd3d3KDQpLmNy
 bIY0aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9tc2NvcnAvY3JsL21zd3d3
-KDMpLmNybIYfaHR0cDovL2NvcnBwa2kvY3JsL21zd3d3KDMpLmNybDB5BggrBgEF
+KDQpLmNybIYfaHR0cDovL2NvcnBwa2kvY3JsL21zd3d3KDQpLmNybDB5BggrBgEF
 BQcBAQRtMGswPAYIKwYBBQUHMAKGMGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w
-a2kvbXNjb3JwL21zd3d3KDMpLmNydDArBggrBgEFBQcwAoYfaHR0cDovL2NvcnBw
-a2kvYWlhL21zd3d3KDMpLmNydDANBgkqhkiG9w0BAQUFAAOCAQEARSzU1qmSJczv
-IiFrscxgYtzXekBWgm2rYVIqN996H5ZfMDaso0tZXmhWo0zX0z0r0H+IIGtJ+4D9
-t6dMTpB26jV/5EtMbtQu48ryCkMHBKNtCn7pQ5Mq2gqjq84KrVUlBFfPT4z4+Hqp
-Q6gVghMggWNtiujdHh7w4ja3OqHkFZTX/wUSTb+BtH+GBZKYAGU6duakb3D0piFu
-W5W6gZ4j15R12ys3ZYTKThZjW5blolA0lzuCSghoSfJHRA4jChIzDNojkf7OxqJw
-yFl8+++iZwTiulCTgOucJxGCT1tEEwdfX2c+XKyJIS/d5Ndtk91WEWU+TzqX9ZT4
-SAMJpIZ1pg==
+a2kvbXNjb3JwL21zd3d3KDQpLmNydDArBggrBgEFBQcwAoYfaHR0cDovL2NvcnBw
+a2kvYWlhL21zd3d3KDQpLmNydDANBgkqhkiG9w0BAQUFAAOCAgEAempuzk/VLM4N
+H9TAbFtCjKc95iGmyx2bHbEk9m2cbGxXjBre+N4cJoIYYmhLrZ6L712ov1NjM73b
+m8fb2Fy8Yw8Cmwc8VtarPZT2yzGr8MhNUDVuZswaKfjCY3H7RYv/XKc7AOMd25WP
+/M0WTT4Bna6hl9dUaDGwv5SZFFIJ17FLo4FR2H7IkOOI/WcUPAHeDXUewp4qRPE/
+560xZrLSeNH2lKnOAwwXxwnXSo5WOF5AQXh1nRdbBV9Nu7yI6jH1QV6fKf6oFU2Y
+IOjpnJ0FihVB6XoZ0wNOUMzPEEQcTfIoVoc+t0iK02wcmTLgBgbYU703dHvvPTcn
+IfdI2mscx8l9MjUOdklIIve0FhCxRPqHpEeKjM95gllbXmWgQxAXiog+A62fEo5d
+M7nfeEyiweSlhj1cv+2dyhzyS5saKYkk3ocCnOMCyD0M+4gJx4n4b/zT3rcujyN+
+7m20PbBTjcdTT1+AxOs75rON2hhKUqqrk2MDCpnEJsNK4TuRyDUtm9r+AxaZ4XRK
+MT8InY1Xl9hzrIK6MVERYH46kxg6odwpzJ8Urn4dREBiMy6Gzq8mtyXvpYEcmeGL
+zz1aT7qNNbQ0qqbPb6RpOMHlUWOIhVWJC71T5WK1pynAc3P9zOm8BkUYvIyJvCbR
+bufCGVng4FAtVZ1advxSVRoa4GyuFZ8=
 -----END CERTIFICATE-----