changeset 20685:02df6998b466

propagate from branch 'im.pidgin.rlaager.merging.2_2_1_conflicts' (head 4ad1081695d083df424898e6e7091f731b401265) to branch 'im.pidgin.pidgin' (head d33243e8f5347776c81f81a0e4ba3a76ae5505a5)
author Richard Laager <rlaager@wiktel.com>
date Fri, 28 Sep 2007 16:34:43 +0000
parents 509ca8ebe515 (current diff) 8d9db4584f02 (diff)
children fd664b4aa4f1
files COPYRIGHT finch/gntconn.c finch/gntconv.c libpurple/protocols/jabber/buddy.c libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/message.c libpurple/protocols/msn/directconn.c libpurple/protocols/msn/msn-utils.c libpurple/protocols/msn/msn-utils.h libpurple/protocols/msn/servconn.c libpurple/protocols/msn/userlist.c libpurple/protocols/myspace/markup.c libpurple/protocols/myspace/myspace.c libpurple/protocols/oscar/oscar.c libpurple/util.c libpurple/win32/win32dep.c pidgin/gtkblist.c pidgin/gtkcellrendererexpander.c pidgin/gtkconv.c pidgin/gtkimhtmltoolbar.c pidgin/gtkmain.c pidgin/gtknotify.c pidgin/gtkprefs.c
diffstat 138 files changed, 12194 insertions(+), 3763 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Fri Sep 28 16:32:28 2007 +0000
+++ b/COPYRIGHT	Fri Sep 28 16:34:43 2007 +0000
@@ -246,6 +246,7 @@
 Kevin Miller
 Paul Miller
 Arkadiusz Miskiewicz
+David Mohr
 Andrew Molloy
 Michael Monreal
 Benjamin Moody
@@ -278,6 +279,7 @@
 Eduardo Pérez
 Matt Perry
 Nathan Peterson
+Sebastián E. Peyrott
 Celso Pinto
 Joao Luís Marques Pinto
 Aleksander Piotrowski
--- a/ChangeLog	Fri Sep 28 16:32:28 2007 +0000
+++ b/ChangeLog	Fri Sep 28 16:34:43 2007 +0000
@@ -1,5 +1,45 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+Version 2.2.1:
+	http://developer.pidgin.im/query?status=closed&milestone=2.2.1
+	
+	libpurple:
+	* A few build issues on Solaris were fixed.
+	* Cancelling the password prompt for an account will no longer leave
+	  it in an ambiguous state.  (It will be disabled.)
+	* Fixed an erroneous size display for MSN file transfers. (galt)
+	* Real usernames are now shown in the system log.
+	* Gmail notifications are better tracked
+
+	Pidgin:
+	* If you alias a buddy to an alias that is already present within
+	  a particular group, we now offer to merge the buddies into the
+	  same contact.
+	* A music emblem is now displayed in the buddy list for a buddy if we
+	  know she is listening to some soothing music.
+	* Added a 'Move to' menu in buddy list context menu for moving buddies
+	  to other groups as an alternative to dragging.
+	* Group headings are now marked via an underline instead of a
+	  different color background.
+	* It is now possible to mark a chat on your buddy list as "Persistent"
+	  so you do not leave the chat when the window or tab is closed.
+	* The auto-join option for chats is now listed in the "Add Chat"
+	  dialog along with the new persistence option.
+	* Closing an IM no longer immediately closes your conversation.  It
+	  will now remain active for a short time so that if the conversation
+	  resumes, the history will be retained.  A preference has been added
+	  to toggle this behavior.
+	* The "Smiley" menu has been moved to the top-level of the toolbar.
+	* Fixed keyboard tab reordering to move tabs one step instead of two.
+	* Pidgin's display is now saved with the command line for session
+	  restoration.  (David Mohr)
+	* You should no longer lose proxy settings when Pidgin is restarted.
+	* ICQ Birthday notifications are shown as buddy list emblems
+
+	Finch:
+	* Pressing 'Insert' in the buddylist will bring up the 'Add Buddy'
+	  dialog.
+
 Version 2.2.0 (09/13/2007):
 	http://developer.pidgin.im/query?status=closed&milestone=2.2.0
 
--- a/doc/funniest_home_convos.txt	Fri Sep 28 16:32:28 2007 +0000
+++ b/doc/funniest_home_convos.txt	Fri Sep 28 16:34:43 2007 +0000
@@ -487,3 +487,21 @@
             established that
 19:03 <user> its functioning just fine
 
+--
+
+17:12 <a_user> I think I foundage a bug
+17:13 <a_user> I don't think blocking works correctly for the AIM protocol
+17:13 <a_user> because a girl attempted to block me in pidgin and I can still
+               talk to her
+17:14 <a_user> [screen name expunged]: I already told you yesterday. You don't
+               need me to ease your mind, you want me to change MY mind. Well,
+               you're out of luck. I don't know how you're still messaging me,
+               because I already blocked you, but I demand you stop immediately.
+               For now on, I will save every message that you send me as
+               evidence for the next time I decide to call the police. I did
+               call them yesterday, but I didn't have evidence. The more you
+               message me now, the more you're digging you're own grave, so I
+               advice you to stop.
+17:14 <a_user> see?
+17:16 <sadrul> I think blocking in pidgin not working is not your biggest
+               problem here.
--- a/finch/gntblist.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/finch/gntblist.c	Fri Sep 28 16:34:43 2007 +0000
@@ -1510,6 +1510,8 @@
 	} else if (strcmp(text, GNT_KEY_CTRL_O) == 0) {
 		purple_prefs_set_bool(PREF_ROOT "/showoffline",
 				!purple_prefs_get_bool(PREF_ROOT "/showoffline"));
+	} else if (strcmp(text, GNT_KEY_INS) == 0) {
+		purple_blist_request_add_buddy(NULL, NULL, NULL, NULL);
 	} else if (!gnt_tree_is_searching(GNT_TREE(ggblist->tree))) {
 		if (strcmp(text, "t") == 0) {
 			finch_blist_toggle_tag_buddy(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)));
@@ -2225,9 +2227,27 @@
 }
 
 static void
+menu_add_buddy_cb(GntMenuItem *item, gpointer null)
+{
+	purple_blist_request_add_buddy(NULL, NULL, NULL, NULL);
+}
+
+static void
+menu_add_chat_cb(GntMenuItem *item, gpointer null)
+{
+	purple_blist_request_add_chat(NULL, NULL, NULL, NULL);
+}
+
+static void
+menu_add_group_cb(GntMenuItem *item, gpointer null)
+{
+	purple_blist_request_add_group();
+}
+
+static void
 create_menu()
 {
-	GntWidget *menu, *sub;
+	GntWidget *menu, *sub, *subsub;
 	GntMenuItem *item;
 	GntWindow *window;
 
@@ -2248,29 +2268,57 @@
 	gnt_menu_add_item(GNT_MENU(sub), item);
 	gnt_menuitem_set_callback(GNT_MENU_ITEM(item), send_im_select, NULL);
 
-	item = gnt_menuitem_check_new(_("Show empty groups"));
+	item = gnt_menuitem_new(_("Show"));
+	gnt_menu_add_item(GNT_MENU(sub), item);
+	subsub = gnt_menu_new(GNT_MENU_POPUP);
+	gnt_menuitem_set_submenu(item, GNT_MENU(subsub));
+
+	item = gnt_menuitem_check_new(_("Empty groups"));
 	gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item),
 				purple_prefs_get_bool(PREF_ROOT "/emptygroups"));
-	gnt_menu_add_item(GNT_MENU(sub), item);
+	gnt_menu_add_item(GNT_MENU(subsub), item);
 	gnt_menuitem_set_callback(GNT_MENU_ITEM(item), toggle_pref_cb, PREF_ROOT "/emptygroups");
 	
-	item = gnt_menuitem_check_new(_("Show offline buddies"));
+	item = gnt_menuitem_check_new(_("Offline buddies"));
 	gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item),
 				purple_prefs_get_bool(PREF_ROOT "/showoffline"));
-	gnt_menu_add_item(GNT_MENU(sub), item);
+	gnt_menu_add_item(GNT_MENU(subsub), item);
 	gnt_menuitem_set_callback(GNT_MENU_ITEM(item), toggle_pref_cb, PREF_ROOT "/showoffline");
 
-	item = gnt_menuitem_new(_("Sort by status"));
+	item = gnt_menuitem_new(_("Sort"));
 	gnt_menu_add_item(GNT_MENU(sub), item);
+	subsub = gnt_menu_new(GNT_MENU_POPUP);
+	gnt_menuitem_set_submenu(item, GNT_MENU(subsub));
+
+	item = gnt_menuitem_new(_("By Status"));
+	gnt_menu_add_item(GNT_MENU(subsub), item);
 	gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "status");
 
-	item = gnt_menuitem_new(_("Sort alphabetically"));
-	gnt_menu_add_item(GNT_MENU(sub), item);
+	item = gnt_menuitem_new(_("Alphabetically"));
+	gnt_menu_add_item(GNT_MENU(subsub), item);
 	gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "text");
 
-	item = gnt_menuitem_new(_("Sort by log size"));
+	item = gnt_menuitem_new(_("By Log Size"));
+	gnt_menu_add_item(GNT_MENU(subsub), item);
+	gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "log");
+
+	item = gnt_menuitem_new(_("Add"));
 	gnt_menu_add_item(GNT_MENU(sub), item);
-	gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "log");
+
+	subsub = gnt_menu_new(GNT_MENU_POPUP);
+	gnt_menuitem_set_submenu(item, GNT_MENU(subsub));
+
+	item = gnt_menuitem_new("Buddy");
+	gnt_menu_add_item(GNT_MENU(subsub), item);
+	gnt_menuitem_set_callback(item, menu_add_buddy_cb, NULL);
+
+	item = gnt_menuitem_new("Chat");
+	gnt_menu_add_item(GNT_MENU(subsub), item);
+	gnt_menuitem_set_callback(item, menu_add_chat_cb, NULL);
+
+	item = gnt_menuitem_new("Group");
+	gnt_menu_add_item(GNT_MENU(subsub), item);
+	gnt_menuitem_set_callback(item, menu_add_group_cb, NULL);
 
 	reconstruct_accounts_menu();
 	gnt_menu_add_item(GNT_MENU(menu), ggblist->accounts);
--- a/finch/gntconn.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/finch/gntconn.c	Fri Sep 28 16:34:43 2007 +0000
@@ -105,10 +105,11 @@
 {
 	FinchAutoRecon *info;
 	PurpleAccount *account = purple_connection_get_account(gc);
-
-	info = g_hash_table_lookup(hash, account);
+	GList *list;
 
 	if (!gc->wants_to_die) {
+		info = g_hash_table_lookup(hash, account);
+
 		if (info == NULL) {
 			info = g_new0(FinchAutoRecon, 1);
 			g_hash_table_insert(hash, account, info);
@@ -141,6 +142,17 @@
 		g_free(secondary);
 		purple_account_set_enabled(account, FINCH_UI, FALSE);
 	}
+
+	/* If we have any open chats, we probably want to rejoin when we get back online. */
+	list = purple_get_chats();
+	while (list) {
+		PurpleConversation *conv = list->data;
+		list = list->next;
+		if (conv->account != account ||
+				purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv)))
+			continue;
+		purple_conversation_set_data(conv, "want-to-rejoin", GINT_TO_POINTER(TRUE));
+	}
 }
 
 static void
--- a/finch/gntconv.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/finch/gntconv.c	Fri Sep 28 16:34:43 2007 +0000
@@ -311,13 +311,40 @@
 static void
 account_signed_on_off(PurpleConnection *gc, gpointer null)
 {
-	GList *ims = purple_get_ims();
-	while (ims) {
-		PurpleConversation *conv = ims->data;
+	GList *list = purple_get_ims();
+	while (list) {
+		PurpleConversation *conv = list->data;
 		PurpleConversation *cc = find_conv_with_contact(conv->account, conv->name);
 		if (cc)
 			generate_send_to_menu(cc->ui_data);
-		ims = ims->next;
+		list = list->next;
+	}
+
+	if (PURPLE_CONNECTION_IS_CONNECTED(gc)) {
+		/* We just signed on. Let's see if there's any chat that we have open,
+		 * and hadn't left before the disconnect. */
+		list = purple_get_chats();
+		while (list) {
+			PurpleConversation *conv = list->data;
+			PurpleChat *chat;
+			GHashTable *comps = NULL;
+
+			list = list->next;
+			if (conv->account != gc->account ||
+					!purple_conversation_get_data(conv, "want-to-rejoin"))
+				continue;
+
+			chat = purple_blist_find_chat(conv->account, conv->name);
+			if (chat == NULL) {
+				if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL)
+					comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, conv->name);
+			} else {
+				comps = chat->components;
+			}
+			serv_join_chat(gc, comps);
+			if (chat == NULL && comps != NULL)
+				g_hash_table_destroy(comps);
+		}
 	}
 }
 
@@ -738,7 +765,8 @@
 		gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv),
 					_("<AUTO-REPLY> "), GNT_TEXT_FLAG_BOLD);
 
-	if (who && *who && (flags & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)))
+	if (who && *who && (flags & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)) &&
+			!(flags & PURPLE_MESSAGE_NOTIFY))
 	{
 		char * name = NULL;
 
--- a/finch/gntnotify.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/finch/gntnotify.c	Fri Sep 28 16:34:43 2007 +0000
@@ -352,14 +352,17 @@
 		gnt_box_add_widget(GNT_BOX(window),
 			gnt_label_new_with_format(secondary, GNT_TEXT_FLAG_NORMAL));
 
-	columns = purple_notify_searchresults_get_columns_count(results);
+	columns = g_list_length(results->columns);
 	tree = gnt_tree_new_with_columns(columns);
 	gnt_tree_set_show_title(GNT_TREE(tree), TRUE);
 	gnt_box_add_widget(GNT_BOX(window), tree);
 
-	for (i = 0; i < columns; i++)
-		gnt_tree_set_column_title(GNT_TREE(tree), i, 
-				purple_notify_searchresults_column_get_title(results, i));
+	i = 0;
+	for (iter = results->columns; iter; iter = iter->next)
+	{
+		gnt_tree_set_column_title(GNT_TREE(tree), i, iter->data);
+		i++;
+	}
 
 	box = gnt_hbox_new(TRUE);
 
--- a/finch/libgnt/gntentry.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/finch/libgnt/gntentry.c	Fri Sep 28 16:34:43 2007 +0000
@@ -100,6 +100,15 @@
 	return changed;
 }
 
+static int
+max_common_prefix(const char *s, const char *t)
+{
+	const char *f = s;
+	while (*f && *t && *f == *t++)
+		f++;
+	return f - s;
+}
+
 static gboolean
 show_suggest_dropdown(GntEntry *entry)
 {
@@ -110,6 +119,7 @@
 	GList *iter;
 	const char *text = NULL;
 	const char *sgst = NULL;
+	int max = -1;
 
 	if (entry->word)
 	{
@@ -121,14 +131,13 @@
 	else
 		suggest = g_strdup(entry->start);
 	len = strlen(suggest);  /* Don't need to use the utf8-function here */
-	
+
 	if (entry->ddown == NULL)
 	{
 		GntWidget *box = gnt_vbox_new(FALSE);
 		entry->ddown = gnt_tree_new();
 		gnt_tree_set_compare_func(GNT_TREE(entry->ddown), (GCompareFunc)g_utf8_collate);
 		gnt_box_add_widget(GNT_BOX(box), entry->ddown);
-		/* XXX: Connect to the "activate" signal for the dropdown tree */
 
 		GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_TRANSIENT);
 
@@ -151,6 +160,10 @@
 					gnt_tree_create_row(GNT_TREE(entry->ddown), text),
 					NULL, NULL);
 			count++;
+			if (max == -1)
+				max = strlen(text) - len;
+			else if (max)
+				max = MIN(max, max_common_prefix(sgst + len, text + len));
 			sgst = text;
 		}
 	}
@@ -163,6 +176,17 @@
 		destroy_suggest(entry);
 		return complete_suggest(entry, sgst);
 	} else {
+		if (max > 0) {
+			GntWidget *ddown = entry->ddown;
+			char *match = g_strndup(sgst + len, max);
+			entry->ddown = NULL;
+			gnt_entry_key_pressed(GNT_WIDGET(entry), match);
+			g_free(match);
+			if (entry->ddown)
+				gnt_widget_destroy(ddown);
+			else
+				entry->ddown = ddown;
+		}
 		gnt_widget_draw(entry->ddown->parent);
 	}
 
--- a/libpurple/blist.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/blist.c	Fri Sep 28 16:34:43 2007 +0000
@@ -632,12 +632,13 @@
 			continue;
 
 		buddy = (PurpleBuddy*)bnode;
-
-		if (!purple_account_is_connected(buddy->account))
+		if (new_priority == NULL)
+		{
+			new_priority = buddy;
 			continue;
-		if (new_priority == NULL)
-			new_priority = buddy;
-		else
+		}
+
+		if (purple_account_is_connected(buddy->account))
 		{
 			int cmp;
 
@@ -1442,29 +1443,7 @@
 
 void purple_contact_set_alias(PurpleContact *contact, const char *alias)
 {
-	PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
-	char *old_alias;
-
-	g_return_if_fail(contact != NULL);
-
-	if (!purple_strings_are_different(contact->alias, alias))
-		return;
-
-	old_alias = contact->alias;
-
-	if ((alias != NULL) && (*alias != '\0'))
-		contact->alias = g_strdup(alias);
-	else
-		contact->alias = NULL;
-
-	purple_blist_schedule_save();
-
-	if (ops && ops->update)
-		ops->update(purplebuddylist, (PurpleBlistNode*)contact);
-
-	purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
-					 contact, old_alias);
-	g_free(old_alias);
+	purple_blist_alias_contact(contact,alias);
 }
 
 const char *purple_contact_get_alias(PurpleContact* contact)
--- a/libpurple/blist.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/blist.h	Fri Sep 28 16:34:43 2007 +0000
@@ -65,11 +65,11 @@
 
 typedef enum
 {
-	PURPLE_BLIST_NODE_FLAG_NO_SAVE = 1 /**< 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;
 
-#define PURPLE_BLIST_NODE_HAS_FLAG(b, f) ((b)->flags & (f))
+#define PURPLE_BLIST_NODE_HAS_FLAG(b, f) (((PurpleBlistNode*)(b))->flags & (f))
 #define PURPLE_BLIST_NODE_SHOULD_SAVE(b) (! PURPLE_BLIST_NODE_HAS_FLAG(b, PURPLE_BLIST_NODE_FLAG_NO_SAVE))
 
 #define PURPLE_BLIST_NODE_NAME(n) ((n)->type == PURPLE_BLIST_CHAT_NODE  ? purple_chat_get_name((PurpleChat*)n) :        \
@@ -488,6 +488,8 @@
  *
  * @param contact  The contact
  * @param alias    The alias to set, or NULL to unset
+ *
+ * @deprecated Use purple_blist_alias_contact() instead.
  */
 void purple_contact_set_alias(PurpleContact *contact, const char *alias);
 
--- a/libpurple/cmds.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/cmds.h	Fri Sep 28 16:34:43 2007 +0000
@@ -67,10 +67,20 @@
 	PURPLE_CMD_P_VERY_HIGH =  6000,
 };
 
+/** Flags used to set various properties of commands.  Every command should
+ *  have at least one of #PURPLE_CMD_FLAG_IM and #PURPLE_CMD_FLAG_CHAT set in
+ *  order to be even slighly useful.
+ *
+ *  @see purple_cmd_register
+ */
 enum _PurpleCmdFlag {
+	/** Command is usable in IMs. */
 	PURPLE_CMD_FLAG_IM               = 0x01,
+	/** Command is usable in multi-user chats. */
 	PURPLE_CMD_FLAG_CHAT             = 0x02,
+	/** 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,
 };
 
@@ -92,36 +102,49 @@
  * The command will only happen if commands are enabled,
  * which is a UI pref. UIs don't have to support commands at all.
  *
- * @param cmd The command. This should be a UTF8 (or ASCII) string, with no spaces
+ * @param cmd The command. This should be a UTF-8 (or ASCII) string, with no spaces
  *            or other white space.
- * @param args This tells Purple how to parse the arguments to the command for you.
- *             If what the user types doesn't match, Purple will keep looking for another
- *             command, unless the flag @c PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS is passed in f.
- *             This string contains no whitespace, and uses a single character for each argument.
- *             The recognized characters are:
- *               'w' Matches a single word.
- *               'W' Matches a single word, with formatting.
- *               's' Matches the rest of the arguments after this point, as a single string.
- *               'S' Same as 's' but with formatting.
+ * @param args A string of characters describing to libpurple how to parse this
+ *             command's arguments.  If what the user types doesn't match this
+ *             pattern, libpurple will keep looking for another command, unless
+ *             the flag #PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS is passed in @a f.
+ *             This string should contain no whitespace, and use a single
+ *             character for each argument.  The recognized characters are:
+ *             <ul>
+ *               <li><tt>'w'</tt>: Matches a single word.</li>
+ *               <li><tt>'W'</tt>: Matches a single word, with formatting.</li>
+ *               <li><tt>'s'</tt>: Matches the rest of the arguments after this
+ *                                 point, as a single string.</li>
+ *               <li><tt>'S'</tt>: Same as <tt>'s'</tt> but with formatting.</li>
+ *             </ul>
  *             If args is the empty string, then the command accepts no arguments.
- *             The args passed to callback func will be a @c NULL terminated array of null
- *             terminated strings, and will always match the number of arguments asked for,
- *             unless PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS is passed.
- * @param p This is the priority. Higher priority commands will be run first, and usually the
- *          first command will stop any others from being called.
- * @param f These are the flags. You need to at least pass one of PURPLE_CMD_FLAG_IM or
- *          PURPLE_CMD_FLAG_CHAT (can may pass both) in order for the command to ever actually
- *          be called.
- * @param prpl_id This is the prpl's id string. This is only meaningful if the proper flag is set.
+ *             The args passed to the callback @a func will be a @c NULL
+ *             terminated array of @c NULL terminated strings, and will always
+ *             match the number of arguments asked for, unless
+ *             #PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS is passed.
+ * @param p This is the priority. Higher priority commands will be run first,
+ *          and usually the first command will stop any others from being
+ *          called.
+ * @param f Flags specifying various options about this command, combined with
+ *          <tt>|</tt> (bitwise OR). You need to at least pass one of
+ *          #PURPLE_CMD_FLAG_IM or #PURPLE_CMD_FLAG_CHAT (you may pass both) in
+ *          order for the command to ever actually be called.
+ * @param prpl_id If the #PURPLE_CMD_FLAG_PRPL_ONLY flag is set, this is the id
+ *                of the prpl to which the command applies (such as
+ *                <tt>"prpl-msn"</tt>). If the flag is not set, this parameter
+ *                is ignored; pass @c NULL (or a humourous string of your
+ *                choice!).
  * @param func This is the function to call when someone enters this command.
- * @param helpstr This is a whitespace sensitive, UTF-8, HTML string describing how to use the command.
- *                The preferred format of this string shall be the commands name, followed by a space
- *                and any arguments it accepts (if it takes any arguments, otherwise no space), followed
- *                by a colon, two spaces, and a description of the command in sentence form. No slash
- *                before the command name.
- * @param data User defined data to pass to the PurpleCmdFunc
- * @return A PurpleCmdId. This is only used for calling purple_cmd_unregister.
- *         Returns 0 on failure.
+ * @param helpstr a whitespace sensitive, UTF-8, HTML string describing how to
+ *                use the command.  The preferred format of this string is the
+ *                command's name, followed by a space and any arguments it
+ *                accepts (if it takes any arguments, otherwise no space),
+ *                followed by a colon, two spaces, and a description of the
+ *                command in sentence form.  Do not include a slash before the
+ *                command name.
+ * @param data User defined data to pass to the #PurpleCmdFunc @a f.
+ * @return A #PurpleCmdId, which is only used for calling
+ *         #purple_cmd_unregister, or @a 0 on failure.
  */
 PurpleCmdId purple_cmd_register(const gchar *cmd, const gchar *args, PurpleCmdPriority p, PurpleCmdFlag f,
                              const gchar *prpl_id, PurpleCmdFunc func, const gchar *helpstr, void *data);
@@ -133,7 +156,7 @@
  * or something else that might go away. Normally this is called when the plugin
  * unloads itself.
  *
- * @param id The PurpleCmdId to unregister.
+ * @param id The #PurpleCmdId to unregister, as returned by #purple_cmd_register.
  */
 void purple_cmd_unregister(PurpleCmdId id);
 
@@ -153,7 +176,7 @@
  *               include both the default formatting and any extra manual formatting.
  * @param errormsg If the command failed errormsg is filled in with the appropriate error
  *                 message. It must be freed by the caller with g_free().
- * @return A PurpleCmdStatus indicated if the command succeeded or failed.
+ * @return A #PurpleCmdStatus indicated if the command succeeded or failed.
  */
 PurpleCmdStatus purple_cmd_do_command(PurpleConversation *conv, const gchar *cmdline,
                                   const gchar *markup, gchar **errormsg);
@@ -161,13 +184,15 @@
 /**
  * List registered commands.
  *
- * Returns a GList (which must be freed by the caller) of all commands
- * that are valid in the context of conv, or all commands, if conv is
- * @c NULL. Don't keep this list around past the main loop, or anything else
- * that might unregister a command, as the char*'s used get freed then.
+ * Returns a <tt>GList</tt> (which must be freed by the caller) of all commands
+ * that are valid in the context of @a conv, or all commands, if @a conv is @c
+ * NULL.  Don't keep this list around past the main loop, or anything else that
+ * might unregister a command, as the <tt>const char *</tt>'s used get freed
+ * then.
  *
  * @param conv The conversation, or @c NULL.
- * @return A GList of const char*, which must be freed with g_list_free().
+ * @return A @c GList of <tt>const char *</tt>, which must be freed with
+ *         <tt>g_list_free()</tt>.
  */
 GList *purple_cmd_list(PurpleConversation *conv);
 
@@ -180,7 +205,7 @@
  * @param conv The conversation, or @c NULL for no context.
  * @param cmd The command. No wildcards accepted, but returns help for all
  *            commands if @c NULL.
- * @return A GList of const char*s, which is the help string
+ * @return A <tt>GList</tt> of <tt>const char *</tt>s, which is the help string
  *         for that command.
  */
 GList *purple_cmd_help(PurpleConversation *conv, const gchar *cmd);
--- a/libpurple/conversation.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/conversation.c	Fri Sep 28 16:34:43 2007 +0000
@@ -2348,7 +2348,7 @@
 
 	purple_signal_register(handle, "chat-invited",
 						 purple_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER,
-						 NULL, 5,
+						 purple_value_new(PURPLE_TYPE_INT), 5,
 						 purple_value_new(PURPLE_TYPE_SUBTYPE,
 										PURPLE_SUBTYPE_ACCOUNT),
 						 purple_value_new(PURPLE_TYPE_STRING),
--- a/libpurple/internal.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/internal.h	Fri Sep 28 16:34:43 2007 +0000
@@ -80,6 +80,7 @@
 #ifndef _WIN32
 #include <sys/time.h>
 #include <sys/wait.h>
+#include <sys/time.h>
 #endif
 #include <ctype.h>
 #include <errno.h>
--- a/libpurple/notify.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/notify.h	Fri Sep 28 16:34:43 2007 +0000
@@ -293,7 +293,17 @@
 
 /**
  * Returns a number of the rows in the search results object.
- * 
+ *
+ * @deprecated This function will be removed in Pidgin 3.0.0 unless
+ *             there is sufficient demand to keep it.  Using this
+ *             function encourages looping through the results
+ *             inefficiently.  Instead of using this function you
+ *             should iterate through the results using a loop
+ *             similar to this:
+ *                for (l = results->rows; l != NULL; l = l->next)
+ *             If you really need to get the number of rows you
+ *             can use g_list_length(results->rows).
+ *
  * @param results The search results object.
  *
  * @return Number of the result rows.
@@ -303,6 +313,16 @@
 /**
  * Returns a number of the columns in the search results object.
  *
+ * @deprecated This function will be removed in Pidgin 3.0.0 unless
+ *             there is sufficient demand to keep it.  Using this
+ *             function encourages looping through the columns
+ *             inefficiently.  Instead of using this function you
+ *             should iterate through the columns using a loop
+ *             similar to this:
+ *                for (l = results->columns; l != NULL; l = l->next)
+ *             If you really need to get the number of columns you
+ *             can use g_list_length(results->columns).
+ *
  * @param results The search results object.
  *
  * @return Number of the columns.
@@ -312,6 +332,16 @@
 /**
  * Returns a row of the results from the search results object.
  *
+ * @deprecated This function will be removed in Pidgin 3.0.0 unless
+ *             there is sufficient demand to keep it.  Using this
+ *             function encourages looping through the results
+ *             inefficiently.  Instead of using this function you
+ *             should iterate through the results using a loop
+ *             similar to this:
+ *                for (l = results->rows; l != NULL; l = l->next)
+ *             If you really need to get the data for a particular
+ *             row you can use g_list_nth_data(results->rows, row_id).
+ *
  * @param results The search results object.
  * @param row_id  Index of the row to be returned.
  *
@@ -322,7 +352,15 @@
 
 /**
  * Returns a title of the search results object's column.
- * 
+ *
+ * @deprecated This function will be removed in Pidgin 3.0.0 unless
+ *             there is sufficient demand to keep it.  Using this
+ *             function encourages looping through the columns
+ *             inefficiently.  Instead of using this function you
+ *             should iterate through the name of a particular
+ *             column you can use
+ *             g_list_nth_data(results->columns, row_id).
+ *
  * @param results   The search results object.
  * @param column_id Index of the column.
  *
--- a/libpurple/plugins/tcl/tcl.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/plugins/tcl/tcl.c	Fri Sep 28 16:34:43 2007 +0000
@@ -60,6 +60,7 @@
 PurpleStringref *PurpleTclRefStatusAttr;
 PurpleStringref *PurpleTclRefStatusType;
 PurpleStringref *PurpleTclRefXfer;
+PurpleStringref *PurpleTclRefHandle;
 
 static GHashTable *tcl_plugins = NULL;
 
@@ -363,6 +364,7 @@
 	PurpleTclRefStatusAttr = purple_stringref_new("StatusAttr");
 	PurpleTclRefStatusType = purple_stringref_new("StatusType");
 	PurpleTclRefXfer = purple_stringref_new("Xfer");
+	PurpleTclRefHandle = purple_stringref_new("Handle");
 
 	tcl_plugins = g_hash_table_new(g_direct_hash, g_direct_equal);
 
--- a/libpurple/plugins/tcl/tcl_cmds.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/plugins/tcl/tcl_cmds.c	Fri Sep 28 16:34:43 2007 +0000
@@ -55,7 +55,7 @@
 			return account;
 	}
 	if (interp != NULL)
-		Tcl_SetStringObj(Tcl_GetObjResult(interp), "invalid account", -1);
+		Tcl_SetObjResult(interp, Tcl_NewStringObj("invalid account", -1));
 	return NULL;
 }
 
@@ -74,7 +74,7 @@
 			return convo;
 	}
 	if (interp != NULL)
-		Tcl_SetStringObj(Tcl_GetObjResult(interp), "invalid conversation", -1);
+		Tcl_SetObjResult(interp, Tcl_NewStringObj("invalid conversation", -1));
 	return NULL;
 }
 
@@ -97,7 +97,7 @@
 
 int tcl_cmd_account(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
 {
-	Tcl_Obj *result = Tcl_GetObjResult(interp), *list, *elem;
+	Tcl_Obj *result, *list, *elem;
 	const char *cmds[] = { "alias", "connect", "connection", "disconnect",
 	                       "enabled", "find", "handle", "isconnected",
 	                       "list", "presence", "protocol", "status",
@@ -139,7 +139,7 @@
 		if ((account = tcl_validate_account(objv[2], interp)) == NULL)
 			return TCL_ERROR;
 		alias = purple_account_get_alias(account);
-		Tcl_SetStringObj(result, alias ? (char *)alias : "", -1);
+		Tcl_SetObjResult(interp, Tcl_NewStringObj(alias ? (char *)alias : "", -1));
 		break;
 	case CMD_ACCOUNT_CONNECT:
 		if (objc != 3) {
@@ -164,7 +164,7 @@
 			return TCL_ERROR;
 		Tcl_SetObjResult(interp,
 		                 purple_tcl_ref_new(PurpleTclRefConnection,
-		                                  purple_account_get_connection(account)));
+						    purple_account_get_connection(account)));
 		break;
 	case CMD_ACCOUNT_DISCONNECT:
 		if (objc != 3) {
@@ -183,9 +183,10 @@
 		if ((account = tcl_validate_account(objv[2], interp)) == NULL)
 			return TCL_ERROR;
 		if (objc == 3) {
-			Tcl_SetBooleanObj(result,
-					  purple_account_get_enabled(account,
-								   purple_core_get_ui()));
+			Tcl_SetObjResult(interp, 
+					 Tcl_NewBooleanObj(
+						 purple_account_get_enabled(account,
+									    purple_core_get_ui())));
 		} else {
 			if ((error = Tcl_GetBooleanFromObj(interp, objv[3], &b)) != TCL_OK)
 				return TCL_ERROR;
@@ -207,7 +208,9 @@
 			Tcl_WrongNumArgs(interp, 2, objv, "");
 			return TCL_ERROR;
 		}
-		Tcl_SetIntObj(result, (int)purple_accounts_get_handle());
+		Tcl_SetObjResult(interp, 
+				 purple_tcl_ref_new(PurpleTclRefHandle,
+						    purple_accounts_get_handle()));
 		break;
 	case CMD_ACCOUNT_ISCONNECTED:
 		if (objc != 3) {
@@ -216,7 +219,9 @@
 		}
 		if ((account = tcl_validate_account(objv[2], interp)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetBooleanObj(result, purple_account_is_connected(account));
+		Tcl_SetObjResult(interp,
+				 Tcl_NewBooleanObj(
+					 purple_account_is_connected(account)));
 		break;
 	case CMD_ACCOUNT_LIST:
 		listopt = CMD_ACCOUNTLIST_ALL;
@@ -255,7 +260,7 @@
 		}
 		if ((account = tcl_validate_account(objv[2], interp)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetStringObj(result, (char *)purple_account_get_protocol_id(account), -1);
+		Tcl_SetObjResult(interp, Tcl_NewStringObj((char *)purple_account_get_protocol_id(account), -1));
 		break;
 	case CMD_ACCOUNT_STATUS:
 		if (objc < 3) {
@@ -271,19 +276,19 @@
 		} else {
 			GList *l = NULL;
 			if (objc % 2) {
-				Tcl_SetStringObj(result, "name without value setting status", -1);
+				Tcl_SetObjResult(interp, Tcl_NewStringObj("name without value setting status", -1));
 				return TCL_ERROR;
 			}
 			status = purple_account_get_status(account, Tcl_GetString(objv[3]));
 			if (status == NULL) {
-				Tcl_SetStringObj(result, "invalid status for account", -1);
+				Tcl_SetObjResult(interp, Tcl_NewStringObj("invalid status for account", -1));
 				return TCL_ERROR;
 			}
 			for (i = 4; i < objc; i += 2) {
 				attr_id = Tcl_GetString(objv[i]);
 				value = purple_status_get_attr_value(status, attr_id);
 				if (value == NULL) {
-					Tcl_SetStringObj(result, "invalid attribute for account", -1);
+					Tcl_SetObjResult(interp, Tcl_NewStringObj("invalid attribute for account", -1));
 					return TCL_ERROR;
 				}
 				switch (purple_value_get_type(value)) {
@@ -306,7 +311,7 @@
 					l = g_list_append(l, Tcl_GetString(objv[i + 1]));
 					break;
 				default:
-					Tcl_SetStringObj(result, "unknown PurpleValue type", -1);
+					Tcl_SetObjResult(interp, Tcl_NewStringObj("unknown PurpleValue type", -1));
 					return TCL_ERROR;
 				}
 			}
@@ -327,10 +332,10 @@
 		} else {
 			PurpleStatusPrimitive primitive;
 			if (strcmp(Tcl_GetString(objv[3]), "-primitive")) {
-				Tcl_SetStringObj(result, "bad option \"", -1);
+				result = Tcl_NewStringObj("bad option \"", -1);
 				Tcl_AppendObjToObj(result, objv[3]);
-				Tcl_AppendToObj(result,
-						"\": should be -primitive", -1);
+				Tcl_AppendToObj(result, "\": should be -primitive", -1);
+				Tcl_SetObjResult(interp,result);
 				return TCL_ERROR;
 			}
 			primitive = purple_primitive_get_type_from_id(Tcl_GetString(objv[4]));
@@ -338,7 +343,7 @@
 										  primitive);
 		}
 		if (status_type == NULL) {
-			Tcl_SetStringObj(result, "status type not found", -1);
+			Tcl_SetObjResult(interp, Tcl_NewStringObj("status type not found", -1));
 			return TCL_ERROR;
 		}
 		Tcl_SetObjResult(interp,
@@ -368,7 +373,8 @@
 		}
 		if ((account = tcl_validate_account(objv[2], interp)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetStringObj(result, (char *)purple_account_get_username(account), -1);
+		Tcl_SetObjResult(interp, 
+				 Tcl_NewStringObj((char *)purple_account_get_username(account), -1));
 		break;
 	}
 
@@ -383,7 +389,8 @@
 	char *type;
 
 	if (count < 3) {
-		Tcl_SetStringObj(Tcl_GetObjResult(interp), "list too short", -1);
+		Tcl_SetObjResult(interp,
+                                 Tcl_NewStringObj("list too short", -1));
 		return NULL;
 	}
 
@@ -420,8 +427,6 @@
 	if ((error = Tcl_GetIndexFromObj(interp, objv[1], cmds, "subcommand", 0, (int *)&cmd)) != TCL_OK)
 		return error;
 
-	result = Tcl_GetObjResult(interp);
-
 	switch (cmd) {
 	case CMD_BUDDY_ALIAS:
 		if (objc != 3) {
@@ -433,9 +438,11 @@
 		if ((node = tcl_list_to_buddy(interp, count, elems)) == NULL)
 			return TCL_ERROR;
 		if (node->type == PURPLE_BLIST_CHAT_NODE)
-			Tcl_SetStringObj(result, ((PurpleChat *)node)->alias, -1);
+			Tcl_SetObjResult(interp,
+					 Tcl_NewStringObj(((PurpleChat *)node)->alias, -1));
 		else if (node->type == PURPLE_BLIST_BUDDY_NODE)
-			Tcl_SetStringObj(result, (char *)purple_buddy_get_alias((PurpleBuddy *)node), -1);
+			Tcl_SetObjResult(interp,
+                                         Tcl_NewStringObj((char *)purple_buddy_get_alias((PurpleBuddy *)node), -1));
 		return TCL_OK;
 		break;
 	case CMD_BUDDY_HANDLE:
@@ -443,7 +450,9 @@
 			Tcl_WrongNumArgs(interp, 2, objv, "");
 			return TCL_ERROR;
 		}
-		Tcl_SetIntObj(result, (int)purple_blist_get_handle());
+		Tcl_SetObjResult(interp,
+				 purple_tcl_ref_new(PurpleTclRefHandle,
+						    purple_blist_get_handle()));
 		break;
 	case CMD_BUDDY_INFO:
 		if (objc != 3 && objc != 4) {
@@ -454,11 +463,13 @@
 			if ((error = Tcl_ListObjGetElements(interp, objv[2], &count, &elems)) != TCL_OK)
 				return error;
 			if (count < 3) {
-				Tcl_SetStringObj(result, "buddy too short", -1);
+				Tcl_SetObjResult(interp,
+						 Tcl_NewStringObj("buddy too short", -1));
 				return TCL_ERROR;
 			}
 			if (strcmp("buddy", Tcl_GetString(elems[0]))) {
-				Tcl_SetStringObj(result, "invalid buddy", -1);
+				Tcl_SetObjResult(interp,
+						 Tcl_NewStringObj("invalid buddy", -1));
 				return TCL_ERROR;
 			}
 			if ((account = tcl_validate_account(elems[2], interp)) == NULL)
@@ -475,8 +486,9 @@
 			if (!strcmp("-all", Tcl_GetString(objv[2]))) {
 				all = 1;
 			} else {
-				Tcl_SetStringObj(result, "", -1);
+				result = Tcl_NewStringObj("",-1);
 				Tcl_AppendStringsToObj(result, "unknown option: ", Tcl_GetString(objv[2]), NULL);
+				Tcl_SetObjResult(interp,result);
 				return TCL_ERROR;
 			}
 		}
@@ -547,7 +559,7 @@
 	const char *cmds[] = { "do", "help", "list", "register", "unregister", NULL };
 	enum { CMD_CMD_DO, CMD_CMD_HELP, CMD_CMD_LIST, CMD_CMD_REGISTER, CMD_CMD_UNREGISTER } cmd;
 	struct tcl_cmd_handler *handler;
-	Tcl_Obj *list, *elem, *result = Tcl_GetObjResult(interp);
+	Tcl_Obj *list, *elem;
 	PurpleConversation *convo;
 	PurpleCmdId id;
 	PurpleCmdStatus status;
@@ -575,7 +587,8 @@
 		status = purple_cmd_do_command(convo, Tcl_GetString(objv[3]),
 				escaped, &errstr);
 		g_free(escaped);
-		Tcl_SetStringObj(result, errstr ? (char *)errstr : "", -1);
+		Tcl_SetObjResult(interp,
+				 Tcl_NewStringObj(errstr ? (char *)errstr : "", -1));
 		g_free(errstr);
 		if (status != PURPLE_CMD_STATUS_OK) {
 			return TCL_ERROR;
@@ -640,10 +653,10 @@
 		handler->interp = interp;
 		if ((id = tcl_cmd_register(handler)) == 0) {
 			tcl_cmd_handler_free(handler);
-			Tcl_SetIntObj(result, 0);
+			Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
 		} else {
 			handler->id = id;
-			Tcl_SetIntObj(result, id);
+			Tcl_SetObjResult(interp, Tcl_NewIntObj(id));
 		}
 		break;
 	case CMD_CMD_UNREGISTER:
@@ -663,7 +676,7 @@
 
 int tcl_cmd_connection(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
 {
-	Tcl_Obj *result = Tcl_GetObjResult(interp), *list, *elem;
+	Tcl_Obj *list, *elem;
 	const char *cmds[] = { "account", "displayname", "handle", "list", NULL };
 	enum { CMD_CONN_ACCOUNT, CMD_CONN_DISPLAYNAME, CMD_CONN_HANDLE, CMD_CONN_LIST } cmd;
 	int error;
@@ -697,14 +710,16 @@
 		}
 		if ((gc = tcl_validate_gc(objv[2], interp)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetStringObj(result, (char *)purple_connection_get_display_name(gc), -1);
+		Tcl_SetObjResult(interp,
+                                 Tcl_NewStringObj(purple_connection_get_display_name(gc), -1));
 		break;
 	case CMD_CONN_HANDLE:
 		if (objc != 2) {
 			Tcl_WrongNumArgs(interp, 2, objv, "");
 			return TCL_ERROR;
 		}
-		Tcl_SetIntObj(result, (int)purple_connections_get_handle());
+		Tcl_SetObjResult(interp, purple_tcl_ref_new(PurpleTclRefHandle,
+							    purple_connections_get_handle()));
 		break;
 	case CMD_CONN_LIST:
 		if (objc != 2) {
@@ -725,7 +740,7 @@
 
 int tcl_cmd_conversation(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
 {
-	Tcl_Obj *list, *elem, *result = Tcl_GetObjResult(interp);
+	Tcl_Obj *list, *elem;
 	const char *cmds[] = { "find", "handle", "list", "new", "write", "name", "title", "send", NULL };
 	enum { CMD_CONV_FIND, CMD_CONV_HANDLE, CMD_CONV_LIST, CMD_CONV_NEW, CMD_CONV_WRITE , CMD_CONV_NAME, CMD_CONV_TITLE, CMD_CONV_SEND } cmd;
 	const char *styles[] = { "send", "recv", "system", NULL };
@@ -766,7 +781,9 @@
 			Tcl_WrongNumArgs(interp, 2, objv, "");
 			return TCL_ERROR;
 		}
-		Tcl_SetIntObj(result, (int)purple_conversations_get_handle());
+		Tcl_SetObjResult(interp,
+		                 purple_tcl_ref_new(PurpleTclRefHandle,
+						    purple_conversations_get_handle()));
 		break;
 	case CMD_CONV_LIST:
 		list = Tcl_NewListObj(0, NULL);
@@ -847,7 +864,8 @@
 
 		if ((convo = tcl_validate_conversation(objv[2], interp)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetStringObj(result, (char *)purple_conversation_get_name(convo), -1);
+		Tcl_SetObjResult(interp,
+				 Tcl_NewStringObj((char *)purple_conversation_get_name(convo), -1));
 		break;
 	case CMD_CONV_TITLE:
 		if (objc != 3) {
@@ -857,7 +875,8 @@
 
 		if ((convo = tcl_validate_conversation(objv[2], interp)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetStringObj(result, (char *)purple_conversation_get_title(convo), -1);
+		Tcl_SetObjResult(interp,
+                                 Tcl_NewStringObj((char *)purple_conversation_get_title(convo), -1));
 		break;
 	case CMD_CONV_SEND:
 		if (objc != 4) {
@@ -879,7 +898,6 @@
 
 int tcl_cmd_core(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
 {
-	Tcl_Obj *result = Tcl_GetObjResult(interp);
 	const char *cmds[] = { "handle", "quit", NULL };
 	enum { CMD_CORE_HANDLE, CMD_CORE_QUIT } cmd;
 	int error;
@@ -898,7 +916,9 @@
 			Tcl_WrongNumArgs(interp, 2, objv, "");
 			return TCL_ERROR;
 		}
-		Tcl_SetIntObj(result, (int)purple_get_core());
+		Tcl_SetObjResult(interp,
+                                 purple_tcl_ref_new(PurpleTclRefHandle,
+						    purple_get_core()));
 		break;
 	case CMD_CORE_QUIT:
 		if (objc != 2) {
@@ -970,7 +990,6 @@
 
 int tcl_cmd_plugins(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
 {
-	Tcl_Obj *result = Tcl_GetObjResult(interp);
 	const char *cmds[] = { "handle", NULL };
 	enum { CMD_PLUGINS_HANDLE } cmd;
 	int error;
@@ -989,7 +1008,9 @@
 			Tcl_WrongNumArgs(interp, 2, objv, "");
 			return TCL_ERROR;
 		}
-		Tcl_SetIntObj(result, (int)purple_plugins_get_handle());
+		Tcl_SetObjResult(interp,
+				purple_tcl_ref_new(PurpleTclRefHandle,
+						   purple_plugins_get_handle()));
 		break;
 	}
 
@@ -998,7 +1019,7 @@
 
 int tcl_cmd_prefs(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
 {
-	Tcl_Obj *result, *list, *elem, **elems;
+	Tcl_Obj *list, *elem, **elems;
 	const char *cmds[] = { "get", "set", "type", NULL };
 	enum { CMD_PREFS_GET, CMD_PREFS_SET, CMD_PREFS_TYPE } cmd;
 	/* char *types[] = { "none", "boolean", "int", "string", "stringlist", NULL }; */
@@ -1015,7 +1036,6 @@
 	if ((error = Tcl_GetIndexFromObj(interp, objv[1], cmds, "subcommand", 0, (int *)&cmd)) != TCL_OK)
 		return error;
 
-	result = Tcl_GetObjResult(interp);
 	switch (cmd) {
 	case CMD_PREFS_GET:
 		if (objc != 3) {
@@ -1025,17 +1045,21 @@
 		preftype = purple_prefs_get_type(Tcl_GetString(objv[2]));
 		switch (preftype) {
 		case PURPLE_PREF_NONE:
-			Tcl_SetStringObj(result, "pref type none", -1);
+			Tcl_SetObjResult(interp,
+					 Tcl_NewStringObj("pref type none", -1));
 			return TCL_ERROR;
 			break;
 		case PURPLE_PREF_BOOLEAN:
-			Tcl_SetBooleanObj(result, purple_prefs_get_bool(Tcl_GetString(objv[2])));
+			Tcl_SetObjResult(interp,
+					 Tcl_NewBooleanObj(
+						 purple_prefs_get_bool(Tcl_GetString(objv[2]))));
 			break;
 		case PURPLE_PREF_INT:
-			Tcl_SetIntObj(result, purple_prefs_get_int(Tcl_GetString(objv[2])));
+			Tcl_SetObjResult(interp, Tcl_NewIntObj(purple_prefs_get_int(Tcl_GetString(objv[2]))));
 			break;
 		case PURPLE_PREF_STRING:
-			Tcl_SetStringObj(result, (char *)purple_prefs_get_string(Tcl_GetString(objv[2])), -1);
+			Tcl_SetObjResult(interp,
+					 Tcl_NewStringObj((char *)purple_prefs_get_string(Tcl_GetString(objv[2])), -1));
 			break;
 		case PURPLE_PREF_STRING_LIST:
 			cur = purple_prefs_get_string_list(Tcl_GetString(objv[2]));
@@ -1049,7 +1073,8 @@
 			break;
 		default:
 			purple_debug(PURPLE_DEBUG_ERROR, "tcl", "tcl does not know about pref type %d\n", preftype);
-			Tcl_SetStringObj(result, "unknown pref type", -1);
+			Tcl_SetObjResult(interp,
+					 Tcl_NewStringObj("unknown pref type", -1));
 			return TCL_ERROR;
 		}
 		break;
@@ -1061,7 +1086,8 @@
 		preftype = purple_prefs_get_type(Tcl_GetString(objv[2]));
 		switch (preftype) {
 		case PURPLE_PREF_NONE:
-			Tcl_SetStringObj(result, "bad path or pref type none", -1);
+			Tcl_SetObjResult(interp,
+					 Tcl_NewStringObj("bad path or pref type none", -1));
 			return TCL_ERROR;
 			break;
 		case PURPLE_PREF_BOOLEAN:
@@ -1100,23 +1126,23 @@
 		preftype = purple_prefs_get_type(Tcl_GetString(objv[2]));
 		switch (preftype) {
 		case PURPLE_PREF_NONE:
-			Tcl_SetStringObj(result, "none", -1);
+			Tcl_SetObjResult(interp, Tcl_NewStringObj("none", -1));
 			break;
 		case PURPLE_PREF_BOOLEAN:
-			Tcl_SetStringObj(result, "boolean", -1);
+			Tcl_SetObjResult(interp, Tcl_NewStringObj("boolean", -1));
 			break;
 		case PURPLE_PREF_INT:
-			Tcl_SetStringObj(result, "int", -1);
+			Tcl_SetObjResult(interp, Tcl_NewStringObj("int", -1));
 			break;
 		case PURPLE_PREF_STRING:
-			Tcl_SetStringObj(result, "string", -1);
+			Tcl_SetObjResult(interp, Tcl_NewStringObj("string", -1));
 			break;
 		case PURPLE_PREF_STRING_LIST:
-			Tcl_SetStringObj(result, "stringlist", -1);
+			Tcl_SetObjResult(interp, Tcl_NewStringObj("stringlist", -1));
 			break;
 		default:
 			purple_debug(PURPLE_DEBUG_ERROR, "tcl", "tcl does not know about pref type %d\n", preftype);
-			Tcl_SetStringObj(result, "unknown", -1);
+			Tcl_SetObjResult(interp, Tcl_NewStringObj("unknown", -1));
 		}
 		break;
 	}
@@ -1134,7 +1160,7 @@
 	       CMD_PRESENCE_CONTEXT, CMD_PRESENCE_CONVERSATION,
 	       CMD_PRESENCE_IDLE, CMD_PRESENCE_LOGIN, CMD_PRESENCE_ONLINE,
 	       CMD_PRESENCE_STATUS, CMD_PRESENCE_STATUSES } cmd;
-	Tcl_Obj *result = Tcl_GetObjResult(interp);
+	Tcl_Obj *result;
 	Tcl_Obj *list, *elem;
 	PurplePresence *presence;
 	GList *cur;
@@ -1171,25 +1197,30 @@
 					 purple_tcl_ref_new(PurpleTclRefStatus,
 							  purple_presence_get_active_status(presence)));
 		} else if (objc == 4) {
-			Tcl_SetBooleanObj(result,
-					  purple_presence_is_status_active(presence,
-									 Tcl_GetString(objv[3])));
+			Tcl_SetObjResult(interp,
+                                         Tcl_NewBooleanObj(
+						 purple_presence_is_status_active(presence,
+										  Tcl_GetString(objv[3]))));
 		} else {
 			PurpleStatusPrimitive primitive;
 			if (strcmp(Tcl_GetString(objv[3]), "-primitive")) {
-				Tcl_SetStringObj(result, "bad option \"", -1);
+				result = Tcl_NewStringObj("bad option \"", -1);
 				Tcl_AppendObjToObj(result, objv[3]);
 				Tcl_AppendToObj(result,
 						"\": should be -primitive", -1);
+				Tcl_SetObjResult(interp,result);
 				return TCL_ERROR;
 			}
 			primitive = purple_primitive_get_type_from_id(Tcl_GetString(objv[4]));
 			if (primitive == PURPLE_STATUS_UNSET) {
-				Tcl_SetStringObj(result, "invalid primitive ", -1);
+				result = Tcl_NewStringObj("invalid primitive ", -1);
 				Tcl_AppendObjToObj(result, objv[4]);
+				Tcl_SetObjResult(interp,result);
 				return TCL_ERROR;
 			}
-			Tcl_SetBooleanObj(result, purple_presence_is_status_primitive_active(presence, primitive));
+			Tcl_SetObjResult(interp,
+                                         Tcl_NewBooleanObj(
+						 purple_presence_is_status_primitive_active(presence, primitive)));
 			break;
 		}
 		break;
@@ -1200,7 +1231,8 @@
 		}
 		if ((presence = purple_tcl_ref_get(interp, objv[2], PurpleTclRefPresence)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetBooleanObj(result, purple_presence_is_available(presence));
+		Tcl_SetObjResult(interp,
+				 Tcl_NewBooleanObj(purple_presence_is_available(presence)));
 		break;
 	case CMD_PRESENCE_CHAT_USER:
 		if (objc != 3) {
@@ -1209,7 +1241,8 @@
 		}
 		if ((presence = purple_tcl_ref_get(interp, objv[2], PurpleTclRefPresence)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetStringObj(result, purple_presence_get_chat_user(presence), -1);
+		Tcl_SetObjResult(interp,
+				 Tcl_NewStringObj(purple_presence_get_chat_user(presence), -1));
 		break;
 	case CMD_PRESENCE_CONTEXT:
 		if (objc != 3) {
@@ -1220,16 +1253,16 @@
 			return TCL_ERROR;
 		switch (purple_presence_get_context(presence)) {
 		case PURPLE_PRESENCE_CONTEXT_UNSET:
-			Tcl_SetStringObj(result, "unset", -1);
+			Tcl_SetObjResult(interp, Tcl_NewStringObj("unset", -1));
 			break;
 		case PURPLE_PRESENCE_CONTEXT_ACCOUNT:
-			Tcl_SetStringObj(result, "account", -1);
+			Tcl_SetObjResult(interp, Tcl_NewStringObj("account", -1));
 			break;
 		case PURPLE_PRESENCE_CONTEXT_CONV:
-			Tcl_SetStringObj(result, "conversation", -1);
+			Tcl_SetObjResult(interp, Tcl_NewStringObj("conversation", -1));
 			break;
 		case PURPLE_PRESENCE_CONTEXT_BUDDY:
-			Tcl_SetStringObj(result, "buddy", -1);
+			Tcl_SetObjResult(interp, Tcl_NewStringObj("buddy", -1));
 			break;
 		}
 		break;
@@ -1253,7 +1286,7 @@
 		if (objc == 3) {
 			if (purple_presence_is_idle(presence)) {
 				idle_time = purple_presence_get_idle_time (presence);
-				Tcl_SetIntObj(result, idle_time);
+				Tcl_SetObjResult(interp, Tcl_NewIntObj(idle_time));
 			} else {
 				result = Tcl_NewListObj(0, NULL);
 				Tcl_SetObjResult(interp, result);
@@ -1280,7 +1313,7 @@
 		if ((presence = purple_tcl_ref_get(interp, objv[2], PurpleTclRefPresence)) == NULL)
 			return TCL_ERROR;
 		if (objc == 3) {
-			Tcl_SetIntObj(result, purple_presence_get_login_time(presence));
+			Tcl_SetObjResult(interp, Tcl_NewIntObj(purple_presence_get_login_time(presence)));
 		} else {
 			if ((error == Tcl_GetIntFromObj(interp,
 			                                objv[3],
@@ -1296,7 +1329,9 @@
 		}
 		if ((presence = purple_tcl_ref_get(interp, objv[2], PurpleTclRefPresence)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetBooleanObj(result, purple_presence_is_online(presence));
+		Tcl_SetObjResult(interp,
+				 Tcl_NewBooleanObj(
+					 purple_presence_is_online(presence)));
 		break;
 	case CMD_PRESENCE_STATUS:
 		if (objc != 4) {
@@ -1332,7 +1367,7 @@
 
 int tcl_cmd_savedstatus(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
 {
-	Tcl_Obj *result = Tcl_GetObjResult(interp);
+	Tcl_Obj *result;
 	const char *cmds[] = { "current", "handle", NULL };
 	enum { CMD_SAVEDSTATUS_CURRENT, CMD_SAVEDSTATUS_HANDLE } cmd;
 	int error;
@@ -1354,16 +1389,20 @@
 		}
 		if ((saved_status = purple_savedstatus_get_current()) == NULL)
 			return TCL_ERROR;
+		result = Tcl_NewListObj(0, NULL);
 		Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(purple_savedstatus_get_title(saved_status), -1));
 		Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(purple_savedstatus_get_type(saved_status)));
 		Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(purple_savedstatus_get_message(saved_status), -1));
+		Tcl_SetObjResult(interp,result);
 		break;
 	case CMD_SAVEDSTATUS_HANDLE:
 		if (objc != 2) {
 			Tcl_WrongNumArgs(interp, 2, objv, "");
 			return TCL_ERROR;
 		}
-		Tcl_SetIntObj(result, (int)purple_savedstatuses_get_handle());
+		Tcl_SetObjResult(interp, 
+				 purple_tcl_ref_new(PurpleTclRefHandle,
+						    purple_savedstatuses_get_handle()));
 		break;
 	}
 
@@ -1396,7 +1435,6 @@
 	const char *cmds[] = { "connect", "disconnect", NULL };
 	enum { CMD_SIGNAL_CONNECT, CMD_SIGNAL_DISCONNECT } cmd;
 	struct tcl_signal_handler *handler;
-	Tcl_Obj *result = Tcl_GetObjResult(interp);
 	void *instance;
 	int error;
 
@@ -1415,7 +1453,7 @@
 			return TCL_ERROR;
 		}
 		handler = g_new0(struct tcl_signal_handler, 1);
-		if ((error = Tcl_GetIntFromObj(interp, objv[2], (int *)&handler->instance)) != TCL_OK) {
+		if ((handler->instance = purple_tcl_ref_get(interp, objv[2],PurpleTclRefHandle)) == NULL) {
 			g_free(handler);
 			return error;
 		}
@@ -1426,9 +1464,9 @@
 		handler->interp = interp;
 		if (!tcl_signal_connect(handler)) {
 			tcl_signal_handler_free(handler);
-			Tcl_SetIntObj(result, 1);
+			Tcl_SetObjResult(interp, Tcl_NewIntObj(1));
 		} else {
-			Tcl_SetIntObj(result, 0);
+			Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
 		}
 		break;
 	case CMD_SIGNAL_DISCONNECT:
@@ -1436,7 +1474,7 @@
 			Tcl_WrongNumArgs(interp, 2, objv, "instance signal");
 			return TCL_ERROR;
 		}
-		if ((error = Tcl_GetIntFromObj(interp, objv[2], (int *)&instance)) != TCL_OK)
+		if ((instance = purple_tcl_ref_get(interp, objv[2],PurpleTclRefHandle)) == NULL)
 			return error;
 		tcl_signal_disconnect(instance, Tcl_GetString(objv[3]), interp);
 		break;
@@ -1449,7 +1487,6 @@
 {
 	const char *cmds[] = { "attr", "type", NULL };
 	enum { CMD_STATUS_ATTR, CMD_STATUS_TYPE } cmd;
-	Tcl_Obj *result = Tcl_GetObjResult(interp);
 	PurpleStatus *status;
 	PurpleStatusType *status_type;
 	PurpleValue *value;
@@ -1475,13 +1512,15 @@
 		attr = Tcl_GetString(objv[3]);
 		value = purple_status_get_attr_value(status, attr);
 		if (value == NULL) {
-			Tcl_SetStringObj(result, "no such attribute", -1);
+			Tcl_SetObjResult(interp,
+					 Tcl_NewStringObj("no such attribute", -1));
 			return TCL_ERROR;
 		}
 		switch (purple_value_get_type(value)) {
 		case PURPLE_TYPE_BOOLEAN:
 			if (objc == 4) {
-				Tcl_SetBooleanObj(result, purple_value_get_boolean(value));
+				Tcl_SetObjResult(interp,
+						 Tcl_NewBooleanObj(purple_value_get_boolean(value)));
 			} else {
 				if ((error = Tcl_GetBooleanFromObj(interp, objv[4], &v)) != TCL_OK)
 					return error;
@@ -1490,7 +1529,7 @@
 			break;
 		case PURPLE_TYPE_INT:
 			if (objc == 4) {
-				Tcl_SetIntObj(result, purple_value_get_int(value));
+				Tcl_SetObjResult(interp, Tcl_NewIntObj(purple_value_get_int(value)));
 			} else {
 				if ((error = Tcl_GetIntFromObj(interp, objv[4], &v)) != TCL_OK)
 					return error;
@@ -1499,12 +1538,14 @@
 			break;
 		case PURPLE_TYPE_STRING:
 			if (objc == 4)
-				Tcl_SetStringObj(result, purple_value_get_string(value), -1);
+				Tcl_SetObjResult(interp,
+						 Tcl_NewStringObj(purple_value_get_string(value), -1));
 			else
 				purple_status_set_attr_string(status, attr, Tcl_GetString(objv[4]));
 			break;
 		default:
-			Tcl_SetStringObj(result, "attribute has unknown type", -1);
+			Tcl_SetObjResult(interp,
+                                         Tcl_NewStringObj("attribute has unknown type", -1));
 			return TCL_ERROR;
 		}
 		break;
@@ -1528,7 +1569,6 @@
 {
 	const char *cmds[] = { "id", "name", NULL };
 	enum { CMD_STATUS_ATTR_ID, CMD_STATUS_ATTR_NAME } cmd;
-	Tcl_Obj *result = Tcl_GetObjResult(interp);
 	PurpleStatusAttr *attr;
 	int error;
 
@@ -1548,7 +1588,8 @@
 		}
 		if ((attr = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusAttr)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetStringObj(result, purple_status_attr_get_id(attr), -1);
+		Tcl_SetObjResult(interp,
+				 Tcl_NewStringObj(purple_status_attr_get_id(attr), -1));
 		break;
 	case CMD_STATUS_ATTR_NAME:
 		if (objc != 3) {
@@ -1557,7 +1598,8 @@
 		}
 		if ((attr = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusAttr)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetStringObj(result, purple_status_attr_get_name(attr), -1);
+		Tcl_SetObjResult(interp,
+				 Tcl_NewStringObj(purple_status_attr_get_name(attr), -1));
 		break;
 	}
 
@@ -1576,7 +1618,6 @@
 	       CMD_STATUS_TYPE_NAME, CMD_STATUS_TYPE_PRIMARY_ATTR,
 	       CMD_STATUS_TYPE_PRIMITIVE, CMD_STATUS_TYPE_SAVEABLE,
 	       CMD_STATUS_TYPE_USER_SETTABLE } cmd;
-	Tcl_Obj *result = Tcl_GetObjResult(interp);
 	PurpleStatusType *status_type;
 	Tcl_Obj *list, *elem;
 	GList *cur;
@@ -1598,7 +1639,8 @@
 		}
 		if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetBooleanObj(result, purple_status_type_is_available(status_type));
+		Tcl_SetObjResult(interp,
+				 Tcl_NewBooleanObj(purple_status_type_is_available(status_type)));
 		break;
 	case CMD_STATUS_TYPE_ATTR:
 		if (objc != 4) {
@@ -1634,7 +1676,8 @@
 		}
 		if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetBooleanObj(result, purple_status_type_is_exclusive(status_type));
+		Tcl_SetObjResult(interp,
+				 Tcl_NewBooleanObj(purple_status_type_is_exclusive(status_type)));
 		break;
 	case CMD_STATUS_TYPE_ID:
 		if (objc != 3) {
@@ -1643,7 +1686,8 @@
 		}
 		if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetStringObj(result, purple_status_type_get_id(status_type), -1);
+		Tcl_SetObjResult(interp,
+				 Tcl_NewStringObj(purple_status_type_get_id(status_type), -1));
 		break;
 	case CMD_STATUS_TYPE_INDEPENDENT:
 		if (objc != 3) {
@@ -1652,7 +1696,8 @@
 		}
 		if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetBooleanObj(result, purple_status_type_is_independent(status_type));
+		Tcl_SetObjResult(interp,
+				 Tcl_NewBooleanObj(purple_status_type_is_independent(status_type)));
 		break;
 	case CMD_STATUS_TYPE_NAME:
 		if (objc != 3) {
@@ -1661,7 +1706,8 @@
 		}
 		if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetStringObj(result, purple_status_type_get_name(status_type), -1);
+		Tcl_SetObjResult(interp,
+				 Tcl_NewStringObj(purple_status_type_get_name(status_type), -1));
 		break;
 	case CMD_STATUS_TYPE_PRIMITIVE:
 		if (objc != 3) {
@@ -1670,7 +1716,9 @@
 		}
 		if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetStringObj(result, purple_primitive_get_id_from_type(purple_status_type_get_primitive(status_type)), -1);
+		Tcl_SetObjResult(interp,
+				 Tcl_NewStringObj(purple_primitive_get_id_from_type
+						  (purple_status_type_get_primitive(status_type)), -1));
 		break;
 	case CMD_STATUS_TYPE_PRIMARY_ATTR:
 		if (objc != 3) {
@@ -1679,7 +1727,8 @@
 		}
 		if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetStringObj(result, purple_status_type_get_primary_attr(status_type), -1);
+		Tcl_SetObjResult(interp,
+				 Tcl_NewStringObj(purple_status_type_get_primary_attr(status_type), -1));
 		break;
 	case CMD_STATUS_TYPE_SAVEABLE:
 		if (objc != 3) {
@@ -1688,7 +1737,9 @@
 		}
 		if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetBooleanObj(result, purple_status_type_is_saveable(status_type));
+		Tcl_SetObjResult(interp,
+				 Tcl_NewBooleanObj(
+					 purple_status_type_is_saveable(status_type)));
 		break;
 	case CMD_STATUS_TYPE_USER_SETTABLE:
 		if (objc != 3) {
@@ -1697,7 +1748,9 @@
 		}
 		if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL)
 			return TCL_ERROR;
-		Tcl_SetBooleanObj(result, purple_status_type_is_user_settable(status_type));
+		Tcl_SetObjResult(interp,
+				 Tcl_NewBooleanObj(
+					 purple_status_type_is_user_settable(status_type)));
 		break;
 	}
 
--- a/libpurple/plugins/tcl/tcl_purple.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/plugins/tcl/tcl_purple.h	Fri Sep 28 16:34:43 2007 +0000
@@ -76,6 +76,7 @@
 extern PurpleStringref *PurpleTclRefStatusAttr;
 extern PurpleStringref *PurpleTclRefStatusType;
 extern PurpleStringref *PurpleTclRefXfer;
+extern PurpleStringref *PurpleTclRefHandle;
 
 PurplePlugin *tcl_interp_get_plugin(Tcl_Interp *interp);
 
--- a/libpurple/protocols/jabber/adhoccommands.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/jabber/adhoccommands.c	Fri Sep 28 16:34:43 2007 +0000
@@ -151,8 +151,11 @@
 		/* display result */
 		xmlnode *note = xmlnode_get_child(command,"note");
 		
-		if(note)
-			purple_notify_info(NULL, xmlnode_get_attrib(packet, "from"), xmlnode_get_data(note), NULL);
+		if(note) {
+			char *data = xmlnode_get_data(note);
+			purple_notify_info(NULL, xmlnode_get_attrib(packet, "from"), data, NULL);
+			g_free(data);
+		}
 		
 		if(xdata)
 			jabber_x_data_request(js, xdata, (jabber_x_data_cb)do_adhoc_ignoreme, NULL);
--- a/libpurple/protocols/jabber/buddy.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Fri Sep 28 16:34:43 2007 +0000
@@ -1455,10 +1455,13 @@
 		return;
 	
 	img = purple_base64_decode(b64data, &size);
-	if(!img)
+	if(!img) {
+		g_free(b64data);
 		return;
+	}
 	
 	purple_buddy_icons_set_for_user(purple_connection_get_account(js->gc), from, img, size, checksum);
+	g_free(b64data);
 }
 
 void jabber_buddy_avatar_update_metadata(JabberStream *js, const char *from, xmlnode *items) {
--- a/libpurple/protocols/jabber/jabber.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Fri Sep 28 16:34:43 2007 +0000
@@ -814,7 +814,7 @@
 		if(account->registration_cb)
 			(account->registration_cb)(account, FALSE, account->registration_cb_user_data);
 		jabber_connection_schedule_close(cbdata->js);
-}
+	}
 	g_free(cbdata->who);
 	g_free(cbdata);
 }
@@ -883,12 +883,12 @@
 				if((href = xmlnode_get_data(url))) {
 					purple_notify_uri(NULL, href);
 					g_free(href);
-				if(js->registration) {
-					js->gc->wants_to_die = TRUE;
-					if(account->registration_cb) /* succeeded, but we have no login info */
-						(account->registration_cb)(account, TRUE, account->registration_cb_user_data);
-					jabber_connection_schedule_close(js);
-				}
+					if(js->registration) {
+						js->gc->wants_to_die = TRUE;
+						if(account->registration_cb) /* succeeded, but we have no login info */
+							(account->registration_cb)(account, TRUE, account->registration_cb_user_data);
+						jabber_connection_schedule_close(js);
+					}
 					return;
 				}
 			}
@@ -988,14 +988,14 @@
 		purple_request_field_group_add_field(group, field);
 	}
 
-		if((y = xmlnode_get_child(query, "instructions")))
-			instructions = xmlnode_get_data(y);
+	if((y = xmlnode_get_child(query, "instructions")))
+		instructions = xmlnode_get_data(y);
 	else if(registered)
 		instructions = g_strdup(_("Please fill out the information below "
 					"to change your account registration."));
-		else
-			instructions = g_strdup(_("Please fill out the information below "
-						"to register your new account."));
+	else
+		instructions = g_strdup(_("Please fill out the information below "
+					"to register your new account."));
 
 	cbdata = g_new0(JabberRegisterCBData, 1);
 	cbdata->js = js;
@@ -1020,8 +1020,8 @@
 		g_free(title);
 	}
 
-		g_free(instructions);
-	}
+	g_free(instructions);
+}
 
 void jabber_register_start(JabberStream *js)
 {
@@ -1532,15 +1532,15 @@
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
 			"mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
 			"moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
-			"tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
-			"tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
+			PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
+			PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
 			"nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
 			"buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN),
 			NULL);
@@ -1555,15 +1555,15 @@
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
 			"mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
 			"moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
-			"tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
-			"tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
+			PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
+			PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
 			"nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
 			"buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN),
 			NULL);
@@ -1578,15 +1578,15 @@
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
 			"mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
 			"moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
-			"tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
-			"tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
+			PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
+			PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
 			"nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
 			"buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN),
 			NULL);
@@ -1601,15 +1601,15 @@
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
 			"mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
 			"moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
-			"tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
-			"tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
+			PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
+			PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
 			"nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
 			"buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN),
 			NULL);
@@ -1624,15 +1624,15 @@
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
 			"mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
 			"moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
-			"tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
-			"tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
-			"tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
+			PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
+			PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
 			"nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
 			"buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN),
 			NULL);
@@ -2240,6 +2240,44 @@
 	return PURPLE_CMD_RET_FAILED;
 }
 
+GList *jabber_attention_types(PurpleAccount *account)
+{
+	static GList *types = NULL;
+	PurpleAttentionType *attn;
+
+	if (!types) {
+		attn = g_new0(PurpleAttentionType, 1);
+		attn->name = _("Buzz");
+		attn->incoming_description = _("%s has buzzed you!");
+		attn->outgoing_description = _("Buzzing %s...");
+		types = g_list_append(types, attn);
+	}
+
+	return types;
+}
+
+gboolean jabber_send_attention(PurpleConnection *gc, const char *username, guint code)
+{
+	PurpleConversation *conv;
+	char *error;
+	char *args[1];
+	PurpleCmdRet ret;
+
+	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, username, gc->account);
+
+	args[0] = (char *)username;
+
+	ret = jabber_cmd_buzz(conv, "buzz", args, &error, NULL);
+
+	if (ret == PURPLE_CMD_RET_FAILED) {
+		purple_debug_error("jabber", "jabber_send_attention: jabber_cmd_buzz failed with error: %s\n", error ? error : "(NULL)");
+		return FALSE;
+	} else {
+		return TRUE;
+	}
+}
+
+
 gboolean jabber_offline_message(const PurpleBuddy *buddy)
 {
 	return TRUE;
--- a/libpurple/protocols/jabber/jabber.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Fri Sep 28 16:34:43 2007 +0000
@@ -66,6 +66,9 @@
 
 #define CAPS0115_NODE "http://pidgin.im/caps"
 
+/* Index into attention_types list */
+#define JABBER_BUZZ 0
+
 typedef enum {
 	JABBER_STREAM_OFFLINE,
 	JABBER_STREAM_CONNECTING,
@@ -231,6 +234,8 @@
 void jabber_register_gateway(JabberStream *js, const char *gateway);
 void jabber_register_account(PurpleAccount *account);
 void jabber_unregister_account(PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data);
+gboolean jabber_send_attention(PurpleConnection *gc, const char *username, guint code);
+GList *jabber_attention_types(PurpleAccount *account);
 void jabber_convo_closed(PurpleConnection *gc, const char *who);
 PurpleChat *jabber_find_blist_chat(PurpleAccount *account, const char *name);
 gboolean jabber_offline_message(const PurpleBuddy *buddy);
--- a/libpurple/protocols/jabber/libxmpp.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Fri Sep 28 16:34:43 2007 +0000
@@ -113,10 +113,10 @@
 	jabber_prpl_send_raw,			/* send_raw */
 	jabber_roomlist_room_serialize, /* roomlist_room_serialize */
 	jabber_unregister_account,		/* unregister_user */
+	jabber_send_attention,			/* send_attention */
+	jabber_attention_types,			/* attention_types */
 
 	/* padding */
-	NULL,
-	NULL,
 	NULL
 };
 
--- a/libpurple/protocols/jabber/message.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/jabber/message.c	Fri Sep 28 16:34:43 2007 +0000
@@ -327,7 +327,7 @@
 	if(type) {
 		if(!strcmp(type, "normal"))
 			jm->type = JABBER_MESSAGE_NORMAL;
-	else if(!strcmp(type, "chat"))
+		else if(!strcmp(type, "chat"))
 			jm->type = JABBER_MESSAGE_CHAT;
 		else if(!strcmp(type, "groupchat"))
 			jm->type = JABBER_MESSAGE_GROUPCHAT;
--- a/libpurple/protocols/jabber/presence.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/jabber/presence.c	Fri Sep 28 16:34:43 2007 +0000
@@ -192,16 +192,11 @@
 		jabber_tune_set(js->gc, &tuneinfo);
 		
 		/* update old values */
-		if(js->old_artist)
-			g_free(js->old_artist);
-		if(js->old_title)
-			g_free(js->old_title);
-		if(js->old_source)
-			g_free(js->old_source);
-		if(js->old_uri)
-			g_free(js->old_uri);
-		if(js->old_track)
-			g_free(js->old_track);
+		g_free(js->old_artist);
+		g_free(js->old_title);
+		g_free(js->old_source);
+		g_free(js->old_uri);
+		g_free(js->old_track);
 		js->old_artist = g_strdup(artist);
 		js->old_title = g_strdup(title);
 		js->old_source = g_strdup(source);
--- a/libpurple/protocols/jabber/usernick.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/jabber/usernick.c	Fri Sep 28 16:34:43 2007 +0000
@@ -33,7 +33,7 @@
 	xmlnode *item = xmlnode_get_child(items, "item");
 	JabberBuddy *buddy = jabber_buddy_find(js, from, FALSE);
 	xmlnode *nick;
-	const char *nickname = NULL;
+	char *nickname = NULL;
 	
 	/* ignore the tune of people not on our buddy list */
 	if (!buddy || !item)
@@ -43,8 +43,8 @@
 	if (!nick)
 		return;
 	nickname = xmlnode_get_data(nick);
-
 	serv_got_alias(js->gc, from, nickname);
+	g_free(nickname);
 }
 
 static void do_nick_set(JabberStream *js, const char *nick) {
@@ -64,7 +64,7 @@
 }
 
 static void do_nick_got_own_nick_cb(JabberStream *js, const char *from, xmlnode *items) {
-	const char *oldnickname = NULL;
+	char *oldnickname = NULL;
 	xmlnode *item = xmlnode_get_child(items,"item");
 	
 	if(item) {
@@ -77,6 +77,7 @@
 		_("This information is visible to all contacts on your contact list, so choose something appropriate."),
 		oldnickname, FALSE, FALSE, NULL, _("Set"), PURPLE_CALLBACK(do_nick_set), _("Cancel"), NULL,
 		purple_connection_get_account(js->gc), NULL, NULL, js);
+	g_free(oldnickname);
 }
 
 static void do_nick_set_nick(PurplePluginAction *action) {
--- a/libpurple/protocols/jabber/usertune.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/jabber/usertune.c	Fri Sep 28 16:34:43 2007 +0000
@@ -41,48 +41,61 @@
 	if (!buddy || !item)
 		return;
 	
-	tuneinfodata.artist = "";
-	tuneinfodata.title = "";
-	tuneinfodata.album = "";
-	tuneinfodata.track = "";
+	tuneinfodata.artist = NULL;
+	tuneinfodata.title = NULL;
+	tuneinfodata.album = NULL;
+	tuneinfodata.track = NULL;
 	tuneinfodata.time = -1;
-	tuneinfodata.url = "";
-	
+	tuneinfodata.url = NULL;
+
 	tune = xmlnode_get_child_with_namespace(item, "tune", "http://jabber.org/protocol/tune");
 	if (!tune)
 		return;
+	resource = jabber_buddy_find_resource(buddy, NULL);
+	if(!resource)
+		return; /* huh? */
 	for (tuneinfo = tune->child; tuneinfo; tuneinfo = tuneinfo->next) {
 		if (tuneinfo->type == XMLNODE_TYPE_TAG) {
 			if (!strcmp(tuneinfo->name, "artist")) {
-				if (tuneinfodata.artist[0] == '\0') /* only pick the first one */
+				if (tuneinfodata.artist == NULL) /* only pick the first one */
 					tuneinfodata.artist = xmlnode_get_data(tuneinfo);
 			} else if (!strcmp(tuneinfo->name, "length")) {
 				if (tuneinfodata.time == -1) {
 					char *length = xmlnode_get_data(tuneinfo);
 					if (length)
 						tuneinfodata.time = strtol(length, NULL, 10);
+					g_free(length);
 				}
 			} else if (!strcmp(tuneinfo->name, "source")) {
-				if (tuneinfodata.album[0] == '\0') /* only pick the first one */
+				if (tuneinfodata.album == NULL) /* only pick the first one */
 					tuneinfodata.album = xmlnode_get_data(tuneinfo);
 			} else if (!strcmp(tuneinfo->name, "title")) {
-				if (tuneinfodata.title[0] == '\0') /* only pick the first one */
+				if (tuneinfodata.title == NULL) /* only pick the first one */
 					tuneinfodata.title = xmlnode_get_data(tuneinfo);
 			} else if (!strcmp(tuneinfo->name, "track")) {
-				if (tuneinfodata.track[0] == '\0') /* only pick the first one */
+				if (tuneinfodata.track == NULL) /* only pick the first one */
 					tuneinfodata.track = xmlnode_get_data(tuneinfo);
 			} else if (!strcmp(tuneinfo->name, "uri")) {
-				if (tuneinfodata.url[0] == '\0') /* only pick the first one */
+				if (tuneinfodata.url == NULL) /* only pick the first one */
 					tuneinfodata.url = xmlnode_get_data(tuneinfo);
 			}
 		}
 	}
-	resource = jabber_buddy_find_resource(buddy, NULL);
-	if(!resource)
-		return; /* huh? */
 	status_id = jabber_buddy_state_get_status_id(resource->state);
 
-	purple_prpl_got_user_status(js->gc->account, from, status_id, PURPLE_TUNE_ARTIST, tuneinfodata.artist, PURPLE_TUNE_TITLE, tuneinfodata.title, PURPLE_TUNE_ALBUM, tuneinfodata.album, PURPLE_TUNE_TRACK, tuneinfodata.track, PURPLE_TUNE_TIME, tuneinfodata.time, PURPLE_TUNE_URL, tuneinfodata.url, NULL);
+	purple_prpl_got_user_status(js->gc->account, from, status_id,
+			PURPLE_TUNE_ARTIST, tuneinfodata.artist,
+			PURPLE_TUNE_TITLE, tuneinfodata.title,
+			PURPLE_TUNE_ALBUM, tuneinfodata.album,
+			PURPLE_TUNE_TRACK, tuneinfodata.track,
+			PURPLE_TUNE_TIME, tuneinfodata.time,
+			PURPLE_TUNE_URL, tuneinfodata.url, NULL);
+
+	g_free(tuneinfodata.artist);
+	g_free(tuneinfodata.title);
+	g_free(tuneinfodata.album);
+	g_free(tuneinfodata.track);
+	g_free(tuneinfodata.url);
 }
 
 void jabber_tune_init(void) {
--- a/libpurple/protocols/msn/Makefile.am	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/Makefile.am	Fri Sep 28 16:34:43 2007 +0000
@@ -1,4 +1,6 @@
 EXTRA_DIST = \
+		directconn.c \
+		directconn.h \
 		Makefile.mingw
 
 pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION)
@@ -8,10 +10,10 @@
 	cmdproc.h \
 	command.c \
 	command.h \
+	contact.c\
+	contact.h\
 	dialog.c \
 	dialog.h \
-	directconn.c \
-	directconn.h \
 	error.c \
 	error.h \
 	group.c \
@@ -30,6 +32,8 @@
 	notification.h \
 	object.c \
 	object.h \
+	oim.c\
+	oim.h\
 	page.c \
 	page.h \
 	servconn.c \
@@ -46,6 +50,8 @@
 	slpmsg.h \
 	slpsession.c \
 	slpsession.h \
+	soap.c\
+	soap.h\
 	state.c \
 	state.h \
 	switchboard.c \
@@ -60,8 +66,8 @@
 	user.h \
 	userlist.c \
 	userlist.h \
-	msn-utils.c \
-	msn-utils.h
+	msnutils.c \
+	msnutils.h
 
 AM_CFLAGS = $(st)
 
--- a/libpurple/protocols/msn/Makefile.mingw	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/Makefile.mingw	Fri Sep 28 16:34:43 2007 +0000
@@ -39,6 +39,7 @@
 ##
 C_SRC =			cmdproc.c \
 			command.c \
+			contact.c\
 			dialog.c \
 			directconn.c \
 			error.c \
@@ -50,6 +51,7 @@
 			nexus.c \
 			notification.c \
 			object.c \
+			oim.c\
 			page.c \
 			servconn.c \
 			session.c \
@@ -58,6 +60,7 @@
 			slplink.c \
 			slpmsg.c \
 			slpsession.c \
+			soap.c\
 			state.c \
 			switchboard.c \
 			sync.c \
@@ -65,7 +68,7 @@
 			transaction.c \
 			user.c \
 			userlist.c \
-			msn-utils.c
+			msnutils.c
 
 OBJECTS = $(C_SRC:%.c=%.o)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/msn/README	Fri Sep 28 16:34:43 2007 +0000
@@ -0,0 +1,55 @@
+MSNP14 Implementation
+by Ma Yuan<mayuan2006@gmail.com>
+
+1. Introduction
+-------------
+
+MSNP14 Protocol, proposed by Windows Live Messenger, is new, and there is no available implementation except the official one on Windows Platform.
+
+It has introduced many new features attractable to many users, such as:
+* Offline Instant Message
+	You can send the offline Message to the offline User,
+	The message will be posted to that user the next time when he is online.
+
+* Communicate with Yahoo User
+	U can chat with the Yahoo User in MSN, That's Fantastic! Till now ,
+	you can send text/Nudge to Yahoo User.
+
+* Windows Live ID authentition
+	WLM use the Window Live ID Authentication process,Known as Passport 3.0,
+	The procedure is totally different to the previous Passport 2.0
+
+* Video/Audio Conversation
+	U can communicate with other's via Video/Audio.
+(Though very interesting, not implemented in this version)
+
+2.New Features Added
+-----------------
+
+Till now, This project has implemented the following Feature:
+* Windows Live ID authentication.
+
+* Offline Instant Message
+Now can send and receive the Offline Instant Message to MSN user and Yahoo User.
+
+*contact management
+Can add/delete Contact
+Can add/delete Group
+
+* Communicate with Yahoo User
+Can send/receive Message/Nudge to Yahoo User.
+
+*. Changes to made to fit MSNP14 Protocol
+
+3. Reference
+-------------
+
+The very useful sites of MSN Protocol:
+MSNpiki site:
+reverse engineer of MSN Protocol.up to dated.
+http://msnpiki.msnfanatic.com/index.php/MSN_Protocol_Version_13
+
+hypothetic site:
+old MSN Protocol Introduction,but very useful for basic idea of MSN protocol
+http://www.hypothetic.org/docs/msn/index.php
+
--- a/libpurple/protocols/msn/cmdproc.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/cmdproc.c	Fri Sep 28 16:34:43 2007 +0000
@@ -258,8 +258,10 @@
 		trans = msn_history_find(cmdproc->history, cmd->trId);
 
 	if (trans != NULL)
-		if (trans->timer)
+		if (trans->timer) {
 			purple_timeout_remove(trans->timer);
+			trans->timer = 0;
+		}
 
 	if (g_ascii_isdigit(cmd->command[0]))
 	{
--- a/libpurple/protocols/msn/command.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/command.c	Fri Sep 28 16:34:43 2007 +0000
@@ -36,6 +36,50 @@
 	return TRUE;
 }
 
+/*
+ * check the command is the command with payload content
+ *  if it is	return TRUE
+ *  else 		return FALSE
+ */
+static gboolean
+msn_check_payload_cmd(char *str)
+{
+	if( (!strcmp(str,"ADL")) ||
+		(!strcmp(str,"GCF")) ||
+		(!strcmp(str,"SG")) ||
+		(!strcmp(str,"MSG")) ||
+		(!strcmp(str,"RML")) ||
+		(!strcmp(str,"UBX")) ||
+		(!strcmp(str,"UBN")) ||
+		(!strcmp(str,"UUM")) ||
+		(!strcmp(str,"UBM")) ||
+		(!strcmp(str,"FQY")) ||
+		(!strcmp(str,"UUN")) ||
+		(!strcmp(str,"UUX")) ||
+		(is_num(str))){
+			return TRUE;
+		}
+
+	return FALSE;
+}
+
+/*
+ * set command Payload length
+ */
+static void
+msn_set_payload_len(MsnCommand *cmd)
+{
+	char *param;
+	int len = 0;
+
+	if (msn_check_payload_cmd(cmd->command) && (cmd->param_count > 0)){
+		param = cmd->params[cmd->param_count - 1];
+		len = is_num(param) ? atoi(param) : 0;
+	}
+
+	cmd->payload_len = len;
+}
+
 MsnCommand *
 msn_command_from_string(const char *string)
 {
@@ -70,7 +114,13 @@
 		cmd->trId = is_num(param) ? atoi(param) : 0;
 	}
 	else
+	{
 		cmd->trId = 0;
+	}
+
+	/*add payload Length checking*/
+	msn_set_payload_len(cmd);
+	purple_debug_info("MSNP14","get payload len:%d\n",cmd->payload_len);
 
 	msn_command_ref(cmd);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/msn/contact.c	Fri Sep 28 16:34:43 2007 +0000
@@ -0,0 +1,1893 @@
+/**
+ * @file contact.c 
+ * 	get MSN contacts via SOAP request
+ *	created by MaYuan<mayuan2006@gmail.com>
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "msn.h"
+#include "contact.h"
+#include "xmlnode.h"
+#include "group.h"
+
+const char *MsnSoapPartnerScenarioText[] =
+{
+	"Initial",
+	"ContactSave",
+	"MessengerPendingList",
+	"ContactMsgrAPI",
+	"BlockUnblock"
+};
+
+const char *MsnMemberRole[] =
+{
+	"Forward",
+	"Allow",
+	"Block",
+	"Reverse",
+	"Pending"
+};
+
+/* new a contact */
+MsnContact *
+msn_contact_new(MsnSession *session)
+{
+	MsnContact *contact;
+
+	contact = g_new0(MsnContact, 1);
+	contact->session = session;
+	contact->soapconn = msn_soap_new(session,contact,1);
+
+	return contact;
+}
+
+/* destroy the contact */
+void
+msn_contact_destroy(MsnContact *contact)
+{
+	msn_soap_destroy(contact->soapconn);
+	g_free(contact);
+}
+
+MsnCallbackState *
+msn_callback_state_new(void)
+{
+	return g_new0(MsnCallbackState, 1);
+}
+
+void
+msn_callback_state_free(MsnCallbackState *state)
+{
+	if (state == NULL)
+		return;
+
+	g_free(state->who);
+	g_free(state->uid);
+	g_free(state->old_group_name);
+	g_free(state->new_group_name);
+	g_free(state->guid);
+
+	g_free(state);
+}
+
+void
+msn_callback_state_set_who(MsnCallbackState *state, const gchar *who)
+{
+	gchar *new_str = NULL;
+
+	g_return_if_fail(state != NULL);
+
+	if (who != NULL)
+		new_str = g_strdup(who);
+
+	g_free(state->who);
+	state->who = new_str;
+}
+
+void
+msn_callback_state_set_uid(MsnCallbackState *state, const gchar *uid)
+{
+	gchar *new_str = NULL;
+
+	g_return_if_fail(state != NULL);
+
+	if (uid != NULL)
+		new_str = g_strdup(uid);
+
+	g_free(state->uid);
+	state->uid = new_str;
+}
+
+void
+msn_callback_state_set_old_group_name(MsnCallbackState *state, const gchar *old_group_name)
+{
+	gchar *new_str = NULL;
+
+	g_return_if_fail(state != NULL);
+
+	if (old_group_name != NULL)
+		new_str = g_strdup(old_group_name);
+
+	g_free(state->old_group_name);
+	state->old_group_name = new_str;
+}
+
+void
+msn_callback_state_set_new_group_name(MsnCallbackState *state, const gchar *new_group_name)
+{
+	gchar *new_str = NULL;
+
+	g_return_if_fail(state != NULL);
+
+	if (new_group_name != NULL)
+		new_str = g_strdup(new_group_name);
+
+	g_free(state->new_group_name);
+	state->new_group_name = new_str;
+}
+
+void
+msn_callback_state_set_guid(MsnCallbackState *state, const gchar *guid)
+{
+	gchar *new_str = NULL;
+
+	g_return_if_fail(state != NULL);
+
+	if (guid != NULL)
+		new_str = g_strdup(guid);
+
+	g_free(state->guid);
+	state->guid = new_str;
+}
+
+
+void
+msn_callback_state_set_list_id(MsnCallbackState *state, MsnListId list_id)
+{
+	g_return_if_fail(state != NULL);
+
+	state->list_id = list_id;
+}
+
+void
+msn_callback_state_set_action(MsnCallbackState *state, MsnCallbackAction action)
+{
+	g_return_if_fail(state != NULL);
+
+	state->action |= action;
+}
+
+/*contact SOAP server login error*/
+static void
+msn_contact_login_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error)
+{
+	MsnSession *session;
+
+	session = soapconn->session;
+	g_return_if_fail(session != NULL);
+
+	msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to contact server"));
+}
+
+/*msn contact SOAP server connect process*/
+static gboolean
+msn_contact_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc)
+{
+	MsnSession * session;
+	MsnContact *contact;
+
+	contact = soapconn->parent;
+	g_return_val_if_fail(contact != NULL, TRUE);
+
+	session = contact->session;
+	g_return_val_if_fail(session != NULL, FALSE);
+
+	/*login ok!We can retrieve the contact list*/
+//	msn_get_contact_list(contact, MSN_PS_INITIAL, NULL);
+	return TRUE;
+}
+
+/*get MSN member role utility*/
+static MsnListId
+msn_get_memberrole(char *role)
+{
+	g_return_val_if_fail(role != NULL, 0);
+
+	if (!strcmp(role,"Allow")) {
+		return MSN_LIST_AL;
+	} else if (!strcmp(role,"Block")) {
+		return MSN_LIST_BL;
+	} else if (!strcmp(role,"Reverse")) {
+		return MSN_LIST_RL;
+	} else if (!strcmp(role,"Pending")) {
+		return MSN_LIST_PL;
+	}
+	return 0;
+}
+
+/*get User Type*/
+static int
+msn_get_user_type(char *type)
+{
+	g_return_val_if_fail(type != NULL, 0);
+
+	if (!strcmp(type,"Regular")) {
+		return MSN_USER_TYPE_PASSPORT;
+	}
+	if (!strcmp(type,"Live")) {
+		return MSN_USER_TYPE_PASSPORT;
+	}
+	if (!strcmp(type,"LivePending")) {
+		return MSN_USER_TYPE_PASSPORT;
+	}
+
+	return MSN_USER_TYPE_UNKNOWN;
+}
+
+/* Create the AddressBook in the server, if we don't have one */
+static gboolean
+msn_create_address_cb(MsnSoapConn *soapconn)
+{
+	MsnContact *contact;
+
+	if (soapconn->body == NULL)
+		return TRUE;
+
+	contact = soapconn->parent;
+	g_return_val_if_fail(contact != NULL, TRUE);
+
+	purple_debug_info("MSN AddressBook", "Address Book successfully created!\n");
+	msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL);
+
+//	msn_soap_free_read_buf(soapconn);
+	return TRUE;
+}
+
+static void
+msn_create_address_written_cb(MsnSoapConn *soapconn)
+{
+	purple_debug_info("MSN AddressBook","AddressBookAdd written\n");
+	soapconn->read_cb = msn_create_address_cb;
+
+	return;
+}
+
+static void
+msn_create_address_book(MsnContact * contact)
+{
+	MsnSoapReq *soap_request;
+	gchar *body;
+
+	g_return_if_fail(contact != NULL);
+	g_return_if_fail(contact->session != NULL);
+	g_return_if_fail(contact->session->user != NULL);
+	g_return_if_fail(contact->session->user->passport != NULL);
+	
+	purple_debug_info("MSN AddressBook","Creating an Address Book.\n");
+
+	body = g_strdup_printf(MSN_ADD_ADDRESSBOOK_TEMPLATE, contact->session->user->passport);
+
+	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
+					MSN_ADDRESS_BOOK_POST_URL,MSN_ADD_ADDRESSBOOK_SOAP_ACTION,
+					body,
+					NULL,
+					msn_create_address_cb,
+					msn_create_address_written_cb,
+					msn_contact_connect_init);
+	msn_soap_post(contact->soapconn, soap_request);
+
+	g_free(body);
+	
+	return;
+}
+
+/*parse contact list*/
+static void
+msn_parse_contact_list(MsnContact * contact)
+{
+	MsnSession * session;
+	MsnListOp list_op = 0;
+	MsnListId list;
+	char * passport, *typedata;
+	xmlnode *fault, *faultstringnode, *faultdetail, *errorcode;
+	xmlnode *node, *body, *response, *result, *services;
+	xmlnode *service, *memberships, *info, *handle, *handletype;
+	xmlnode *membershipnode, *members, *member, *passportNode;
+
+	session = contact->session;
+	node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len);
+
+	if (node == NULL) {
+		purple_debug_error("MSNCL","Unable to parse SOAP data!\n");
+		return;
+	}
+
+	purple_debug_misc("MSNCL","Parsing contact list with size %d\n", contact->soapconn->body_len);
+
+	purple_debug_misc("MSNCL","Root node @ %p: Name: '%s', child: '%s', lastchild: '%s'\n", node,
+		node->name ? node->name : "(null)",
+		(node->child && node->child->name) ? node->child->name : "(null)",
+		(node->lastchild && node->lastchild->name) ? node->lastchild->name : "(null)");
+
+	body = xmlnode_get_child(node, "Body");
+
+	if (body == NULL) {
+		purple_debug_warning("MSNCL", "Failed to parse contact list Body node\n");
+		xmlnode_free(node);
+		return;
+	}
+	purple_debug_info("MSNCL","Body @ %p:  Name: '%s'\n",body,body->name);
+
+	/* Did we receive a <Fault> ? */
+	if ( (fault = xmlnode_get_child(body, "Fault")) != NULL) {
+	        purple_debug_info("MSNCL","Fault received from SOAP server!\n");
+
+		if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) {
+			gchar * faultstring = xmlnode_get_data(faultstringnode);
+			purple_debug_info("MSNCL", "Faultstring: %s\n", faultstring ? faultstring : "(null)");
+			g_free(faultstring);
+		}
+		if ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) {
+			purple_debug_info("MSNCL","detail @ %p, name: %s\n",faultdetail, faultdetail->name);
+
+			if ( (errorcode = xmlnode_get_child(faultdetail, "errorcode")) != NULL ) {
+				purple_debug_info("MSNCL","errorcode @ %p, name: %s\n", errorcode, errorcode->name);
+
+				if (errorcode->child != NULL) {
+					gchar *errorcodestring = xmlnode_get_data(errorcode);
+					purple_debug_info("MSNCL", "Error Code: %s\n", errorcodestring ? errorcodestring : "(null)");
+
+					if (errorcodestring && !strncmp(errorcodestring, "ABDoesNotExist", 14) ) {
+						xmlnode_free(node);
+						g_free(errorcodestring);
+						msn_create_address_book(contact);
+						return;
+					}
+					g_free(errorcodestring);
+				}
+			}
+		}
+		xmlnode_free(node);
+		msn_get_contact_list(contact, MSN_PS_INITIAL, NULL);
+		return;
+	}
+
+	response = xmlnode_get_child(body,"FindMembershipResponse");
+
+	if (response == NULL) {
+		/* we may get a response if our cache data is too old:
+		 *
+		 * <faultstring>Need to do full sync. Can't sync deltas Client
+		 * has too old a copy for us to do a delta sync</faultstring>
+		 */
+		xmlnode_free(node);
+		msn_get_contact_list(contact, MSN_PS_INITIAL, NULL);
+		return;
+	}
+	purple_debug_info("MSNCL","FindMembershipResponse @ %p: Name: '%s'\n",response,response->name);
+
+	result = xmlnode_get_child(response,"FindMembershipResult");
+	if (result == NULL) {
+		purple_debug_warning("MSNCL","Received No Update!\n");
+		xmlnode_free(node);
+		return;
+	}
+	purple_debug_info("MSNCL","Result @ %p: Name: '%s'\n", result, result->name);
+
+	if ( (services = xmlnode_get_child(result,"Services")) == NULL) {
+		purple_debug_misc("MSNCL","No <Services> received.\n");
+		xmlnode_free(node);
+		return;
+	}
+
+	purple_debug_info("MSNCL","Services @ %p\n",services);
+	
+	for (service = xmlnode_get_child(services, "Service"); service;
+	                                service = xmlnode_get_next_twin(service)) {
+		purple_debug_info("MSNCL","Service @ %p\n",service);
+
+		if ( (info = xmlnode_get_child(service,"Info")) == NULL ) {
+			purple_debug_error("MSNCL","Error getting 'Info' child node\n");
+			continue;
+		}
+		if ( (handle = xmlnode_get_child(info,"Handle")) == NULL ) {
+			purple_debug_error("MSNCL","Error getting 'Handle' child node\n");
+			continue;
+		}
+		if ( (handletype = xmlnode_get_child(handle,"Type")) == NULL ) {
+			purple_debug_error("MSNCL","Error getting 'Type' child node\n");
+			continue;
+		}
+
+		if ( (typedata = xmlnode_get_data(handletype)) == NULL) {
+			purple_debug_error("MSNCL","Error retrieving data from 'Type' child node\n");
+			continue;
+		}
+
+		purple_debug_info("MSNCL","processing '%s' Service\n", typedata);
+
+		if ( !g_strcasecmp(typedata, "Profile") ) {
+			/* Process Windows Live 'Messenger Roaming Identity' */
+			g_free(typedata);
+			continue;
+		}
+
+		if ( !g_strcasecmp(typedata, "Messenger") ) {
+			char *LastChangeStr = NULL;
+			xmlnode *LastChangeNode;
+
+			/*Last Change Node*/
+			if ((LastChangeNode = xmlnode_get_child(service, "LastChange")))
+				LastChangeStr = xmlnode_get_data(LastChangeNode);
+			purple_debug_info("MSNCL","LastChangeNode: '%s'\n",LastChangeStr ? LastChangeStr : "(null)");
+			purple_account_set_string(session->account, "CLLastChange", LastChangeStr);
+			g_free(LastChangeStr);
+
+			memberships = xmlnode_get_child(service,"Memberships");
+			if (memberships == NULL) {
+				purple_debug_warning("MSNCL","Memberships = NULL, cleaning up and returning.\n");
+				g_free(typedata);
+				xmlnode_free(node);
+				return;
+			}
+			purple_debug_info("MSNCL","Memberships @ %p: Name: '%s'\n",memberships,memberships->name);
+			for (membershipnode = xmlnode_get_child(memberships, "Membership"); membershipnode;
+							membershipnode = xmlnode_get_next_twin(membershipnode)){
+				xmlnode *roleNode;
+				char *role = NULL;
+				list = 0;
+
+				if ((roleNode = xmlnode_get_child(membershipnode,"MemberRole"))) {
+					role = xmlnode_get_data(roleNode);
+					list = msn_get_memberrole(role);
+				}
+				list_op = 1 << list;
+
+				purple_debug_info("MSNCL","MemberRole role: %s, list_op: %d\n", role ? role : "(null)", list_op);
+
+				g_free(role);
+
+				members = xmlnode_get_child(membershipnode, "Members");
+				for (member = xmlnode_get_child(members, "Member"); member;
+						member = xmlnode_get_next_twin(member)){
+					MsnUser *user = NULL;
+					xmlnode *typeNode, *membershipIdNode = NULL;
+					gchar *type, *membershipId = NULL;
+					const char *member_type = xmlnode_get_attrib(member, "type");
+
+					purple_debug_info("MSNCL","Member type: %s\n", member_type ? member_type : "(null)");
+
+					if (!member_type)
+						continue;
+
+					if(!g_strcasecmp(member_type, "PassportMember") ) {
+						passport = type = NULL;
+						if ((passportNode = xmlnode_get_child(member, "PassportName")))
+							passport = xmlnode_get_data(passportNode);
+						if ((typeNode = xmlnode_get_child(member, "Type")))
+							type = xmlnode_get_data(typeNode);
+						purple_debug_info("MSNCL","Passport name: '%s', Type: %s\n", passport ? passport : "(null)", type ? type : "(null)");
+						/* Why do we even bother parsing it just to free it??? */
+						g_free(type);
+
+						user = msn_userlist_find_add_user(session->userlist,passport,NULL);
+						g_free(passport);
+
+						membershipIdNode = xmlnode_get_child(member,"MembershipId");
+						if (membershipIdNode != NULL) {
+							membershipId = xmlnode_get_data(membershipIdNode);
+							if (membershipId != NULL) {
+								user->membership_id[list] = atoi(membershipId);
+								g_free(membershipId);
+							}
+						}
+
+						msn_got_lst_user(session, user, list_op, NULL);
+					}
+					else if (!g_strcasecmp(member_type, "PhoneMember")) {
+					}
+					else if (!g_strcasecmp(member_type, "EmailMember")) {
+						xmlnode *emailNode;
+						passport = NULL;
+
+						if ((emailNode = xmlnode_get_child(member, "Email")))
+							passport = xmlnode_get_data(emailNode);
+						purple_debug_info("MSNCL","Email Member: Name: '%s', list_op: %d\n", passport ? passport : "(null)", list_op);
+
+						user = msn_userlist_find_add_user(session->userlist, passport, NULL);
+						g_free(passport);
+
+						membershipIdNode = xmlnode_get_child(member,"MembershipId");
+						if (membershipIdNode != NULL) {
+							membershipId = xmlnode_get_data(membershipIdNode);
+							if (membershipId != NULL) {
+								user->membership_id[list] = atoi(membershipId);
+								g_free(membershipId);
+							}
+						}
+
+						msn_got_lst_user(session, user, list_op, NULL);
+					}
+				}
+			}
+			g_free(typedata);	/* Free 'Type' node data after processing 'Messenger' Service */
+		}
+	}
+
+	xmlnode_free(node);	/* Free the whole XML tree */
+}
+
+static gboolean
+msn_get_contact_list_cb(MsnSoapConn *soapconn)
+{
+	MsnContact *contact;
+	MsnSession *session;
+	const char *abLastChange;
+	const char *dynamicItemLastChange;
+	gchar *partner_scenario;
+
+	if (soapconn->body == NULL)
+		return TRUE;
+
+	purple_debug_misc("MSNCL","Got the contact list!\n");
+
+	contact = soapconn->parent;
+	g_return_val_if_fail(contact != NULL, TRUE);
+	session = soapconn->session;
+	g_return_val_if_fail(session != NULL, FALSE);
+	g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
+
+	partner_scenario = soapconn->data_cb;
+
+	msn_parse_contact_list(contact);
+	/*free the read buffer*/
+	msn_soap_free_read_buf(soapconn);
+
+	abLastChange = purple_account_get_string(session->account, "ablastChange", NULL);
+	dynamicItemLastChange = purple_account_get_string(session->account, "dynamicItemLastChange", NULL);
+
+	if (!strcmp(partner_scenario, MsnSoapPartnerScenarioText[MSN_PS_INITIAL])) {
+
+#ifdef MSN_PARTIAL_LISTS
+		/* XXX: this should be enabled when we can correctly do partial
+	 	  syncs with the server. Currently we need to retrieve the whole
+	 	  list to detect sync issues */
+		msn_get_address_book(contact, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange);
+#else
+		msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL);
+#endif
+	} else {
+		msn_soap_free_read_buf(soapconn);
+	}
+
+	return TRUE;
+}
+
+static void
+msn_get_contact_written_cb(MsnSoapConn *soapconn)
+{
+	purple_debug_misc("MSNCL","Sent SOAP request for the contact list.\n");
+	soapconn->read_cb = msn_get_contact_list_cb;
+}
+
+/* SOAP  get contact list*/
+void
+msn_get_contact_list(MsnContact * contact, const MsnSoapPartnerScenario partner_scenario, const char *update_time)
+{
+	MsnSoapReq *soap_request;
+	gchar *body = NULL;
+	gchar * update_str;
+	const gchar *partner_scenario_str = MsnSoapPartnerScenarioText[partner_scenario];
+
+	purple_debug_misc("MSNCL","Getting Contact List.\n");
+
+	if ( update_time != NULL ) {
+		purple_debug_info("MSNCL","Last update time: %s\n",update_time);
+		update_str = g_strdup_printf(MSN_GET_CONTACT_UPDATE_XML,update_time);
+	} else {
+		update_str = g_strdup("");
+	}
+
+	body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, update_str);
+	g_free(update_str);
+
+	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
+					MSN_GET_CONTACT_POST_URL,
+					MSN_GET_CONTACT_SOAP_ACTION,
+					body,
+					(gpointer) partner_scenario_str,
+					msn_get_contact_list_cb,
+					msn_get_contact_written_cb,
+					msn_contact_connect_init);
+	msn_soap_post(contact->soapconn,soap_request);
+	g_free(body);
+}
+
+static void
+msn_parse_addressbook_groups(MsnContact *contact, xmlnode *node)
+{
+	MsnSession *session = contact->session;
+	xmlnode *group;
+
+	purple_debug_info("MsnAb","msn_parse_addressbook_groups()\n");
+
+	for(group = xmlnode_get_child(node, "Group"); group;
+					group = xmlnode_get_next_twin(group)){
+		xmlnode *groupId, *groupInfo, *groupname;
+		char *group_id, *group_name;
+
+		groupId = xmlnode_get_child(group,"groupId");
+		group_id = xmlnode_get_data(groupId);
+		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){
+			/* Group of ungroupped buddies */
+			g_free(group_name);
+			continue;
+		}
+
+		purple_debug_info("MsnAB","group_id: %s, name: %s\n",group_id,group_name);
+		if ((purple_find_group(group_name)) == NULL){
+			PurpleGroup *g = purple_group_new(group_name);
+			purple_blist_add_group(g, NULL);
+		}
+		g_free(group_id);
+		g_free(group_name);
+	}
+}
+
+static void
+msn_parse_addressbook_contacts(MsnContact *contact, xmlnode *node)
+{
+	MsnSession *session = contact->session;
+	xmlnode *contactNode;
+	char *passport = NULL, *Name = NULL, *uid = NULL, *type = NULL;
+
+	for(contactNode = xmlnode_get_child(node, "Contact"); contactNode;
+				contactNode = xmlnode_get_next_twin(contactNode)) {
+		xmlnode *contactId, *contactInfo, *contactType, *passportName, *displayName, *guid, *groupIds;
+		MsnUser *user;
+		MsnUserType usertype;
+
+		if (!(contactId = xmlnode_get_child(contactNode,"contactId"))
+				|| !(contactInfo = xmlnode_get_child(contactNode, "contactInfo"))
+				|| !(contactType = xmlnode_get_child(contactInfo, "contactType")))
+			continue;
+
+		g_free(passport);
+		g_free(Name);
+		g_free(uid);
+		g_free(type);
+		passport = Name = uid = type = NULL;
+
+		uid = xmlnode_get_data(contactId);
+		type = xmlnode_get_data(contactType);
+
+		/*setup the Display Name*/
+		if (type && !strcmp(type, "Me")){
+			char *friendly = NULL;
+			if ((displayName = xmlnode_get_child(contactInfo, "displayName")))
+				friendly = xmlnode_get_data(displayName);
+			purple_connection_set_display_name(session->account->gc, friendly ? purple_url_decode(friendly) : NULL);
+			g_free(friendly);
+			continue; /* Not adding own account as buddy to buddylist */
+		}
+
+		usertype = msn_get_user_type(type);
+		passportName = xmlnode_get_child(contactInfo, "passportName");
+		if (passportName == NULL) {
+			xmlnode *emailsNode, *contactEmailNode, *emailNode;
+			xmlnode *messengerEnabledNode;
+			char *msnEnabled;
+
+			/*TODO: add it to the none-instant Messenger group and recognize as email Membership*/
+			/*Yahoo User?*/
+			emailsNode = xmlnode_get_child(contactInfo, "emails");
+			if (emailsNode == NULL) {
+				/*TODO:  need to support the Mobile type*/
+				continue;
+			}
+			for(contactEmailNode = xmlnode_get_child(emailsNode, "ContactEmail"); contactEmailNode;
+					contactEmailNode = xmlnode_get_next_twin(contactEmailNode) ){
+				if (!(messengerEnabledNode = xmlnode_get_child(contactEmailNode, "isMessengerEnabled"))) {
+					/* XXX: Should this be a continue instead of a break? It seems like it'd cause unpredictable results otherwise. */
+					break;
+				}
+
+				msnEnabled = xmlnode_get_data(messengerEnabledNode);
+
+				if ((emailNode = xmlnode_get_child(contactEmailNode, "email"))) {
+					g_free(passport);
+					passport = xmlnode_get_data(emailNode);
+				}
+
+				if(msnEnabled && !strcmp(msnEnabled, "true")) {
+					/*Messenger enabled, Get the Passport*/
+					purple_debug_info("MsnAB", "Yahoo User %s\n", passport ? passport : "(null)");
+					usertype = MSN_USER_TYPE_YAHOO;
+					g_free(msnEnabled);
+					break;
+				} else {
+					/*TODO maybe we can just ignore it in Purple?*/
+					purple_debug_info("MSNAB", "Other type user\n");
+				}
+
+				g_free(msnEnabled);
+			}
+		} else {
+			passport = xmlnode_get_data(passportName);
+		}
+
+		if (passport == NULL)
+			continue;
+
+		if ((displayName = xmlnode_get_child(contactInfo, "displayName")))
+			Name = xmlnode_get_data(displayName);
+		else
+			Name = g_strdup(passport);
+
+		purple_debug_misc("MsnAB","passport:{%s} uid:{%s} display:{%s}\n",
+						passport, uid ? uid : "(null)", Name ? Name : "(null)");
+
+		user = msn_userlist_find_add_user(session->userlist, passport, Name);
+		msn_user_set_uid(user, uid);
+		msn_user_set_type(user, usertype);
+
+		purple_debug_misc("MsnAB","parse guid...\n");
+		groupIds = xmlnode_get_child(contactInfo, "groupIds");
+		if (groupIds) {
+			for (guid = xmlnode_get_child(groupIds, "guid"); guid;
+							guid = xmlnode_get_next_twin(guid)){
+				char *group_id = xmlnode_get_data(guid);
+				msn_user_add_group_id(user, group_id);
+				purple_debug_misc("MsnAB", "guid:%s\n", group_id ? group_id : "(null)");
+				g_free(group_id);
+			}
+		} else {
+			/*not in any group,Then set default group*/
+			msn_user_add_group_id(user, MSN_INDIVIDUALS_GROUP_ID);
+		}
+
+		msn_got_lst_user(session, user, MSN_LIST_FL_OP, NULL);
+	}
+
+	g_free(passport);
+	g_free(Name);
+	g_free(uid);
+	g_free(type);
+}
+
+static gboolean
+msn_parse_addressbook(MsnContact * contact)
+{
+	MsnSession * session;
+	xmlnode * node,*body,*response,*result;
+	xmlnode *groups;
+	xmlnode	*contacts;
+	xmlnode *abNode;
+	xmlnode *fault, *faultstringnode, *faultdetail, *errorcode;
+
+	session = contact->session;
+
+	
+
+	node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len);
+	if ( node == NULL ) {
+		purple_debug_error("MSN AddressBook","Error parsing Address Book with size %d\n", contact->soapconn->body_len);
+		return FALSE;
+	}
+
+	purple_debug_misc("MSN AddressBook", "Parsing Address Book with size %d\n", contact->soapconn->body_len);
+
+	purple_debug_misc("MSN AddressBook","node{%p},name:%s,child:%s,last:%s\n",node,node->name,node->child->name,node->lastchild->name);
+	
+	body = xmlnode_get_child(node,"Body");
+	purple_debug_misc("MSN AddressBook","body{%p},name:%s\n",body,body->name);
+
+	/* TODO: This appears to be used in a number of places and should be de-duplicated */
+	if ( (fault = xmlnode_get_child(body, "Fault")) != NULL) {
+		purple_debug_info("MSN AddressBook","Fault received from SOAP server!\n");
+		
+		if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) {
+			gchar *faultstring = xmlnode_get_data(faultstringnode);
+			purple_debug_info("MSN AddressBook","Faultstring: %s\n", faultstring ? faultstring : "(null)");
+			g_free(faultstring);
+		}
+		if ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) {
+			purple_debug_info("MSN AddressBook","detail @ %p, name: %s\n",faultdetail, faultdetail->name);
+
+			if ( (errorcode = xmlnode_get_child(faultdetail, "errorcode")) != NULL ) {
+				gchar *errorcodestring;
+				purple_debug_info("MSN AddressBook","errorcode @ %p, name: %s\n",errorcode, errorcode->name);
+
+				errorcodestring = xmlnode_get_data(errorcode);
+				purple_debug_info("MSN AddressBook", "Error Code: %s\n", errorcodestring ? errorcodestring : "(null)");
+						
+				if (errorcodestring && !strncmp(errorcodestring, "ABDoesNotExist", 14) ) {
+					g_free(errorcodestring);
+					xmlnode_free(node);
+					return TRUE;
+				}
+				g_free(errorcodestring);
+			}
+		}
+		xmlnode_free(node);
+		return FALSE;
+	}
+
+
+	response = xmlnode_get_child(body,"ABFindAllResponse");
+
+	if (response == NULL) {
+		xmlnode_free(node);
+		return FALSE;
+	}
+
+	purple_debug_misc("MSN SOAP","response{%p},name:%s\n",response,response->name);
+	result = xmlnode_get_child(response,"ABFindAllResult");
+	if(result == NULL){
+		purple_debug_misc("MSNAB","receive no address book update\n");
+		xmlnode_free(node);
+		return TRUE;
+	}
+	purple_debug_info("MSN SOAP","result{%p},name:%s\n",result,result->name);
+
+	/*Process Group List*/
+	groups = xmlnode_get_child(result,"groups");
+	if (groups != NULL) {
+		msn_parse_addressbook_groups(contact, groups);
+	}
+
+	/*add a default No group to set up the no group Membership*/
+	msn_group_new(session->userlist, MSN_INDIVIDUALS_GROUP_ID,
+				  MSN_INDIVIDUALS_GROUP_NAME);
+	purple_debug_misc("MsnAB","group_id:%s name:%s\n",
+					  MSN_INDIVIDUALS_GROUP_ID, MSN_INDIVIDUALS_GROUP_NAME);
+	if ((purple_find_group(MSN_INDIVIDUALS_GROUP_NAME)) == NULL){
+		PurpleGroup *g = purple_group_new(MSN_INDIVIDUALS_GROUP_NAME);
+		purple_blist_add_group(g, NULL);
+	}
+
+	/*add a default No group to set up the no group Membership*/
+	msn_group_new(session->userlist, MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME);
+	purple_debug_misc("MsnAB","group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME);
+	if ((purple_find_group(MSN_NON_IM_GROUP_NAME)) == NULL){
+		PurpleGroup *g = purple_group_new(MSN_NON_IM_GROUP_NAME);
+		purple_blist_add_group(g, NULL);
+	}
+
+	/*Process contact List*/
+	purple_debug_info("MSNAB","process contact list...\n");
+	contacts =xmlnode_get_child(result,"contacts");
+	if (contacts != NULL) {
+		msn_parse_addressbook_contacts(contact, contacts);
+	}
+
+	abNode =xmlnode_get_child(result,"ab");
+	if(abNode != NULL){
+		xmlnode *node2;
+		char *tmp = NULL;
+
+		if ((node2 = xmlnode_get_child(abNode, "lastChange")))
+			tmp = xmlnode_get_data(node2);
+		purple_debug_info("MsnAB"," lastchanged Time:{%s}\n", tmp ? tmp : "(null)");
+		purple_account_set_string(session->account, "ablastChange", tmp);
+
+		g_free(tmp); tmp = NULL;
+		if ((node2 = xmlnode_get_child(abNode, "DynamicItemLastChanged")))
+			tmp = xmlnode_get_data(node2);
+		purple_debug_info("MsnAB"," DynamicItemLastChanged :{%s}\n", tmp ? tmp : "(null)");
+		purple_account_set_string(session->account, "DynamicItemLastChanged", tmp);
+		g_free(tmp);
+	}
+
+	xmlnode_free(node);
+	msn_soap_free_read_buf(contact->soapconn);
+	return TRUE;
+}
+
+static gboolean
+msn_get_address_cb(MsnSoapConn *soapconn)
+{
+	MsnContact *contact;
+	MsnSession *session;
+
+	if (soapconn->body == NULL)
+		return TRUE;
+
+	contact = soapconn->parent;
+	g_return_val_if_fail(contact != NULL, TRUE);
+	session = soapconn->session;
+	g_return_val_if_fail(session != NULL, FALSE);
+
+	purple_debug_misc("MSN AddressBook", "Got the Address Book!\n");
+
+	if ( msn_parse_addressbook(contact) ) {
+		//msn_soap_free_read_buf(soapconn);
+
+		if (!session->logged_in) {
+			msn_send_privacy(session->account->gc);
+			msn_notification_dump_contact(session);
+		}
+
+		/*free the read buffer*/
+		msn_soap_free_read_buf(soapconn);
+		return TRUE;
+	} else {
+		/* This is making us loop infinitely when we fail to parse the address book,
+		  disable for now (we should re-enable when we send timestamps)
+		*/
+		/*
+		msn_get_address_book(contact, NULL, NULL);
+		*/
+		msn_session_disconnect(session);
+		purple_connection_error(session->account->gc, _("Unable to retrieve MSN Address Book"));
+		return FALSE;
+	}
+}
+
+/**/
+static void
+msn_address_written_cb(MsnSoapConn *soapconn)
+{
+	purple_debug_misc("MSN AddressBook","Sent SOAP request for the Address Book.\n");
+	soapconn->read_cb = msn_get_address_cb;
+}
+
+/*get the address book*/
+void
+msn_get_address_book(MsnContact *contact, const MsnSoapPartnerScenario partner_scenario, const char *LastChanged, const char *dynamicItemLastChange)
+{
+	MsnSoapReq *soap_request;
+	char *body;
+	char *update_str = NULL;
+
+	purple_debug_misc("MSN AddressBook","Getting Address Book\n");
+
+	/*build SOAP and POST it*/
+	if (dynamicItemLastChange != NULL)
+		update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, dynamicItemLastChange);
+	else if (LastChanged != NULL)
+		update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, LastChanged);
+
+
+	body = g_strdup_printf(MSN_GET_ADDRESS_TEMPLATE, MsnSoapPartnerScenarioText[partner_scenario], update_str ? update_str : "");
+	g_free(update_str);
+
+	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
+					MSN_ADDRESS_BOOK_POST_URL,MSN_GET_ADDRESS_SOAP_ACTION,
+					body,
+					NULL,
+					msn_get_address_cb,
+					msn_address_written_cb,
+					msn_contact_connect_init);
+	msn_soap_post(contact->soapconn,soap_request);
+	g_free(body);
+}
+
+static gboolean
+msn_add_contact_read_cb(MsnSoapConn *soapconn)
+{
+	MsnCallbackState *state = NULL;
+	MsnUserList *userlist;
+	MsnUser *user;
+	
+	g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
+	g_return_val_if_fail(soapconn->session != NULL, FALSE);
+	g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE);
+
+	state = (MsnCallbackState *) soapconn->data_cb;
+
+	if (soapconn->body == NULL) {
+		msn_callback_state_free(state);
+		return TRUE;
+	}
+	
+	userlist = soapconn->session->userlist;
+	
+	purple_debug_info("MSNCL","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(soapconn->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(soapconn->session, state->who);
+
+	user = msn_userlist_find_add_user(userlist, state->who, state->who);
+	msn_user_add_group_id(user, state->guid);
+
+	if (msn_userlist_user_is_in_list(user, MSN_LIST_PL)) {
+		msn_del_contact_from_list(soapconn->session->contact, NULL, state->who, MSN_LIST_PL);
+	} else {
+		msn_soap_free_read_buf(soapconn);
+	}
+	
+	msn_callback_state_free(state);
+
+	return TRUE;
+}
+
+static void
+msn_add_contact_written_cb(MsnSoapConn *soapconn)
+{
+	purple_debug_info("MSNCL","Add contact request written\n");
+	soapconn->read_cb = msn_add_contact_read_cb;
+}
+
+/* add a Contact in MSN_INDIVIDUALS_GROUP */
+void
+msn_add_contact(MsnContact *contact, MsnCallbackState *state, const char *passport)
+{
+	MsnSoapReq *soap_request;
+	gchar *body = NULL;
+	gchar *contact_xml = NULL;
+
+	g_return_if_fail(passport != NULL);
+/*	gchar *escaped_displayname;
+
+
+	 if (displayname != NULL) {
+		escaped_displayname = g_markup_decode_text(displayname, -1);
+	 } else {
+		escaped_displayname = passport;
+	 }
+	contact_xml = g_strdup_printf(MSN_XML_ADD_CONTACT, escaped_displayname, passport);
+*/
+	purple_debug_info("MSNCL","Adding contact %s to contact list\n", passport);
+
+//	if ( !strcmp(state->guid, MSN_INDIVIDUALS_GROUP_ID) ) {
+		contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport);
+//	}
+	body = g_strdup_printf(MSN_ADD_CONTACT_TEMPLATE, contact_xml);
+
+	g_free(contact_xml);
+
+	/*build SOAP and POST it*/
+
+	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
+					MSN_ADDRESS_BOOK_POST_URL,
+					MSN_CONTACT_ADD_SOAP_ACTION,
+					body,
+					state,
+					msn_add_contact_read_cb,
+					msn_add_contact_written_cb,
+					msn_contact_connect_init);
+	msn_soap_post(contact->soapconn,soap_request);
+
+	g_free(body);
+}
+
+static gboolean
+msn_add_contact_to_group_read_cb(MsnSoapConn *soapconn)
+{
+	MsnCallbackState *state; 
+	MsnUserList *userlist;
+
+	g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
+	g_return_val_if_fail(soapconn->session != NULL, FALSE);
+	g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE);
+
+	userlist = soapconn->session->userlist;
+
+	state = (MsnCallbackState *) soapconn->data_cb;
+
+	if (soapconn->body == NULL) {
+		msn_callback_state_free(state);
+		return TRUE;
+	}
+	
+	if (msn_userlist_add_buddy_to_group(userlist, state->who, state->new_group_name) == TRUE) {
+		purple_debug_info("MSNCL", "Contact %s added to group %s successfully!\n", state->who, state->new_group_name);
+	} else {
+		purple_debug_info("MSNCL","Contact %s added to group %s successfully on server, but failed in the local list\n", state->who, state->new_group_name);
+	}
+
+	if (state->action & MSN_ADD_BUDDY) {
+		MsnUser *user = msn_userlist_find_user(userlist, state->who);
+
+        	if ( !msn_user_is_yahoo(soapconn->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(soapconn->session, state->who);
+
+		if (msn_userlist_user_is_in_list(user, MSN_LIST_PL)) {
+			msn_del_contact_from_list(soapconn->session->contact, NULL, state->who, MSN_LIST_PL);
+			msn_callback_state_free(state);
+			return TRUE;
+		}
+	}
+
+	if (state->action & MSN_MOVE_BUDDY) {
+		msn_del_contact_from_group(soapconn->session->contact, state->who, state->old_group_name);
+	} else {
+		msn_callback_state_free(state);
+		msn_soap_free_read_buf(soapconn);
+	}
+	return TRUE;
+}
+
+static void
+msn_add_contact_to_group_written_cb(MsnSoapConn *soapconn)
+{
+	purple_debug_info("MSNCL","Add contact to group request sent!\n");
+	soapconn->read_cb = msn_add_contact_to_group_read_cb;
+}
+
+void
+msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state, 
+			 const char *passport, const char *groupId)
+{
+	MsnSoapReq *soap_request;
+	MsnUserList *userlist;
+	MsnUser *user;
+	gchar *body = NULL, *contact_xml;
+
+	g_return_if_fail(passport != NULL);
+	g_return_if_fail(groupId != NULL);
+
+	g_return_if_fail(contact != NULL);
+	g_return_if_fail(contact->session != NULL);
+	g_return_if_fail(contact->session->userlist != NULL);
+	
+	userlist = contact->session->userlist;
+
+	if (!strcmp(groupId, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(groupId, MSN_NON_IM_GROUP_ID)) {
+		
+		user = msn_userlist_find_add_user(userlist, passport, passport);
+
+		if (state->action & MSN_ADD_BUDDY) {
+			msn_add_contact(contact, state, passport);
+			return;
+		}
+
+		if (state->action & MSN_MOVE_BUDDY) {
+			msn_user_add_group_id(user, groupId);
+			msn_del_contact_from_group(contact, passport, state->old_group_name);
+		} else {
+			msn_callback_state_free(state);
+		}
+
+		return;
+	}
+
+
+	purple_debug_info("MSNCL", "Adding user %s to group %s\n", passport, 
+			  msn_userlist_find_group_name(userlist, groupId));
+
+	user = msn_userlist_find_user(userlist, passport);
+	if (user == NULL) {
+		purple_debug_warning("MSN CL", "Unable to retrieve user %s from the userlist!\n", passport);
+	}
+
+	if (user->uid != NULL) {
+		contact_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid);
+	} else {
+		contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport);
+	}
+
+	body = g_strdup_printf(MSN_ADD_CONTACT_GROUP_TEMPLATE, groupId, contact_xml);
+	g_free(contact_xml);
+
+	/*build SOAP and POST it*/
+
+	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
+					MSN_ADDRESS_BOOK_POST_URL,
+					MSN_ADD_CONTACT_GROUP_SOAP_ACTION,
+					body,
+					state,
+					msn_add_contact_to_group_read_cb,
+					msn_add_contact_to_group_written_cb,
+					msn_contact_connect_init);
+	msn_soap_post(contact->soapconn,soap_request);
+
+	g_free(body);
+}
+
+
+
+static gboolean
+msn_delete_contact_read_cb(MsnSoapConn *soapconn)
+{
+	MsnUser *user;
+	MsnCallbackState *state = (MsnCallbackState *) soapconn->data_cb;
+	MsnUserList *userlist; 
+
+	g_return_val_if_fail(soapconn->session != NULL, FALSE);
+	g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE);
+
+	userlist = soapconn->session->userlist;
+
+        if (soapconn->body == NULL) {
+                msn_callback_state_free(state);
+                return TRUE;
+        }
+
+	purple_debug_info("MSNCL","Delete contact successful\n");
+
+	user = msn_userlist_find_user_with_id(userlist, state->uid);
+	if (user != NULL) {
+		msn_userlist_remove_user(userlist, user);
+	}
+
+	msn_callback_state_free(state);
+	msn_soap_free_read_buf(soapconn);
+
+	return TRUE;
+}
+
+static void
+msn_delete_contact_written_cb(MsnSoapConn *soapconn)
+{
+	purple_debug_info("MSNCL","Delete contact request written\n");
+	soapconn->read_cb = msn_delete_contact_read_cb;
+}
+
+/*delete a Contact*/
+void
+msn_delete_contact(MsnContact *contact, const char *contactId)
+{	
+	gchar *body = NULL;
+	gchar *contact_id_xml = NULL ;
+	MsnSoapReq *soap_request;
+	MsnCallbackState *state;
+
+	g_return_if_fail(contactId != NULL);
+	contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, contactId);
+
+	state = msn_callback_state_new();
+	msn_callback_state_set_uid(state, contactId);
+
+	/* build SOAP request */
+	purple_debug_info("MSNCL","Deleting contact with contactId: %s\n", contactId);
+	body = g_strdup_printf(MSN_DEL_CONTACT_TEMPLATE, contact_id_xml);
+	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
+					MSN_ADDRESS_BOOK_POST_URL,
+					MSN_CONTACT_DEL_SOAP_ACTION,
+					body,
+					state,
+					msn_delete_contact_read_cb,
+					msn_delete_contact_written_cb,
+					msn_contact_connect_init);
+
+	g_free(contact_id_xml);
+
+	/* POST the SOAP request */
+	msn_soap_post(contact->soapconn, soap_request);
+
+	g_free(body);
+}
+
+static gboolean
+msn_del_contact_from_group_read_cb(MsnSoapConn *soapconn)
+{
+	MsnCallbackState *state = (MsnCallbackState *) soapconn->data_cb;
+
+	if (soapconn->body == NULL) {
+		msn_callback_state_free(state);
+		return TRUE;
+	}
+	
+	if (msn_userlist_rem_buddy_from_group(soapconn->session->userlist, state->who, state->old_group_name)) {
+		purple_debug_info("MSN CL", "Contact %s deleted successfully from group %s\n", state->who, state->old_group_name);
+	} else {
+		purple_debug_info("MSN CL", "Contact %s deleted successfully from group %s in the server, but failed in the local list\n", state->who, state->old_group_name);
+	}
+	
+	msn_callback_state_free(state);
+	msn_soap_free_read_buf(soapconn);
+
+	return TRUE;
+}
+
+static void
+msn_del_contact_from_group_written_cb(MsnSoapConn *soapconn)
+{
+	purple_debug_info("MSN CL","Del contact from group request sent!\n");
+	soapconn->read_cb = msn_del_contact_from_group_read_cb;
+}
+
+void
+msn_del_contact_from_group(MsnContact *contact, const char *passport, const char *group_name)
+{
+	MsnSoapReq *soap_request;
+	MsnUserList * userlist;
+	MsnUser *user;
+	MsnCallbackState *state;
+	gchar *body = NULL, *contact_id_xml;
+	const gchar *groupId;
+	
+	g_return_if_fail(passport != NULL);
+	g_return_if_fail(group_name != NULL);
+	g_return_if_fail(contact != NULL);
+	g_return_if_fail(contact->session != NULL);
+	g_return_if_fail(contact->session->userlist != NULL);
+	
+	userlist = contact->session->userlist;
+	
+	groupId = msn_userlist_find_group_id(userlist, group_name);
+	if (groupId != NULL) {
+		purple_debug_info("MSN CL", "Deleting user %s from group %s\n", passport, group_name);
+	} else {
+		purple_debug_warning("MSN CL", "Unable to retrieve group id from group %s !\n", group_name);
+		return;
+	}
+	
+	user = msn_userlist_find_user(userlist, passport);
+	
+	if (user == NULL) {
+		purple_debug_warning("MSN CL", "Unable to retrieve user from passport %s!\n", passport);
+		return;
+	}
+
+	if ( !strcmp(groupId, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(groupId, MSN_NON_IM_GROUP_ID)) {
+		msn_user_remove_group_id(user, groupId);
+		return;
+	}
+
+	state = msn_callback_state_new();
+	msn_callback_state_set_who(state, passport);
+	msn_callback_state_set_guid(state, groupId);
+	msn_callback_state_set_old_group_name(state, group_name);
+
+	contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid);
+	body = g_strdup_printf(MSN_CONTACT_DEL_GROUP_TEMPLATE, contact_id_xml, groupId);
+	g_free(contact_id_xml);
+
+	/*build SOAP and POST it*/
+	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
+					    MSN_ADDRESS_BOOK_POST_URL,
+					    MSN_CONTACT_DEL_GROUP_SOAP_ACTION,
+					    body,
+					    state,
+					    msn_del_contact_from_group_read_cb,
+					    msn_del_contact_from_group_written_cb,
+					    msn_contact_connect_init);
+	msn_soap_post(contact->soapconn,soap_request);
+
+	g_free(body);
+}
+
+
+static gboolean
+msn_update_contact_read_cb(MsnSoapConn *soapconn)
+{
+	if (soapconn->body == NULL)
+		return TRUE;
+
+	purple_debug_info("MSN CL","Contact updated successfully\n");
+
+	return TRUE;
+}
+
+static void
+msn_update_contact_written_cb(MsnSoapConn *soapconn)
+{
+	purple_debug_info("MSN CL","Update contact information request sent\n");
+	soapconn->read_cb = msn_update_contact_read_cb;
+}
+
+/* Update a contact's nickname */
+
+void
+msn_update_contact(MsnContact *contact, const char* nickname)
+{
+	MsnSoapReq *soap_request;
+	gchar *body = NULL, *escaped_nickname;
+
+	purple_debug_info("MSN CL","Update contact information with new friendly name: %s\n", nickname);
+	
+	escaped_nickname = g_markup_escape_text(nickname, -1);
+
+	body = g_strdup_printf(MSN_CONTACT_UPDATE_TEMPLATE, escaped_nickname);
+	
+	g_free(escaped_nickname);
+	/*build SOAP and POST it*/
+	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
+					MSN_ADDRESS_BOOK_POST_URL,
+					MSN_CONTACT_UPDATE_SOAP_ACTION,
+					body,
+					NULL,
+					msn_update_contact_read_cb,
+					msn_update_contact_written_cb,
+					msn_contact_connect_init);
+	msn_soap_post(contact->soapconn, soap_request);
+
+	g_free(body);
+}
+
+
+static gboolean
+msn_del_contact_from_list_read_cb(MsnSoapConn *soapconn)
+{
+	MsnCallbackState *state = NULL;
+
+	g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
+	g_return_val_if_fail(soapconn->session != NULL, FALSE);
+	g_return_val_if_fail(soapconn->session->contact != NULL, FALSE);
+
+	state = (MsnCallbackState *) soapconn->data_cb;
+
+	if (soapconn->body == NULL) {
+		msn_callback_state_free(state);
+		return TRUE;
+	}
+	
+	purple_debug_info("MSN CL", "Contact %s deleted successfully from %s list on server!\n", state->who, MsnMemberRole[state->list_id]);
+
+	if (state->list_id == MSN_LIST_PL) {
+		msn_add_contact_to_list(soapconn->session->contact, state, state->who, MSN_LIST_RL);
+		return TRUE;
+	}
+
+	if (state->list_id == MSN_LIST_AL) {
+		purple_privacy_permit_remove(soapconn->session->account, state->who, TRUE);
+		msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_BL);
+		msn_callback_state_free(state);
+		return TRUE;
+	}
+
+	if (state->list_id == MSN_LIST_BL) {
+		purple_privacy_deny_remove(soapconn->session->account, state->who, TRUE);
+		msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_AL);
+		msn_callback_state_free(state);
+		return TRUE;
+	}
+
+	msn_callback_state_free(state);
+	msn_soap_free_read_buf(soapconn);
+
+	return TRUE;
+}
+
+static void
+msn_del_contact_from_list_written_cb(MsnSoapConn *soapconn)
+{
+	purple_debug_info("MSN CL","Delete contact from list SOAP request sent!\n");
+	soapconn->read_cb = msn_del_contact_from_list_read_cb;
+}
+
+void
+msn_del_contact_from_list(MsnContact *contact, MsnCallbackState *state,
+			  const gchar *passport, const MsnListId list)
+{
+	MsnSoapReq *soap_request;
+	gchar *body = NULL, *member = NULL;
+	MsnSoapPartnerScenario partner_scenario;
+	MsnUser *user;
+
+	g_return_if_fail(contact != NULL);
+	g_return_if_fail(passport != NULL);
+	g_return_if_fail(list < 5);
+
+	purple_debug_info("MSN CL", "Deleting contact %s from %s list\n", passport, MsnMemberRole[list]);
+
+	if (state == NULL) {
+		state = msn_callback_state_new();
+	}
+	msn_callback_state_set_list_id(state, list);
+	msn_callback_state_set_who(state, passport);
+
+	if (list == MSN_LIST_PL) {
+		g_return_if_fail(contact->session != NULL);
+		g_return_if_fail(contact->session->userlist != NULL);
+
+		user = msn_userlist_find_user(contact->session->userlist, passport);
+
+		partner_scenario = MSN_PS_CONTACT_API;
+		member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML, user->membership_id[MSN_LIST_PL]);
+	} else {
+		/* list == MSN_LIST_AL || list == MSN_LIST_BL */
+		partner_scenario = MSN_PS_BLOCK_UNBLOCK;
+		
+		member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, passport);
+	}
+
+	body = g_strdup_printf( MSN_CONTACT_DELECT_FROM_LIST_TEMPLATE,
+			        MsnSoapPartnerScenarioText[partner_scenario],
+			        MsnMemberRole[list],
+			        member);
+	g_free(member);
+
+	soap_request = msn_soap_request_new( MSN_CONTACT_SERVER,
+					     MSN_SHARE_POST_URL,
+					     MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION,
+					     body,
+					     state,
+					     msn_del_contact_from_list_read_cb,
+					     msn_del_contact_from_list_written_cb,
+					     msn_contact_connect_init);
+
+	msn_soap_post(contact->soapconn,soap_request);
+	
+	g_free(body);
+}
+
+static gboolean
+msn_add_contact_to_list_read_cb(MsnSoapConn *soapconn)
+{
+	MsnCallbackState *state = NULL;
+
+	g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
+
+	state = (MsnCallbackState *) soapconn->data_cb;
+	
+	if (soapconn->body == NULL) {
+		msn_callback_state_free(state);
+		return TRUE;
+	}
+	
+	purple_debug_info("MSN CL", "Contact %s added successfully to %s list on server!\n", state->who, MsnMemberRole[state->list_id]);
+
+	if (state->list_id == MSN_LIST_RL && (state->action & MSN_DENIED_BUDDY) ) {
+		g_return_val_if_fail(soapconn->session != NULL, FALSE);
+		g_return_val_if_fail(soapconn->session->contact != NULL, FALSE);
+
+		msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_BL);
+		return TRUE;
+	}
+
+	if (state->list_id == MSN_LIST_AL) {
+		purple_privacy_permit_add(soapconn->session->account, state->who, TRUE);
+	} else if (state->list_id == MSN_LIST_BL) {
+		purple_privacy_deny_add(soapconn->session->account, state->who, TRUE);
+	}
+
+	msn_callback_state_free(state);
+	msn_soap_free_read_buf(soapconn);
+	return TRUE;
+}
+
+
+static void
+msn_add_contact_to_list_written_cb(MsnSoapConn *soapconn)
+{
+	purple_debug_info("MSN CL","Add contact to list SOAP request sent!\n");
+	soapconn->read_cb = msn_add_contact_to_list_read_cb;
+}
+
+void
+msn_add_contact_to_list(MsnContact *contact, MsnCallbackState *state,
+			const gchar *passport, const MsnListId list)
+{
+	MsnSoapReq *soap_request;
+	gchar *body = NULL, *member = NULL;
+	MsnSoapPartnerScenario partner_scenario;
+
+	g_return_if_fail(contact != NULL);
+	g_return_if_fail(passport != NULL);
+	g_return_if_fail(list < 5);
+
+	purple_debug_info("MSN CL", "Adding contact %s to %s list\n", passport, MsnMemberRole[list]);
+
+	if (state == NULL) {
+		state = msn_callback_state_new();
+	}
+	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;
+
+	member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, passport);
+
+	body = g_strdup_printf(MSN_CONTACT_ADD_TO_LIST_TEMPLATE, 
+			       MsnSoapPartnerScenarioText[partner_scenario],
+			       MsnMemberRole[list], 
+			       member);
+
+	g_free(member);
+
+	soap_request = msn_soap_request_new( MSN_CONTACT_SERVER,
+					     MSN_SHARE_POST_URL,
+					     MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION,
+					     body,
+					     state,
+					     msn_add_contact_to_list_read_cb,
+					     msn_add_contact_to_list_written_cb,
+					     msn_contact_connect_init);
+
+	msn_soap_post(contact->soapconn, soap_request);
+
+	g_free(body);
+}
+
+
+#if 0
+static gboolean
+msn_gleams_read_cb(MsnSoapConn * soapconn)
+{
+	purple_debug_info("MSN CL","Gleams read done\n");
+	return TRUE;
+}
+
+static void
+msn_gleams_written_cb(MsnSoapConn * soapconn)
+{
+	purple_debug_info("MSNP14","finish Group written\n");
+	soapconn->read_cb = msn_gleams_read_cb;
+//	msn_soap_read_cb(data,source,cond);
+}
+
+/*get the gleams info*/
+void
+msn_get_gleams(MsnContact *contact)
+{
+	MsnSoapReq *soap_request;
+
+	purple_debug_info("MSNP14","msn get gleams info...\n");
+	/*build SOAP and POST it*/
+	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
+					MSN_ADDRESS_BOOK_POST_URL,
+					MSN_GET_GLEAMS_SOAP_ACTION,
+					MSN_GLEAMS_TEMPLATE,
+					NULL,
+					msn_gleams_read_cb,
+					msn_gleams_written_cb,
+					msn_contact_connect_init);
+	msn_soap_post(contact->soapconn,soap_request);
+}
+#endif
+
+
+/***************************************************************
+ * Group Operations
+ ***************************************************************/
+
+static gboolean
+msn_group_read_cb(MsnSoapConn *soapconn)
+{
+	MsnUserList *userlist;
+	MsnCallbackState *state = NULL;
+	
+	purple_debug_info("MSN CL", "Group request successful.\n");
+	
+	g_return_val_if_fail(soapconn->session != NULL, FALSE);
+	g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE);
+	g_return_val_if_fail(soapconn->session->contact != NULL, FALSE);
+
+	state = (MsnCallbackState *) soapconn->data_cb;
+	
+	if (soapconn->body == NULL) {
+		msn_callback_state_free(state);
+		return TRUE;
+	}
+	
+	if (state) {
+		userlist = soapconn->session->userlist;
+		
+		if (state->action & MSN_RENAME_GROUP) {
+			msn_userlist_rename_group_id(soapconn->session->userlist,
+						     state->guid,
+						     state->new_group_name);
+		}
+		
+		if (state->action & MSN_ADD_GROUP) {
+			gchar *guid, *endguid;
+			
+			guid = g_strstr_len(soapconn->read_buf, soapconn->read_len, "<guid>");
+			guid += 6;
+			endguid = g_strstr_len(soapconn->read_buf, soapconn->read_len, "</guid>");
+			*endguid = '\0';
+			/* create and add the new group to the userlist */
+			purple_debug_info("MSN CL", "Adding group %s with guid = %s to the userlist\n", state->new_group_name, guid);
+			msn_group_new(soapconn->session->userlist, guid, state->new_group_name);
+
+			if (state->action & MSN_ADD_BUDDY) {
+				msn_userlist_add_buddy(soapconn->session->userlist,
+						       state->who,
+						       state->new_group_name);
+				msn_callback_state_free(state);
+				return TRUE;
+			}
+			
+			if (state->action & MSN_MOVE_BUDDY) {
+				msn_add_contact_to_group(soapconn->session->contact, state, state->who, guid); 
+				return TRUE;
+			}
+		}
+		
+		if (state->action & MSN_DEL_GROUP) {
+			GList *l;
+			
+			msn_userlist_remove_group_id(soapconn->session->userlist, state->guid);
+			for (l = userlist->users; l != NULL; l = l->next) {
+				msn_user_remove_group_id( (MsnUser *)l->data, state->guid);
+			}
+			
+		}
+			
+		msn_callback_state_free(state);
+	}
+	
+	msn_soap_free_read_buf(soapconn);
+	return TRUE;
+}
+
+static void
+msn_group_written_cb(MsnSoapConn *soapconn)
+{
+	purple_debug_info("MSN CL","Sent group request.\n");
+	soapconn->read_cb = msn_group_read_cb;
+}
+
+/* add group */
+void
+msn_add_group(MsnSession *session, MsnCallbackState *state, const char* group_name)
+{
+	MsnSoapReq *soap_request;
+	MsnContact *contact;
+	char *body = NULL;
+	gchar *escaped_group_name;
+
+	g_return_if_fail(session != NULL);
+	g_return_if_fail(group_name != NULL);
+	
+	contact = session->contact;
+	purple_debug_info("MSN CL","Adding group %s to contact list.\n", group_name);
+
+	if (state == NULL) {
+		state = msn_callback_state_new();
+	}
+
+	msn_callback_state_set_action(state, MSN_ADD_GROUP);
+	msn_callback_state_set_new_group_name(state, group_name);
+
+	/* escape group name's html special chars so it can safely be sent
+	* in a XML SOAP request
+	*/
+	escaped_group_name = g_markup_escape_text(group_name, -1);
+	body = g_strdup_printf(MSN_GROUP_ADD_TEMPLATE, escaped_group_name);
+	g_free(escaped_group_name);
+
+	/*build SOAP and POST it*/
+	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
+					MSN_ADDRESS_BOOK_POST_URL,
+					MSN_GROUP_ADD_SOAP_ACTION,
+					body,
+					state,
+					msn_group_read_cb,
+					msn_group_written_cb,
+					msn_contact_connect_init);
+	msn_soap_post(contact->soapconn,soap_request);
+	
+	g_free(body);
+}
+
+/* delete group */
+void
+msn_del_group(MsnSession *session, const gchar *group_name)
+{
+	MsnSoapReq *soap_request;
+	MsnContact *contact;
+	MsnCallbackState *state;
+	char *body = NULL;
+	const gchar *guid;
+
+	g_return_if_fail(session != NULL);
+	
+	g_return_if_fail(group_name != NULL);
+	contact = session->contact;
+	purple_debug_info("MSN CL","Deleting group %s from contact list\n", group_name);
+	
+	guid = msn_userlist_find_group_id(session->userlist, group_name);
+	
+	/* if group uid we need to del is NULL, 
+	*  we need to delete nothing
+	*/
+	if (guid == NULL) {
+		purple_debug_info("MSN CL", "Group %s guid not found, returning.\n", group_name);
+		return;
+	}
+
+	if ( !strcmp(guid, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(guid, MSN_NON_IM_GROUP_ID) ) {
+		// XXX add back PurpleGroup since it isn't really removed in the server?
+		return;
+	}
+
+	state = msn_callback_state_new();
+	msn_callback_state_set_action(state, MSN_DEL_GROUP);
+	msn_callback_state_set_guid(state, guid);
+	
+	body = g_strdup_printf(MSN_GROUP_DEL_TEMPLATE, guid);
+	/*build SOAP and POST it*/
+	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
+					    MSN_ADDRESS_BOOK_POST_URL,
+					    MSN_GROUP_DEL_SOAP_ACTION,
+					    body,
+					    state,
+					    msn_group_read_cb,
+					    msn_group_written_cb,
+					    msn_contact_connect_init);
+	msn_soap_post(contact->soapconn, soap_request);
+
+	g_free(body);
+}
+
+/* rename group */
+void
+msn_contact_rename_group(MsnSession *session, const char *old_group_name, const char *new_group_name)
+{
+	MsnSoapReq *soap_request;
+	MsnContact *contact;
+	gchar * escaped_group_name, *body = NULL;
+	const gchar * guid;
+	MsnCallbackState *state = msn_callback_state_new();
+	
+	g_return_if_fail(session != NULL);
+	g_return_if_fail(session->userlist != NULL);
+	g_return_if_fail(old_group_name != NULL);
+	g_return_if_fail(new_group_name != NULL);
+	
+	contact = session->contact;
+	purple_debug_info("MSN CL", "Renaming group %s to %s.\n", old_group_name, new_group_name);
+	
+	guid = msn_userlist_find_group_id(session->userlist, old_group_name);
+	if (guid == NULL)
+		return;
+
+	msn_callback_state_set_guid(state, guid);
+	msn_callback_state_set_new_group_name(state, new_group_name);
+
+	if ( !strcmp(guid, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(guid, MSN_NON_IM_GROUP_ID) ) {
+		msn_add_group(session, state, new_group_name);
+		// XXX move every buddy there (we probably need to fix concurrent SOAP reqs first)
+	}
+
+	msn_callback_state_set_action(state, MSN_RENAME_GROUP);
+	
+	/* escape group name's html special chars so it can safely be sent
+	 * in a XML SOAP request
+	*/
+	escaped_group_name = g_markup_escape_text(new_group_name, -1);
+	
+	body = g_strdup_printf(MSN_GROUP_RENAME_TEMPLATE, guid, escaped_group_name);
+	
+	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
+					    MSN_ADDRESS_BOOK_POST_URL,
+					    MSN_GROUP_RENAME_SOAP_ACTION,
+					    body,
+					    state,
+					    msn_group_read_cb,
+					    msn_group_written_cb,
+					    msn_contact_connect_init);
+	msn_soap_post(contact->soapconn, soap_request);
+	
+	g_free(escaped_group_name);
+	g_free(body);
+}
+
+void
+msn_contact_connect_init(MsnSoapConn *soapconn)
+{
+	msn_soap_init(soapconn, MSN_CONTACT_SERVER, 1,
+		      msn_contact_login_connect_cb,
+		      msn_contact_login_error_cb);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/msn/contact.h	Fri Sep 28 16:34:43 2007 +0000
@@ -0,0 +1,448 @@
+/**
+ * @file contact.h			Header file for contact.c
+ *	Author
+ * 		MaYuan<mayuan2006@gmail.com>
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _MSN_CONTACT_H_
+#define _MSN_CONTACT_H_
+
+#define MSN_CONTACT_SERVER	"contacts.msn.com"
+
+/* Get Contact List */
+
+#define MSN_GET_CONTACT_POST_URL	"/abservice/SharingService.asmx"
+#define MSN_GET_CONTACT_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/FindMembership"
+#define MSN_GET_CONTACT_UPDATE_XML "<View>Full</View>"\
+	"<deltasOnly>true</deltasOnly>"\
+	"<lastChange>%s</lastChange>"
+#define MSN_GET_CONTACT_TEMPLATE	"<?xml version='1.0' encoding='utf-8'?>"\
+"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\
+	"<soap:Header xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\
+		"<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ApplicationId xmlns=\"http://www.msn.com/webservices/AddressBook\">09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\
+			"<IsMigration xmlns=\"http://www.msn.com/webservices/AddressBook\">false</IsMigration>"\
+			"<PartnerScenario xmlns=\"http://www.msn.com/webservices/AddressBook\">%s</PartnerScenario>"\
+		 "</ABApplicationHeader>"\
+		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ManagedGroupRequest xmlns=\"http://www.msn.com/webservices/AddressBook\">false</ManagedGroupRequest>"\
+		"</ABAuthHeader>"\
+	"</soap:Header>"\
+	"<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\
+		"<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<serviceFilter xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+				"<Types xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+					"<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Messenger</ServiceType>"\
+					"<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Invitation</ServiceType>"\
+					"<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">SocialNetwork</ServiceType>"\
+					"<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Space</ServiceType>"\
+					"<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Profile</ServiceType>"\
+				"</Types>"\
+			"</serviceFilter>"\
+			"%s"\
+		"</FindMembership>"\
+	"</soap:Body>"\
+"</soap:Envelope>"
+
+/************************************************
+ * Address Book SOAP
+ * *********************************************/
+
+#define MSN_ADDRESS_BOOK_POST_URL	"/abservice/abservice.asmx"
+
+/* Create AddressBook template */
+#define MSN_ADD_ADDRESSBOOK_SOAP_ACTION     "http://www.msn.com/webservices/AddressBook/ABAdd"
+
+#define MSN_ADD_ADDRESSBOOK_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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\
+	"<soap:Header>"\
+		"<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\
+			"<IsMigration>false</IsMigration>"\
+			"<PartnerScenario>Initial</PartnerScenario>"\
+		"</ABApplicationHeader>"\
+		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+		"</ABAuthHeader>"\
+	"</soap:Header>"\
+	"<soap:Body>"\
+		"<ABAdd xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<abInfo>"\
+				"<name/>"\
+				"<ownerPuid>0</ownerPuid>"\
+				"<ownerEmail>%s</ownerEmail>"\
+				"<fDefault>true</fDefault>"\
+			"</abInfo>"\
+		"</ABAdd>"\
+	"</soap:Body>"\
+"</soap:Envelope>"
+
+/* Get AddressBook */
+#define MSN_GET_ADDRESS_SOAP_ACTION	"http://www.msn.com/webservices/AddressBook/ABFindAll"
+#define MSN_GET_ADDRESS_FULL_TIME	"0001-01-01T00:00:00.0000000-08:00"
+#define MSN_GET_ADDRESS_UPDATE_XML "<deltasOnly>true</deltasOnly>"\
+	"<lastChange>%s</lastChange>"
+
+#define MSN_GET_GLEAM_UPDATE_XML \
+	"%s"\
+	"<dynamicItemView>Gleam</dynamicItemView>"\
+	"<dynamicItemLastChange>%s</dynamicItemLastChange>"
+
+#define MSN_GET_ADDRESS_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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\
+	"<soap:Header>"\
+		"<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\
+			"<IsMigration>false</IsMigration>"\
+			"<PartnerScenario>%s</PartnerScenario>"\
+		"</ABApplicationHeader>"\
+		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+		"</ABAuthHeader>"\
+	"</soap:Header>"\
+	"<soap:Body>"\
+		"<ABFindAll xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<abId>00000000-0000-0000-0000-000000000000</abId>"\
+			"<abView>Full</abView>"\
+			"%s"\
+		"</ABFindAll>"\
+	"</soap:Body>"\
+"</soap:Envelope>"
+
+
+/*Gleams SOAP request template*/
+#define MSN_GET_GLEAMS_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABFindAll"
+#define MSN_GLEAMS_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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\
+	"<soap:Header>"\
+		"<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\
+			"<IsMigration>false</IsMigration>"\
+			"<PartnerScenario>Initial</PartnerScenario>"\
+		"</ABApplicationHeader>"\
+		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+		"</ABAuthHeader>"\
+	"</soap:Header>"\
+	"<soap:Body>"\
+		"<ABFindAll xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<abId>00000000-0000-0000-0000-000000000000</abId>"\
+			"<abView>Full</abView>"\
+			"<dynamicItemView>Gleam</dynamicItemView>"\
+			"<dynamicItemLastChange>0001-01-01T00:00:00.0000000-08:00</dynamicItemLastChange>"\
+		"</ABFindAll>"\
+	"</soap:Body>"\
+"</soap:Envelope>"
+
+
+/*******************************************************
+ * Contact Management SOAP actions
+ *******************************************************/
+
+/* Add a new contact t*/
+#define MSN_CONTACT_ADD_SOAP_ACTION	"http://www.msn.com/webservices/AddressBook/ABContactAdd"
+#define MSN_CONTACT_LIVE_PENDING_XML	"<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\"><contactInfo><contactType>LivePending</contactType><passportName>%s</passportName><isMessengerUser>true</isMessengerUser></contactInfo></Contact>"
+
+#define MSN_CONTACT_XML	"<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+				"<contactInfo>"\
+					"<passportName>%s</passportName>"\
+					"<isSmtp>false</isSmtp>"\
+					"<isMessengerUser>true</isMessengerUser>"\
+				"</contactInfo>"\
+			"</Contact>"
+
+#define MSN_CONTACT_DISPLAYNAME_XML	"<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\"><contactInfo><displayName>%s</displayName><passportName>%s</passportName><isMessengerUser>true</isMessengerUser></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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>ContactSave</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABContactAdd xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><contacts>%s</contacts><options><EnableAllowListManagement>true</EnableAllowListManagement></options></ABContactAdd></soap:Body></soap:Envelope>"
+
+/* Add a contact to a group */
+#define MSN_ADD_CONTACT_GROUP_SOAP_ACTION	"http://www.msn.com/webservices/AddressBook/ABGroupContactAdd"
+#define MSN_ADD_CONTACT_GROUP_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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\
+	"<soap:Header>"\
+		"<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\
+			"<IsMigration>false</IsMigration>"\
+			"<PartnerScenario>ContactSave</PartnerScenario>"\
+		"</ABApplicationHeader>"\
+		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+		"</ABAuthHeader>"\
+	"</soap:Header>"\
+	"<soap:Body>"\
+		"<ABGroupContactAdd xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<abId>00000000-0000-0000-0000-000000000000</abId>"\
+			"<groupFilter>"\
+				"<groupIds>"\
+					"<guid>%s</guid>"\
+				"</groupIds>"\
+			"</groupFilter>"\
+			"<contacts>%s</contacts>"\
+			"<groupContactAddOptions>"\
+				"<fGenerateMissingQuickName>true</fGenerateMissingQuickName>"\
+				"<EnableAllowListManagement>true</EnableAllowListManagement>"\
+			"</groupContactAddOptions>"\
+		"</ABGroupContactAdd>"\
+	"</soap:Body>"\
+"</soap:Envelope>"
+
+/* 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/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>Timer</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABContactDelete xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><contacts>%s</contacts></ABContactDelete></soap:Body></soap:Envelope>"
+
+/* Remove a contact from a group */
+#define MSN_CONTACT_DEL_GROUP_SOAP_ACTION	"http://www.msn.com/webservices/AddressBook/ABGroupContactDelete"
+#define MSN_CONTACT_DEL_GROUP_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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>Timer</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupContactDelete xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><contacts>%s</contacts><groupFilter><groupIds><guid>%s</guid></groupIds></groupFilter></ABGroupContactDelete></soap:Body></soap:Envelope>"
+
+
+/* Update Contact Nickname */
+#define MSN_CONTACT_UPDATE_SOAP_ACTION	"http://www.msn.com/webservices/AddressBook/ABContactUpdate"
+#define MSN_CONTACT_UPDATE_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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\
+	"<soap:Header>"\
+		"<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\
+			"<IsMigration>false</IsMigration>"\
+			"<PartnerScenario>Timer</PartnerScenario>"\
+		"</ABApplicationHeader>"\
+		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+		"</ABAuthHeader>"\
+	"</soap:Header>"\
+	"<soap:Body>"\
+		"<ABContactUpdate xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<abId>00000000-0000-0000-0000-000000000000</abId>"\
+			"<contacts>"\
+				"<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+					"<contactInfo>"\
+						"<contactType>Me</contactType>"\
+						"<displayName>%s</displayName>"\
+					"</contactInfo>"\
+					"<propertiesChanged>DisplayName</propertiesChanged>"\
+				"</Contact>"\
+			"</contacts>"\
+		"</ABContactUpdate>"\
+	"</soap:Body>"\
+"</soap:Envelope>"
+
+
+/*******************************************************
+ * Add/Delete contact from lists SOAP actions
+ *******************************************************/
+
+/* block means delete from allow list and add contact to block list */
+#define MSN_SHARE_POST_URL		"/abservice/SharingService.asmx"
+
+#define MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION	"http://www.msn.com/webservices/AddressBook/AddMember"
+#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\">"\
+					"<Type>Passport</Type>"\
+					"<State>Accepted</State>"\
+					"<PassportName>%s</PassportName>"\
+				"</Member>"
+
+#define MSN_MEMBER_MEMBERSHIPID_XML	"<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"PassportMember\">"\
+						"<Type>Passport</Type>"\
+						"<MembershipId>%u</MembershipId>"\
+						"<State>Accepted</State>"\
+					"</Member>"
+
+/* first delete contact from allow list */
+
+#define MSN_CONTACT_DELECT_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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\
+	"<soap:Header>"\
+		"<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\
+			"<IsMigration>false</IsMigration>"\
+			"<PartnerScenario>%s</PartnerScenario>"\
+		"</ABApplicationHeader>"\
+		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+		"</ABAuthHeader>"\
+	"</soap:Header>"\
+	"<soap:Body>"\
+		"<DeleteMember xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<serviceHandle>"\
+				"<Id>0</Id>"\
+				"<Type>Messenger</Type>"\
+				"<ForeignId></ForeignId>"\
+			"</serviceHandle>"\
+			"<memberships>"\
+				"<Membership>"\
+					"<MemberRole>%s</MemberRole>"\
+					"<Members>"\
+						"%s"\
+					"</Members>"\
+				"</Membership>"\
+			"</memberships>"\
+		"</DeleteMember>"\
+	"</soap:Body>"\
+"</soap:Envelope>"
+
+#define MSN_CONTACT_ADD_TO_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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\
+	"<soap:Header>"\
+		"<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\
+			"<IsMigration>false</IsMigration>"\
+			"<PartnerScenario>%s</PartnerScenario>"\
+		"</ABApplicationHeader>"\
+		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+		"</ABAuthHeader>"\
+	"</soap:Header>"\
+	"<soap:Body>"\
+		"<AddMember xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
+			"<serviceHandle>"\
+				"<Id>0</Id>"\
+				"<Type>Messenger</Type>"\
+				"<ForeignId></ForeignId>"\
+			"</serviceHandle>"\
+			"<memberships>"\
+				"<Membership>"\
+					"<MemberRole>%s</MemberRole>"\
+					"<Members>"\
+						"%s"\
+					"</Members>"\
+				"</Membership>"\
+			"</memberships>"\
+		"</AddMember>"\
+	"</soap:Body>"\
+"</soap:Envelope>"
+
+
+
+/*******************************************************
+ * Group management SOAP actions
+ *******************************************************/
+
+/* add a group */
+#define MSN_GROUP_ADD_SOAP_ACTION	"http://www.msn.com/webservices/AddressBook/ABGroupAdd"
+#define MSN_GROUP_ADD_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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>GroupSave</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupAdd xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groupAddOptions><fRenameOnMsgrConflict>false</fRenameOnMsgrConflict></groupAddOptions><groupInfo><GroupInfo><name>%s</name><groupType>C8529CE2-6EAD-434d-881F-341E17DB3FF8</groupType><fMessenger>false</fMessenger><annotations><Annotation><Name>MSN.IM.Display</Name><Value>1</Value></Annotation></annotations></GroupInfo></groupInfo></ABGroupAdd></soap:Body></soap:Envelope>"
+
+/* delete a group */
+#define MSN_GROUP_DEL_SOAP_ACTION	"http://www.msn.com/webservices/AddressBook/ABGroupDelete"
+#define MSN_GROUP_DEL_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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>Timer</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupDelete xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groupFilter><groupIds><guid>%s</guid></groupIds></groupFilter></ABGroupDelete></soap:Body></soap:Envelope>"
+
+/* change a group's name */
+#define MSN_GROUP_RENAME_SOAP_ACTION	"http://www.msn.com/webservices/AddressBook/ABGroupUpdate"
+#define MSN_GROUP_RENAME_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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>Timer</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupUpdate xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groups><Group><groupId>%s</groupId><groupInfo><name>%s</name></groupInfo><propertiesChanged>GroupName </propertiesChanged></Group></groups></ABGroupUpdate></soap:Body></soap:Envelope>"
+
+typedef enum 
+{
+	MSN_ADD_BUDDY			= 0x01,
+	MSN_MOVE_BUDDY			= 0x02,
+	MSN_ACCEPTED_BUDDY		= 0x04,
+	MSN_DENIED_BUDDY		= 0x08,
+	MSN_ADD_GROUP			= 0x10,
+	MSN_DEL_GROUP			= 0x20,
+	MSN_RENAME_GROUP		= 0x40,
+} MsnCallbackAction;
+
+typedef struct _MsnContact MsnContact;
+
+struct _MsnContact
+{
+	MsnSession *session;
+
+	MsnSoapConn *soapconn;
+};
+
+typedef struct _MsnCallbackState MsnCallbackState;
+
+struct _MsnCallbackState
+{
+	gchar * who;
+	gchar * uid;
+	gchar * old_group_name;
+	gchar * new_group_name;
+	gchar * guid;
+	MsnListId list_id;
+	MsnCallbackAction action;
+};
+
+typedef enum 
+{
+	MSN_PS_INITIAL,
+	MSN_PS_SAVE_CONTACT,
+	MSN_PS_PENDING_LIST,
+	MSN_PS_CONTACT_API,
+	MSN_PS_BLOCK_UNBLOCK
+} MsnSoapPartnerScenario;
+
+/************************************************
+ * function prototype
+ ************************************************/
+MsnContact * msn_contact_new(MsnSession *session);
+void msn_contact_destroy(MsnContact *contact);
+
+MsnCallbackState * msn_callback_state_new(void);
+void msn_callback_state_free(MsnCallbackState *state);
+void msn_callback_state_set_who(MsnCallbackState *state, const gchar *who);
+void msn_callback_state_set_uid(MsnCallbackState *state, const gchar *uid);
+void msn_callback_state_set_old_group_name(MsnCallbackState *state,
+					   const gchar *old_group_name);
+void msn_callback_state_set_new_group_name(MsnCallbackState *state, 
+					   const gchar *new_group_name);
+void msn_callback_state_set_guid(MsnCallbackState *state, const gchar *guid);
+void msn_callback_state_set_list_id(MsnCallbackState *state, MsnListId list_id);
+void msn_callback_state_set_action(MsnCallbackState *state, 
+				   MsnCallbackAction action);
+
+void msn_contact_connect(MsnContact *contact);
+void msn_get_contact_list(MsnContact * contact, 
+			  const MsnSoapPartnerScenario partner_scenario,
+			  const char *update);
+void msn_get_address_book(MsnContact *contact, 
+			  const MsnSoapPartnerScenario partner_scenario,
+			  const char * update, const char * gupdate);
+
+/* contact SOAP operations */
+void msn_update_contact(MsnContact *contact, const char* nickname);
+
+void msn_add_contact(MsnContact *contact, MsnCallbackState *state, 
+		     const char *passport);
+void msn_delete_contact(MsnContact *contact, const char *contactId);
+
+void msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state, 
+			      const char *passport, const char *groupId);
+void msn_del_contact_from_group(MsnContact *contact, const char *passport, 
+				const char *group_name);
+/* group operations */
+void msn_add_group(MsnSession *session, MsnCallbackState *state, 
+					const char* group_name);
+void msn_del_group(MsnSession *session, const gchar *group_name);
+void msn_contact_rename_group(MsnSession *session, const char *old_group_name,
+						   const char *new_group_name);
+
+/* lists operations */
+void msn_add_contact_to_list(MsnContact *contact, MsnCallbackState *state,
+			     const gchar *passport, const MsnListId list);
+void msn_del_contact_from_list(MsnContact *contact, MsnCallbackState *state,
+			       const gchar *passport, const MsnListId list);
+
+void msn_contact_connect_init(MsnSoapConn *soapconn);
+
+#endif /* _MSN_CONTACT_H_ */
+
--- a/libpurple/protocols/msn/dialog.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/dialog.c	Fri Sep 28 16:34:43 2007 +0000
@@ -36,6 +36,7 @@
 
 /* Remove the buddy referenced by the MsnAddRemData before the serverside list is changed.
  * If the buddy will be added, he'll be added back; if he will be removed, he won't be. */
+/* Actually with our MSNP14 code that isn't true yet, he won't be added back :( */
 static void
 msn_complete_sync_issue(MsnAddRemData *data)
 {
@@ -44,28 +45,32 @@
 
 	if (data->group != NULL)
 		group = purple_find_group(data->group);
-	
+
 	if (group != NULL)
 		buddy = purple_find_buddy_in_group(purple_connection_get_account(data->gc), data->who, group);
 	else
 		buddy = purple_find_buddy(purple_connection_get_account(data->gc), data->who);
-	
+
 	if (buddy != NULL)
 		purple_blist_remove_buddy(buddy);
 }
 
+
 static void
 msn_add_cb(MsnAddRemData *data)
 {
-	MsnSession *session;
-	MsnUserList *userlist;
-
+#if 0
+	/* this *should* be necessary !! */
 	msn_complete_sync_issue(data);
+#endif
 
-	session = data->gc->proto_data;
-	userlist = session->userlist;
+	if (g_list_find(purple_connections_get_all(), data->gc) != NULL)
+	{
+		MsnSession *session = data->gc->proto_data;
+		MsnUserList *userlist = session->userlist;
 
-	msn_userlist_add_buddy(userlist, data->who, MSN_LIST_FL, data->group);
+		msn_userlist_add_buddy(userlist, data->who, data->group);
+	}
 
 	g_free(data->group);
 	g_free(data->who);
@@ -75,17 +80,20 @@
 static void
 msn_rem_cb(MsnAddRemData *data)
 {
-	MsnSession *session;
-	MsnUserList *userlist;
-
 	msn_complete_sync_issue(data);
 
-	session = data->gc->proto_data;
-	userlist = session->userlist;
+	if (g_list_find(purple_connections_get_all(), data->gc) != NULL)
+	{
+		MsnSession *session = data->gc->proto_data;
+		MsnUserList *userlist = session->userlist;
 
-	msn_userlist_rem_buddy(userlist, data->who, MSN_LIST_FL, data->group);
+		if (data->group == NULL) {
+			msn_userlist_rem_buddy_from_list(userlist, data->who, MSN_LIST_FL);
+		} else {
+			g_free(data->group);
+		}
+	}
 
-	g_free(data->group);
 	g_free(data->who);
 	g_free(data);
 }
@@ -104,7 +112,7 @@
 
 	data        = g_new0(MsnAddRemData, 1);
 	data->who   = g_strdup(passport);
-	data->group = g_strdup(group_name);
+	data->group = group_name != NULL ? g_strdup(group_name) : NULL;
 	data->gc    = gc;
 
 	msg = g_strdup_printf(_("Buddy list synchronization issue in %s (%s)"),
--- a/libpurple/protocols/msn/directconn.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/directconn.c	Fri Sep 28 16:34:43 2007 +0000
@@ -76,7 +76,6 @@
  * Connection Functions
  **************************************************************************/
 
-#if 0
 static int
 create_listener(int port)
 {
@@ -160,7 +159,6 @@
 
 	return fd;
 }
-#endif
 
 static size_t
 msn_directconn_write(MsnDirectConn *directconn,
@@ -288,6 +286,11 @@
 		/* ERROR */
 		purple_debug_error("msn", "error reading\n");
 
+		if (directconn->inpa)
+			purple_input_remove(directconn->inpa);
+
+		close(directconn->fd);
+
 		msn_directconn_destroy(directconn);
 
 		return;
@@ -302,6 +305,11 @@
 		/* ERROR */
 		purple_debug_error("msn", "error reading\n");
 
+		if (directconn->inpa)
+			purple_input_remove(directconn->inpa);
+
+		close(directconn->fd);
+
 		msn_directconn_destroy(directconn);
 
 		return;
@@ -348,17 +356,22 @@
 		/* ERROR */
 		purple_debug_error("msn", "error reading\n");
 
+		if (directconn->inpa)
+			purple_input_remove(directconn->inpa);
+
+		close(directconn->fd);
+
 		msn_directconn_destroy(directconn);
 	}
 }
 
 static void
-connect_cb(gpointer data, gint source, const gchar *error_message)
+connect_cb(gpointer data, gint source, PurpleInputCondition cond)
 {
 	MsnDirectConn* directconn;
 	int fd;
 
-	purple_debug_misc("msn", "directconn: connect_cb: %d\n", source);
+	purple_debug_misc("msn", "directconn: connect_cb: %d, %d.\n", source, cond);
 
 	directconn = data;
 	directconn->connect_data = NULL;
@@ -438,7 +451,6 @@
 	return (directconn->connect_data != NULL);
 }
 
-#if 0
 void
 msn_directconn_listen(MsnDirectConn *directconn)
 {
@@ -458,7 +470,6 @@
 	directconn->port = port;
 	directconn->c = 0;
 }
-#endif
 
 MsnDirectConn*
 msn_directconn_new(MsnSlpLink *slplink)
--- a/libpurple/protocols/msn/directconn.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/directconn.h	Fri Sep 28 16:34:43 2007 +0000
@@ -52,9 +52,7 @@
 MsnDirectConn *msn_directconn_new(MsnSlpLink *slplink);
 gboolean msn_directconn_connect(MsnDirectConn *directconn,
 								const char *host, int port);
-#if 0
 void msn_directconn_listen(MsnDirectConn *directconn);
-#endif
 void msn_directconn_send_msg(MsnDirectConn *directconn, MsnMessage *msg);
 void msn_directconn_parse_nonce(MsnDirectConn *directconn, const char *nonce);
 void msn_directconn_destroy(MsnDirectConn *directconn);
--- a/libpurple/protocols/msn/group.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/group.c	Fri Sep 28 16:34:43 2007 +0000
@@ -25,18 +25,18 @@
 #include "group.h"
 
 MsnGroup *
-msn_group_new(MsnUserList *userlist, int id, const char *name)
+msn_group_new(MsnUserList *userlist, const char *id, const char *name)
 {
 	MsnGroup *group;
 
-	g_return_val_if_fail(id >= 0,      NULL);
+	g_return_val_if_fail(id != NULL,      NULL);
 	g_return_val_if_fail(name != NULL, NULL);
 
 	group = g_new0(MsnGroup, 1);
 
 	msn_userlist_add_group(userlist, group);
 
-	group->id      = id;
+	group->id      = g_strdup(id);
 	group->name    = g_strdup(name);
 
 	return group;
@@ -47,17 +47,18 @@
 {
 	g_return_if_fail(group != NULL);
 
+	g_free(group->id);
 	g_free(group->name);
 	g_free(group);
 }
 
 void
-msn_group_set_id(MsnGroup *group, int id)
+msn_group_set_id(MsnGroup *group, const char *id)
 {
 	g_return_if_fail(group != NULL);
-	g_return_if_fail(id >= 0);
+	g_return_if_fail(id != NULL);
 
-	group->id = id;
+	group->id = g_strdup(id);
 }
 
 void
@@ -72,10 +73,10 @@
 	group->name = g_strdup(name);
 }
 
-int
+char*
 msn_group_get_id(const MsnGroup *group)
 {
-	g_return_val_if_fail(group != NULL, -1);
+	g_return_val_if_fail(group != NULL, NULL);
 
 	return group->id;
 }
--- a/libpurple/protocols/msn/group.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/group.h	Fri Sep 28 16:34:43 2007 +0000
@@ -30,8 +30,21 @@
 
 #include "session.h"
 #include "user.h"
+#include "soap.h"
+#include "userlist.h"
 
-#include "userlist.h"
+#define MSN_ADD_GROUPS	"<GroupInfo><name>test111</name><groupType>C8529CE2-6EAD-434d-881F-341E17DB3FF8</groupType><fMessenger>false</fMessenger><annotations><Annotation><Name>MSN.IM.Display</Name><Value>1</Value></Annotation></annotations></GroupInfo>"
+
+#define MSN_ADD_GROUP_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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>GroupSave</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupAdd xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groupAddOptions><fRenameOnMsgrConflict>false</fRenameOnMsgrConflict></groupAddOptions><groupInfo>%s</groupInfo></ABGroupAdd></soap:Body></soap:Envelope>"
+
+#define MSN_GROUP_IDS	"<guid>9e57e654-59f0-44d1-aedc-0a7500b7e51f</guid>"
+#define MSN_DELETE_GROUP_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\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>Timer</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupDelete xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groupFilter><groupIds>%s</groupIds></groupFilter></ABGroupDelete></soap:Body></soap:Envelope>"
+
+#define MSN_INDIVIDUALS_GROUP_ID	"1983"
+#define MSN_INDIVIDUALS_GROUP_NAME	"Other Contacts"
+
+#define MSN_NON_IM_GROUP_ID		"email"
+#define MSN_NON_IM_GROUP_NAME	"Non-IM Contacts"
 
 /**
  * A group.
@@ -39,8 +52,9 @@
 struct _MsnGroup
 {
 	MsnSession *session;    /**< The MSN session.           */
+	MsnSoapConn *soapconn;
 
-	int id;                 /**< The group ID.              */
+	char *id;                 /**< The group ID.              */
 	char *name;             /**< The name of the group.     */
 };
 
@@ -58,7 +72,7 @@
  *
  * @return A new group structure.
  */
-MsnGroup *msn_group_new(MsnUserList *userlist, int id, const char *name);
+MsnGroup *msn_group_new(MsnUserList *userlist, const char *id, const char *name);
 
 /**
  * Destroys a group structure.
@@ -73,7 +87,7 @@
  * @param group The group.
  * @param id    The ID.
  */
-void msn_group_set_id(MsnGroup *group, int id);
+void msn_group_set_id(MsnGroup *group, const char *id);
 
 /**
  * Sets the name for a group.
@@ -90,7 +104,7 @@
  *
  * @return The ID.
  */
-int msn_group_get_id(const MsnGroup *group);
+char* msn_group_get_id(const MsnGroup *group);
 
 /**
  * Returns the name for a group.
--- a/libpurple/protocols/msn/history.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/history.c	Fri Sep 28 16:34:43 2007 +0000
@@ -84,3 +84,4 @@
 		msn_transaction_destroy(trans);
 	}
 }
+
--- a/libpurple/protocols/msn/msg.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/msg.c	Fri Sep 28 16:34:43 2007 +0000
@@ -126,7 +126,7 @@
 	msn_message_set_charset(msg, "UTF-8");
 	msn_message_set_flag(msg, 'A');
 	msn_message_set_attr(msg, "X-MMS-IM-Format",
-						 "FN=MS%20Sans%20Serif; EF=; CO=0; PF=0");
+						 "FN=MS%20Sans%20Serif; EF=; CO=0; CS=86;PF=0");
 
 	message_cr = purple_str_add_cr(message);
 	msn_message_set_bin_data(msg, message_cr, strlen(message_cr));
@@ -206,7 +206,8 @@
 
 void
 msn_message_parse_payload(MsnMessage *msg,
-						  const char *payload, size_t payload_len)
+						  const char *payload, size_t payload_len,
+						  const char *line_dem,const char *body_dem)
 {
 	char *tmp_base, *tmp;
 	const char *content_type;
@@ -214,12 +215,11 @@
 	char **elems, **cur, **tokens;
 
 	g_return_if_fail(payload != NULL);
-
 	tmp_base = tmp = g_malloc0(payload_len + 1);
 	memcpy(tmp_base, payload, payload_len);
 
 	/* Parse the attributes. */
-	end = strstr(tmp, "\r\n\r\n");
+	end = strstr(tmp, body_dem);
 	/* TODO? some clients use \r delimiters instead of \r\n, the official client
 	 * doesn't send such messages, but does handle receiving them. We'll just
 	 * avoid crashing for now */
@@ -229,7 +229,7 @@
 	}
 	*end = '\0';
 
-	elems = g_strsplit(tmp, "\r\n", 0);
+	elems = g_strsplit(tmp, line_dem, 0);
 
 	for (cur = elems; *cur != NULL; cur++)
 	{
@@ -240,6 +240,7 @@
 		key = tokens[0];
 		value = tokens[1];
 
+		/*if not MIME content ,then return*/
 		if (!strcmp(key, "MIME-Version"))
 		{
 			g_strfreev(tokens);
@@ -274,7 +275,7 @@
 	g_strfreev(elems);
 
 	/* Proceed to the end of the "\r\n\r\n" */
-	tmp = end + 4;
+	tmp = end + strlen(body_dem);
 
 	/* Now we *should* be at the body. */
 	content_type = msn_message_get_content_type(msg);
@@ -480,6 +481,7 @@
 		{
 			memcpy(n, body, body_len);
 			n += body_len;
+			*n = '\0';
 		}
 	}
 
--- a/libpurple/protocols/msn/msg.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/msg.h	Fri Sep 28 16:34:43 2007 +0000
@@ -34,6 +34,12 @@
 
 typedef void (*MsnMsgCb)(MsnMessage *, void *data);
 
+#define MSG_BODY_DEM	"\r\n\r\n"
+#define MSG_LINE_DEM	"\r\n"
+
+#define MSG_OIM_BODY_DEM	"\n\n"
+#define MSG_OIM_LINE_DEM	"\n"
+
 /*
 typedef enum
 {
@@ -180,7 +186,8 @@
  * @param payload_len The length of the payload.
  */
 void msn_message_parse_payload(MsnMessage *msg, const char *payload,
-							   size_t payload_len);
+							   size_t payload_len,
+						  const char *line_dem,const char *body_dem);
 
 /**
  * Destroys a message.
--- a/libpurple/protocols/msn/msn-utils.c	Fri Sep 28 16:32:28 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,440 +0,0 @@
-/**
- * @file msn-utils.c Utility functions
- *
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * 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  02111-1301  USA
- */
-#include "msn.h"
-#include "msn-utils.h"
-
-void
-msn_parse_format(const char *mime, char **pre_ret, char **post_ret)
-{
-	char *cur;
-	GString *pre  = g_string_new(NULL);
-	GString *post = g_string_new(NULL);
-	unsigned int colors[3];
-
-	if (pre_ret  != NULL) *pre_ret  = NULL;
-	if (post_ret != NULL) *post_ret = NULL;
-
-	cur = strstr(mime, "FN=");
-
-	if (cur && (*(cur = cur + 3) != ';'))
-	{
-		pre = g_string_append(pre, "<FONT FACE=\"");
-
-		while (*cur && *cur != ';')
-		{
-			pre = g_string_append_c(pre, *cur);
-			cur++;
-		}
-
-		pre = g_string_append(pre, "\">");
-		post = g_string_prepend(post, "</FONT>");
-	}
-
-	cur = strstr(mime, "EF=");
-
-	if (cur && (*(cur = cur + 3) != ';'))
-	{
-		while (*cur && *cur != ';')
-		{
-			pre = g_string_append_c(pre, '<');
-			pre = g_string_append_c(pre, *cur);
-			pre = g_string_append_c(pre, '>');
-			post = g_string_prepend_c(post, '>');
-			post = g_string_prepend_c(post, *cur);
-			post = g_string_prepend_c(post, '/');
-			post = g_string_prepend_c(post, '<');
-			cur++;
-		}
-	}
-
-	cur = strstr(mime, "CO=");
-
-	if (cur && (*(cur = cur + 3) != ';'))
-	{
-		int i;
-
-		i = sscanf(cur, "%02x%02x%02x;", &colors[0], &colors[1], &colors[2]);
-
-		if (i > 0)
-		{
-			char tag[64];
-
-			if (i == 1)
-			{
-				colors[1] = 0;
-				colors[2] = 0;
-			}
-			else if (i == 2)
-			{
-				unsigned int temp = colors[0];
-
-				colors[0] = colors[1];
-				colors[1] = temp;
-				colors[2] = 0;
-			}
-			else if (i == 3)
-			{
-				unsigned int temp = colors[2];
-
-				colors[2] = colors[0];
-				colors[0] = temp;
-			}
-
-			g_snprintf(tag, sizeof(tag),
-					   "<FONT COLOR=\"#%02hhx%02hhx%02hhx\">",
-					   colors[0], colors[1], colors[2]);
-
-			pre = g_string_append(pre, tag);
-			post = g_string_prepend(post, "</FONT>");
-		}
-	}
-
-	cur = strstr(mime, "RL=");
-
-	if (cur && (*(cur = cur + 3) != ';'))
-	{
-		if (*cur == '1')
-		{
-			/* RTL text was received */
-			pre = g_string_append(pre, "<SPAN style=\"direction:rtl;text-align:right;\">");
-			post = g_string_prepend(post, "</SPAN>");
-		}
-	}
-
-	cur = g_strdup(purple_url_decode(pre->str));
-	g_string_free(pre, TRUE);
-
-	if (pre_ret != NULL)
-		*pre_ret = cur;
-	else
-		g_free(cur);
-
-	cur = g_strdup(purple_url_decode(post->str));
-	g_string_free(post, TRUE);
-
-	if (post_ret != NULL)
-		*post_ret = cur;
-	else
-		g_free(cur);
-}
-
-/*
- * We need this because we're only supposed to encode spaces in the font
- * names. purple_url_encode() isn't acceptable.
- */
-static const char *
-encode_spaces(const char *str)
-{
-	static char buf[BUF_LEN];
-	const char *c;
-	char *d;
-
-	g_return_val_if_fail(str != NULL, NULL);
-
-	for (c = str, d = buf; *c != '\0'; c++)
-	{
-		if (*c == ' ')
-		{
-			*d++ = '%';
-			*d++ = '2';
-			*d++ = '0';
-		}
-		else
-			*d++ = *c;
-	}
-
-	return buf;
-}
-
-/*
- * Taken from the zephyr plugin.
- * This parses HTML formatting (put out by one of the gtkimhtml widgets
- * and converts it to msn formatting. It doesn't deal with the tag closing,
- * but gtkimhtml widgets give valid html.
- * It currently deals properly with <b>, <u>, <i>, <font face=...>,
- * <font color=...>, <span dir=...>, <span style="direction: ...">.
- * It ignores <font back=...> and <font size=...>
- */
-void
-msn_import_html(const char *html, char **attributes, char **message)
-{
-	int len, retcount = 0;
-	const char *c;
-	char *msg;
-	char *fontface = NULL;
-	char fonteffect[4];
-	char fontcolor[7];
-	char direction = '0';
-
-	gboolean has_bold = FALSE;
-	gboolean has_italic = FALSE;
-	gboolean has_underline = FALSE;
-	gboolean has_strikethrough = FALSE;
-
-	g_return_if_fail(html       != NULL);
-	g_return_if_fail(attributes != NULL);
-	g_return_if_fail(message    != NULL);
-
-	len = strlen(html);
-	msg = g_malloc0(len + 1);
-
-	memset(fontcolor, 0, sizeof(fontcolor));
-	strcat(fontcolor, "0");
-	memset(fonteffect, 0, sizeof(fonteffect));
-
-	for (c = html; *c != '\0';)
-	{
-		if (*c == '<')
-		{
-			if (!g_ascii_strncasecmp(c + 1, "br>", 3))
-			{
-				msg[retcount++] = '\r';
-				msg[retcount++] = '\n';
-				c += 4;
-			}
-			else if (!g_ascii_strncasecmp(c + 1, "i>", 2))
-			{
-				if (!has_italic)
-				{
-					strcat(fonteffect, "I");
-					has_italic = TRUE;
-				}
-				c += 3;
-			}
-			else if (!g_ascii_strncasecmp(c + 1, "b>", 2))
-			{
-				if (!has_bold)
-				{
-					strcat(fonteffect, "B");
-					has_bold = TRUE;
-				}
-				c += 3;
-			}
-			else if (!g_ascii_strncasecmp(c + 1, "u>", 2))
-			{
-				if (!has_underline)
-				{
-					strcat(fonteffect, "U");
-					has_underline = TRUE;
-				}
-				c += 3;
-			}
-			else if (!g_ascii_strncasecmp(c + 1, "s>", 2))
-			{
-				if (!has_strikethrough)
-				{
-					strcat(fonteffect, "S");
-					has_strikethrough = TRUE;
-				}
-				c += 3;
-			}
-			else if (!g_ascii_strncasecmp(c + 1, "a href=\"", 8))
-			{
-				c += 9;
-
-				if (!g_ascii_strncasecmp(c, "mailto:", 7))
-					c += 7;
-
-				while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2))
-					msg[retcount++] = *c++;
-
-				if (*c != '\0')
-					c += 2;
-
-				/* ignore descriptive string */
-				while ((*c != '\0') && g_ascii_strncasecmp(c, "</a>", 4))
-					c++;
-
-				if (*c != '\0')
-					c += 4;
-			}
-			else if (!g_ascii_strncasecmp(c + 1, "span", 4))
-			{
-				/* Bi-directional text support using CSS properties in span tags */
-				c += 5;
-
-				while (*c != '\0' && *c != '>')
-				{
-					while (*c == ' ')
-						c++;
-					if (!g_ascii_strncasecmp(c, "dir=\"rtl\"", 9))
-					{
-						c += 9;
-						direction = '1';
-					}
-					else if (!g_ascii_strncasecmp(c, "style=\"", 7))
-					{
-						/* Parse inline CSS attributes */
-						char *attributes;
-						int attr_len = 0;
-						c += 7;
-						while (*(c + attr_len) != '\0' && *(c + attr_len) != '"')
-							attr_len++;
-						if (*(c + attr_len) == '"')
-						{
-							char *attr_dir;
-							attributes = g_strndup(c, attr_len);
-							attr_dir = purple_markup_get_css_property(attributes, "direction");
-							if (attr_dir && (!g_ascii_strncasecmp(attr_dir, "RTL", 3)))
-								direction = '1';
-							g_free(attr_dir);
-							g_free(attributes);
-						}
-
-					}
-					else
-					{
-						c++;
-					}
-				}
-				if (*c == '>')
-					c++;
-			}
-			else if (!g_ascii_strncasecmp(c + 1, "font", 4))
-			{
-				c += 5;
-
-				while ((*c != '\0') && !g_ascii_strncasecmp(c, " ", 1))
-					c++;
-
-				if (!g_ascii_strncasecmp(c, "color=\"#", 7))
-				{
-					c += 8;
-
-					fontcolor[0] = *(c + 4);
-					fontcolor[1] = *(c + 5);
-					fontcolor[2] = *(c + 2);
-					fontcolor[3] = *(c + 3);
-					fontcolor[4] = *c;
-					fontcolor[5] = *(c + 1);
-
-					c += 8;
-				}
-				else if (!g_ascii_strncasecmp(c, "face=\"", 6))
-				{
-					const char *end = NULL;
-					const char *comma = NULL;
-					unsigned int namelen = 0;
-
-					c += 6;
-					end = strchr(c, '\"');
-					comma = strchr(c, ',');
-
-					if (comma == NULL || comma > end)
-						namelen = (unsigned int)(end - c);
-					else
-						namelen = (unsigned int)(comma - c);
-
-					fontface = g_strndup(c, namelen);
-					c = end + 2;
-				}
-				else
-				{
-					/* Drop all unrecognized/misparsed font tags */
-					while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2))
-						c++;
-
-					if (*c != '\0')
-						c += 2;
-				}
-			}
-			else
-			{
-				while ((*c != '\0') && (*c != '>'))
-					c++;
-				if (*c != '\0')
-					c++;
-			}
-		}
-		else if (*c == '&')
-		{
-			if (!g_ascii_strncasecmp(c, "&lt;", 4))
-			{
-				msg[retcount++] = '<';
-				c += 4;
-			}
-			else if (!g_ascii_strncasecmp(c, "&gt;", 4))
-			{
-				msg[retcount++] = '>';
-				c += 4;
-			}
-			else if (!g_ascii_strncasecmp(c, "&nbsp;", 6))
-			{
-				msg[retcount++] = ' ';
-				c += 6;
-			}
-			else if (!g_ascii_strncasecmp(c, "&quot;", 6))
-			{
-				msg[retcount++] = '"';
-				c += 6;
-			}
-			else if (!g_ascii_strncasecmp(c, "&amp;", 5))
-			{
-				msg[retcount++] = '&';
-				c += 5;
-			}
-			else if (!g_ascii_strncasecmp(c, "&apos;", 6))
-			{
-				msg[retcount++] = '\'';
-				c += 6;
-			}
-			else
-				msg[retcount++] = *c++;
-		}
-		else
-			msg[retcount++] = *c++;
-	}
-
-	if (fontface == NULL)
-		fontface = g_strdup("MS Sans Serif");
-
-	*attributes = g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c",
-								  encode_spaces(fontface),
-								  fonteffect, fontcolor, direction);
-	*message = g_strdup(msg);
-
-	g_free(fontface);
-	g_free(msg);
-}
-
-void
-msn_parse_socket(const char *str, char **ret_host, int *ret_port)
-{
-	char *host;
-	char *c;
-	int port;
-
-	host = g_strdup(str);
-
-	if ((c = strchr(host, ':')) != NULL)
-	{
-		*c = '\0';
-		port = atoi(c + 1);
-	}
-	else
-		port = 1863;
-
-	*ret_host = host;
-	*ret_port = port;
-}
--- a/libpurple/protocols/msn/msn-utils.h	Fri Sep 28 16:32:28 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/**
- * @file msn-utils.h Utility functions
- *
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * 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  02111-1301  USA
- */
-#ifndef _MSN_UTILS_H_
-#define _MSN_UTILS_H_
-
-/**
- * Parses the MSN message formatting into a format compatible with Purple.
- *
- * @param mime     The mime header with the formatting.
- * @param pre_ret  The returned prefix string.
- * @param post_ret The returned postfix string.
- *
- * @return The new message.
- */
-void msn_parse_format(const char *mime, char **pre_ret, char **post_ret);
-
-/**
- * Parses the Purple message formatting (html) into the MSN format.
- *
- * @param html			The html message to format.
- * @param attributes	The returned attributes string.
- * @param message		The returned message string.
- *
- * @return The new message.
- */
-void msn_import_html(const char *html, char **attributes, char **message);
-
-void msn_parse_socket(const char *str, char **ret_host, int *ret_port);
-
-#endif /* _MSN_UTILS_H_ */
--- a/libpurple/protocols/msn/msn.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/msn.c	Fri Sep 28 16:34:43 2007 +0000
@@ -37,7 +37,7 @@
 #include "cmds.h"
 #include "core.h"
 #include "prpl.h"
-#include "msn-utils.h"
+#include "msnutils.h"
 #include "version.h"
 
 #include "switchboard.h"
@@ -151,7 +151,7 @@
 	return PURPLE_CMD_RET_OK;
 }
 
-static void
+void
 msn_act_id(PurpleConnection *gc, const char *entry)
 {
 	MsnCmdProc *cmdproc;
@@ -175,9 +175,12 @@
 		return;
 	}
 
-	msn_cmdproc_send(cmdproc, "REA", "%s %s",
-					 purple_account_get_username(account),
-					 alias);
+	if (*alias == '\0') {
+		alias = purple_url_encode(purple_account_get_username(account));
+	}
+
+	msn_cmdproc_send(cmdproc, "PRP", "MFN %s", alias);
+
 }
 
 static void
@@ -414,6 +417,28 @@
 	return user && user->mobile;
 }
 
+void
+msn_send_privacy(PurpleConnection *gc)
+{
+       PurpleAccount *account;
+        MsnSession *session;
+        MsnCmdProc *cmdproc;
+
+        account = purple_connection_get_account(gc);
+        session = gc->proto_data;
+        cmdproc = session->notification->cmdproc;
+
+        if (account->perm_deny == PURPLE_PRIVACY_ALLOW_ALL ||
+                account->perm_deny == PURPLE_PRIVACY_DENY_USERS)
+        {
+                msn_cmdproc_send(cmdproc, "BLP", "%s", "AL");
+        }
+        else
+        {
+                msn_cmdproc_send(cmdproc, "BLP", "%s", "BL");
+        }
+}
+
 static void
 initiate_chat_cb(PurpleBlistNode *node, gpointer data)
 {
@@ -460,6 +485,7 @@
 	session = gc->proto_data;
 
 	xfer = purple_xfer_new(gc->account, PURPLE_XFER_SEND, who);
+
 	if (xfer)
 	{
 		slplink = msn_session_get_slplink(session, who);
@@ -511,20 +537,27 @@
 	return "msn";
 }
 
+/*
+ * Set the User status text
+ * Add the PSM String Using "Name - PSM String" format
+ */
 static char *
 msn_status_text(PurpleBuddy *buddy)
 {
 	PurplePresence *presence;
 	PurpleStatus *status;
+	const char *msg, *cmedia;
 
 	presence = purple_buddy_get_presence(buddy);
 	status = purple_presence_get_active_status(presence);
 
-	if (!purple_presence_is_available(presence) && !purple_presence_is_idle(presence))
-	{
-		return g_strdup(purple_status_get_name(status));
-	}
+	msg = purple_status_get_attr_string(status, "message");
+	cmedia = purple_status_get_attr_string(status, "currentmedia");
 
+	if (cmedia)
+		return g_markup_escape_text(cmedia, -1);
+	else if (msg)
+		return g_markup_escape_text(msg, -1);
 	return NULL;
 }
 
@@ -540,14 +573,43 @@
 
 	if (purple_presence_is_online(presence))
 	{
-		purple_notify_user_info_add_pair(user_info, _("Status"),
-									   (purple_presence_is_idle(presence) ? _("Idle") : purple_status_get_name(status)));
-	}
+		const char *psm, *currentmedia, *name;
+		char *tmp;
+
+		psm = purple_status_get_attr_string(status, "message");
+		currentmedia = purple_status_get_attr_string(status, "currentmedia");
+
+		if (!purple_presence_is_available(presence)) {
+			name = purple_status_get_name(status);
+		} else {
+			name = NULL;
+		}
+
+		if (name != NULL && *name) {
+			char *tmp2 = g_markup_escape_text(name, -1);
 
-	if (full && user)
-	{
-		purple_notify_user_info_add_pair(user_info, _("Has you"),
-									   ((user->list_op & (1 << MSN_LIST_RL)) ? _("Yes") : _("No")));
+			if (psm != NULL && *psm) {
+				tmp = g_markup_escape_text(psm, -1);
+				purple_notify_user_info_add_pair(user_info, tmp2, tmp);
+				g_free(tmp);
+			} else {
+				purple_notify_user_info_add_pair(user_info, _("Status"), tmp2);
+			}
+
+			g_free(tmp2);
+		} else {
+			if (psm != NULL && *psm) {
+				tmp = g_markup_escape_text(psm, -1);
+				purple_notify_user_info_add_pair(user_info, _("Status"), tmp);
+				g_free(tmp);
+			}
+		}
+
+		if (currentmedia) {
+			tmp = g_markup_escape_text(currentmedia, -1);
+			purple_notify_user_info_add_pair(user_info, _("Current media"), tmp);
+			g_free(tmp);
+		}
 	}
 
 	/* XXX: This is being shown in non-full tooltips because the
@@ -567,28 +629,44 @@
 	PurpleStatusType *status;
 	GList *types = NULL;
 
-	status = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE,
-			NULL, NULL, FALSE, TRUE, FALSE);
+	status = purple_status_type_new_with_attrs(
+				PURPLE_STATUS_AVAILABLE, NULL, NULL, TRUE, TRUE, FALSE,
+				"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
+				"currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING),
+				NULL);
 	types = g_list_append(types, status);
 
-	status = purple_status_type_new_full(PURPLE_STATUS_AWAY,
-			NULL, NULL, FALSE, TRUE, FALSE);
+	status = purple_status_type_new_with_attrs(
+			PURPLE_STATUS_AWAY, NULL, NULL, TRUE, TRUE, FALSE,
+			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
+			"currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING),
+			NULL);
 	types = g_list_append(types, status);
 
-	status = purple_status_type_new_full(PURPLE_STATUS_AWAY,
-			"brb", _("Be Right Back"), FALSE, TRUE, FALSE);
+	status = purple_status_type_new_with_attrs(
+			PURPLE_STATUS_AWAY, "brb", _("Be Right Back"), TRUE, TRUE, FALSE,
+			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
+			"currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING),
+			NULL);
 	types = g_list_append(types, status);
 
-	status = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE,
-			"busy", _("Busy"), FALSE, TRUE, FALSE);
+	status = purple_status_type_new_with_attrs(
+			PURPLE_STATUS_UNAVAILABLE, "busy", _("Busy"), TRUE, TRUE, FALSE,
+			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
+			"currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING),
+			NULL);
 	types = g_list_append(types, status);
-
-	status = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE,
-			"phone", _("On the Phone"), FALSE, TRUE, FALSE);
+	status = purple_status_type_new_with_attrs(
+			PURPLE_STATUS_UNAVAILABLE, "phone", _("On the Phone"), TRUE, TRUE, FALSE,
+			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
+			"currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING),
+			NULL);
 	types = g_list_append(types, status);
-
-	status = purple_status_type_new_full(PURPLE_STATUS_AWAY,
-			"lunch", _("Out to Lunch"), FALSE, TRUE, FALSE);
+	status = purple_status_type_new_with_attrs(
+			PURPLE_STATUS_AWAY, "lunch", _("Out to Lunch"), TRUE, TRUE, FALSE,
+			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
+			"currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING),
+			NULL);
 	types = g_list_append(types, status);
 
 	status = purple_status_type_new_full(PURPLE_STATUS_INVISIBLE,
@@ -731,7 +809,7 @@
 	http_method = purple_account_get_bool(account, "http_method", FALSE);
 
 	if (http_method)
-		host = purple_account_get_string(account, "http_method_server", MSN_SERVER);
+		host = purple_account_get_string(account, "http_method_server", MSN_HTTPCONN_SERVER);
 	else
 		host = purple_account_get_string(account, "server", MSN_SERVER);
 	port = purple_account_get_int(account, "port", MSN_PORT);
@@ -788,6 +866,7 @@
 	char *msgformat;
 	char *msgtext;
 
+	purple_debug_info("MSNP14","send IM {%s} to %s\n",message,who);
 	account = purple_connection_get_account(gc);
 
 	if (buddy) {
@@ -801,62 +880,91 @@
 	}
 
 	msn_import_html(message, &msgformat, &msgtext);
+	if(msn_user_is_online(account, who)||
+		msn_user_is_yahoo(account, who)){
+		/*User online,then send Online Instant Message*/
 
-	if (strlen(msgtext) + strlen(msgformat) + strlen(VERSION) > 1564)
-	{
+		if (strlen(msgtext) + strlen(msgformat) + strlen(VERSION) > 1564)
+		{
+			g_free(msgformat);
+			g_free(msgtext);
+
+			return -E2BIG;
+		}
+
+		msg = msn_message_new_plain(msgtext);
+		msg->remote_user = g_strdup(who);
+		msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat);
+
 		g_free(msgformat);
 		g_free(msgtext);
 
-		return -E2BIG;
-	}
+		purple_debug_info("MSNP14","prepare to send online Message\n");
+		if (g_ascii_strcasecmp(who, purple_account_get_username(account)))
+		{
+			MsnSession *session;
+			MsnSwitchBoard *swboard;
 
-	msg = msn_message_new_plain(msgtext);
-	msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat);
-
-	g_free(msgformat);
-	g_free(msgtext);
+			session = gc->proto_data;
+			if(msn_user_is_yahoo(account,who)){
+				/*we send the online and offline Message to Yahoo User via UBM*/
+				purple_debug_info("MSNP14","send to Yahoo User\n");
+				uum_send_msg(session,msg);
+			}else{
+				purple_debug_info("MSNP14","send via switchboard\n");
+				swboard = msn_session_get_swboard(session, who, MSN_SB_FLAG_IM);
+				msn_switchboard_send_msg(swboard, msg, TRUE);
+			}
+		}
+		else
+		{
+			char *body_str, *body_enc, *pre, *post;
+			const char *format;
+			MsnIMData *imdata = g_new0(MsnIMData, 1);
+			/*
+			 * In MSN, you can't send messages to yourself, so
+			 * we'll fake like we received it ;)
+			 */
+			body_str = msn_message_to_string(msg);
+			body_enc = g_markup_escape_text(body_str, -1);
+			g_free(body_str);
 
-	if (g_ascii_strcasecmp(who, purple_account_get_username(account)))
-	{
-		MsnSession *session;
-		MsnSwitchBoard *swboard;
+			format = msn_message_get_attr(msg, "X-MMS-IM-Format");
+			msn_parse_format(format, &pre, &post);
+			body_str = g_strdup_printf("%s%s%s", pre ? pre :  "",
+									   body_enc ? body_enc : "", post ? post : "");
+			g_free(body_enc);
+			g_free(pre);
+			g_free(post);
+
+			serv_got_typing_stopped(gc, who);
+			imdata->gc = gc;
+			imdata->who = who;
+			imdata->msg = body_str;
+			imdata->flags = flags;
+			imdata->when = time(NULL);
+			g_idle_add(msn_send_me_im, imdata);
+		}
 
+		msn_message_destroy(msg);
+	}else	{
+		/*send Offline Instant Message,only to MSN Passport User*/
+		MsnSession *session;
+		MsnOim *oim;
+		char *friendname;
+
+		purple_debug_info("MSNP14","prepare to send offline Message\n");
 		session = gc->proto_data;
-		swboard = msn_session_get_swboard(session, who, MSN_SB_FLAG_IM);
+		/* XXX/khc: hack */
+		if (!session->oim)
+			session->oim = msn_oim_new(session);
 
-		msn_switchboard_send_msg(swboard, msg, TRUE);
+		oim = session->oim;
+		friendname = msn_encode_mime(account->username);
+		msn_oim_prep_send_msg_info(oim, purple_account_get_username(account),
+								   friendname, who,	message);
+		msn_oim_send_msg(oim);
 	}
-	else
-	{
-		char *body_str, *body_enc, *pre, *post;
-		const char *format;
-		MsnIMData *imdata = g_new0(MsnIMData, 1);
-		/*
-		 * In MSN, you can't send messages to yourself, so
-		 * we'll fake like we received it ;)
-		 */
-		body_str = msn_message_to_string(msg);
-		body_enc = g_markup_escape_text(body_str, -1);
-		g_free(body_str);
-
-		format = msn_message_get_attr(msg, "X-MMS-IM-Format");
-		msn_parse_format(format, &pre, &post);
-		body_str = g_strdup_printf("%s%s%s", pre ? pre :  "",
-								   body_enc ? body_enc : "", post ? post : "");
-		g_free(body_enc);
-		g_free(pre);
-		g_free(post);
-
-		serv_got_typing_stopped(gc, who);
-		imdata->gc = gc;
-		imdata->who = who;
-		imdata->msg = body_str;
-		imdata->flags = flags;
-		imdata->when = time(NULL);
-		g_idle_add(msn_send_me_im, imdata);
-	}
-
-	msn_message_destroy(msg);
 
 	return 1;
 }
@@ -995,6 +1103,7 @@
 	userlist = session->userlist;
 	who = msn_normalize(gc->account, buddy->name);
 
+	purple_debug_info("MSN","Add user:%s to group:%s\n", who, group->name);
 	if (!session->logged_in)
 	{
 #if 0
@@ -1028,8 +1137,7 @@
 	/* 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, MSN_LIST_FL,
-						   group ? group->name : NULL);
+	msn_userlist_add_buddy(userlist, who, group ? group->name : NULL);
 }
 
 static void
@@ -1045,7 +1153,7 @@
 		return;
 
 	/* XXX - Does buddy->name need to be msn_normalize'd here?  --KingAnt */
-	msn_userlist_rem_buddy(userlist, buddy->name, MSN_LIST_FL, group->name);
+	msn_userlist_rem_buddy(userlist, buddy->name);
 }
 
 static void
@@ -1062,10 +1170,18 @@
 	if (!session->logged_in)
 		return;
 
-	if (user != NULL && user->list_op & MSN_LIST_BL_OP)
-		msn_userlist_rem_buddy(userlist, who, MSN_LIST_BL, NULL);
+	if (user != NULL && user->list_op & MSN_LIST_BL_OP) {
+		msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL);
 
-	msn_userlist_add_buddy(userlist, who, MSN_LIST_AL, NULL);
+		/* delete contact from Block list and add it to Allow in the callback */
+		msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_BL);
+	} else {
+		/* just add the contact to Allow list */
+		msn_add_contact_to_list(session->contact, NULL, who, MSN_LIST_AL);
+	}
+
+
+	msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_AL);
 }
 
 static void
@@ -1082,10 +1198,17 @@
 	if (!session->logged_in)
 		return;
 
-	if (user != NULL && user->list_op & MSN_LIST_AL_OP)
-		msn_userlist_rem_buddy(userlist, who, MSN_LIST_AL, NULL);
+	if (user != NULL && user->list_op & MSN_LIST_AL_OP) {
+		msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_AL);
 
-	msn_userlist_add_buddy(userlist, who, MSN_LIST_BL, NULL);
+		/* delete contact from Allow list and add it to Block in the callback */
+		msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_AL);
+	} else {
+		/* just add the contact to Block list */
+		msn_add_contact_to_list(session->contact, NULL, who, MSN_LIST_BL);
+	}
+
+	msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_BL);
 }
 
 static void
@@ -1103,10 +1226,12 @@
 
 	user = msn_userlist_find_user(userlist, who);
 
-	msn_userlist_rem_buddy(userlist, who, MSN_LIST_AL, NULL);
+	msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_AL);
+
+	msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_AL);
 
 	if (user != NULL && user->list_op & MSN_LIST_RL_OP)
-		msn_userlist_add_buddy(userlist, who, MSN_LIST_BL, NULL);
+		msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_BL);
 }
 
 static void
@@ -1124,32 +1249,18 @@
 
 	user = msn_userlist_find_user(userlist, who);
 
-	msn_userlist_rem_buddy(userlist, who, MSN_LIST_BL, NULL);
+	msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL);
+
+	msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_BL);
 
 	if (user != NULL && user->list_op & MSN_LIST_RL_OP)
-		msn_userlist_add_buddy(userlist, who, MSN_LIST_AL, NULL);
+		msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_AL);
 }
 
 static void
 msn_set_permit_deny(PurpleConnection *gc)
 {
-	PurpleAccount *account;
-	MsnSession *session;
-	MsnCmdProc *cmdproc;
-
-	account = purple_connection_get_account(gc);
-	session = gc->proto_data;
-	cmdproc = session->notification->cmdproc;
-
-	if (account->perm_deny == PURPLE_PRIVACY_ALLOW_ALL ||
-		account->perm_deny == PURPLE_PRIVACY_DENY_USERS)
-	{
-		msn_cmdproc_send(cmdproc, "BLP", "%s", "AL");
-	}
-	else
-	{
-		msn_cmdproc_send(cmdproc, "BLP", "%s", "BL");
-	}
+	msn_send_privacy(gc);
 }
 
 static void
@@ -1286,24 +1397,20 @@
 				 PurpleGroup *group, GList *moved_buddies)
 {
 	MsnSession *session;
-	MsnCmdProc *cmdproc;
-	int old_gid;
-	const char *enc_new_group_name;
 
 	session = gc->proto_data;
-	cmdproc = session->notification->cmdproc;
-	enc_new_group_name = purple_url_encode(group->name);
-
-	old_gid = msn_userlist_find_group_id(session->userlist, old_name);
-
-	if (old_gid >= 0)
+	
+	g_return_if_fail(session != NULL);
+	g_return_if_fail(session->userlist != NULL);
+	
+	if (msn_userlist_find_group_with_name(session->userlist, old_name) != NULL)
 	{
-		msn_cmdproc_send(cmdproc, "REG", "%d %s 0", old_gid,
-						 enc_new_group_name);
+		msn_contact_rename_group(session, old_name, group->name);
 	}
 	else
 	{
-		msn_cmdproc_send(cmdproc, "ADG", "%s 0", enc_new_group_name);
+		/* not found */
+		msn_add_group(session, NULL, group->name);
 	}
 }
 
@@ -1363,15 +1470,20 @@
 {
 	MsnSession *session;
 	MsnCmdProc *cmdproc;
-	int group_id;
 
 	session = gc->proto_data;
 	cmdproc = session->notification->cmdproc;
 
-	if ((group_id = msn_userlist_find_group_id(session->userlist, group->name)) >= 0)
+	purple_debug_info("MSN", "Remove group %s\n", group->name);
+	/*we can't delete the default group*/
+	if(!strcmp(group->name, MSN_INDIVIDUALS_GROUP_NAME)||
+		!strcmp(group->name, MSN_NON_IM_GROUP_NAME))
 	{
-		msn_cmdproc_send(cmdproc, "RMG", "%d", group_id);
+		purple_debug_info("MSN", "This group can't be removed, returning.\n");
+		return ;
 	}
+	
+	msn_del_group(session, group->name);
 }
 
 /**
@@ -1421,12 +1533,11 @@
 {
 	char *p, *q;
 
-	if ((p = strstr(url_text, " contactparams:photopreauthurl=\"")) != NULL)
+	if ((p = strstr(url_text, PHOTO_URL)) != NULL)
 	{
-		p += strlen(" contactparams:photopreauthurl=\"");
+		p += strlen(PHOTO_URL);
 	}
-
-	if (p && (strncmp(p, "http://", 8) == 0) && ((q = strchr(p, '"')) != NULL))
+	if (p && (strncmp(p, "http://",strlen("http://")) == 0) && ((q = strchr(p, '"')) != NULL))
 			return g_strndup(p, q - p);
 
 	return NULL;
@@ -1464,8 +1575,7 @@
 msn_info_strip_search_link(const char *field, size_t len)
 {
 	const char *c;
-	if ((c = strstr(field, " (http://spaces.live.com/default.aspx?page=searchresults")) == NULL &&
-		(c = strstr(field, " (http://spaces.msn.com/default.aspx?page=searchresults")) == NULL)
+	if ((c = strstr(field, " (http://")) == NULL)
 		return g_strndup(field, len);
 	return g_strndup(field, c - field);
 }
@@ -1491,7 +1601,7 @@
 	MsnGetInfoStepTwoData *info2_data = NULL;
 #endif
 
-	purple_debug_info("msn", "In msn_got_info\n");
+	purple_debug_info("msn", "In msn_got_info,url_text:{%s}\n",url_text);
 
 	/* Make sure the connection is still valid */
 	if (g_list_find(purple_connections_get_all(), info_data->gc) == NULL)
@@ -1875,6 +1985,7 @@
 #if PHOTO_SUPPORT
 	/* Find the URL to the photo; must be before the marshalling [Bug 994207] */
 	photo_url_text = msn_get_photo_url(url_text);
+	purple_debug_info("MSNP14","photo url:{%s}\n",photo_url_text);
 
 	/* Marshall the existing state */
 	info2_data = g_malloc0(sizeof(MsnGetInfoStepTwoData));
@@ -2099,7 +2210,7 @@
 	msn_add_deny,			/* add_deny */
 	msn_rem_permit,			/* rem_permit */
 	msn_rem_deny,			/* rem_deny */
-	msn_set_permit_deny,		/* set_permit_deny */
+	msn_set_permit_deny,	/* set_permit_deny */
 	NULL,					/* join_chat */
 	NULL,					/* reject chat invite */
 	NULL,					/* get_chat_name */
@@ -2155,10 +2266,11 @@
 	"MSN",                                            /**< name           */
 	VERSION,                                          /**< version        */
 	                                                  /**  summary        */
-	N_("MSN Protocol Plugin"),
+	N_("Windows Live Messenger Protocol Plugin"),
 	                                                  /**  description    */
-	N_("MSN Protocol Plugin"),
-	"Christian Hammond <chipx86@gnupdate.org>",       /**< author         */
+	N_("Windows Live Messenger Protocol Plugin"),
+	"Christian Hammond <chipx86@gnupdate.org>, "
+	"MaYuan <mayuan2006@gmail.com>",				  /**< author         */
 	PURPLE_WEBSITE,                                     /**< homepage       */
 
 	msn_load,                                         /**< load           */
@@ -2183,11 +2295,11 @@
 	PurpleAccountOption *option;
 
 	option = purple_account_option_string_new(_("Server"), "server",
-											MSN_SERVER);
+											WLM_SERVER);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
 											   option);
 
-	option = purple_account_option_int_new(_("Port"), "port", 1863);
+	option = purple_account_option_int_new(_("Port"), "port", WLM_PORT);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
 											   option);
 
--- a/libpurple/protocols/msn/msn.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/msn.h	Fri Sep 28 16:34:43 2007 +0000
@@ -63,12 +63,23 @@
 #define USEROPT_MSNPORT 4
 #define MSN_PORT 1863
 
+/* Windows Live Messenger Server*/
+#define WLM_SERVER			"muser.messenger.hotmail.com"
+#define WLM_PORT			1863
+#define WLM_PROT_VER		13
+/*This MSNP14 Support chat with Yahoo Messenger*/
+#define WLM_YAHOO_PROT_VER	14
+
+#define WLM_MAX_PROTOCOL	14
+#define WLM_MIN_PROTOCOL	13
+
 #define MSN_TYPING_RECV_TIMEOUT 6
 #define MSN_TYPING_SEND_TIMEOUT	4
 
-#define HOTMAIL_URL "http://www.hotmail.com/cgi-bin/folders"
+#define HOTMAIL_URL "http://www.hotmail.com/cgi-bin/folders"w3
 #define PASSPORT_URL "http://lc1.law13.hotmail.passport.com/cgi-bin/dologin?login="
 #define PROFILE_URL "http://spaces.live.com/profile.aspx?mem="
+#define PHOTO_URL	" contactparams:photopreauthurl=\""
 
 #define USEROPT_HOTMAIL 0
 
@@ -88,9 +99,11 @@
 	MSN_LIST_FL_OP = 0x01,
 	MSN_LIST_AL_OP = 0x02,
 	MSN_LIST_BL_OP = 0x04,
-	MSN_LIST_RL_OP = 0x08
+	MSN_LIST_RL_OP = 0x08,
+	MSN_LIST_PL_OP = 0x10
 
 } MsnListOp;
+#define MSN_LIST_OP_MASK	0x07
 
 typedef enum
 {
@@ -131,4 +144,7 @@
 	 (MSN_CLIENT_ID_RESERVED_2 <<  8) | \
 	 (MSN_CLIENT_ID_CAPABILITIES))
 
+void msn_act_id(PurpleConnection *gc, const char *entry);
+void msn_send_privacy(PurpleConnection *gc);
+
 #endif /* _MSN_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/msn/msnutils.c	Fri Sep 28 16:34:43 2007 +0000
@@ -0,0 +1,591 @@
+/**
+ * @file msnutils.c Utility functions
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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  02111-1301  USA
+ */
+#include "msn.h"
+#include "msnutils.h"
+#include "time.h"
+//#include <openssl/md5.h>
+
+char *rand_guid(void);
+
+/**************************************************************************
+ * Util
+ **************************************************************************/
+char *
+rand_guid()
+{
+	return g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X",
+			rand() % 0xAAFF + 0x1111,
+			rand() % 0xAAFF + 0x1111,
+			rand() % 0xAAFF + 0x1111,
+			rand() % 0xAAFF + 0x1111,
+			rand() % 0xAAFF + 0x1111,
+			rand() % 0xAAFF + 0x1111,
+			rand() % 0xAAFF + 0x1111,
+			rand() % 0xAAFF + 0x1111);
+}
+
+void
+msn_parse_format(const char *mime, char **pre_ret, char **post_ret)
+{
+	char *cur;
+	GString *pre  = g_string_new(NULL);
+	GString *post = g_string_new(NULL);
+	unsigned int colors[3];
+
+	if (pre_ret  != NULL) *pre_ret  = NULL;
+	if (post_ret != NULL) *post_ret = NULL;
+
+	cur = strstr(mime, "FN=");
+
+	if (cur && (*(cur = cur + 3) != ';'))
+	{
+		pre = g_string_append(pre, "<FONT FACE=\"");
+
+		while (*cur && *cur != ';')
+		{
+			pre = g_string_append_c(pre, *cur);
+			cur++;
+		}
+
+		pre = g_string_append(pre, "\">");
+		post = g_string_prepend(post, "</FONT>");
+	}
+
+	cur = strstr(mime, "EF=");
+
+	if (cur && (*(cur = cur + 3) != ';'))
+	{
+		while (*cur && *cur != ';')
+		{
+			pre = g_string_append_c(pre, '<');
+			pre = g_string_append_c(pre, *cur);
+			pre = g_string_append_c(pre, '>');
+			post = g_string_prepend_c(post, '>');
+			post = g_string_prepend_c(post, *cur);
+			post = g_string_prepend_c(post, '/');
+			post = g_string_prepend_c(post, '<');
+			cur++;
+		}
+	}
+
+	cur = strstr(mime, "CO=");
+
+	if (cur && (*(cur = cur + 3) != ';'))
+	{
+		int i;
+
+		i = sscanf(cur, "%02x%02x%02x;", &colors[0], &colors[1], &colors[2]);
+
+		if (i > 0)
+		{
+			char tag[64];
+
+			if (i == 1)
+			{
+				colors[1] = 0;
+				colors[2] = 0;
+			}
+			else if (i == 2)
+			{
+				unsigned int temp = colors[0];
+
+				colors[0] = colors[1];
+				colors[1] = temp;
+				colors[2] = 0;
+			}
+			else if (i == 3)
+			{
+				unsigned int temp = colors[2];
+
+				colors[2] = colors[0];
+				colors[0] = temp;
+			}
+
+			g_snprintf(tag, sizeof(tag),
+					   "<FONT COLOR=\"#%02hhx%02hhx%02hhx\">",
+					   colors[0], colors[1], colors[2]);
+
+			pre = g_string_append(pre, tag);
+			post = g_string_prepend(post, "</FONT>");
+		}
+	}
+
+	cur = strstr(mime, "RL=");
+
+	if (cur && (*(cur = cur + 3) != ';'))
+	{
+		if (*cur == '1')
+		{
+			/* RTL text was received */
+			pre = g_string_append(pre, "<SPAN style=\"direction:rtl;text-align:right;\">");
+			post = g_string_prepend(post, "</SPAN>");
+		}
+	}
+
+	cur = g_strdup(purple_url_decode(pre->str));
+	g_string_free(pre, TRUE);
+
+	if (pre_ret != NULL)
+		*pre_ret = cur;
+	else
+		g_free(cur);
+
+	cur = g_strdup(purple_url_decode(post->str));
+	g_string_free(post, TRUE);
+
+	if (post_ret != NULL)
+		*post_ret = cur;
+	else
+		g_free(cur);
+}
+
+/*encode the str to RFC2047 style
+ * Currently only support the UTF-8 and base64 encode
+ */
+char *
+msn_encode_mime(const char *str)
+{
+	char *base64;
+	
+	base64 = purple_base64_encode((guchar *)str, strlen(str));
+	return g_strdup_printf("=?utf-8?B?%s?=", base64);
+}
+
+/*
+ * We need this because we're only supposed to encode spaces in the font
+ * names. purple_url_encode() isn't acceptable.
+ */
+static const char *
+encode_spaces(const char *str)
+{
+	static char buf[BUF_LEN];
+	const char *c;
+	char *d;
+
+	g_return_val_if_fail(str != NULL, NULL);
+
+	for (c = str, d = buf; *c != '\0'; c++)
+	{
+		if (*c == ' ')
+		{
+			*d++ = '%';
+			*d++ = '2';
+			*d++ = '0';
+		}
+		else
+			*d++ = *c;
+	}
+
+	return buf;
+}
+
+/*
+ * Taken from the zephyr plugin.
+ * This parses HTML formatting (put out by one of the gtkimhtml widgets
+ * and converts it to msn formatting. It doesn't deal with the tag closing,
+ * but gtkimhtml widgets give valid html.
+ * It currently deals properly with <b>, <u>, <i>, <font face=...>,
+ * <font color=...>, <span dir=...>, <span style="direction: ...">.
+ * It ignores <font back=...> and <font size=...>
+ */
+void
+msn_import_html(const char *html, char **attributes, char **message)
+{
+	int len, retcount = 0;
+	const char *c;
+	char *msg;
+	char *fontface = NULL;
+	char fonteffect[4];
+	char fontcolor[7];
+	char direction = '0';
+
+	gboolean has_bold = FALSE;
+	gboolean has_italic = FALSE;
+	gboolean has_underline = FALSE;
+	gboolean has_strikethrough = FALSE;
+
+	g_return_if_fail(html       != NULL);
+	g_return_if_fail(attributes != NULL);
+	g_return_if_fail(message    != NULL);
+
+	len = strlen(html);
+	msg = g_malloc0(len + 1);
+
+	memset(fontcolor, 0, sizeof(fontcolor));
+	strcat(fontcolor, "0");
+	memset(fonteffect, 0, sizeof(fonteffect));
+
+	for (c = html; *c != '\0';)
+	{
+		if (*c == '<')
+		{
+			if (!g_ascii_strncasecmp(c + 1, "br>", 3))
+			{
+				msg[retcount++] = '\r';
+				msg[retcount++] = '\n';
+				c += 4;
+			}
+			else if (!g_ascii_strncasecmp(c + 1, "i>", 2))
+			{
+				if (!has_italic)
+				{
+					strcat(fonteffect, "I");
+					has_italic = TRUE;
+				}
+				c += 3;
+			}
+			else if (!g_ascii_strncasecmp(c + 1, "b>", 2))
+			{
+				if (!has_bold)
+				{
+					strcat(fonteffect, "B");
+					has_bold = TRUE;
+				}
+				c += 3;
+			}
+			else if (!g_ascii_strncasecmp(c + 1, "u>", 2))
+			{
+				if (!has_underline)
+				{
+					strcat(fonteffect, "U");
+					has_underline = TRUE;
+				}
+				c += 3;
+			}
+			else if (!g_ascii_strncasecmp(c + 1, "s>", 2))
+			{
+				if (!has_strikethrough)
+				{
+					strcat(fonteffect, "S");
+					has_strikethrough = TRUE;
+				}
+				c += 3;
+			}
+			else if (!g_ascii_strncasecmp(c + 1, "a href=\"", 8))
+			{
+				c += 9;
+
+				if (!g_ascii_strncasecmp(c, "mailto:", 7))
+					c += 7;
+
+				while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2))
+					msg[retcount++] = *c++;
+
+				if (*c != '\0')
+					c += 2;
+
+				/* ignore descriptive string */
+				while ((*c != '\0') && g_ascii_strncasecmp(c, "</a>", 4))
+					c++;
+
+				if (*c != '\0')
+					c += 4;
+			}
+			else if (!g_ascii_strncasecmp(c + 1, "span", 4))
+			{
+				/* Bi-directional text support using CSS properties in span tags */
+				c += 5;
+
+				while (*c != '\0' && *c != '>')
+				{
+					while (*c == ' ')
+						c++;
+					if (!g_ascii_strncasecmp(c, "dir=\"rtl\"", 9))
+					{
+						c += 9;
+						direction = '1';
+					}
+					else if (!g_ascii_strncasecmp(c, "style=\"", 7))
+					{
+						/* Parse inline CSS attributes */
+						char *attributes;
+						int attr_len = 0;
+						c += 7;
+						while (*(c + attr_len) != '\0' && *(c + attr_len) != '"')
+							attr_len++;
+						if (*(c + attr_len) == '"')
+						{
+							char *attr_dir;
+							attributes = g_strndup(c, attr_len);
+							attr_dir = purple_markup_get_css_property(attributes, "direction");
+							if (attr_dir && (!g_ascii_strncasecmp(attr_dir, "RTL", 3)))
+								direction = '1';
+							g_free(attr_dir);
+							g_free(attributes);
+						}
+
+					}
+					else
+					{
+						c++;
+					}
+				}
+				if (*c == '>')
+					c++;
+			}
+			else if (!g_ascii_strncasecmp(c + 1, "font", 4))
+			{
+				c += 5;
+
+				while ((*c != '\0') && !g_ascii_strncasecmp(c, " ", 1))
+					c++;
+
+				if (!g_ascii_strncasecmp(c, "color=\"#", 7))
+				{
+					c += 8;
+
+					fontcolor[0] = *(c + 4);
+					fontcolor[1] = *(c + 5);
+					fontcolor[2] = *(c + 2);
+					fontcolor[3] = *(c + 3);
+					fontcolor[4] = *c;
+					fontcolor[5] = *(c + 1);
+
+					c += 8;
+				}
+				else if (!g_ascii_strncasecmp(c, "face=\"", 6))
+				{
+					const char *end = NULL;
+					const char *comma = NULL;
+					unsigned int namelen = 0;
+
+					c += 6;
+					end = strchr(c, '\"');
+					comma = strchr(c, ',');
+
+					if (comma == NULL || comma > end)
+						namelen = (unsigned int)(end - c);
+					else
+						namelen = (unsigned int)(comma - c);
+
+					fontface = g_strndup(c, namelen);
+					c = end + 2;
+				}
+				else
+				{
+					/* Drop all unrecognized/misparsed font tags */
+					while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2))
+						c++;
+
+					if (*c != '\0')
+						c += 2;
+				}
+			}
+			else
+			{
+				while ((*c != '\0') && (*c != '>'))
+					c++;
+				if (*c != '\0')
+					c++;
+			}
+		}
+		else if (*c == '&')
+		{
+			if (!g_ascii_strncasecmp(c, "&lt;", 4))
+			{
+				msg[retcount++] = '<';
+				c += 4;
+			}
+			else if (!g_ascii_strncasecmp(c, "&gt;", 4))
+			{
+				msg[retcount++] = '>';
+				c += 4;
+			}
+			else if (!g_ascii_strncasecmp(c, "&nbsp;", 6))
+			{
+				msg[retcount++] = ' ';
+				c += 6;
+			}
+			else if (!g_ascii_strncasecmp(c, "&quot;", 6))
+			{
+				msg[retcount++] = '"';
+				c += 6;
+			}
+			else if (!g_ascii_strncasecmp(c, "&amp;", 5))
+			{
+				msg[retcount++] = '&';
+				c += 5;
+			}
+			else if (!g_ascii_strncasecmp(c, "&apos;", 6))
+			{
+				msg[retcount++] = '\'';
+				c += 6;
+			}
+			else
+				msg[retcount++] = *c++;
+		}
+		else
+			msg[retcount++] = *c++;
+	}
+
+	if (fontface == NULL)
+		fontface = g_strdup("MS Sans Serif");
+
+	*attributes = g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c",
+								  encode_spaces(fontface),
+								  fonteffect, fontcolor, direction);
+	*message = g_strdup(msg);
+
+	g_free(fontface);
+	g_free(msg);
+}
+
+void
+msn_parse_socket(const char *str, char **ret_host, int *ret_port)
+{
+	char *host;
+	char *c;
+	int port;
+
+	host = g_strdup(str);
+
+	if ((c = strchr(host, ':')) != NULL){
+		*c = '\0';
+		port = atoi(c + 1);
+	}else{
+		port = 1863;
+	}
+
+	*ret_host = host;
+	*ret_port = port;
+}
+/***************************************************************************
+ * MSN Time Related Funciton
+ ***************************************************************************/
+#if 0
+int
+msn_convert_iso8601(const char *timestr,struct tm tm_time)
+{
+	char temp[64];
+	struct tm ctime;
+	time_t ts;
+
+	purple_debug_info("MSNP14","convert string is{%s}\n",timestr);
+	tzset();
+	/*copy string first*/
+	memset(temp, 0, sizeof(temp));
+	strncpy(temp, timestr, strlen(timestr));
+
+	/*convert via strptime()*/
+	memset(&ctime, 0, sizeof(struct tm));
+	strptime(temp, "%d %b %Y %T %Z", &ctime);
+	ts = mktime(&ctime) - timezone;
+	localtime_r(&ts, tm_time);
+}
+#endif
+
+/***************************************************************************
+ * MSN Challenge Computing Function
+ ***************************************************************************/
+
+/*
+ * Handle MSN Chanllege computation
+ *This algorithm reference with http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges
+ */
+#define BUFSIZE	256
+void 
+msn_handle_chl(char *input, char *output)
+{
+		PurpleCipher *cipher;
+		PurpleCipherContext *context;
+		char *productKey = MSNP13_WLM_PRODUCT_KEY,
+			 *productID  = MSNP13_WLM_PRODUCT_ID,
+			 *hexChars   = "0123456789abcdef",
+			 buf[BUFSIZE];
+		unsigned char md5Hash[16], *newHash;
+		unsigned int *md5Parts, *chlStringParts, newHashParts[5];
+
+		long long nHigh=0, nLow=0;
+
+		int i;
+
+		/* Create the MD5 hash by using Purple MD5 algorithm*/
+		cipher = purple_ciphers_find_cipher("md5");
+		context = purple_cipher_context_new(cipher, NULL);
+
+		purple_cipher_context_append(context, (const guchar *)input,
+						strlen(input));
+		purple_cipher_context_append(context, (const guchar *)productKey,
+						strlen(productKey));
+		purple_cipher_context_digest(context, sizeof(md5Hash), md5Hash, NULL);
+		purple_cipher_context_destroy(context);
+
+		/* Split it into four integers */
+		md5Parts = (unsigned int *)md5Hash;
+		for(i=0; i<4; i++){  
+				/* adjust endianess */
+				md5Parts[i] = GUINT_TO_LE(md5Parts[i]);
+
+				/* & each integer with 0x7FFFFFFF          */
+				/* and save one unmodified array for later */
+				newHashParts[i] = md5Parts[i];
+				md5Parts[i] &= 0x7FFFFFFF;
+		}
+
+		/* make a new string and pad with '0' */
+		snprintf(buf, BUFSIZE-5, "%s%s", input, productID);
+		i = strlen(buf);
+		memset(&buf[i], '0', 8 - (i % 8));
+		buf[i + (8 - (i % 8))]='\0';
+
+		/* split into integers */
+		chlStringParts = (unsigned int *)buf;
+
+		/* this is magic */
+		for (i=0; i<(strlen(buf)/4)-1; i+=2){
+				long long temp;
+
+				chlStringParts[i]   = GUINT_TO_LE(chlStringParts[i]);
+				chlStringParts[i+1] = GUINT_TO_LE(chlStringParts[i+1]);
+
+				temp=(md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF;
+				nHigh=(md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF;
+				nLow=nLow + nHigh + temp;
+		}
+		nHigh=(nHigh+md5Parts[1]) % 0x7FFFFFFF;
+		nLow=(nLow+md5Parts[3]) % 0x7FFFFFFF;
+
+		newHashParts[0]^=nHigh;
+		newHashParts[1]^=nLow;
+		newHashParts[2]^=nHigh;
+		newHashParts[3]^=nLow;
+
+		/* adjust endianness */
+		for(i=0; i<4; i++)
+				newHashParts[i] = GUINT_TO_LE(newHashParts[i]); 
+
+		/* make a string of the parts */
+		newHash = (unsigned char *)newHashParts;
+
+		/* convert to hexadecimal */
+		for (i=0; i<16; i++)
+		{
+				output[i*2]=hexChars[(newHash[i]>>4)&0xF];
+				output[(i*2)+1]=hexChars[newHash[i]&0xF];
+		}
+
+		output[32]='\0';
+
+//		purple_debug_info("MSNP14","chl output{%s}\n",output);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/msn/msnutils.h	Fri Sep 28 16:34:43 2007 +0000
@@ -0,0 +1,60 @@
+/**
+ * @file msnutils.h Utility functions
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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  02111-1301  USA
+ */
+#ifndef _MSN_UTILS_H_
+#define _MSN_UTILS_H_
+
+/*encode the str to RFC2047 style*/
+char * msn_encode_mime(const char *str);
+
+/**
+ * Generate the Random GUID
+ */
+char * rand_guid(void);
+
+/**
+ * Parses the MSN message formatting into a format compatible with Purple.
+ *
+ * @param mime     The mime header with the formatting.
+ * @param pre_ret  The returned prefix string.
+ * @param post_ret The returned postfix string.
+ *
+ * @return The new message.
+ */
+void msn_parse_format(const char *mime, char **pre_ret, char **post_ret);
+
+/**
+ * Parses the Purple message formatting (html) into the MSN format.
+ *
+ * @param html			The html message to format.
+ * @param attributes	The returned attributes string.
+ * @param message		The returned message string.
+ *
+ * @return The new message.
+ */
+void msn_import_html(const char *html, char **attributes, char **message);
+
+void msn_parse_socket(const char *str, char **ret_host, int *ret_port);
+void msn_handle_chl(char *input, char *output);
+
+#endif /* _MSN_UTILS_H_ */
--- a/libpurple/protocols/msn/nexus.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/nexus.c	Fri Sep 28 16:34:43 2007 +0000
@@ -22,9 +22,15 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 #include "msn.h"
+#include "soap.h"
 #include "nexus.h"
 #include "notification.h"
 
+#undef NEXUS_LOGIN_TWN
+
+/*Local Function Prototype*/
+static gboolean nexus_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc);
+
 /**************************************************************************
  * Main
  **************************************************************************/
@@ -36,6 +42,9 @@
 
 	nexus = g_new0(MsnNexus, 1);
 	nexus->session = session;
+	/*we must use SSL connection to do Windows Live ID authentication*/
+	nexus->soapconn = msn_soap_new(session,nexus,1);
+
 	nexus->challenge_data = g_hash_table_new_full(g_str_hash,
 		g_str_equal, g_free, g_free);
 
@@ -45,24 +54,14 @@
 void
 msn_nexus_destroy(MsnNexus *nexus)
 {
-	if (nexus->gsc)
-		purple_ssl_close(nexus->gsc);
-
-	g_free(nexus->login_host);
-
-	g_free(nexus->login_path);
-
 	if (nexus->challenge_data != NULL)
 		g_hash_table_destroy(nexus->challenge_data);
 
-	if (nexus->input_handler > 0)
-		purple_input_remove(nexus->input_handler);
-	g_free(nexus->write_buf);
-	g_free(nexus->read_buf);
-
+	msn_soap_destroy(nexus->soapconn);
 	g_free(nexus);
 }
 
+#if 0 /* khc */
 /**************************************************************************
  * Util
  **************************************************************************/
@@ -121,285 +120,237 @@
 	nexus->written_cb(nexus, source, 0);
 }
 
+#endif
 /**************************************************************************
  * Login
  **************************************************************************/
-
 static void
-login_connect_cb(gpointer data, PurpleSslConnection *gsc,
-				 PurpleInputCondition cond);
-
-static void
-login_error_cb(PurpleSslConnection *gsc, PurpleSslErrorType error, void *data)
+nexus_login_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error)
 {
-	MsnNexus *nexus;
 	MsnSession *session;
 
-	nexus = data;
-	g_return_if_fail(nexus != NULL);
-
-	nexus->gsc = NULL;
-
-	session = nexus->session;
+	session = soapconn->session;
 	g_return_if_fail(session != NULL);
 
-	msn_session_set_error(session, MSN_ERROR_AUTH, _("Unable to connect"));
+	soapconn->gsc = NULL;
+
+	msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication:Unable to connect"));
 	/* the above line will result in nexus being destroyed, so we don't want
 	 * to destroy it here, or we'd crash */
 }
 
-static void
-nexus_login_written_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
-	MsnNexus *nexus = data;
-	MsnSession *session;
-	int len;
-
-	session = nexus->session;
-	g_return_if_fail(session != NULL);
-
-	if (nexus->input_handler == 0)
-		/* TODO: Use purple_ssl_input_add()? */
-		nexus->input_handler = purple_input_add(nexus->gsc->fd,
-			PURPLE_INPUT_READ, nexus_login_written_cb, nexus);
-
-
-	len = msn_ssl_read(nexus);
-
-	if (len < 0 && errno == EAGAIN)
-		return;
-	else if (len < 0) {
-		purple_input_remove(nexus->input_handler);
-		nexus->input_handler = 0;
-		g_free(nexus->read_buf);
-		nexus->read_buf = NULL;
-		nexus->read_len = 0;
-		/* TODO: error handling */
-		return;
-	}
-
-	if (g_strstr_len(nexus->read_buf, nexus->read_len,
-			"\r\n\r\n") == NULL)
-		return;
-
-	purple_input_remove(nexus->input_handler);
-	nexus->input_handler = 0;
-
-	purple_ssl_close(nexus->gsc);
-	nexus->gsc = NULL;
-
-	purple_debug_misc("msn", "ssl buffer: {%s}\n", nexus->read_buf);
-
-	if (strstr(nexus->read_buf, "HTTP/1.1 302") != NULL)
-	{
-		/* Redirect. */
-		char *location, *c;
-
-		location = strstr(nexus->read_buf, "Location: ");
-		if (location == NULL)
-		{
-			g_free(nexus->read_buf);
-			nexus->read_buf = NULL;
-			nexus->read_len = 0;
-
-			return;
-		}
-		location = strchr(location, ' ') + 1;
-
-		if ((c = strchr(location, '\r')) != NULL)
-			*c = '\0';
-
-		/* Skip the http:// */
-		if ((c = strchr(location, '/')) != NULL)
-			location = c + 2;
-
-		if ((c = strchr(location, '/')) != NULL)
-		{
-			g_free(nexus->login_path);
-			nexus->login_path = g_strdup(c);
-
-			*c = '\0';
-		}
-
-		g_free(nexus->login_host);
-		nexus->login_host = g_strdup(location);
-
-		nexus->gsc = purple_ssl_connect(session->account,
-				nexus->login_host, PURPLE_SSL_DEFAULT_PORT,
-				login_connect_cb, login_error_cb, nexus);
-	}
-	else if (strstr(nexus->read_buf, "HTTP/1.1 401 Unauthorized") != NULL)
-	{
-		const char *error;
-
-		if ((error = strstr(nexus->read_buf, "WWW-Authenticate")) != NULL)
-		{
-			if ((error = strstr(error, "cbtxt=")) != NULL)
-			{
-				const char *c;
-				char *temp;
-
-				error += strlen("cbtxt=");
-
-				if ((c = strchr(error, '\n')) == NULL)
-					c = error + strlen(error);
-
-				temp = g_strndup(error, c - error);
-				error = purple_url_decode(temp);
-				g_free(temp);
-				if ((temp = strstr(error, " Do one of the following or try again:")) != NULL)
-					*temp = '\0';
-			}
-		}
-
-		msn_session_set_error(session, MSN_ERROR_AUTH, error);
-	}
-	else if (strstr(nexus->read_buf, "HTTP/1.1 503 Service Unavailable"))
-	{
-		msn_session_set_error(session, MSN_ERROR_SERV_UNAVAILABLE, NULL);
-	}
-	else if (strstr(nexus->read_buf, "HTTP/1.1 200 OK"))
-	{
-		char *base, *c;
-		char *login_params;
-
-#if 0
-		/* All your base are belong to us. */
-		base = buffer;
-
-		/* For great cookie! */
-		while ((base = strstr(base, "Set-Cookie: ")) != NULL)
-		{
-			base += strlen("Set-Cookie: ");
-
-			c = strchr(base, ';');
-
-			session->login_cookies =
-				g_list_append(session->login_cookies,
-							  g_strndup(base, c - base));
-		}
-#endif
-
-		base  = strstr(nexus->read_buf, "Authentication-Info: ");
-
-		g_return_if_fail(base != NULL);
-
-		base  = strstr(base, "from-PP='");
-		base += strlen("from-PP='");
-		c     = strchr(base, '\'');
-
-		login_params = g_strndup(base, c - base);
-
-		msn_got_login_params(session, login_params);
-
-		g_free(login_params);
-
-		msn_nexus_destroy(nexus);
-		session->nexus = NULL;
-		return;
-	}
-
-	g_free(nexus->read_buf);
-	nexus->read_buf = NULL;
-	nexus->read_len = 0;
-
-}
-
-/* this guards against missing hash entries */
-static char *
-nexus_challenge_data_lookup(GHashTable *challenge_data, const char *key)
-{
-	char *entry;
-
-	return (entry = (char *)g_hash_table_lookup(challenge_data, key)) ?
-		entry : "(null)";
-}
-
-void
-login_connect_cb(gpointer data, PurpleSslConnection *gsc,
-				 PurpleInputCondition cond)
+/*process the SOAP reply, get the Authentication Info*/
+static gboolean
+nexus_login_read_cb(MsnSoapConn *soapconn)
 {
 	MsnNexus *nexus;
 	MsnSession *session;
+
+	char *base, *c;
+	char *msn_twn_t,*msn_twn_p;
+	char *login_params;
+	char **elems, **cur, **tokens;
+	char * cert_str;
+
+	nexus = soapconn->parent;
+	g_return_val_if_fail(nexus != NULL, TRUE);
+	session = nexus->session;
+	g_return_val_if_fail(session != NULL, FALSE);
+
+	/*reply OK, we should process the SOAP body*/
+	purple_debug_info("MSN Nexus","TWN Server Windows Live ID Reply OK!\n");
+
+	//TODO: we should parse it using XML
+#ifdef NEXUS_LOGIN_TWN
+	base  = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_START_TOKEN);
+	base += strlen(TWN_START_TOKEN);
+	c     = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_END_TOKEN);
+#else
+	base  = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_LIVE_START_TOKEN);
+	base += strlen(TWN_LIVE_START_TOKEN);
+	c     = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_LIVE_END_TOKEN);
+#endif
+	login_params = g_strndup(base, c - base);
+
+	//		purple_debug_info("msn", "TWN Cert: {%s}\n", login_params);
+
+	/* Parse the challenge data. */
+	elems = g_strsplit(login_params, "&amp;", 0);
+
+	for (cur = elems; *cur != NULL; cur++){
+			tokens = g_strsplit(*cur, "=", 2);
+			g_hash_table_insert(nexus->challenge_data, tokens[0], tokens[1]);
+			/* Don't free each of the tokens, only the array. */
+			g_free(tokens);
+	}
+
+	g_strfreev(elems);
+
+	msn_twn_t = (char *)g_hash_table_lookup(nexus->challenge_data, "t");
+	msn_twn_p = (char *)g_hash_table_lookup(nexus->challenge_data, "p");
+
+	/*setup the t and p parameter for session*/
+	if (session->passport_info.t != NULL){
+			g_free(session->passport_info.t);
+	}
+	session->passport_info.t = g_strdup(msn_twn_t);
+
+	if (session->passport_info.p != NULL)
+			g_free(session->passport_info.p);
+	session->passport_info.p = g_strdup(msn_twn_p);
+
+	cert_str = g_strdup_printf("t=%s&p=%s",msn_twn_t,msn_twn_p);
+	msn_got_login_params(session, cert_str);
+
+	purple_debug_info("MSN Nexus","Close nexus connection!\n");
+	g_free(cert_str);
+	g_free(login_params);
+	msn_nexus_destroy(nexus);
+	session->nexus = NULL;
+
+	return FALSE;
+}
+
+static void
+nexus_login_written_cb(MsnSoapConn *soapconn)
+{
+	soapconn->read_cb = nexus_login_read_cb;
+//	msn_soap_read_cb(data,source,cond);
+}
+
+
+/*when connect, do the SOAP Style windows Live ID authentication */
+gboolean
+nexus_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc)
+{
+	MsnNexus * nexus;
+	MsnSession *session;
+	char *ru,*lc,*id,*tw,*ct,*kpp,*kv,*ver,*rn,*tpf;
+	char *fs0,*fs;
 	char *username, *password;
 	char *request_str, *head, *tail;
-	char *buffer = NULL;
-	guint32 ctint;
+#ifdef NEXUS_LOGIN_TWN
+	char *challenge_str;
+#else
+	char *rst1_str,*rst2_str,*rst3_str;
+#endif
+	
+	purple_debug_info("MSN Nexus","Starting Windows Live ID authentication\n");
 
-	nexus = data;
-	g_return_if_fail(nexus != NULL);
+	g_return_val_if_fail(soapconn != NULL, FALSE);
+
+	nexus = soapconn->parent;
+	g_return_val_if_fail(nexus != NULL, TRUE);
 
-	session = nexus->session;
-	g_return_if_fail(session != NULL);
+	session = soapconn->session;
+	g_return_val_if_fail(session != NULL, FALSE);
+
+	msn_soap_set_process_step(soapconn, MSN_SOAP_PROCESSING);
 
 	msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE);
 
-	username =
-		g_strdup(purple_url_encode(purple_account_get_username(session->account)));
+	/*prepare the Windows Live ID authentication token*/
+	username = g_strdup(purple_account_get_username(session->account));
+	password = g_strdup(purple_connection_get_password(session->account->gc));
 
-	password =
-		g_strdup(purple_url_encode(purple_connection_get_password(session->account->gc)));
+	lc =	(char *)g_hash_table_lookup(nexus->challenge_data, "lc");
+	id =	(char *)g_hash_table_lookup(nexus->challenge_data, "id");
+	tw =	(char *)g_hash_table_lookup(nexus->challenge_data, "tw");
+	fs0=	(char *)g_hash_table_lookup(nexus->challenge_data, "fs");
+	ru =	(char *)g_hash_table_lookup(nexus->challenge_data, "ru");
+	ct =	(char *)g_hash_table_lookup(nexus->challenge_data, "ct");
+	kpp=	(char *)g_hash_table_lookup(nexus->challenge_data, "kpp");
+	kv =	(char *)g_hash_table_lookup(nexus->challenge_data, "kv");
+	ver=	(char *)g_hash_table_lookup(nexus->challenge_data, "ver");
+	rn =	(char *)g_hash_table_lookup(nexus->challenge_data, "rn");
+	tpf=	(char *)g_hash_table_lookup(nexus->challenge_data, "tpf");
 
-	ctint = strtoul((char *)g_hash_table_lookup(nexus->challenge_data, "ct"), NULL, 10) + 200;
+	/*
+	 * add some fail-safe code to avoid windows Purple Crash bug #1540454
+	 * If any of these string is NULL, will return Authentication Fail!
+	 * for when windows g_strdup_printf() implementation get NULL point,It crashed!
+	 */
+	if(!(lc && id && tw && ru && ct && kpp && kv && ver && tpf)){
+		purple_debug_error("MSN Nexus","WLM Authenticate Key Error!\n");
+		msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication Failed"));
+		g_free(username);
+		g_free(password);
+		purple_ssl_close(gsc);
+		msn_nexus_destroy(nexus);
+		session->nexus = NULL;
+		return FALSE;
+	}
 
-	head = g_strdup_printf(
-		"GET %s HTTP/1.1\r\n"
-		"Authorization: Passport1.4 OrgVerb=GET,OrgURL=%s,sign-in=%s",
-		nexus->login_path,
-		(char *)g_hash_table_lookup(nexus->challenge_data, "ru"),
-		username);
+	/*
+	 * in old MSN NS server's "USR TWN S" return,didn't include fs string
+	 * so we use a default "1" for fs.
+	 */
+	if(fs0){
+		fs = g_strdup(fs0);
+	}else{
+		fs = g_strdup("1");
+	}
 
-	tail = g_strdup_printf(
-		"lc=%s,id=%s,tw=%s,fs=%s,ru=%s,ct=%" G_GUINT32_FORMAT ",kpp=%s,kv=%s,ver=%s,tpf=%s\r\n"
-		"User-Agent: MSMSGS\r\n"
-		"Host: %s\r\n"
-		"Connection: Keep-Alive\r\n"
-		"Cache-Control: no-cache\r\n",
-		nexus_challenge_data_lookup(nexus->challenge_data, "lc"),
-		nexus_challenge_data_lookup(nexus->challenge_data, "id"),
-		nexus_challenge_data_lookup(nexus->challenge_data, "tw"),
-		nexus_challenge_data_lookup(nexus->challenge_data, "fs"),
-		nexus_challenge_data_lookup(nexus->challenge_data, "ru"),
-		ctint,
-		nexus_challenge_data_lookup(nexus->challenge_data, "kpp"),
-		nexus_challenge_data_lookup(nexus->challenge_data, "kv"),
-		nexus_challenge_data_lookup(nexus->challenge_data, "ver"),
-		nexus_challenge_data_lookup(nexus->challenge_data, "tpf"),
-		nexus->login_host);
+#ifdef NEXUS_LOGIN_TWN
+	challenge_str = g_strdup_printf(
+		"lc=%s&amp;id=%s&amp;tw=%s&amp;fs=%s&amp;ru=%s&amp;ct=%s&amp;kpp=%s&amp;kv=%s&amp;ver=%s&amp;rn=%s&amp;tpf=%s\r\n",
+		lc,id,tw,fs,ru,ct,kpp,kv,ver,rn,tpf
+		);
 
-	buffer = g_strdup_printf("%s,pwd=XXXXXXXX,%s\r\n", head, tail);
-	request_str = g_strdup_printf("%s,pwd=%s,%s\r\n", head, password, tail);
+	/*build the SOAP windows Live ID XML body */
+	tail = g_strdup_printf(TWN_ENVELOP_TEMPLATE,username,password,challenge_str	);
+	g_free(challenge_str);
+#else
+	rst1_str = g_strdup_printf(
+		"id=%s&amp;tw=%s&amp;fs=%s&amp;kpp=%s&amp;kv=%s&amp;ver=%s&amp;rn=%s",
+		id,tw,fs,kpp,kv,ver,rn
+		);
+	rst2_str = g_strdup_printf(
+		"fs=%s&amp;id=%s&amp;kv=%s&amp;rn=%s&amp;tw=%s&amp;ver=%s",
+		fs,id,kv,rn,tw,ver
+		);
+	rst3_str = g_strdup_printf("id=%s",id);
+	tail = g_strdup_printf(TWN_LIVE_ENVELOP_TEMPLATE,username,password,rst1_str,rst2_str,rst3_str);
+	g_free(rst1_str);
+	g_free(rst2_str);
+	g_free(rst3_str);
+#endif
+	g_free(fs);
 
-	purple_debug_misc("msn", "Sending: {%s}\n", buffer);
+	soapconn->login_path = g_strdup(TWN_POST_URL);
+	head = g_strdup_printf(
+					"POST %s HTTP/1.1\r\n"
+					"Accept: text/*\r\n"
+					"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n"
+					"Host: %s\r\n"
+					"Content-Length: %" G_GSIZE_FORMAT "\r\n"
+					"Connection: Keep-Alive\r\n"
+					"Cache-Control: no-cache\r\n\r\n",
+					soapconn->login_path, soapconn->login_host, strlen(tail));
 
-	g_free(buffer);
+	request_str = g_strdup_printf("%s%s", head,tail);
+
+#ifdef MSN_SOAP_DEBUG	
+	purple_debug_misc("MSN Nexus", "TWN Sending:\n%s\n", request_str);
+#endif
 	g_free(head);
 	g_free(tail);
 	g_free(username);
 	g_free(password);
 
-	nexus->write_buf = request_str;
-	nexus->written_len = 0;
-
-	nexus->read_len = 0;
-
-	nexus->written_cb = nexus_login_written_cb;
+	/*prepare to send the SOAP request*/
+	msn_soap_write(soapconn, request_str, nexus_login_written_cb);
 
-	nexus->input_handler = purple_input_add(gsc->fd, PURPLE_INPUT_WRITE,
-		nexus_write_cb, nexus);
-
-	nexus_write_cb(nexus, gsc->fd, PURPLE_INPUT_WRITE);
-
-	return;
-
-
+	return TRUE;
 }
 
+#if 0 /* khc */
 static void
 nexus_connect_written_cb(gpointer data, gint source, PurpleInputCondition cond)
 {
 	MsnNexus *nexus = data;
 	int len;
+
 	char *da_login;
 	char *base, *c;
 
@@ -408,6 +359,7 @@
 		nexus->input_handler = purple_input_add(nexus->gsc->fd,
 			PURPLE_INPUT_READ, nexus_connect_written_cb, nexus);
 
+
 	/* Get the PassportURLs line. */
 	len = msn_ssl_read(nexus);
 
@@ -470,10 +422,13 @@
 }
 
 
+#endif
+
 /**************************************************************************
  * Connect
  **************************************************************************/
 
+#if 0 /* khc */
 static void
 nexus_connect_cb(gpointer data, PurpleSslConnection *gsc,
 				 PurpleInputCondition cond)
@@ -502,10 +457,12 @@
 	nexus_write_cb(nexus, gsc->fd, PURPLE_INPUT_WRITE);
 }
 
+#endif
+
 void
 msn_nexus_connect(MsnNexus *nexus)
 {
-	nexus->gsc = purple_ssl_connect(nexus->session->account,
-			"nexus.passport.com", PURPLE_SSL_DEFAULT_PORT,
-			nexus_connect_cb, login_error_cb, nexus);
+	/*  Authenticate via Windows Live ID. */
+	msn_soap_init(nexus->soapconn, MSN_TWN_SERVER, 1, nexus_login_connect_cb, nexus_login_error_cb);
+	msn_soap_connect(nexus->soapconn);
 }
--- a/libpurple/protocols/msn/nexus.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/nexus.h	Fri Sep 28 16:34:43 2007 +0000
@@ -24,25 +24,124 @@
 #ifndef _MSN_NEXUS_H_
 #define _MSN_NEXUS_H_
 
+#include "soap.h"
+
+/*#define MSN_TWN_SERVER	"loginnet.passport.com"*/
+#define MSN_TWN_SERVER	"login.live.com"
+
+#define TWN_START_TOKEN		"<wsse:BinarySecurityToken Id=\"PPToken1\">"
+#define TWN_END_TOKEN		"</wsse:BinarySecurityToken>"
+
+#define TWN_POST_URL			"/RST.srf"
+#define TWN_ENVELOP_TEMPLATE 	"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"\
+						"<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\" xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\" xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">"\
+						"<Header>"\
+						"<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">"\
+						"<ps:HostingApp>{3:B}</ps:HostingApp>"\
+						"<ps:BinaryVersion>4</ps:BinaryVersion>"\
+						"<ps:UIVersion>1</ps:UIVersion>"\
+						"<ps:Cookies></ps:Cookies>"\
+						"<ps:RequestParams>AQAAAAIAAABsYwQAAAAzMDg0</ps:RequestParams>"\
+						"</ps:AuthInfo>"\
+						"<wsse:Security>"\
+						"<wsse:UsernameToken Id=\"user\">"\
+						"<wsse:Username>%s</wsse:Username>"\
+						"<wsse:Password>%s</wsse:Password>"\
+						"</wsse:UsernameToken>"\
+						"</wsse:Security>"\
+						"</Header>"\
+						"<Body>"\
+						"<ps:RequestMultipleSecurityTokens xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"RSTS\">"\
+						"<wst:RequestSecurityToken Id=\"RST0\">"\
+						"<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\
+						"<wsp:AppliesTo>"\
+						"<wsa:EndpointReference>"\
+						"<wsa:Address>http://Passport.NET/tb</wsa:Address>"\
+						"</wsa:EndpointReference>"\
+						"</wsp:AppliesTo>"\
+						"</wst:RequestSecurityToken>"\
+						"<wst:RequestSecurityToken Id=\"RST1\">"\
+						"<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\
+						"<wsp:AppliesTo>"\
+						"<wsa:EndpointReference>"\
+						"<wsa:Address>messenger.msn.com</wsa:Address>"\
+						"</wsa:EndpointReference>"\
+						"</wsp:AppliesTo>"\
+						"<wsse:PolicyReference URI=\"?%s\">"\
+						"</wsse:PolicyReference>"\
+						"</wst:RequestSecurityToken>"\
+						"</ps:RequestMultipleSecurityTokens>"\
+						"</Body>"\
+						"</Envelope>"
+
+#define TWN_LIVE_START_TOKEN	"<wsse:BinarySecurityToken Id=\"PPToken1\">"
+#define TWN_LIVE_END_TOKEN	"</wsse:BinarySecurityToken>"
+#define TWN_LIVE_ENVELOP_TEMPLATE	"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"\
+"<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\" xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\" xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">"\
+  "<Header>"\
+    "<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">"\
+      "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>"\
+      "<ps:BinaryVersion>4</ps:BinaryVersion>"\
+      "<ps:UIVersion>1</ps:UIVersion>"\
+      "<ps:Cookies></ps:Cookies>"\
+      "<ps:RequestParams>AQAAAAIAAABsYwQAAAAyMDUy</ps:RequestParams>"\
+    "</ps:AuthInfo>"\
+    "<wsse:Security>"\
+      "<wsse:UsernameToken Id=\"user\">"\
+        "<wsse:Username>%s</wsse:Username>"\
+        "<wsse:Password>%s</wsse:Password>"\
+      "</wsse:UsernameToken>"\
+    "</wsse:Security>"\
+  "</Header>"\
+  "<Body>"\
+    "<ps:RequestMultipleSecurityTokens xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"RSTS\">"\
+      "<wst:RequestSecurityToken Id=\"RST0\">"\
+        "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\
+        "<wsp:AppliesTo>"\
+          "<wsa:EndpointReference>"\
+            "<wsa:Address>http://Passport.NET/tb</wsa:Address>"\
+          "</wsa:EndpointReference>"\
+        "</wsp:AppliesTo>"\
+      "</wst:RequestSecurityToken>"\
+      "<wst:RequestSecurityToken Id=\"RST1\">"\
+        "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\
+        "<wsp:AppliesTo>"\
+          "<wsa:EndpointReference>"\
+            "<wsa:Address>messenger.msn.com</wsa:Address>"\
+          "</wsa:EndpointReference>"\
+        "</wsp:AppliesTo>"\
+        "<wsse:PolicyReference URI=\"?%s\"></wsse:PolicyReference>"\
+      "</wst:RequestSecurityToken>"\
+      "<wst:RequestSecurityToken Id=\"RST2\">"\
+        "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\
+        "<wsp:AppliesTo>"\
+          "<wsa:EndpointReference>"\
+            "<wsa:Address>contacts.msn.com</wsa:Address>"\
+         "</wsa:EndpointReference>"\
+        "</wsp:AppliesTo>"\
+       "<wsse:PolicyReference URI=\"?%s\"></wsse:PolicyReference>"\
+     " </wst:RequestSecurityToken>"\
+      "<wst:RequestSecurityToken Id=\"RST3\">"\
+        "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\
+        "<wsp:AppliesTo>"\
+          "<wsa:EndpointReference>"\
+            "<wsa:Address>voice.messenger.msn.com</wsa:Address>"\
+          "</wsa:EndpointReference>"\
+       " </wsp:AppliesTo>"\
+        "<wsse:PolicyReference URI=\"?%s\"></wsse:PolicyReference>"\
+      "</wst:RequestSecurityToken>"\
+    "</ps:RequestMultipleSecurityTokens>"\
+  "</Body>"\
+"</Envelope>"
+
 typedef struct _MsnNexus MsnNexus;
 
 struct _MsnNexus
 {
 	MsnSession *session;
-
-	char *login_host;
-	char *login_path;
+	MsnSoapConn *soapconn;
+	char * challenge_data_str;
 	GHashTable *challenge_data;
-	PurpleSslConnection *gsc;
-
-	guint input_handler;
-
-	char *write_buf;
-	gsize written_len;
-	PurpleInputFunction written_cb;
-
-	char *read_buf;
-	gsize read_len;
 };
 
 void msn_nexus_connect(MsnNexus *nexus);
--- a/libpurple/protocols/msn/notification.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/notification.c	Fri Sep 28 16:34:43 2007 +0000
@@ -25,7 +25,7 @@
 #include "notification.h"
 #include "state.h"
 #include "error.h"
-#include "msn-utils.h"
+#include "msnutils.h"
 #include "page.h"
 
 #include "userlist.h"
@@ -34,6 +34,15 @@
 
 static MsnTable *cbs_table;
 
+/****************************************************************************
+ * 	Local Function Prototype
+ ****************************************************************************/
+
+static void msn_notification_post_adl(MsnCmdProc *cmdproc, const char *payload, int payload_len);
+static void
+msn_add_contact_xml(MsnSession *session, xmlnode *mlNode,const char *passport,
+					 MsnListOp list_op, MsnUserType type);
+
 /**************************************************************************
  * Main
  **************************************************************************/
@@ -102,9 +111,11 @@
 	account = session->account;
 
 	/* Allocate an array for CVR0, NULL, and all the versions */
-	a = c = g_new0(char *, session->protocol_ver - 8 + 3);
+//	a = c = g_new0(char *, session->protocol_ver - WLM_MIN_PROTOCOL + 3);
+	a = c = g_new0(char *, WLM_MAX_PROTOCOL - WLM_MIN_PROTOCOL + 3);
 
-	for (i = session->protocol_ver; i >= 8; i--)
+//	for (i = session->protocol_ver; i >= WLM_MIN_PROTOCOL; i--)
+	for (i = WLM_MAX_PROTOCOL; i >= WLM_MIN_PROTOCOL; i--)
 		*c++ = g_strdup_printf("MSNP%d", i);
 
 	*c++ = g_strdup("CVR0");
@@ -112,9 +123,13 @@
 	vers = g_strjoinv(" ", a);
 
 	if (session->login_step == MSN_LOGIN_STEP_START)
+	{
 		msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE);
+	}
 	else
+	{
 		msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE2);
+	}
 
 	msn_cmdproc_send(cmdproc, "VER", "%s", vers);
 
@@ -153,7 +168,7 @@
  **************************************************************************/
 
 static void
-group_error_helper(MsnSession *session, const char *msg, int group_id, int error)
+group_error_helper(MsnSession *session, const char *msg, const char *group_id, int error)
 {
 	PurpleAccount *account;
 	PurpleConnection *gc;
@@ -172,9 +187,7 @@
 		else
 		{
 			const char *group_name;
-			group_name =
-				msn_userlist_find_group_name(session->userlist,
-											 group_id);
+			group_name = msn_userlist_find_group_name(session->userlist,group_id);
 			reason = g_strdup_printf(_("%s is not a valid group."),
 									 group_name);
 		}
@@ -214,7 +227,6 @@
 	PurpleAccount *account;
 
 	account = cmdproc->session->account;
-
 	msn_cmdproc_send(cmdproc, "USR", "TWN I %s",
 					 purple_account_get_username(account));
 }
@@ -232,14 +244,17 @@
 
 	if (!g_ascii_strcasecmp(cmd->params[1], "OK"))
 	{
-		/* OK */
+		/* authenticate OK */
+		/* friendly name part no longer true in msnp11 */
+#if 0
 		const char *friendly = purple_url_decode(cmd->params[3]);
 
 		purple_connection_set_display_name(gc, friendly);
-
+#endif
 		msn_session_set_login_step(session, MSN_LOGIN_STEP_SYN);
 
-		msn_cmdproc_send(cmdproc, "SYN", "%s", "0");
+//		msn_cmdproc_send(cmdproc, "SYN", "%s", "0");
+		//TODO we should use SOAP contact to fetch contact list
 	}
 	else if (!g_ascii_strcasecmp(cmd->params[1], "TWN"))
 	{
@@ -249,15 +264,20 @@
 		session->nexus = msn_nexus_new(session);
 
 		/* Parse the challenge data. */
-
+		session->nexus->challenge_data_str = g_strdup(cmd->params[3]);
 		elems = g_strsplit(cmd->params[3], ",", 0);
 
 		for (cur = elems; *cur != NULL; cur++)
 		{
-				tokens = g_strsplit(*cur, "=", 2);
+			tokens = g_strsplit(*cur, "=", 2);
+			if(tokens[0]&&tokens[1])
+			{
+				purple_debug_info("MSNP14","challenge %p,key:%s,value:%s\n",
+									session->nexus->challenge_data,tokens[0],tokens[1]);
 				g_hash_table_insert(session->nexus->challenge_data, tokens[0], tokens[1]);
-				/* Don't free each of the tokens, only the array. */
-				g_free(tokens);
+			}
+			/* Don't free each of the tokens, only the array. */
+			g_free(tokens);
 		}
 
 		g_strfreev(elems);
@@ -322,8 +342,15 @@
 		return;
 	}
 
+	/*
+	 * Windows Live Messenger 8.0 
+	 * Notice :CVR String discriminate!
+	 * reference of http://www.microsoft.com/globaldev/reference/oslocversion.mspx
+	 * to see the Local ID
+	 */
 	msn_cmdproc_send(cmdproc, "CVR",
-					 "0x0409 winnt 5.1 i386 MSNMSGR 6.0.0602 MSMSGS %s",
+//					 "0x0409 winnt 5.1 i386 MSG80BETA 8.0.0689 msmsgs %s",
+					"0x0804 winnt 5.1 i386 MSNMSGR 8.0.0792 msmsgs %s",
 					 purple_account_get_username(account));
 }
 
@@ -366,7 +393,7 @@
 
 	msg = msn_message_new_from_cmd(cmdproc->session, cmd);
 
-	msn_message_parse_payload(msg, payload, len);
+	msn_message_parse_payload(msg, payload, len,MSG_LINE_DEM,MSG_BODY_DEM);
 #ifdef MSN_DEBUG_NS
 	msn_message_show_readable(msg, "Notification", TRUE);
 #endif
@@ -379,9 +406,12 @@
 static void
 msg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
+	purple_debug_info("MSNP14","Processing MSG... \n");
+	if(cmd->payload_len == 0){
+		return;
+	}
 	/* NOTE: cmd is not always cmdproc->last_cmd, sometimes cmd is a queued
 	 * command and we are processing it */
-
 	if (cmd->payload == NULL)
 	{
 		cmdproc->last_cmd->payload_cb  = msg_cmd_post;
@@ -391,32 +421,145 @@
 	{
 		g_return_if_fail(cmd->payload_cb != NULL);
 
+		purple_debug_info("MSNP14","MSG payload:{%s}\n",cmd->payload);
 		cmd->payload_cb(cmdproc, cmd, cmd->payload, cmd->payload_len);
 	}
 }
 
+/*send Message to Yahoo Messenger*/
+void
+uum_send_msg(MsnSession *session,MsnMessage *msg)
+{
+	MsnCmdProc *cmdproc;
+	MsnTransaction *trans;
+	char *payload;
+	gsize payload_len;
+	int type;
+	
+	cmdproc = session->notification->cmdproc;
+	g_return_if_fail(msg     != NULL);
+	payload = msn_message_gen_payload(msg, &payload_len);
+	purple_debug_info("MSNP14","send UUM,payload{%s},strlen:%d,len:%d\n",
+		payload,strlen(payload),payload_len);
+	type = msg->type;
+	trans = msn_transaction_new(cmdproc, "UUM","%s 32 %d %d",msg->remote_user,type,payload_len);
+	msn_transaction_set_payload(trans, payload, strlen(payload));
+	msn_cmdproc_send_trans(cmdproc, trans);
+}
+
+static void
+ubm_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+			 size_t len)
+{
+	MsnMessage *msg;
+	PurpleConnection *gc;
+	const char *passport;
+	const char *content_type;
+
+	purple_debug_info("MSNP14","Process UBM payload:%s\n",payload);
+	msg = msn_message_new_from_cmd(cmdproc->session, cmd);
+
+	msn_message_parse_payload(msg, payload, len,MSG_LINE_DEM,MSG_BODY_DEM);
+#ifdef MSN_DEBUG_NS
+	msn_message_show_readable(msg, "Notification", TRUE);
+#endif
+
+	gc = cmdproc->session->account->gc;
+	passport = msg->remote_user;
+
+	content_type = msn_message_get_content_type(msg);
+	purple_debug_info("MSNP14","type:%d\n",content_type);
+	if(!strcmp(content_type,"text/plain")){
+		const char *value;
+		const char *body;
+		char *body_str;
+		char *body_enc;
+		char *body_final = NULL;
+		size_t body_len;
+
+		body = msn_message_get_bin_data(msg, &body_len);
+		body_str = g_strndup(body, body_len);
+		body_enc = g_markup_escape_text(body_str, -1);
+		g_free(body_str);
+
+		if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL)	{
+			char *pre, *post;
+
+			msn_parse_format(value, &pre, &post);
+			body_final = g_strdup_printf("%s%s%s", pre ? pre : "",
+							body_enc ? body_enc : "", post ? post : "");
+			g_free(pre);
+			g_free(post);
+		}
+		g_free(body_enc);
+		serv_got_im(gc, passport, body_final, 0, time(NULL));
+	}
+	if(!strcmp(content_type,"text/x-msmsgscontrol")){
+		if(msn_message_get_attr(msg, "TypingUser") != NULL){
+			serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT,
+						PURPLE_TYPING);
+		}
+	}
+	if(!strcmp(content_type,"text/x-msnmsgr-datacast")){
+		char *username, *str;
+		PurpleAccount *account;
+		PurpleBuddy *buddy;
+		const char *user;
+
+		account = cmdproc->session->account;
+		user = msg->remote_user;
+
+		if ((buddy = purple_find_buddy(account, user)) != NULL){
+			username = g_markup_escape_text(purple_buddy_get_alias(buddy), -1);
+		}else{
+			username = g_markup_escape_text(user, -1);
+		}
+
+		str = g_strdup_printf(_("%s just sent you a Nudge!"), username);
+		g_free(username);
+		msn_session_report_user(cmdproc->session,user,str,PURPLE_MESSAGE_SYSTEM);
+		g_free(str);
+	}
+	msn_message_destroy(msg);
+}
+
+/*Yahoo msg process*/
+static void
+ubm_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_info("MSNP14","Processing UBM... \n");
+	if(cmd->payload_len == 0){
+		return;
+	}
+	/* NOTE: cmd is not always cmdproc->last_cmd, sometimes cmd is a queued
+	 * command and we are processing it */
+	if (cmd->payload == NULL){
+		cmdproc->last_cmd->payload_cb  = ubm_cmd_post;
+		cmdproc->servconn->payload_len = atoi(cmd->params[2]);
+	}else{
+		g_return_if_fail(cmd->payload_cb != NULL);
+
+		purple_debug_info("MSNP14","UBM payload:{%s}\n",cmd->payload);
+		ubm_cmd_post(cmdproc, cmd, cmd->payload, cmd->payload_len);
+	}
+}
+
 /**************************************************************************
  * Challenges
+ *  we use MD5 to caculate the Challenges
  **************************************************************************/
-
 static void
 chl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnTransaction *trans;
 	char buf[33];
-	const char *challenge_resp;
-	PurpleCipher *cipher;
-	PurpleCipherContext *context;
-	guchar digest[16];
-	int i;
 
+#if 0
 	cipher = purple_ciphers_find_cipher("md5");
 	context = purple_cipher_context_new(cipher, NULL);
-
 	purple_cipher_context_append(context, (const guchar *)cmd->params[1],
 							   strlen(cmd->params[1]));
-
-	challenge_resp = "VT6PX?UQTM4WM%YR";
+	challenge_resp = MSNP13_WLM_PRODUCT_KEY;
 
 	purple_cipher_context_append(context, (const guchar *)challenge_resp,
 							   strlen(challenge_resp));
@@ -424,9 +567,14 @@
 	purple_cipher_context_destroy(context);
 
 	for (i = 0; i < 16; i++)
+	{
 		g_snprintf(buf + (i*2), 3, "%02x", digest[i]);
-
-	trans = msn_transaction_new(cmdproc, "QRY", "%s 32", "PROD0038W!61ZTF9");
+	}
+#else
+	msn_handle_chl(cmd->params[1], buf);
+#endif
+//	purple_debug_info("MSNP14","<<challenge:{%s}:{%s}\n",cmd->params[1],buf);
+	trans = msn_transaction_new(cmdproc, "QRY", "%s 32", MSNP13_WLM_PRODUCT_ID);
 
 	msn_transaction_set_payload(trans, buf, 32);
 
@@ -436,43 +584,301 @@
 /**************************************************************************
  * Buddy Lists
  **************************************************************************/
+/* add contact to xmlnode */
+static void
+msn_add_contact_xml(MsnSession *session, xmlnode *mlNode,const char *passport, MsnListOp list_op, MsnUserType type)
+{
+	xmlnode *d_node,*c_node;
+	char **tokens;
+	char *email,*domain;
+	char *list_op_str,*type_str;
+
+	purple_debug_info("MSNP14","Passport: %s, type: %d\n", passport, type);
+	tokens = g_strsplit(passport, "@", 2);
+	email = tokens[0];
+	domain = tokens[1];
+
+	/*find a domain Node*/
+	for(d_node = xmlnode_get_child(mlNode,"d"); d_node; d_node = xmlnode_get_next_twin(d_node))
+	{
+		const char * attr = NULL;
+		purple_debug_info("MSNP14","d_node: %s\n",d_node->name);
+		attr = xmlnode_get_attrib(d_node,"n");
+		if(attr == NULL){
+			continue;
+		}
+		if(!strcmp(attr,domain)){
+			break;
+		}
+	}
+	if(d_node == NULL)
+	{
+		/*domain not found, create a new domain Node*/
+		purple_debug_info("MSNP14","get No d_node\n");
+		d_node = xmlnode_new("d");
+		xmlnode_set_attrib(d_node,"n",domain);
+		xmlnode_insert_child(mlNode,d_node);
+	}
+
+	/*create contact node*/
+	c_node = xmlnode_new("c");
+	xmlnode_set_attrib(c_node,"n",email);
+
+	list_op_str = g_strdup_printf("%d",list_op);
+	purple_debug_info("MSNP14","list_op: %d\n",list_op);
+	xmlnode_set_attrib(c_node,"l",list_op_str);
+	g_free(list_op_str);
+
+	if (type != MSN_USER_TYPE_UNKNOWN) {
+		type_str = g_strdup_printf("%d", type);
+	} else {
+		if (msn_user_is_yahoo(session->account, passport))
+			type_str = g_strdup_printf("%d", MSN_USER_TYPE_YAHOO);
+		else
+			type_str = g_strdup_printf("%d", MSN_USER_TYPE_PASSPORT);
+	}
+	/*mobile*/
+	//type_str = g_strdup_printf("4");
+	xmlnode_set_attrib(c_node,"t",type_str);
+	g_free(type_str);
+
+	xmlnode_insert_child(d_node, c_node);
+
+	g_strfreev(tokens);
+}
 
 static void
-add_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+msn_notification_post_adl(MsnCmdProc *cmdproc, const char *payload, int payload_len)
+{
+	MsnTransaction *trans;
+	purple_debug_info("MSN Notification","Sending ADL with payload: %s\n", payload);
+	trans = msn_transaction_new(cmdproc, "ADL","%d", strlen(payload));
+	msn_transaction_set_payload(trans, payload, strlen(payload));
+	msn_cmdproc_send_trans(cmdproc, trans);
+}
+
+/*dump contact info to NS*/
+void
+msn_notification_dump_contact(MsnSession *session)
+{
+	MsnUser *user;
+	GList *l;
+	xmlnode *adl_node;
+	char *payload;
+	int payload_len;
+	int adl_count = 0;
+	const char *display_name;
+
+	adl_node = xmlnode_new("ml");
+	adl_node->child = NULL;
+	xmlnode_set_attrib(adl_node, "l", "1");
+
+	/*get the userlist*/
+	for (l = session->userlist->users; l != NULL; l = l->next){
+		user = l->data;
+
+		/* skip RL & PL during initial dump */
+		if (!(user->list_op & MSN_LIST_OP_MASK))
+			continue;
+
+		msn_add_contact_xml(session, adl_node, user->passport,
+			user->list_op & MSN_LIST_OP_MASK, user->type);
+
+		/* each ADL command may contain up to 150 contacts */
+		if (++adl_count % 150 == 0 || l->next == NULL) {
+			payload = xmlnode_to_str(adl_node,&payload_len);
+
+			msn_notification_post_adl(session->notification->cmdproc,
+				payload, payload_len);
+
+			g_free(payload);
+			xmlnode_free(adl_node);
+
+			if (l->next) {
+				adl_node = xmlnode_new("ml");
+				adl_node->child = NULL;
+				xmlnode_set_attrib(adl_node, "l", "1");
+			}
+		}
+	}
+
+	if (adl_count == 0) {
+		payload = xmlnode_to_str(adl_node,&payload_len);
+
+		msn_notification_post_adl(session->notification->cmdproc, payload, payload_len);
+
+		g_free(payload);
+		xmlnode_free(adl_node);
+	}
+
+	display_name = purple_connection_get_display_name(session->account->gc);
+	if (display_name 
+	    && strcmp(display_name, 
+		      purple_account_get_username(session->account))) {
+		msn_act_id(session->account->gc, display_name);
+	}
+
+}
+
+/*Post FQY to NS,Inform add a Yahoo User*/
+void
+msn_notification_send_fqy(MsnSession *session, const char *passport)
+{
+	MsnTransaction *trans;
+	MsnCmdProc *cmdproc;
+	char* email,*domain,*payload;
+	char **tokens;
+
+	cmdproc = session->notification->cmdproc;
+
+	tokens = g_strsplit(passport, "@", 2);
+	email = tokens[0];
+	domain = tokens[1];
+
+	payload = g_strdup_printf("<ml><d n=\"%s\"><c n=\"%s\"/></d></ml>", domain, email);
+	trans = msn_transaction_new(cmdproc, "FQY","%d", strlen(payload));
+	msn_transaction_set_payload(trans, payload, strlen(payload));
+	msn_cmdproc_send_trans(cmdproc, trans);
+
+	g_free(payload);
+	g_free(tokens);
+}
+
+static void
+blp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+}
+
+static void
+adl_cmd_parse(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+		                         size_t len)
+{
+	xmlnode *root, *domain_node;
+
+	purple_debug_misc("MSN Notification", "Parsing received ADL XML data\n");
+
+	g_return_if_fail(payload != NULL);
+	
+	root = xmlnode_from_str(payload, (gssize) len);
+	
+	if (root == NULL) {
+		purple_debug_info("MSN Notification", "Invalid XML!\n");
+		return;
+	}
+	for (domain_node = xmlnode_get_child(root, "d"); domain_node; domain_node = xmlnode_get_next_twin(domain_node)) {
+		const gchar * domain = NULL; 
+		xmlnode *contact_node = NULL;
+
+		domain = xmlnode_get_attrib(domain_node, "n");
+
+		for (contact_node = xmlnode_get_child(domain_node, "c"); contact_node; contact_node = xmlnode_get_next_twin(contact_node)) {
+//			gchar *name = NULL, *friendlyname = NULL, *passport= NULL;
+			const gchar *list;
+			gint list_op = 0;
+
+//			name = xmlnode_get_attrib(contact_node, "n");
+			list = xmlnode_get_attrib(contact_node, "l");
+			if (list != NULL) {
+				list_op = atoi(list);
+			}
+//			friendlyname = xmlnode_get_attrib(contact_node, "f");
+
+//			passport = g_strdup_printf("%s@%s", name, domain);
+
+//			if (friendlyname != NULL) {
+//				decoded_friendlyname = g_strdup(purple_url_decode(friendlyname));
+//			} else {
+//				decoded_friendlyname = g_strdup(passport);
+//			}
+
+			if (list_op & MSN_LIST_RL_OP) {
+				/* someone is adding us */
+//				got_new_entry(cmdproc->session->account->gc, passport, decoded_friendly_name);
+				msn_get_contact_list(cmdproc->session->contact, MSN_PS_PENDING_LIST, NULL);
+			}
+
+//			g_free(decoded_friendly_name);
+//			g_free(passport);
+		}
+	}
+
+	xmlnode_free(root);
+}
+
+static void
+adl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSession *session;
-	MsnUser *user;
-	const char *list;
-	const char *passport;
-	const char *friendly;
-	MsnListId list_id;
-	int group_id;
 
-	list     = cmd->params[1];
-	passport = cmd->params[3];
-	friendly = purple_url_decode(cmd->params[4]);
+	g_return_if_fail(cmdproc != NULL);
+	g_return_if_fail(cmdproc->session != NULL);
+	g_return_if_fail(cmdproc->last_cmd != NULL);
+	g_return_if_fail(cmd != NULL);
 
 	session = cmdproc->session;
 
-	user = msn_userlist_find_user(session->userlist, passport);
+	if ( !strcmp(cmd->params[1], "OK")) {
+		/* ADL ack */
+		msn_session_finish_login(session);
+	} else {
+		cmdproc->last_cmd->payload_cb = adl_cmd_parse;
+	}
+
+	return;
+}
 
-	if (user == NULL)
-	{
-		user = msn_user_new(session->userlist, passport, friendly);
-		msn_userlist_add_user(session->userlist, user);
-	}
-	else
-		msn_user_set_friendly_name(user, friendly);
+static void
+adl_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
+{
+	MsnSession *session;
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	char *reason = NULL;
+
+	session = cmdproc->session;
+	account = session->account;
+	gc = purple_account_get_connection(account);
+
+	purple_debug_error("msn","ADL error\n");
+	reason = g_strdup_printf(_("Unknown error (%d)"), error);
+	purple_notify_error(gc, NULL, _("Unable to add user"), reason);
+	g_free(reason);
+}
 
-	list_id = msn_get_list_id(list);
+static void
+fqy_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+			 size_t len)
+{
+	purple_debug_info("MSN Notification","FQY payload:\n%s\n", payload);
+	g_return_if_fail(cmdproc->session != NULL);
+	g_return_if_fail(cmdproc->session->contact != NULL);
+//	msn_notification_post_adl(cmdproc, payload, len);
+//	msn_get_address_book(cmdproc->session->contact, MSN_AB_SAVE_CONTACT, NULL, NULL);
+}
 
-	if (cmd->param_count >= 6)
-		group_id = atoi(cmd->params[5]);
-	else
-		group_id = -1;
+static void
+fqy_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_info("MSNP14","Process FQY\n");
+	cmdproc->last_cmd->payload_cb = fqy_cmd_post;
+}
 
-	msn_got_add_user(session, user, list_id, group_id);
-	msn_user_update(user);
+static void
+rml_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+#if 0
+	MsnTransaction *trans;
+	char * payload;
+#endif
+
+	purple_debug_info("MSNP14","Process RML\n");
+#if 0
+	trans = msn_transaction_new(cmdproc, "RML","");
+
+	msn_transaction_set_payload(trans, payload, strlen(payload));
+
+	msn_cmdproc_send_trans(cmdproc, trans);
+#endif
 }
 
 static void
@@ -567,24 +973,22 @@
 
 	group_name = purple_url_decode(cmd->params[2]);
 
-	msn_group_new(session->userlist, group_id, group_name);
+	msn_group_new(session->userlist, cmd->params[3], group_name);
 
-	/* There is a user that must me moved to this group */
+	/* There is a user that must be moved to this group */
 	if (cmd->trans->data)
 	{
 		/* msn_userlist_move_buddy(); */
 		MsnUserList *userlist = cmdproc->session->userlist;
-		MsnMoveBuddy *data = cmd->trans->data;
+		MsnCallbackState *data = cmd->trans->data;
 
 		if (data->old_group_name != NULL)
 		{
-			msn_userlist_rem_buddy(userlist, data->who, MSN_LIST_FL, data->old_group_name);
+			msn_userlist_move_buddy(userlist, data->who, data->old_group_name, group_name);
 			g_free(data->old_group_name);
+		} else {
+			// msn_add_contact_to_group(userlist, data, data->who, group_name);
 		}
-
-		msn_userlist_add_buddy(userlist, data->who, MSN_LIST_FL, group_name);
-		g_free(data->who);
-
 	}
 }
 
@@ -642,6 +1046,7 @@
 	PurpleConnection *gc;
 	MsnUser *user;
 	MsnObject *msnobj;
+	int wlmclient;
 	const char *state, *passport, *friendly;
 
 	session = cmdproc->session;
@@ -650,7 +1055,9 @@
 
 	state    = cmd->params[1];
 	passport = cmd->params[2];
-	friendly = purple_url_decode(cmd->params[3]);
+	/*if a contact is actually on the WLM part or the yahoo part*/
+	wlmclient = atoi(cmd->params[3]);
+	friendly = purple_url_decode(cmd->params[4]);
 
 	user = msn_userlist_find_user(session->userlist, passport);
 
@@ -658,9 +1065,9 @@
 
 	msn_user_set_friendly_name(user, friendly);
 
-	if (session->protocol_ver >= 9 && cmd->param_count == 6)
+	if (session->protocol_ver >= 9 && cmd->param_count == 8)
 	{
-		msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[5]));
+		msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[6]));
 		msn_user_set_object(user, msnobj);
 	}
 
@@ -692,6 +1099,7 @@
 	MsnUser *user;
 	MsnObject *msnobj;
 	int clientid;
+	int wlmclient;
 	const char *state, *passport, *friendly, *old_friendly;
 
 	session = cmdproc->session;
@@ -700,7 +1108,8 @@
 
 	state    = cmd->params[0];
 	passport = cmd->params[1];
-	friendly = purple_url_decode(cmd->params[2]);
+	wlmclient = atoi(cmd->params[2]);
+	friendly = purple_url_decode(cmd->params[3]);
 
 	user = msn_userlist_find_user(session->userlist, passport);
 
@@ -713,10 +1122,9 @@
 
 	if (session->protocol_ver >= 9)
 	{
-		if (cmd->param_count == 5)
+		if (cmd->param_count == 7)
 		{
-			msnobj =
-				msn_object_new_from_string(purple_url_decode(cmd->params[4]));
+			msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[5]));
 			msn_user_set_object(user, msnobj);
 		}
 		else
@@ -725,7 +1133,7 @@
 		}
 	}
 
-	clientid = atoi(cmd->params[3]);
+	clientid = atoi(cmd->params[4]);
 	user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE);
 
 	msn_user_set_state(user, state);
@@ -797,7 +1205,9 @@
 prp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSession *session = cmdproc->session;
-	const char *type, *value;
+	const char *type, *value, *friendlyname;
+
+	purple_debug_info("MSN Notification", "prp_cmd()\n");
 
 	g_return_if_fail(cmd->param_count >= 3);
 
@@ -821,6 +1231,18 @@
 			msn_user_set_work_phone(session->user, NULL);
 		else if (!strcmp(type, "PHM"))
 			msn_user_set_mobile_phone(session->user, NULL);
+		else {
+			type = cmd->params[1];
+			if (!strcmp(type, "MFN")) {
+				friendlyname = purple_url_decode(cmd->params[2]);
+				
+				msn_update_contact(session->contact, friendlyname);
+
+				purple_connection_set_display_name(
+					purple_account_get_connection(session->account),
+					friendlyname);
+			}
+		}
 	}
 }
 
@@ -828,11 +1250,10 @@
 reg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSession *session;
-	int group_id;
-	const char *group_name;
+	const char *group_id, *group_name;
 
 	session = cmdproc->session;
-	group_id = atoi(cmd->params[2]);
+	group_id = cmd->params[2];
 	group_name = purple_url_decode(cmd->params[3]);
 
 	msn_userlist_rename_group_id(session->userlist, group_id, group_name);
@@ -841,27 +1262,26 @@
 static void
 reg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
 {
-	int group_id;
+	const char * group_id;
 	char **params;
 
 	params = g_strsplit(trans->params, " ", 0);
 
-	group_id = atoi(params[0]);
+	group_id = params[0];
 
 	group_error_helper(cmdproc->session, _("Unable to rename group"), group_id, error);
 
 	g_strfreev(params);
 }
 
+#if 0
 static void
 rem_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSession *session;
 	MsnUser *user;
-	const char *list;
-	const char *passport;
+	const char *group_id, *list, *passport;
 	MsnListId list_id;
-	int group_id;
 
 	session = cmdproc->session;
 	list = cmd->params[1];
@@ -873,22 +1293,23 @@
 	list_id = msn_get_list_id(list);
 
 	if (cmd->param_count == 5)
-		group_id = atoi(cmd->params[4]);
+		group_id = cmd->params[4];
 	else
-		group_id = -1;
+		group_id = NULL;
 
 	msn_got_rem_user(session, user, list_id, group_id);
 	msn_user_update(user);
 }
+#endif
 
 static void
 rmg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSession *session;
-	int group_id;
+	const char *group_id;
 
 	session = cmdproc->session;
-	group_id = atoi(cmd->params[2]);
+	group_id = cmd->params[2];
 
 	msn_userlist_remove_group_id(session->userlist, group_id);
 }
@@ -896,18 +1317,19 @@
 static void
 rmg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
 {
-	int group_id;
+	const char *group_id;
 	char **params;
 
 	params = g_strsplit(trans->params, " ", 0);
 
-	group_id = atoi(params[0]);
+	group_id = params[0];
 
 	group_error_helper(cmdproc->session, _("Unable to delete group"), group_id, error);
 
 	g_strfreev(params);
 }
 
+#if 0
 static void
 syn_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
@@ -938,6 +1360,7 @@
 	session->sync = sync;
 	cmdproc->cbs_table = sync->cbs_table;
 }
+#endif
 
 /**************************************************************************
  * Misc commands
@@ -1146,6 +1569,103 @@
 	g_free(host);
 }
 
+static void
+gcf_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+			 size_t len)
+{
+	xmlnode * root;
+	gchar * buf;
+
+	g_return_if_fail(cmd->payload != NULL);
+
+	if ( (root = xmlnode_from_str(cmd->payload, cmd->payload_len)) == NULL)
+	{
+		purple_debug_error("MSN","Unable to parse GCF payload into a XML tree");
+		return;
+	}
+	
+	buf = xmlnode_to_formatted_str(root, NULL);
+
+	/* get the payload content */
+	purple_debug_info("MSNP14","GCF command payload:\n%s\n",buf);
+	
+	g_free(buf);
+	xmlnode_free(root);
+}
+
+static void
+gcf_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_info("MSNP14","Processing GCF command\n");
+	cmdproc->last_cmd->payload_cb  = gcf_cmd_post;
+	return;
+}
+
+static void
+sbs_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_info("MSNP14","Processing SBS... \n");
+	if(cmd->payload_len == 0){
+		return;
+	}
+	/*get the payload content*/
+}
+
+/*
+ * Get the UBX's PSM info
+ * Post it to the User status
+ * Thanks for Chris <ukdrizzle@yahoo.co.uk>'s code
+ */
+static void
+ubx_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+			 size_t len)
+{
+	MsnSession *session;
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	MsnUser *user;
+	const char *passport;
+	char *psm_str, *currentmedia_str, *str;
+
+	/*get the payload content*/
+//	purple_debug_info("MSNP14","UBX {%s} payload{%s}\n",cmd->params[0], cmd->payload);
+
+	session = cmdproc->session;
+	account = session->account;
+	gc = purple_account_get_connection(account);
+
+	passport = cmd->params[0];
+	user = msn_userlist_find_user(session->userlist, passport);
+	
+	psm_str = msn_get_psm(cmd->payload,len);
+	currentmedia_str = msn_parse_currentmedia(
+	                                 str = msn_get_currentmedia(cmd->payload, len));
+	g_free(str);
+
+	msn_user_set_statusline(user, psm_str);
+	msn_user_set_currentmedia(user, currentmedia_str);
+	msn_user_update(user);
+
+	g_free(psm_str);
+	g_free(currentmedia_str);
+}
+
+static void
+ubx_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_misc("MSNP14","UBX received.\n");
+	if(cmd->payload_len == 0){
+		return;
+	}
+	cmdproc->last_cmd->payload_cb  = ubx_cmd_post;
+}
+
+static void
+uux_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_misc("MSNP14","UUX received.\n");
+}
+
 /**************************************************************************
  * Message Types
  **************************************************************************/
@@ -1155,6 +1675,7 @@
 {
 	MsnSession *session;
 	const char *value;
+	const char *clLastChange;
 
 	session = cmdproc->session;
 
@@ -1187,10 +1708,27 @@
 	}
 
 	if ((value = msn_message_get_attr(msg, "ClientPort")) != NULL)
+	{
 		session->passport_info.client_port = ntohs(atoi(value));
+	}
 
 	if ((value = msn_message_get_attr(msg, "LoginTime")) != NULL)
 		session->passport_info.sl = atol(value);
+
+	/*starting retrieve the contact list*/
+	clLastChange = purple_account_get_string(session->account, "CLLastChange", NULL);
+	session->contact = msn_contact_new(session);
+#ifdef MSN_PARTIAL_LISTS
+	/* msn_userlist_load defeats all attempts at trying to detect blist sync issues */
+	msn_userlist_load(session);
+	msn_get_contact_list(session->contact, MSN_PS_INITIAL, clLastChange);
+#else
+	/* always get the full list? */
+	msn_get_contact_list(session->contact, MSN_PS_INITIAL, NULL);
+#endif
+#if 0
+	msn_contact_connect(session->contact);
+#endif
 }
 
 static void
@@ -1246,6 +1784,86 @@
 	g_hash_table_destroy(table);
 }
 
+/*offline Message notification process*/
+static void
+initial_mdata_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
+{
+	MsnSession *session;
+	PurpleConnection *gc;
+	GHashTable *table;
+	const char *mdata, *unread;
+
+	session = cmdproc->session;
+	gc = session->account->gc;
+
+	if (strcmp(msg->remote_user, "Hotmail"))
+		/* This isn't an official message. */
+		return;
+
+	/*new a oim session*/
+	session->oim = msn_oim_new(session);
+//	msn_oim_connect(session->oim);
+
+	table = msn_message_get_hashtable_from_body(msg);
+
+	mdata = g_hash_table_lookup(table, "Mail-Data");
+
+	if (mdata != NULL)
+		msn_parse_oim_msg(session->oim, mdata);
+
+	if (g_hash_table_lookup(table, "Inbox-URL") == NULL)
+	{
+		g_hash_table_destroy(table);
+		return;
+	}
+
+	if (session->passport_info.file == NULL)
+	{
+		MsnTransaction *trans;
+		trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX");
+		msn_transaction_queue_cmd(trans, msg->cmd);
+
+		msn_cmdproc_send_trans(cmdproc, trans);
+
+		g_hash_table_destroy(table);
+		return;
+	}
+
+	if (!purple_account_get_check_mail(session->account))
+	{
+		g_hash_table_destroy(table);
+		return;
+	}
+
+	unread = g_hash_table_lookup(table, "Inbox-Unread");
+
+	if (unread != NULL)
+	{
+		int count = atoi(unread);
+
+		if (count > 0)
+		{
+			const char *passport;
+			const char *url;
+
+			passport = msn_user_get_passport(session->user);
+			url = session->passport_info.file;
+
+			purple_notify_emails(gc, atoi(unread), FALSE, NULL, NULL,
+							   &passport, &url, NULL, NULL);
+		}
+	}
+
+	g_hash_table_destroy(table);
+}
+
+/*offline Message Notification*/
+static void
+delete_oim_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
+{
+	purple_debug_misc("MSN Notification","Delete OIM message.\n");
+}
+
 static void
 email_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
 {
@@ -1347,48 +1965,62 @@
 }
 
 void
-msn_notification_add_buddy(MsnNotification *notification, const char *list,
-						   const char *who, const char *store_name,
-						   int group_id)
+msn_notification_add_buddy_to_list(MsnNotification *notification, MsnListId list_id,
+						   	  const char *who)
 {
 	MsnCmdProc *cmdproc;
+	MsnListOp list_op = 1 << list_id;
+	xmlnode *adl_node;
+	char *payload;
+	int payload_len;
+
 	cmdproc = notification->servconn->cmdproc;
 
-	if (group_id < 0 && !strcmp(list, "FL"))
-		group_id = 0;
+	adl_node = xmlnode_new("ml");
+	adl_node->child = NULL;
+
+	msn_add_contact_xml(notification->session, adl_node, who, list_op, 
+						MSN_USER_TYPE_PASSPORT);
 
-	if (group_id >= 0)
-	{
-		msn_cmdproc_send(cmdproc, "ADD", "%s %s %s %d",
-						 list, who, store_name, group_id);
-	}
-	else
-	{
-		msn_cmdproc_send(cmdproc, "ADD", "%s %s %s", list, who, store_name);
-	}
+	payload = xmlnode_to_str(adl_node,&payload_len);
+	xmlnode_free(adl_node);
+	
+	msn_notification_post_adl(notification->servconn->cmdproc,
+						payload,payload_len);
+	g_free(payload);
 }
 
 void
-msn_notification_rem_buddy(MsnNotification *notification, const char *list,
-						   const char *who, int group_id)
+msn_notification_rem_buddy_from_list(MsnNotification *notification, MsnListId list_id,
+						   const char *who)
 {
 	MsnCmdProc *cmdproc;
+	MsnTransaction *trans;
+	MsnListOp list_op = 1 << list_id;
+	xmlnode *rml_node;
+	char *payload;
+	int payload_len;
+
 	cmdproc = notification->servconn->cmdproc;
 
-	if (group_id >= 0)
-	{
-		msn_cmdproc_send(cmdproc, "REM", "%s %s %d", list, who, group_id);
-	}
-	else
-	{
-		msn_cmdproc_send(cmdproc, "REM", "%s %s", list, who);
-	}
+	rml_node = xmlnode_new("ml");
+	rml_node->child = NULL;
+
+	msn_add_contact_xml(notification->session, rml_node, who, list_op, MSN_USER_TYPE_PASSPORT);
+
+	payload = xmlnode_to_str(rml_node, &payload_len);
+	xmlnode_free(rml_node);
+
+	purple_debug_info("MSN Notification","Send RML with payload:\n%s\n", payload);
+	trans = msn_transaction_new(cmdproc, "RML","%d", strlen(payload));
+	msn_transaction_set_payload(trans, payload, strlen(payload));
+	msn_cmdproc_send_trans(cmdproc, trans);
+	g_free(payload);
 }
 
 /**************************************************************************
  * Init
  **************************************************************************/
-
 void
 msn_notification_init(void)
 {
@@ -1399,18 +2031,18 @@
 	/* Synchronous */
 	msn_table_add_cmd(cbs_table, "CHG", "CHG", NULL);
 	msn_table_add_cmd(cbs_table, "CHG", "ILN", iln_cmd);
-	msn_table_add_cmd(cbs_table, "ADD", "ADD", add_cmd);
-	msn_table_add_cmd(cbs_table, "ADD", "ILN", iln_cmd);
-	msn_table_add_cmd(cbs_table, "REM", "REM", rem_cmd);
+	msn_table_add_cmd(cbs_table, "ADL", "ILN", iln_cmd);
+//	msn_table_add_cmd(cbs_table, "REM", "REM", rem_cmd);	/* Removed as of MSNP13 */
 	msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd);
 	msn_table_add_cmd(cbs_table, "USR", "XFR", xfr_cmd);
-	msn_table_add_cmd(cbs_table, "SYN", "SYN", syn_cmd);
+	msn_table_add_cmd(cbs_table, "USR", "GCF", gcf_cmd);
+//	msn_table_add_cmd(cbs_table, "SYN", "SYN", syn_cmd);	/* Removed as of MSNP13 */
 	msn_table_add_cmd(cbs_table, "CVR", "CVR", cvr_cmd);
 	msn_table_add_cmd(cbs_table, "VER", "VER", ver_cmd);
 	msn_table_add_cmd(cbs_table, "REA", "REA", rea_cmd);
 	msn_table_add_cmd(cbs_table, "PRP", "PRP", prp_cmd);
-	/* msn_table_add_cmd(cbs_table, "BLP", "BLP", blp_cmd); */
-	msn_table_add_cmd(cbs_table, "BLP", "BLP", NULL);
+	msn_table_add_cmd(cbs_table, "BLP", "BLP", blp_cmd);
+//	msn_table_add_cmd(cbs_table, "BLP", "BLP", NULL);
 	msn_table_add_cmd(cbs_table, "REG", "REG", reg_cmd);
 	msn_table_add_cmd(cbs_table, "ADG", "ADG", adg_cmd);
 	msn_table_add_cmd(cbs_table, "RMG", "RMG", rmg_cmd);
@@ -1419,11 +2051,15 @@
 	/* Asynchronous */
 	msn_table_add_cmd(cbs_table, NULL, "IPG", ipg_cmd);
 	msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "UBM", ubm_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "GCF", gcf_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "SBS", sbs_cmd);
 	msn_table_add_cmd(cbs_table, NULL, "NOT", not_cmd);
 
 	msn_table_add_cmd(cbs_table, NULL, "CHL", chl_cmd);
-	msn_table_add_cmd(cbs_table, NULL, "REM", rem_cmd);
-	msn_table_add_cmd(cbs_table, NULL, "ADD", add_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "RML", rml_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "ADL", adl_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "FQY", fqy_cmd);
 
 	msn_table_add_cmd(cbs_table, NULL, "QRY", NULL);
 	msn_table_add_cmd(cbs_table, NULL, "QNG", qng_cmd);
@@ -1433,11 +2069,15 @@
 	msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd);
 	msn_table_add_cmd(cbs_table, NULL, "RNG", rng_cmd);
 
+	msn_table_add_cmd(cbs_table, NULL, "UBX", ubx_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "UUX", uux_cmd);
+
 	msn_table_add_cmd(cbs_table, NULL, "URL", url_cmd);
 
 	msn_table_add_cmd(cbs_table, "fallback", "XFR", xfr_cmd);
 
 	msn_table_add_error(cbs_table, "ADD", add_error);
+	msn_table_add_error(cbs_table, "ADL", adl_error);
 	msn_table_add_error(cbs_table, "REG", reg_error);
 	msn_table_add_error(cbs_table, "RMG", rmg_error);
 	/* msn_table_add_error(cbs_table, "REA", rea_error); */
@@ -1446,12 +2086,24 @@
 	msn_table_add_msg_type(cbs_table,
 						   "text/x-msmsgsprofile",
 						   profile_msg);
+	/*initial OIM notification*/
+	msn_table_add_msg_type(cbs_table,
+							"text/x-msmsgsinitialmdatanotification",
+							initial_mdata_msg);	
+	/*OIM notification when user online*/
+	msn_table_add_msg_type(cbs_table,
+							"text/x-msmsgsoimnotification",
+							initial_mdata_msg);	
 	msn_table_add_msg_type(cbs_table,
 						   "text/x-msmsgsinitialemailnotification",
 						   initial_email_msg);
 	msn_table_add_msg_type(cbs_table,
 						   "text/x-msmsgsemailnotification",
 						   email_msg);
+	/*delete an offline Message notification*/
+	msn_table_add_msg_type(cbs_table,
+							"text/x-msmsgsactivemailnotification",
+						   delete_oim_msg);
 	msn_table_add_msg_type(cbs_table,
 						   "application/x-msmsgssystemmessage",
 						   system_msg);
@@ -1462,3 +2114,4 @@
 {
 	msn_table_destroy(cbs_table);
 }
+
--- a/libpurple/protocols/msn/notification.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/notification.h	Fri Sep 28 16:34:43 2007 +0000
@@ -24,6 +24,14 @@
 #ifndef _MSN_NOTIFICATION_H_
 #define _MSN_NOTIFICATION_H_
 
+/*MSN protocol challenge info*/
+/*MSNP13 challenge*/
+#define MSNP13_WLM_PRODUCT_KEY	"O4BG@C7BWLYQX?5G"
+#define MSNP13_WLM_PRODUCT_ID	"PROD01065C%ZFN6F"
+
+#define MSNP10_PRODUCT_KEY		"VT6PX?UQTM4WM%YR"
+#define MSNP10_PRODUCT_ID		"PROD0038W!61ZTF9" 
+
 typedef struct _MsnNotification MsnNotification;
 
 #include "session.h"
@@ -40,21 +48,24 @@
 };
 
 #include "state.h"
+void uum_send_msg(MsnSession *session,MsnMessage *msg);
 
 void msn_notification_end(void);
 void msn_notification_init(void);
 
-void msn_notification_add_buddy(MsnNotification *notification,
-								const char *list, const char *who,
-								const char *store_name, int group_id);
-void msn_notification_rem_buddy(MsnNotification *notification,
-								const char *list, const char *who,
-								int group_id);
+void msn_notification_add_buddy_to_list(MsnNotification *notification,
+					MsnListId list_id, const char *who);
+void msn_notification_rem_buddy_from_list(MsnNotification *notification,
+					  MsnListId list_id, const char *who);
+
+void msn_notification_send_fqy(MsnSession *session, const char *passport);
+
 MsnNotification *msn_notification_new(MsnSession *session);
 void msn_notification_destroy(MsnNotification *notification);
 gboolean msn_notification_connect(MsnNotification *notification,
-							  const char *host, int port);
+				  const char *host, int port);
 void msn_notification_disconnect(MsnNotification *notification);
+void msn_notification_dump_contact(MsnSession *session);
 
 /**
  * Closes a notification.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/msn/oim.c	Fri Sep 28 16:34:43 2007 +0000
@@ -0,0 +1,712 @@
+/**
+ * @file oim.c 
+ * 	get and send MSN offline Instant Message via SOAP request
+ *	Author
+ * 		MaYuan<mayuan2006@gmail.com>
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "msn.h"
+#include "soap.h"
+#include "oim.h"
+#include "msnutils.h"
+
+/*Local Function Prototype*/
+static void msn_oim_post_single_get_msg(MsnOim *oim,const char *msgid);
+static MsnOimSendReq *msn_oim_new_send_req(const char *from_member,
+					   const char *friendname,
+					   const char* to_member,
+					   gint send_seq,
+					   const char *msg);
+static void msn_oim_retrieve_connect_init(MsnSoapConn *soapconn);
+static void msn_oim_send_connect_init(MsnSoapConn *soapconn);
+static void msn_oim_free_send_req(MsnOimSendReq *req);
+static void msn_oim_report_to_user(MsnOim *oim, const char *msg_str);
+static void msn_oim_get_process(MsnOim *oim, const char *oim_msg);
+static char *msn_oim_msg_to_str(MsnOim *oim, const char *body);
+static void msn_oim_send_process(MsnOim *oim, const char *body, int len);
+
+/*new a OIM object*/
+MsnOim *
+msn_oim_new(MsnSession *session)
+{
+	MsnOim *oim;
+
+	oim = g_new0(MsnOim, 1);
+	oim->session = session;
+	oim->retrieveconn = msn_soap_new(session,oim,1);
+	
+	oim->oim_list	= NULL;
+	oim->sendconn = msn_soap_new(session,oim,1);
+	oim->run_id = rand_guid();
+	oim->challenge = NULL;
+	oim->send_queue = g_queue_new();
+	oim->send_seq = 1;
+	return oim;
+}
+
+/*destroy the oim object*/
+void
+msn_oim_destroy(MsnOim *oim)
+{
+	MsnOimSendReq *request;
+	
+	purple_debug_info("OIM","destroy the OIM \n");
+	msn_soap_destroy(oim->retrieveconn);
+	msn_soap_destroy(oim->sendconn);
+	g_free(oim->run_id);
+	g_free(oim->challenge);
+	
+	while((request = g_queue_pop_head(oim->send_queue)) != NULL){
+		msn_oim_free_send_req(request);
+	}
+	g_queue_free(oim->send_queue);
+	
+	g_free(oim);
+}
+
+static MsnOimSendReq *
+msn_oim_new_send_req(const char *from_member, const char*friendname,
+					 const char* to_member, gint send_seq,
+					 const char *msg)
+{
+	MsnOimSendReq *request;
+	
+	request = g_new0(MsnOimSendReq, 1);
+	request->from_member	=g_strdup(from_member);
+	request->friendname		= g_strdup(friendname);
+	request->to_member		= g_strdup(to_member);
+	request->send_seq		= send_seq;
+	request->oim_msg		= g_strdup(msg);
+	return request;
+}
+
+static void
+msn_oim_free_send_req(MsnOimSendReq *req)
+{
+	g_return_if_fail(req != NULL);
+
+	g_free(req->from_member);
+	g_free(req->friendname);
+	g_free(req->to_member);
+	g_free(req->oim_msg);
+	
+	g_free(req);
+}
+
+/****************************************
+ * OIM send SOAP request
+ * **************************************/
+/*encode the message to OIM Message Format*/
+static char *
+msn_oim_msg_to_str(MsnOim *oim, const char *body)
+{
+	char *oim_body,*oim_base64;
+	
+	purple_debug_info("MSN OIM","encode OIM Message...\n");	
+	oim_base64 = purple_base64_encode((const guchar *)body, strlen(body));
+	purple_debug_info("MSN OIM","encoded base64 body:{%s}\n",oim_base64);	
+	oim_body = g_strdup_printf(MSN_OIM_MSG_TEMPLATE,
+				oim->run_id,oim->send_seq,oim_base64);
+
+	return oim_body;
+}
+
+/*oim SOAP server login error*/
+static void
+msn_oim_send_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error)
+{
+	MsnSession *session;
+
+	session = soapconn->session;
+	g_return_if_fail(session != NULL);
+
+	msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to OIM server"));
+}
+
+/*msn oim SOAP server connect process*/
+static gboolean
+msn_oim_send_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc)
+{
+	MsnSession * session;
+	MsnOim *oim;
+
+	oim = soapconn->parent;
+	g_return_val_if_fail(oim != NULL, TRUE);
+
+	session = oim->session;
+	g_return_val_if_fail(session != NULL, FALSE);
+
+	return TRUE;
+}
+
+/*
+ * Process the send return SOAP string
+ * If got SOAP Fault,get the lock key,and resend it.
+ */
+static void
+msn_oim_send_process(MsnOim *oim, const char *body, int len)
+{
+	xmlnode *responseNode, *bodyNode;
+	xmlnode	*faultNode, *faultCodeNode, *faultstringNode;
+	xmlnode *detailNode, *challengeNode;
+	char *faultCodeStr = NULL, *faultstring = NULL;
+
+	responseNode = xmlnode_from_str(body,len);
+	g_return_if_fail(responseNode != NULL);
+	bodyNode = xmlnode_get_child(responseNode,"Body");
+	faultNode = xmlnode_get_child(bodyNode,"Fault");
+	if(faultNode == NULL){
+		/*Send OK! return*/
+		MsnOimSendReq *request;
+		
+		purple_debug_info("MSN OIM","send OIM OK!");
+		xmlnode_free(responseNode);
+		request = g_queue_pop_head(oim->send_queue);
+		msn_oim_free_send_req(request);
+		/*send next buffered Offline Message*/
+		msn_soap_post(oim->sendconn, NULL);
+		return;
+	}
+	/*get the challenge,and repost it*/
+	faultCodeNode = xmlnode_get_child(faultNode,"faultcode");
+	if(faultCodeNode == NULL){
+		purple_debug_info("MSN OIM","faultcode Node is NULL\n");
+		goto oim_send_process_fail;
+	}
+	faultCodeStr = xmlnode_get_data(faultCodeNode);
+	purple_debug_info("MSN OIM","fault code:{%s}\n",faultCodeStr);
+#if 0
+	if(!strcmp(faultCodeStr,"q0:AuthenticationFailed")){
+		/*other Fault Reason?*/
+		goto oim_send_process_fail;
+	}
+#endif
+
+	faultstringNode = xmlnode_get_child(faultNode,"faultstring");
+	faultstring = xmlnode_get_data(faultstringNode);
+	purple_debug_info("MSN OIM","fault string :{%s}\n",faultstring);
+
+	/* lock key fault reason,
+	 * compute the challenge and resend it
+	 */
+	detailNode = xmlnode_get_child(faultNode, "detail");
+	if(detailNode == NULL){
+		goto oim_send_process_fail;
+	}
+	challengeNode = xmlnode_get_child(detailNode,"LockKeyChallenge");
+	if (challengeNode == NULL) {
+		goto oim_send_process_fail;
+	}
+
+	g_free(oim->challenge);
+	oim->challenge = xmlnode_get_data(challengeNode);
+	purple_debug_info("MSN OIM","lockkey:{%s}\n",oim->challenge);
+
+	/*repost the send*/
+	purple_debug_info("MSN OIM","prepare to repost the send...\n");
+	msn_oim_send_msg(oim);
+
+oim_send_process_fail:
+	g_free(faultstring);
+	g_free(faultCodeStr);
+	xmlnode_free(responseNode);
+	return ;
+}
+
+static gboolean
+msn_oim_send_read_cb(MsnSoapConn *soapconn)
+{
+	MsnSession *session = soapconn->session;
+	MsnOim * oim;
+
+	if (soapconn->body == NULL)
+		return TRUE;
+
+	g_return_val_if_fail(session != NULL, FALSE);
+	oim = soapconn->session->oim;
+	g_return_val_if_fail(oim != NULL, TRUE);
+
+	purple_debug_info("MSN OIM","read buffer:{%s}\n", soapconn->body);
+	msn_oim_send_process(oim,soapconn->body,soapconn->body_len);
+
+	return TRUE;
+}
+
+static void
+msn_oim_send_written_cb(MsnSoapConn *soapconn)
+{
+	soapconn->read_cb = msn_oim_send_read_cb;
+//	msn_soap_read_cb(data,source,cond);
+}
+
+void
+msn_oim_prep_send_msg_info(MsnOim *oim, const char *membername,
+						   const char* friendname, const char *tomember,
+						   const char * msg)
+{
+	MsnOimSendReq *request;
+
+	g_return_if_fail(oim != NULL);
+
+	request = msn_oim_new_send_req(membername,friendname,tomember,oim->send_seq,msg);
+	g_queue_push_tail(oim->send_queue,request);
+}
+
+/*post send single message request to oim server*/
+void 
+msn_oim_send_msg(MsnOim *oim)
+{
+	MsnSoapReq *soap_request;
+	MsnOimSendReq *oim_request;
+	char *soap_body,*mspauth;
+	char *msg_body;
+	char buf[33];
+
+	g_return_if_fail(oim != NULL);
+	oim_request = g_queue_pop_head(oim->send_queue);
+	g_return_if_fail(oim_request != NULL);
+
+	purple_debug_info("MSN OIM","send single OIM Message\n");
+	mspauth = g_strdup_printf("t=%s&amp;p=%s",
+		oim->session->passport_info.t,
+		oim->session->passport_info.p
+		);
+	g_queue_push_head(oim->send_queue,oim_request);
+
+	/* if we got the challenge lock key, we compute it
+	 * else we go for the SOAP fault and resend it.
+	 */
+	if(oim->challenge != NULL){
+		msn_handle_chl(oim->challenge, buf);
+	}else{
+		purple_debug_info("MSN OIM","no lock key challenge,wait for SOAP Fault and Resend\n");
+		buf[0]='\0';
+	}
+	purple_debug_info("MSN OIM","get the lock key challenge {%s}\n",buf);	
+
+	msg_body = msn_oim_msg_to_str(oim, oim_request->oim_msg);
+	soap_body = g_strdup_printf(MSN_OIM_SEND_TEMPLATE,
+					oim_request->from_member,
+					oim_request->friendname,
+					oim_request->to_member,
+					mspauth,
+					MSNP13_WLM_PRODUCT_ID,
+					buf,
+					oim_request->send_seq,
+					msg_body
+					);
+	soap_request = msn_soap_request_new(MSN_OIM_SEND_HOST,
+					MSN_OIM_SEND_URL,
+					MSN_OIM_SEND_SOAP_ACTION,
+					soap_body,
+					NULL,
+					msn_oim_send_read_cb,
+					msn_oim_send_written_cb,
+					msn_oim_send_connect_init);
+	g_free(mspauth);
+	g_free(msg_body);
+	g_free(soap_body);
+
+	/*increase the offline Sequence control*/
+	if(oim->challenge != NULL){
+		oim->send_seq++;
+	}
+	msn_soap_post(oim->sendconn,soap_request);
+}
+
+/****************************************
+ * OIM delete SOAP request
+ * **************************************/
+static gboolean
+msn_oim_delete_read_cb(MsnSoapConn *soapconn)
+{
+	if (soapconn->body == NULL)
+		return TRUE;
+	purple_debug_info("MSN OIM","OIM delete read buffer:{%s}\n",soapconn->body);
+
+	msn_soap_free_read_buf(soapconn);
+	/*get next single Offline Message*/
+//	msn_soap_post(soapconn,NULL);	/* we already do this in soap.c */
+	return TRUE;
+}
+
+static void
+msn_oim_delete_written_cb(MsnSoapConn *soapconn)
+{
+	soapconn->read_cb = msn_oim_delete_read_cb;
+}
+
+/*Post to get the Offline Instant Message*/
+static void
+msn_oim_post_delete_msg(MsnOim *oim,const char *msgid)
+{
+	MsnSoapReq *soap_request;
+	const char *soap_body,*t,*p;
+
+	g_return_if_fail(oim != NULL);
+	g_return_if_fail(msgid != NULL);
+
+	purple_debug_info("MSN OIM","Delete single OIM Message {%s}\n",msgid);
+	t = oim->session->passport_info.t;
+	p = oim->session->passport_info.p;
+
+	soap_body = g_strdup_printf(MSN_OIM_DEL_TEMPLATE,
+					t,
+					p,
+					msgid
+					);
+	soap_request = msn_soap_request_new(MSN_OIM_RETRIEVE_HOST,
+					MSN_OIM_RETRIEVE_URL,
+					MSN_OIM_DEL_SOAP_ACTION,
+					soap_body,
+					NULL,
+					msn_oim_delete_read_cb,
+					msn_oim_delete_written_cb,
+					msn_oim_retrieve_connect_init);
+	msn_soap_post(oim->retrieveconn,soap_request);
+}
+
+/****************************************
+ * OIM get SOAP request
+ * **************************************/
+/*oim SOAP server login error*/
+static void
+msn_oim_get_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error)
+{
+	MsnSession *session;
+
+	session = soapconn->session;
+	g_return_if_fail(session != NULL);
+	msn_soap_clean_unhandled_requests(soapconn);
+
+//	msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to OIM server"));
+}
+
+/*msn oim SOAP server connect process*/
+static gboolean
+msn_oim_get_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc)
+{
+	MsnSession * session;
+	MsnOim *oim;
+
+	oim = soapconn->parent;
+	g_return_val_if_fail(oim != NULL, TRUE);
+
+	session = oim->session;
+	g_return_val_if_fail(session != NULL, FALSE);
+
+	purple_debug_info("MSN OIM","Connected and ready to get OIM!\n");
+
+	return TRUE;
+}
+
+/* like purple_str_to_time, but different. The format of the timestamp
+ * is like this: 5 Sep 2007 21:42:12 -0700 */
+static time_t
+msn_oim_parse_timestamp(const char *timestamp)
+{
+	char month_str[4], tz_str[6];
+	char *tz_ptr = tz_str;
+	static const char *months[] = {
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL
+	};
+	struct tm t;
+	memset(&t, 0, sizeof(t));
+
+	if (sscanf(timestamp, "%02d %03s %04d %02d:%02d:%02d %05s",
+					&t.tm_mday, month_str, &t.tm_year,
+					&t.tm_hour, &t.tm_min, &t.tm_sec, tz_str) == 7) {
+		gboolean offset_positive = TRUE;
+		int tzhrs;
+		int tzmins;
+		
+		for (t.tm_mon = 0;
+			 months[t.tm_mon] != NULL &&
+				 strcmp(months[t.tm_mon], month_str) != 0; t.tm_mon++);
+		if (months[t.tm_mon] != NULL) {
+			if (*tz_str == '-') {
+				offset_positive = FALSE;
+				tz_ptr++;
+			} else if (*tz_str == '+') {
+				tz_ptr++;
+			}
+
+			if (sscanf(tz_ptr, "%02d%02d", &tzhrs, &tzmins) == 2) {
+				time_t tzoff = tzhrs * 60 * 60 + tzmins * 60;
+#ifdef _WIN32
+				long sys_tzoff;
+#endif
+
+				if (!offset_positive)
+					tzoff *= -1;
+
+				t.tm_year -= 1900;
+				t.tm_isdst = 0;
+
+#ifdef _WIN32
+				if ((sys_tzoff = wpurple_get_tz_offset()) != -1)
+					tzoff += sys_tzoff;
+#else
+#ifdef HAVE_TM_GMTOFF
+				tzoff += t.tm_gmtoff;
+#else
+#	ifdef HAVE_TIMEZONE
+				tzset();    /* making sure */
+				tzoff -= timezone;
+#	endif
+#endif
+#endif /* _WIN32 */
+
+				return mktime(&t) + tzoff;
+			}
+		}
+	}
+
+	purple_debug_info("MSN OIM:OIM", "Can't parse timestamp %s\n", timestamp);
+	return time(NULL);
+}
+
+/*Post the Offline Instant Message to User Conversation*/
+static void
+msn_oim_report_to_user(MsnOim *oim, const char *msg_str)
+{
+	MsnMessage *message;
+	char *date,*from,*decode_msg;
+	gsize body_len;
+	char **tokens;
+	char *start,*end;
+	int has_nick = 0;
+	char *passport_str, *passport;
+	char *msg_id;
+	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);
+	purple_debug_info("MSN OIM","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","oim Date:{%s},nickname:{%s},tokens[1]:{%s} passport{%s}\n",
+							date,tokens[0],tokens[1],passport_str);
+		g_strfreev(tokens);
+	}else{
+		passport_str = g_strdup(from);
+		purple_debug_info("MSN OIM","oim Date:{%s},passport{%s}\n",
+					date,passport_str);
+	}
+	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","oim Date:{%s},passport{%s}\n",date,passport);
+
+	stamp = msn_oim_parse_timestamp(date);
+
+	serv_got_im(oim->session->account->gc, passport, decode_msg, 0, 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
+	 */
+	if(oim->oim_list != NULL){
+		msg_id = oim->oim_list->data;
+		msn_oim_post_delete_msg(oim,msg_id);
+		oim->oim_list = g_list_remove(oim->oim_list, oim->oim_list->data);
+		g_free(msg_id);
+	}
+
+	g_free(passport);
+}
+
+/* Parse the XML data,
+ * prepare to report the OIM to user
+ */
+static void
+msn_oim_get_process(MsnOim *oim, const char *oim_msg)
+{
+	xmlnode *oim_node,*bodyNode,*responseNode,*msgNode;
+	char *msg_str;
+
+	oim_node = xmlnode_from_str(oim_msg, strlen(oim_msg));
+	bodyNode = xmlnode_get_child(oim_node,"Body");
+	responseNode = xmlnode_get_child(bodyNode,"GetMessageResponse");
+	msgNode = xmlnode_get_child(responseNode,"GetMessageResult");
+	msg_str = xmlnode_get_data(msgNode);
+	purple_debug_info("OIM","msg:{%s}\n",msg_str);
+	msn_oim_report_to_user(oim,msg_str);
+
+	g_free(msg_str);
+	xmlnode_free(oim_node);
+}
+
+static gboolean
+msn_oim_get_read_cb(MsnSoapConn *soapconn)
+{
+	MsnOim * oim = soapconn->session->oim;
+
+	if (soapconn->body == NULL)
+		return TRUE;
+
+	purple_debug_info("MSN OIM","OIM get read buffer:{%s}\n",soapconn->body);
+
+	/*we need to process the read message!*/
+	msn_oim_get_process(oim,soapconn->body);
+	msn_soap_free_read_buf(soapconn);
+
+	/*get next single Offline Message*/
+//	msn_soap_post(soapconn,NULL); /* we already do this in soap.c */
+	return TRUE;
+}
+
+static void
+msn_oim_get_written_cb(MsnSoapConn *soapconn)
+{
+	soapconn->read_cb = msn_oim_get_read_cb;
+//	msn_soap_read_cb(data,source,cond);
+}
+
+/* parse the oim XML data 
+ * and post it to the soap server to get the Offline Message
+ * */
+void
+msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg)
+{
+	xmlnode *node, *mNode,*ENode,*INode,*rtNode,*nNode;
+	char *passport,*msgid,*nickname, *unread, *rTime = NULL;
+	MsnSession *session = oim->session;
+
+	purple_debug_info("MSN OIM:OIM", "%s", xmlmsg);
+
+	node = xmlnode_from_str(xmlmsg, strlen(xmlmsg));
+	if (strcmp(node->name, "MD") != 0) {
+		xmlnode_free(node);
+		return;
+	}
+
+	ENode = xmlnode_get_child(node, "E");
+	INode = xmlnode_get_child(ENode, "IU");
+	unread = xmlnode_get_data(INode);
+
+	if (unread != NULL && purple_account_get_check_mail(session->account))
+	{
+		int count = atoi(unread);
+
+		if (count > 0)
+		{
+			const char *passport;
+			const char *url;
+
+			passport = msn_user_get_passport(session->user);
+			url = session->passport_info.file;
+
+			purple_notify_emails(session->account->gc, atoi(unread), FALSE, NULL, NULL,
+					&passport, &url, NULL, NULL);
+		}
+	}
+
+	for(mNode = xmlnode_get_child(node, "M"); mNode;
+					mNode = xmlnode_get_next_twin(mNode)){
+		/*email Node*/
+		ENode = xmlnode_get_child(mNode,"E");
+		passport = xmlnode_get_data(ENode);
+		/*Index */
+		INode = xmlnode_get_child(mNode,"I");
+		msgid = xmlnode_get_data(INode);
+		/*Nickname*/
+		nNode = xmlnode_get_child(mNode,"N");
+		nickname = xmlnode_get_data(nNode);
+		/*receive time*/
+		rtNode = xmlnode_get_child(mNode,"RT");
+		if(rtNode != NULL) {
+			rTime = xmlnode_get_data(rtNode);
+			rtNode = NULL;
+		}
+/*		purple_debug_info("MSN OIM","E:{%s},I:{%s},rTime:{%s}\n",passport,msgid,rTime); */
+
+		oim->oim_list = g_list_append(oim->oim_list,strdup(msgid));
+		msn_oim_post_single_get_msg(oim,msgid);
+		g_free(passport);
+		g_free(msgid);
+		g_free(rTime);
+		rTime = NULL;
+		g_free(nickname);
+	}
+	g_free(unread);
+	xmlnode_free(node);
+}
+
+/*Post to get the Offline Instant Message*/
+static void
+msn_oim_post_single_get_msg(MsnOim *oim,const char *msgid)
+{
+	MsnSoapReq *soap_request;
+	const char *soap_body,*t,*p;
+
+	purple_debug_info("MSN OIM","Get single OIM Message\n");
+	t = oim->session->passport_info.t;
+	p = oim->session->passport_info.p;
+
+	soap_body = g_strdup_printf(MSN_OIM_GET_TEMPLATE,
+					t,
+					p,
+					msgid
+					);
+	soap_request = msn_soap_request_new(MSN_OIM_RETRIEVE_HOST,
+					MSN_OIM_RETRIEVE_URL,
+					MSN_OIM_GET_SOAP_ACTION,
+					soap_body,
+					NULL,
+					msn_oim_get_read_cb,
+					msn_oim_get_written_cb,
+					msn_oim_retrieve_connect_init);
+	msn_soap_post(oim->retrieveconn,soap_request);
+}
+
+/*msn oim retrieve server connect init */
+static void
+msn_oim_retrieve_connect_init(MsnSoapConn *soapconn)
+{
+	purple_debug_info("MSN OIM","Initializing OIM retrieve connection\n");
+	msn_soap_init(soapconn, MSN_OIM_RETRIEVE_HOST, 1,
+		      msn_oim_get_connect_cb,
+		      msn_oim_get_error_cb);
+}
+
+/*Msn OIM Send Server Connect Init Function*/
+static void
+msn_oim_send_connect_init(MsnSoapConn *sendconn)
+{
+	purple_debug_info("MSN OIM","Initializing OIM send connection\n");
+	msn_soap_init(sendconn, MSN_OIM_SEND_HOST, 1,
+		      msn_oim_send_connect_cb,
+		      msn_oim_send_error_cb);
+}
+
+/* EOF oim.c*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/msn/oim.h	Fri Sep 28 16:34:43 2007 +0000
@@ -0,0 +1,148 @@
+/**
+ * @file oim.h			Header file for oim.c
+ *	Author
+ * 		MaYuan<mayuan2006@gmail.com>
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _MSN_OIM_H_
+#define _MSN_OIM_H_
+
+/*OIM Retrieve SOAP Template*/
+#define MSN_OIM_RETRIEVE_HOST	"rsi.hotmail.com"
+#define MSN_OIM_RETRIEVE_URL	"/rsi/rsi.asmx"
+#define MSN_OIM_GET_SOAP_ACTION	"http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMessage"
+
+#define MSN_OIM_GET_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\
+"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\
+	"<soap:Header>"\
+		"<PassportCookie xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\
+			"<t>%s</t>"\
+			"<p>%s</p>"\
+		"</PassportCookie>"\
+	"</soap:Header>"\
+	"<soap:Body>"\
+		"<GetMessage xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\
+			"<messageId>%s</messageId>"\
+			"<alsoMarkAsRead>false</alsoMarkAsRead>"\
+		"</GetMessage>"\
+	"</soap:Body>"\
+"</soap:Envelope>"
+
+/*OIM Delete SOAP Template*/
+#define MSN_OIM_DEL_SOAP_ACTION	"http://www.hotmail.msn.com/ws/2004/09/oim/rsi/DeleteMessages"
+
+#define MSN_OIM_DEL_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\
+"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\
+	"<soap:Header>"\
+		"<PassportCookie xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\
+			"<t>%s</t>"\
+			" <p>%s</p>"\
+		"</PassportCookie>"\
+	"</soap:Header>"\
+	"<soap:Body>"\
+		"<DeleteMessages xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\
+			"<messageIds>"\
+				"<messageId>%s</messageId>"\
+			"</messageIds>"\
+		"</DeleteMessages>"\
+	"</soap:Body>"\
+"</soap:Envelope>"
+
+/*OIM Send SOAP Template*/
+#define MSN_OIM_MSG_TEMPLATE "MIME-Version: 1.0\n"\
+	"Content-Type: text/plain; charset=UTF-8\n"\
+	"Content-Transfer-Encoding: base64\n"\
+	"X-OIM-Message-Type: OfflineMessage\n"\
+	"X-OIM-Run-Id: {%s}\n"\
+	"X-OIM-Sequence-Num: %d\n\n"\
+	"%s"
+
+#define MSN_OIM_SEND_HOST	"ows.messenger.msn.com"
+#define MSN_OIM_SEND_URL	"/OimWS/oim.asmx"
+#define MSN_OIM_SEND_SOAP_ACTION	"http://messenger.msn.com/ws/2004/09/oim/Store"
+#define MSN_OIM_SEND_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\
+"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\
+	"<soap:Header>"\
+		"<From memberName=\"%s\" friendlyName=\"%s\" xml:lang=\"en-US\" proxy=\"MSNMSGR\" xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\" msnpVer=\"MSNP14\" buildVer=\"8.0.0792\"/>"\
+		"<To memberName=\"%s\" xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\"/>"\
+		"<Ticket passport=\"%s\" appid=\"%s\" lockkey=\"%s\" xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\"/>"\
+		"<Sequence xmlns=\"http://schemas.xmlsoap.org/ws/2003/03/rm\">"\
+			"<Identifier xmlns=\"http://schemas.xmlsoap.org/ws/2002/07/utility\">http://messenger.msn.com</Identifier>"\
+			"<MessageNumber>%d</MessageNumber>"\
+		"</Sequence>"\
+	"</soap:Header>"\
+	"<soap:Body>"\
+		"<MessageType xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\">text</MessageType>"\
+		"<Content xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\">%s</Content>"\
+	"</soap:Body>"\
+"</soap:Envelope>"
+
+typedef struct _MsnOimSendReq MsnOimSendReq;
+
+struct _MsnOimSendReq
+{
+	char *from_member;
+	char *friendname;
+	char *to_member;
+	char *oim_msg;
+	gint send_seq;
+};
+
+typedef struct _MsnOim MsnOim;
+
+struct _MsnOim
+{
+	MsnSession *session;
+
+	MsnSoapConn *retrieveconn;
+	GList * oim_list;
+
+	MsnSoapConn *sendconn;
+	char *challenge;
+	char *run_id;
+	gint send_seq;
+	GQueue *send_queue;
+};
+
+/****************************************************
+ * function prototype
+ * **************************************************/
+MsnOim * msn_oim_new(MsnSession *session);
+void msn_oim_destroy(MsnOim *oim);
+void msn_oim_connect(MsnOim *oim);
+
+void msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg);
+
+/*Send OIM Message*/
+void msn_oim_prep_send_msg_info(MsnOim *oim, const char *membername,
+								const char *friendname, const char *tomember,
+								const char * msg);
+
+void msn_oim_send_msg(MsnOim *oim);
+
+/*get the OIM message*/
+void msn_oim_get_msg(MsnOim *oim);
+
+/*report the oim message to the conversation*/
+void msn_oim_report_user(MsnOim *oim,const char *passport,char *msg);
+
+#endif/* _MSN_OIM_H_*/
+/*endof oim.h*/
--- a/libpurple/protocols/msn/servconn.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/servconn.c	Fri Sep 28 16:34:43 2007 +0000
@@ -168,7 +168,7 @@
  **************************************************************************/
 
 static void
-connect_cb(gpointer data, gint source, const gchar *error_message)
+connect_cb(gpointer data, gint source, const char *error_message)
 {
 	MsnServConn *servconn;
 
@@ -245,7 +245,9 @@
 		return TRUE;
 	}
 	else
+	{
 		return FALSE;
+	}
 }
 
 void
@@ -390,14 +392,21 @@
 
 	len = read(servconn->fd, buf, sizeof(buf) - 1);
 
-	if (len < 0 && errno == EAGAIN)
-		return;
-	else if (len <= 0)
-	{
-		purple_debug_error("msn", "servconn read error, len: %d error: %s\n", len, strerror(errno));
-		msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ);
+	if (len <= 0) {
+		switch (errno) {
+
+			case 0:	
 
-		return;
+			case EBADF:
+			case EAGAIN: return;
+	
+			default: purple_debug_error("msn", "servconn read error,"
+						"len: %d, errno: %d, error: %s\n",
+						len, errno, strerror(errno));
+				 msn_servconn_got_error(servconn, 
+						 MSN_SERVCONN_ERROR_READ);
+				 return;
+		}
 	}
 
 	buf[len] = '\0';
@@ -446,6 +455,7 @@
 		else
 		{
 			msn_cmdproc_process_cmd_text(servconn->cmdproc, cur);
+			servconn->payload_len = servconn->cmdproc->last_cmd->payload_len;
 		}
 	} while (servconn->connected && !servconn->wasted && servconn->rx_len > 0);
 
--- a/libpurple/protocols/msn/session.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/session.c	Fri Sep 28 16:34:43 2007 +0000
@@ -43,7 +43,9 @@
 	session->user = msn_user_new(session->userlist,
 								 purple_account_get_username(account), NULL);
 
-	session->protocol_ver = 9;
+	/*if you want to chat with Yahoo Messenger*/
+	//session->protocol_ver = WLM_YAHOO_PROT_VER;
+	session->protocol_ver = WLM_PROT_VER;
 	session->conv_seq = 1;
 
 	return session;
@@ -70,6 +72,8 @@
 
 	msn_userlist_destroy(session->userlist);
 
+	g_free(session->passport_info.t);
+	g_free(session->passport_info.p);
 	g_free(session->passport_info.kv);
 	g_free(session->passport_info.sid);
 	g_free(session->passport_info.mspauth);
@@ -87,6 +91,11 @@
 	if (session->nexus != NULL)
 		msn_nexus_destroy(session->nexus);
 
+	if (session->contact != NULL)
+		msn_contact_destroy(session->contact);
+	if (session->oim != NULL)
+		msn_oim_destroy(session->oim);
+
 	if (session->user != NULL)
 		msn_user_destroy(session->user);
 
@@ -154,6 +163,37 @@
 	return NULL;
 }
 
+static PurpleConversation *
+msn_session_get_conv(MsnSession *session,const char *passport)
+{
+	PurpleAccount *account;
+	PurpleConversation * conv;
+
+	g_return_val_if_fail(session != NULL, NULL);
+	account = session->account;
+
+	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
+									passport, account);
+	if(conv == NULL){
+		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, passport);
+	}
+	return conv;
+}
+
+/* put Message to User Conversation
+ *
+ * 	passport - the one want to talk to you
+ */
+void
+msn_session_report_user(MsnSession *session,const char *passport,char *msg,PurpleMessageFlags flags)
+{
+	PurpleConversation * conv;
+
+	if ((conv = msn_session_get_conv(session,passport)) != NULL){
+		purple_conversation_write(conv, NULL, msg, flags, time(NULL));
+	}
+}
+
 MsnSwitchBoard *
 msn_session_find_swboard_with_conv(MsnSession *session, PurpleConversation *conv)
 {
@@ -229,13 +269,14 @@
 
 	/* The core used to use msn_add_buddy to add all buddies before
 	 * being logged in. This no longer happens, so we manually iterate
-	 * over the whole buddy list to identify sync issues. */
-
-	for (gnode = purple_blist_get_root(); gnode; gnode = gnode->next) {
+	 * over the whole buddy list to identify sync issues.
+	 */
+	for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {
 		PurpleGroup *group = (PurpleGroup *)gnode;
-		const char *group_name = group->name;
+		const char *group_name;
 		if(!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
+		group_name = group->name;
 		for(cnode = gnode->child; cnode; cnode = cnode->next) {
 			if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
@@ -252,21 +293,17 @@
 
 					if ((remote_user != NULL) && (remote_user->list_op & MSN_LIST_FL_OP))
 					{
-						int group_id;
 						GList *l;
 
-						group_id = msn_userlist_find_group_id(remote_user->userlist,
-								group_name);
-
 						for (l = remote_user->group_ids; l != NULL; l = l->next)
 						{
-							if (group_id == GPOINTER_TO_INT(l->data))
+							const char *name = msn_userlist_find_group_name(remote_user->userlist, l->data);
+							if (name && !g_strcasecmp(group_name, name))
 							{
 								found = TRUE;
 								break;
 							}
 						}
-
 					}
 
 					if (!found)
@@ -305,6 +342,8 @@
 		case MSN_ERROR_SIGN_OTHER:
 			gc->wants_to_die = TRUE;
 			msg = g_strdup(_("You have signed on from another location."));
+			if (!purple_account_get_remember_password(session->account))
+				purple_account_set_password(session->account, NULL);
 			break;
 		case MSN_ERROR_SERV_UNAVAILABLE:
 			msg = g_strdup(_("The MSN servers are temporarily "
@@ -419,3 +458,4 @@
 		msn_cmdproc_send(session->notification->cmdproc, "URL", "%s", "INBOX");
 	}
 }
+
--- a/libpurple/protocols/msn/session.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/session.h	Fri Sep 28 16:34:43 2007 +0000
@@ -38,6 +38,8 @@
 #include "cmdproc.h"
 #include "nexus.h"
 #include "httpconn.h"
+#include "contact.h"
+#include "oim.h"
 
 #include "userlist.h"
 #include "sync.h"
@@ -94,6 +96,8 @@
 
 	MsnNotification *notification;
 	MsnNexus *nexus;
+	MsnContact *contact;
+	MsnOim		*oim;
 	MsnSync *sync;
 
 	MsnUserList *userlist;
@@ -105,8 +109,15 @@
 
 	int conv_seq; /**< The current conversation sequence number. */
 
+	/*psm info*/
+	char *psm;
+
 	struct
 	{
+		/*t and p, get via USR TWN*/
+		char *t;
+		char *p;
+
 		char *kv;
 		char *sid;
 		char *mspauth;
@@ -114,7 +125,6 @@
 		char *file;
 		char *client_ip;
 		int client_port;
-
 	} passport_info;
 };
 
@@ -224,4 +234,8 @@
  */
 void msn_session_finish_login(MsnSession *session);
 
+/*post message to User*/
+void msn_session_report_user(MsnSession *session,const char *passport,
+							char *msg,PurpleMessageFlags flags);
+
 #endif /* _MSN_SESSION_H_ */
--- a/libpurple/protocols/msn/slp.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/slp.c	Fri Sep 28 16:34:43 2007 +0000
@@ -33,6 +33,8 @@
 
 /* ms to delay between sending buddy icon requests to the server. */
 #define BUDDY_ICON_DELAY 20000
+/*debug SLP*/
+#define MSN_DEBUG_UD
 
 static void send_ok(MsnSlpCall *slpcall, const char *branch,
 					const char *type, const char *content);
@@ -777,11 +779,11 @@
 	if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, gc->account))) {
 
 		/* FIXME: it would be better if we wrote the data as we received it
-		          instead of all at once, calling write multiple times and
-		          close once at the very end
-		*/
+		   instead of all at once, calling write multiple times and
+		   close once at the very end
+		 */
 		purple_conv_custom_smiley_write(conv, slpcall->data_info, data, size);
-		purple_conv_custom_smiley_close(conv, slpcall->data_info);
+		purple_conv_custom_smiley_close(conv, slpcall->data_info );
 	}
 #ifdef MSN_DEBUG_UD
 	purple_debug_info("msn", "Got smiley: %s\n", slpcall->data_info);
--- a/libpurple/protocols/msn/slpcall.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/slpcall.c	Fri Sep 28 16:34:43 2007 +0000
@@ -22,6 +22,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 #include "msn.h"
+#include "msnutils.h"
 #include "slpcall.h"
 #include "slpsession.h"
 
@@ -30,24 +31,6 @@
 /* #define MSN_DEBUG_SLPCALL */
 
 /**************************************************************************
- * Util
- **************************************************************************/
-
-static char *
-rand_guid()
-{
-	return g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X",
-			rand() % 0xAAFF + 0x1111,
-			rand() % 0xAAFF + 0x1111,
-			rand() % 0xAAFF + 0x1111,
-			rand() % 0xAAFF + 0x1111,
-			rand() % 0xAAFF + 0x1111,
-			rand() % 0xAAFF + 0x1111,
-			rand() % 0xAAFF + 0x1111,
-			rand() % 0xAAFF + 0x1111);
-}
-
-/**************************************************************************
  * Main
  **************************************************************************/
 
--- a/libpurple/protocols/msn/slplink.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/slplink.c	Fri Sep 28 16:34:43 2007 +0000
@@ -112,8 +112,10 @@
 	if (slplink->remote_user != NULL)
 		g_free(slplink->remote_user);
 
+#if 0
 	if (slplink->directconn != NULL)
 		msn_directconn_destroy(slplink->directconn);
+#endif
 
 	while (slplink->slp_calls != NULL)
 		msn_slp_call_destroy(slplink->slp_calls->data);
@@ -244,11 +246,13 @@
 void
 msn_slplink_send_msg(MsnSlpLink *slplink, MsnMessage *msg)
 {
+#if 0
 	if (slplink->directconn != NULL)
 	{
 		msn_directconn_send_msg(slplink->directconn, msg);
 	}
 	else
+#endif
 	{
 		if (slplink->swboard == NULL)
 		{
@@ -634,9 +638,10 @@
 			MsnDirectConn *directconn;
 
 			directconn = slplink->directconn;
-
+#if 0
 			if (!directconn->acked)
 				msn_directconn_send_handshake(directconn);
+#endif
 		}
 		else if (slpmsg->flags == 0x0 || slpmsg->flags == 0x20 ||
 				 slpmsg->flags == 0x1000030)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/msn/soap.c	Fri Sep 28 16:34:43 2007 +0000
@@ -0,0 +1,870 @@
+/**
+ * @file soap.c 
+ * 	SOAP connection related process
+ *	Author
+ * 		MaYuan<mayuan2006@gmail.com>
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "msn.h"
+#include "soap.h"
+
+
+/*local function prototype*/
+void msn_soap_set_process_step(MsnSoapConn *soapconn, MsnSoapStep step);
+
+/*setup the soap process step*/
+void
+msn_soap_set_process_step(MsnSoapConn *soapconn, MsnSoapStep step)
+{
+#ifdef MSN_SOAP_DEBUG
+	const char *MsnSoapStepText[] =
+	{
+		"Unconnected",
+		"Connecting",
+		"Connected",
+		"Processing",
+		"Connected Idle"
+	};
+
+	purple_debug_info("MSN SOAP", "Setting SOAP process step to %s\n", MsnSoapStepText[step]);
+#endif
+	soapconn->step = step;
+}
+
+//msn_soap_new(MsnSession *session,gpointer data,int sslconn)
+/*new a soap connection*/
+MsnSoapConn *
+msn_soap_new(MsnSession *session,gpointer data,int sslconn)
+{
+	MsnSoapConn *soapconn;
+
+	soapconn = g_new0(MsnSoapConn, 1);
+	soapconn->session = session;
+	soapconn->parent = data;
+	soapconn->ssl_conn = sslconn;
+
+	soapconn->gsc = NULL;
+	soapconn->input_handler = 0;
+	soapconn->output_handler = 0;
+
+	msn_soap_set_process_step(soapconn, MSN_SOAP_UNCONNECTED);
+	soapconn->soap_queue = g_queue_new();
+
+	return soapconn;
+}
+
+/*ssl soap connect callback*/
+void
+msn_soap_connect_cb(gpointer data, PurpleSslConnection *gsc,
+				 PurpleInputCondition cond)
+{
+	MsnSoapConn * soapconn;
+	MsnSession *session;
+	gboolean soapconn_is_valid = FALSE;
+
+	purple_debug_misc("MSN SOAP","SOAP server connection established!\n");
+
+	soapconn = data;
+	g_return_if_fail(soapconn != NULL);
+
+	session = soapconn->session;
+	g_return_if_fail(session != NULL);
+
+	soapconn->gsc = gsc;
+
+	msn_soap_set_process_step(soapconn, MSN_SOAP_CONNECTED);
+
+	/*connection callback*/
+	if (soapconn->connect_cb != NULL) {
+		soapconn_is_valid = soapconn->connect_cb(soapconn, gsc);
+	}
+
+	if (!soapconn_is_valid) {
+		return;
+	}
+
+	/*we do the SOAP request here*/
+	msn_soap_post_head_request(soapconn);
+}
+
+/*ssl soap error callback*/
+static void
+msn_soap_error_cb(PurpleSslConnection *gsc, PurpleSslErrorType error, void *data)
+{	
+	MsnSoapConn * soapconn = data;
+
+	g_return_if_fail(data != NULL);
+
+	purple_debug_warning("MSN SOAP","Soap connection error!\n");
+
+	msn_soap_set_process_step(soapconn, MSN_SOAP_UNCONNECTED);
+
+	/*error callback*/
+	if (soapconn->error_cb != NULL) {
+		soapconn->error_cb(soapconn, gsc, error);
+	} else {
+		msn_soap_post(soapconn, NULL);
+	}
+}
+
+/*init the soap connection*/
+void
+msn_soap_init(MsnSoapConn *soapconn,char * host,int ssl,
+				MsnSoapSslConnectCbFunction connect_cb,
+				MsnSoapSslErrorCbFunction error_cb)
+{
+	purple_debug_misc("MSN SOAP","Initializing SOAP connection\n");
+	soapconn->login_host = g_strdup(host);
+	soapconn->ssl_conn = ssl;
+	soapconn->connect_cb = connect_cb;
+	soapconn->error_cb = error_cb;
+}
+
+/*connect the soap connection*/
+void
+msn_soap_connect(MsnSoapConn *soapconn)
+{
+	if (soapconn->ssl_conn) {
+		purple_ssl_connect(soapconn->session->account, soapconn->login_host,
+				PURPLE_SSL_DEFAULT_PORT, msn_soap_connect_cb, msn_soap_error_cb,
+				soapconn);
+	} else {
+	}
+
+	msn_soap_set_process_step(soapconn, MSN_SOAP_CONNECTING);
+}
+
+
+static void
+msn_soap_close_handler(guint *handler)
+{
+	if (*handler > 0) {
+		purple_input_remove(*handler);
+		*handler = 0;
+	} 
+#ifdef MSN_SOAP_DEBUG
+	else {
+		purple_debug_misc("MSN SOAP", "Handler inactive, not removing\n");
+	}
+#endif
+
+}
+
+
+/*close the soap connection*/
+void
+msn_soap_close(MsnSoapConn *soapconn)
+{
+	if (soapconn->ssl_conn) {
+		if (soapconn->gsc != NULL) {
+			purple_ssl_close(soapconn->gsc);
+			soapconn->gsc = NULL;
+		}
+	} else {
+	}
+	msn_soap_set_process_step(soapconn, MSN_SOAP_UNCONNECTED);
+}
+
+/*clean the unhandled SOAP request*/
+void
+msn_soap_clean_unhandled_requests(MsnSoapConn *soapconn)
+{
+	MsnSoapReq *request;
+
+	g_return_if_fail(soapconn != NULL);
+
+	soapconn->body = NULL;
+
+	while ((request = g_queue_pop_head(soapconn->soap_queue)) != NULL){
+		if (soapconn->read_cb) {
+			soapconn->read_cb(soapconn);
+		}
+		msn_soap_request_free(request);
+	}
+}
+
+/*destroy the soap connection*/
+void
+msn_soap_destroy(MsnSoapConn *soapconn)
+{
+	if(soapconn->login_host)
+		g_free(soapconn->login_host);
+
+	if(soapconn->login_path)
+		g_free(soapconn->login_path);
+
+	/*remove the write handler*/
+	if (soapconn->output_handler > 0){
+		purple_input_remove(soapconn->output_handler);
+		soapconn->output_handler = 0;
+	}
+	/*remove the read handler*/
+	if (soapconn->input_handler > 0){
+		purple_input_remove(soapconn->input_handler);
+		soapconn->input_handler = 0;
+	}
+	msn_soap_free_read_buf(soapconn);
+	msn_soap_free_write_buf(soapconn);
+
+	/*close ssl connection*/
+	msn_soap_close(soapconn);
+
+	/*process the unhandled soap request*/
+	msn_soap_clean_unhandled_requests(soapconn);
+
+	g_queue_free(soapconn->soap_queue);
+	g_free(soapconn);
+}
+
+/*check the soap is connected?
+ * if connected return 1
+ */
+int
+msn_soap_connected(MsnSoapConn *soapconn)
+{
+	if (soapconn->ssl_conn) {
+		return (soapconn->gsc == NULL ? 0 : 1);
+	}
+	return (soapconn->fd > 0 ? 1 : 0);
+}
+
+/*read and append the content to the buffer*/
+static gssize
+msn_soap_read(MsnSoapConn *soapconn)
+{
+	gssize len, requested_len;
+	char temp_buf[MSN_SOAP_READ_BUFF_SIZE];
+	
+	if ( soapconn->need_to_read == 0 || soapconn->need_to_read > MSN_SOAP_READ_BUFF_SIZE) {
+		requested_len = MSN_SOAP_READ_BUFF_SIZE;
+	}
+	else {
+		requested_len = soapconn->need_to_read;
+	}
+
+	if ( soapconn->ssl_conn ) {
+		len = purple_ssl_read(soapconn->gsc, temp_buf, requested_len);
+	} else {
+		len = read(soapconn->fd, temp_buf, requested_len);
+	}
+
+	
+	if ( len <= 0 ) {
+		switch (errno) {
+
+			case 0:
+			case EBADF: /* we are sometimes getting this in Windows */
+			case EAGAIN: return len;
+
+			default : purple_debug_error("MSN SOAP", "Read error!"
+						"read len: %d, error = %s\n",
+						len, strerror(errno));
+				  purple_input_remove(soapconn->input_handler);
+				  //soapconn->input_handler = 0;
+				  g_free(soapconn->read_buf);
+				  soapconn->read_buf = NULL;
+				  soapconn->read_len = 0;
+				  /* TODO: error handling */
+				  return len;
+		}
+	}
+	else {
+		soapconn->read_buf = g_realloc(soapconn->read_buf,
+						soapconn->read_len + len + 1);
+		if ( soapconn->read_buf != NULL ) {
+			memcpy(soapconn->read_buf + soapconn->read_len, temp_buf, len);
+			soapconn->read_len += len;
+			soapconn->read_buf[soapconn->read_len] = '\0';
+		}
+		else {
+			purple_debug_error("MSN SOAP", "Failure re-allocating %d bytes of memory!\n", soapconn->read_len + len + 1);
+			exit(EXIT_FAILURE);
+		}
+			
+	}
+
+#if defined(MSN_SOAP_DEBUG)
+	if (len > 0)
+		purple_debug_info("MSN SOAP","Read %d bytes from SOAP server:\n%s\n", len, soapconn->read_buf + soapconn->read_len - len);
+#endif
+
+	return len;
+}
+
+/*read the whole SOAP server response*/
+void 
+msn_soap_read_cb(gpointer data, gint source, PurpleInputCondition cond)
+{
+	MsnSoapConn *soapconn = data;
+	MsnSession *session;
+	int len;
+	char * body_start,*body_len;
+	char *length_start,*length_end;
+#ifdef MSN_SOAP_DEBUG
+#if !defined(_WIN32)
+	gchar * formattedxml = NULL;
+	gchar * http_headers = NULL;
+	xmlnode * node = NULL;
+#endif
+	purple_debug_misc("MSN SOAP", "msn_soap_read_cb()\n");
+#endif
+	session = soapconn->session;
+	g_return_if_fail(session != NULL);
+
+	
+	/*read the request header*/
+	len = msn_soap_read(soapconn);
+	
+	if ( len < 0 )
+		return;
+
+	if (soapconn->read_buf == NULL) {
+		return;
+	}
+
+	if ( (strstr(soapconn->read_buf, "HTTP/1.1 302") != NULL) 
+		|| ( strstr(soapconn->read_buf, "HTTP/1.1 301") != NULL ) )
+	{
+		/* Redirect. */
+		char *location, *c;
+
+		purple_debug_info("MSN SOAP", "HTTP Redirect\n");
+		location = strstr(soapconn->read_buf, "Location: ");
+		if (location == NULL)
+		{
+			c = (char *) g_strstr_len(soapconn->read_buf, soapconn->read_len,"\r\n\r\n");
+			if (c != NULL) {
+				/* we have read the whole HTTP headers and found no Location: */
+				msn_soap_free_read_buf(soapconn);
+				msn_soap_post(soapconn, NULL);
+			}
+
+			return;
+		}
+		location = strchr(location, ' ') + 1;
+
+		if ((c = strchr(location, '\r')) != NULL)
+			*c = '\0';
+		else
+			return;
+
+		/* Skip the http:// */
+		if ((c = strchr(location, '/')) != NULL)
+			location = c + 2;
+
+		if ((c = strchr(location, '/')) != NULL)
+		{
+			g_free(soapconn->login_path);
+			soapconn->login_path = g_strdup(c);
+
+			*c = '\0';
+		}
+
+		g_free(soapconn->login_host);
+		soapconn->login_host = g_strdup(location);
+		
+		msn_soap_close_handler( &(soapconn->input_handler) );
+		msn_soap_close(soapconn);
+
+		if (purple_ssl_connect(session->account, soapconn->login_host,
+			PURPLE_SSL_DEFAULT_PORT, msn_soap_connect_cb,
+			msn_soap_error_cb, soapconn) == NULL) {
+		
+			purple_debug_error("MSN SOAP", "Unable to connect to %s !\n", soapconn->login_host);
+			// dispatch next request
+			msn_soap_post(soapconn, NULL);
+		}
+	}
+	/* Another case of redirection, active on May, 2007
+	   See http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener#Redirect
+	 */
+	else if (strstr(soapconn->read_buf,
+                    "<faultcode>psf:Redirect</faultcode>") != NULL)
+	{
+		char *location, *c;
+
+		if ( (location = strstr(soapconn->read_buf, "<psf:redirectUrl>") ) == NULL)
+			return;
+
+		/* Omit the tag preceding the URL */
+		location += strlen("<psf:redirectUrl>");
+		if (location > soapconn->read_buf + soapconn->read_len)
+			return;
+		if ( (location = strstr(location, "://")) == NULL)
+			return;
+
+		location += strlen("://"); /* Skip http:// or https:// */
+
+		if ( (c = strstr(location, "</psf:redirectUrl>")) != NULL )
+			*c = '\0';
+		else
+			return;
+
+		if ( (c = strstr(location, "/")) != NULL )
+		{
+			g_free(soapconn->login_path);
+			soapconn->login_path = g_strdup(c);
+			*c = '\0';
+		}
+
+		g_free(soapconn->login_host);
+		soapconn->login_host = g_strdup(location);
+		
+		msn_soap_close_handler( &(soapconn->input_handler) );
+		msn_soap_close(soapconn);
+
+		if (purple_ssl_connect(session->account, soapconn->login_host,
+				PURPLE_SSL_DEFAULT_PORT, msn_soap_connect_cb,
+				msn_soap_error_cb, soapconn) == NULL) {
+
+			purple_debug_error("MSN SOAP", "Unable to connect to %s !\n", soapconn->login_host);
+			// dispatch next request
+			msn_soap_post(soapconn, NULL);
+		}
+	}
+	else if (strstr(soapconn->read_buf, "HTTP/1.1 401 Unauthorized") != NULL)
+	{
+		const char *error;
+
+		purple_debug_error("MSN SOAP", "Received HTTP error 401 Unauthorized\n");
+		if ((error = strstr(soapconn->read_buf, "WWW-Authenticate")) != NULL)
+		{
+			if ((error = strstr(error, "cbtxt=")) != NULL)
+			{
+				const char *c;
+				char *temp;
+
+				error += strlen("cbtxt=");
+
+				if ((c = strchr(error, '\n')) == NULL)
+					c = error + strlen(error);
+
+				temp = g_strndup(error, c - error);
+				error = purple_url_decode(temp);
+				g_free(temp);
+			}
+		}
+
+		msn_session_set_error(session, MSN_ERROR_AUTH, error);
+	}
+	/* Handle Passport 3.0 authentication failures.
+	 * Further info: http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener
+	 */
+	else if (strstr(soapconn->read_buf,
+				"<faultcode>wsse:FailedAuthentication</faultcode>") != NULL)
+	{
+		gchar *faultstring;
+
+		faultstring = strstr(soapconn->read_buf, "<faultstring>");
+
+		if (faultstring != NULL)
+		{
+			gchar *c;
+			faultstring += strlen("<faultstring>");
+			if (faultstring < soapconn->read_buf + soapconn->read_len) {
+				c = strstr(soapconn->read_buf, "</faultstring>");
+				if (c != NULL) {
+					*c = '\0';
+					msn_session_set_error(session, MSN_ERROR_AUTH, faultstring);
+				}
+			}
+		}
+		
+	}
+	else if (strstr(soapconn->read_buf, "HTTP/1.1 503 Service Unavailable"))
+	{
+		msn_session_set_error(session, MSN_ERROR_SERV_UNAVAILABLE, NULL);
+	}
+	else if ((strstr(soapconn->read_buf, "HTTP/1.1 200 OK"))
+		||(strstr(soapconn->read_buf, "HTTP/1.1 500")))
+	{
+		gboolean soapconn_is_valid = FALSE;
+
+		/*OK! process the SOAP body*/
+		body_start = (char *)g_strstr_len(soapconn->read_buf, soapconn->read_len,"\r\n\r\n");
+		if (!body_start) {
+			return;
+		}
+		body_start += 4;
+
+		if (body_start > soapconn->read_buf + soapconn->read_len)
+			return;
+
+		/* we read the content-length*/
+		if ( (length_start = g_strstr_len(soapconn->read_buf, soapconn->read_len, "Content-Length: ")) != NULL)
+			length_start += strlen("Content-Length: ");
+
+		if (length_start > soapconn->read_buf + soapconn->read_len)
+			return;
+
+		if ( (length_end = strstr(length_start, "\r\n")) == NULL )
+			return;
+
+		body_len = g_strndup(length_start, length_end - length_start);
+
+		/*setup the conn body */
+		soapconn->body		= body_start;
+		soapconn->body_len	= atoi(body_len);
+		g_free(body_len);
+#ifdef MSN_SOAP_DEBUG
+		purple_debug_misc("MSN SOAP","SOAP bytes read so far: %d, Content-Length: %d\n", soapconn->read_len, soapconn->body_len);
+#endif
+		soapconn->need_to_read = (body_start - soapconn->read_buf + soapconn->body_len) - soapconn->read_len;
+		if ( soapconn->need_to_read > 0 ) {
+			return;
+		}
+
+#if defined(MSN_SOAP_DEBUG) && !defined(_WIN32)
+
+		node = xmlnode_from_str(soapconn->body, soapconn->body_len);
+	
+		if (node != NULL) {
+			formattedxml = xmlnode_to_formatted_str(node, NULL);
+			http_headers = g_strndup(soapconn->read_buf, soapconn->body - soapconn->read_buf);
+				
+			purple_debug_info("MSN SOAP","Data with XML payload received from the SOAP server:\n%s%s\n", http_headers, formattedxml);
+			g_free(http_headers);
+			g_free(formattedxml);
+			xmlnode_free(node);
+		}
+		else
+			purple_debug_info("MSN SOAP","Data received from the SOAP server:\n%s\n", soapconn->read_buf);
+#endif
+
+		/*remove the read handler*/
+		msn_soap_close_handler( &(soapconn->input_handler) );
+//		purple_input_remove(soapconn->input_handler);
+//		soapconn->input_handler = 0;
+		/*
+		 * close the soap connection,if more soap request came,
+		 * Just reconnect to do it,
+		 *
+		 * To solve the problem described below:
+		 * When I post the soap request in one socket one after the other,
+		 * The first read is ok, But the second soap read always got 0 bytes,
+		 * Weird!
+		 * */
+		msn_soap_close(soapconn);
+
+		/*call the read callback*/
+		if ( soapconn->read_cb != NULL ) {
+			soapconn_is_valid = soapconn->read_cb(soapconn);
+		}
+		
+		if (!soapconn_is_valid) {
+			return;
+		}
+
+		/* dispatch next request in queue */
+		msn_soap_post(soapconn, NULL);
+	}	
+	return;
+}
+
+void 
+msn_soap_free_read_buf(MsnSoapConn *soapconn)
+{
+	g_return_if_fail(soapconn != NULL);
+	
+	if (soapconn->read_buf) {
+		g_free(soapconn->read_buf);
+	}
+	soapconn->read_buf = NULL;
+	soapconn->read_len = 0;
+	soapconn->need_to_read = 0;
+}
+
+void
+msn_soap_free_write_buf(MsnSoapConn *soapconn)
+{
+	g_return_if_fail(soapconn != NULL);
+
+	if (soapconn->write_buf) {
+		g_free(soapconn->write_buf);
+	}
+	soapconn->write_buf = NULL;
+	soapconn->written_len = 0;
+}
+
+/*Soap write process func*/
+static void
+msn_soap_write_cb(gpointer data, gint source, PurpleInputCondition cond)
+{
+	MsnSoapConn *soapconn = data;
+	int len, total_len;
+
+	g_return_if_fail(soapconn != NULL);
+	if ( soapconn->write_buf == NULL ) {
+		purple_debug_error("MSN SOAP","SOAP write buffer is NULL\n");
+	//	msn_soap_check_conn_errors(soapconn);
+	//	purple_input_remove(soapconn->output_handler);
+	//	soapconn->output_handler = 0;
+		msn_soap_close_handler( &(soapconn->output_handler) );
+		return;
+	}
+	total_len = strlen(soapconn->write_buf);
+
+	/* 
+	 * write the content to SSL server,
+	 */
+	len = purple_ssl_write(soapconn->gsc,
+		soapconn->write_buf + soapconn->written_len,
+		total_len - soapconn->written_len);
+
+	if (len < 0 && errno == EAGAIN)
+		return;
+	else if (len <= 0){
+		/*SSL write error!*/
+//		msn_soap_check_conn_errors(soapconn);
+
+		msn_soap_close_handler( &(soapconn->output_handler) );
+//		purple_input_remove(soapconn->output_handler);
+//		soapconn->output_handler = 0;
+
+		msn_soap_close(soapconn);
+
+		/* TODO: notify of the error */
+		purple_debug_error("MSN SOAP", "Error writing to SSL connection!\n");
+		msn_soap_post(soapconn, NULL);
+		return;
+	}
+	soapconn->written_len += len;
+
+	if (soapconn->written_len < total_len)
+		return;
+
+	msn_soap_close_handler( &(soapconn->output_handler) );
+//	purple_input_remove(soapconn->output_handler);
+//	soapconn->output_handler = 0;
+
+	/*clear the write buff*/
+	msn_soap_free_write_buf(soapconn);
+
+	/* Write finish!
+	 * callback for write done
+	 */
+	if(soapconn->written_cb != NULL){
+		soapconn->written_cb(soapconn);
+	}
+	/*maybe we need to read the input?*/
+	if ( soapconn->input_handler == 0 ) {
+		soapconn->input_handler = purple_input_add(soapconn->gsc->fd,
+			PURPLE_INPUT_READ, msn_soap_read_cb, soapconn);
+	}
+}
+
+/*write the buffer to SOAP connection*/
+void
+msn_soap_write(MsnSoapConn * soapconn, char *write_buf, MsnSoapWrittenCbFunction written_cb)
+{
+	if (soapconn == NULL) {
+		return;
+	}
+
+	msn_soap_set_process_step(soapconn, MSN_SOAP_PROCESSING);
+
+	soapconn->write_buf = write_buf;
+	soapconn->written_len = 0;
+	soapconn->written_cb = written_cb;
+	
+	msn_soap_free_read_buf(soapconn);
+
+	/*clear the read buffer first*/
+	/*start the write*/
+	soapconn->output_handler = purple_input_add(soapconn->gsc->fd, PURPLE_INPUT_WRITE,
+						    msn_soap_write_cb, soapconn);
+	msn_soap_write_cb(soapconn, soapconn->gsc->fd, PURPLE_INPUT_WRITE);
+}
+
+/* New a soap request*/
+MsnSoapReq *
+msn_soap_request_new(const char *host,const char *post_url,const char *soap_action,
+				const char *body, const gpointer data_cb,
+				MsnSoapReadCbFunction read_cb,
+				MsnSoapWrittenCbFunction written_cb,
+				MsnSoapConnectInitFunction connect_init)
+{
+	MsnSoapReq *request;
+
+	request = g_new0(MsnSoapReq, 1);
+	request->id = 0;
+
+	request->login_host = g_strdup(host);
+	request->login_path = g_strdup(post_url);
+	request->soap_action		= g_strdup(soap_action);
+	request->body		= g_strdup(body);
+	request->data_cb 	= data_cb;
+	request->read_cb	= read_cb;
+	request->written_cb	= written_cb;
+	request->connect_init	= connect_init;
+
+	return request;
+}
+
+/*free a soap request*/
+void
+msn_soap_request_free(MsnSoapReq *request)
+{
+	g_return_if_fail(request != NULL);
+
+	g_free(request->login_host);
+	g_free(request->login_path);
+	g_free(request->soap_action);
+	g_free(request->body);
+	request->read_cb	= NULL;
+	request->written_cb	= NULL;
+	request->connect_init	= NULL;
+
+	g_free(request);
+}
+
+/*post the soap request queue's head request*/
+void
+msn_soap_post_head_request(MsnSoapConn *soapconn)
+{
+	g_return_if_fail(soapconn != NULL);
+	g_return_if_fail(soapconn->soap_queue != NULL);
+	
+	if (soapconn->step == MSN_SOAP_CONNECTED ||
+	    soapconn->step == MSN_SOAP_CONNECTED_IDLE) {
+
+		purple_debug_info("MSN SOAP", "Posting new request from head of the queue\n");
+
+		if ( !g_queue_is_empty(soapconn->soap_queue) ) {
+			MsnSoapReq *request;
+
+			if ( (request = g_queue_pop_head(soapconn->soap_queue)) != NULL ) {
+				msn_soap_post_request(soapconn,request);
+			}
+		} else {
+			purple_debug_info("MSN SOAP", "No requests to process found.\n");
+			msn_soap_set_process_step(soapconn, MSN_SOAP_CONNECTED_IDLE);
+		}
+	}
+}
+
+/*post the soap request ,
+ * if not connected, Connected first.
+ */
+void
+msn_soap_post(MsnSoapConn *soapconn,MsnSoapReq *request)
+{
+	MsnSoapReq *head_request;
+
+	if (soapconn == NULL)
+		return;
+
+	if (request != NULL) {
+#ifdef MSN_SOAP_DEBUG
+		purple_debug_misc("MSN SOAP", "Request added to the queue\n");
+#endif
+		g_queue_push_tail(soapconn->soap_queue, request);
+	}
+
+	if ( !g_queue_is_empty(soapconn->soap_queue)) {
+
+		/* we may have to reinitialize the soap connection, so avoid
+		 * reusing the connection for now */
+
+		if (soapconn->step == MSN_SOAP_CONNECTED_IDLE) {
+			purple_debug_misc("MSN SOAP","Already connected to SOAP server, re-initializing\n");
+			msn_soap_close_handler( &(soapconn->input_handler) );
+			msn_soap_close_handler( &(soapconn->output_handler) );
+			msn_soap_close(soapconn);
+		}
+
+		if (!msn_soap_connected(soapconn) && (soapconn->step == MSN_SOAP_UNCONNECTED)) {
+
+			/*not connected?and we have something to process connect it first*/
+			purple_debug_misc("MSN SOAP","No connection to SOAP server. Connecting...\n");
+			head_request = g_queue_peek_head(soapconn->soap_queue);
+
+			if (head_request == NULL) {
+				purple_debug_error("MSN SOAP", "Queue is not empty, but failed to peek the head request!\n");
+				return;
+			}
+
+			if (head_request->connect_init != NULL) {
+				head_request->connect_init(soapconn);
+			}
+			msn_soap_connect(soapconn);
+			return;
+		}
+
+		purple_debug_info("MSN SOAP", "Currently processing another SOAP request\n");
+	} else {
+		purple_debug_info("MSN SOAP", "No requests left to dispatch\n");
+	}
+}
+
+/*Post the soap request action*/
+void
+msn_soap_post_request(MsnSoapConn *soapconn, MsnSoapReq *request)
+{
+	char * soap_head = NULL;
+	char * request_str = NULL;
+#ifdef MSN_SOAP_DEBUG
+#if !defined(_WIN32)
+	xmlnode * node;
+#endif
+	purple_debug_misc("MSN SOAP","msn_soap_post_request()\n");
+#endif
+
+	msn_soap_set_process_step(soapconn, MSN_SOAP_PROCESSING);
+	soap_head = g_strdup_printf(
+					"POST %s HTTP/1.1\r\n"
+					"SOAPAction: %s\r\n"
+					"Content-Type:text/xml; charset=utf-8\r\n"
+					"Cookie: MSPAuth=%s\r\n"
+					"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n"
+					"Accept: */*\r\n"
+					"Host: %s\r\n"
+					"Content-Length: %" G_GSIZE_FORMAT "\r\n"
+					"Connection: Keep-Alive\r\n"
+					"Cache-Control: no-cache\r\n\r\n",
+					request->login_path,
+					request->soap_action,
+					soapconn->session->passport_info.mspauth,
+					request->login_host,
+					strlen(request->body)
+					);
+	request_str = g_strdup_printf("%s%s", soap_head, request->body);
+
+#if defined(MSN_SOAP_DEBUG) && !defined(_WIN32)
+	node = xmlnode_from_str(request->body, -1);
+	if (node != NULL) {
+		char *formattedstr = xmlnode_to_formatted_str(node, NULL);
+		purple_debug_info("MSN SOAP","Posting request to SOAP server:\n%s%s\n",soap_head, formattedstr);
+		g_free(formattedstr);
+		xmlnode_free(node);
+	}
+	else
+		purple_debug_info("MSN SOAP","Failed to parse SOAP request being sent:\n%s\n", request_str);
+#endif
+	
+	g_free(soap_head);
+	/*free read buffer*/
+	// msn_soap_free_read_buf(soapconn);
+	/*post it to server*/
+	soapconn->data_cb = request->data_cb;
+	msn_soap_write(soapconn, request_str, request->written_cb);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/msn/soap.h	Fri Sep 28 16:34:43 2007 +0000
@@ -0,0 +1,167 @@
+/**
+ * @file soap.h
+ * 	header file for SOAP connection related process
+ *	Author
+ * 		MaYuan<mayuan2006@gmail.com>
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _MSN_SOAP_H_
+#define _MSN_SOAP_H_
+
+#define MSN_SOAP_READ_BUFF_SIZE		8192
+
+/* define this to debug the communications with the SOAP server */
+/* #define MSN_SOAP_DEBUG */
+
+#define MSN_SOAP_READ 1
+#define MSN_SOAP_WRITE 2
+
+typedef enum
+{
+	MSN_SOAP_UNCONNECTED,
+	MSN_SOAP_CONNECTING,
+	MSN_SOAP_CONNECTED,
+	MSN_SOAP_PROCESSING,
+	MSN_SOAP_CONNECTED_IDLE
+}MsnSoapStep;
+
+/* MSN SoapRequest structure*/
+typedef struct _MsnSoapReq MsnSoapReq;
+
+/* MSN Https connection structure*/
+typedef struct _MsnSoapConn MsnSoapConn;
+
+typedef void (*MsnSoapConnectInitFunction)(MsnSoapConn *);
+typedef gboolean (*MsnSoapReadCbFunction)(MsnSoapConn *);
+typedef void (*MsnSoapWrittenCbFunction)(MsnSoapConn *);
+
+typedef gboolean (*MsnSoapSslConnectCbFunction)(MsnSoapConn *, PurpleSslConnection *);
+typedef void (*MsnSoapSslErrorCbFunction)(MsnSoapConn *, PurpleSslConnection *, PurpleSslErrorType);
+
+
+struct _MsnSoapReq{
+	/*request sequence*/
+	int	 id;
+
+	char *login_host;
+	char *login_path;
+	char *soap_action;
+
+	char *body;
+	
+	gpointer data_cb;
+	MsnSoapReadCbFunction read_cb;
+	MsnSoapWrittenCbFunction written_cb;
+	MsnSoapConnectInitFunction connect_init;
+};
+
+struct _MsnSoapConn{
+	MsnSession *session;
+	gpointer parent;
+
+	char *login_host;
+	char *login_path;
+	char *soap_action;
+
+	MsnSoapStep step;
+	/*ssl connection?*/
+	guint	ssl_conn;
+	/*normal connection*/
+	guint	fd;
+	/*SSL connection*/
+	PurpleSslConnection *gsc;
+	/*ssl connection callback*/
+	MsnSoapSslConnectCbFunction connect_cb;
+	/*ssl error callback*/
+	MsnSoapSslErrorCbFunction error_cb;
+
+	/*read handler*/
+	guint input_handler;
+	/*write handler*/
+	guint output_handler;
+
+	/*Queue of SOAP request to send*/
+	int soap_id;
+	GQueue *soap_queue;
+
+	/*write buffer*/
+	char *write_buf;
+	gsize written_len;
+	MsnSoapWrittenCbFunction written_cb;
+
+	/*read buffer*/
+	char *read_buf;
+	gsize read_len;
+	gsize need_to_read;
+	MsnSoapReadCbFunction read_cb;
+
+	gpointer data_cb;
+
+	/*HTTP reply body part*/
+	char *body;
+	int body_len;
+};
+
+
+/*Function Prototype*/
+/*Soap Request Function */
+MsnSoapReq *msn_soap_request_new(const char *host, const char *post_url,
+				 const char *soap_action, const char *body,
+				 const gpointer data_cb,
+				 MsnSoapReadCbFunction read_cb,
+				 MsnSoapWrittenCbFunction written_cb,
+				 MsnSoapConnectInitFunction connect_init);
+
+void msn_soap_request_free(MsnSoapReq *request);
+void msn_soap_post_request(MsnSoapConn *soapconn,MsnSoapReq *request);
+void msn_soap_post_head_request(MsnSoapConn *soapconn);
+
+/*new a soap conneciton */
+MsnSoapConn *msn_soap_new(MsnSession *session,gpointer data,int sslconn);
+
+/*destroy */
+void msn_soap_destroy(MsnSoapConn *soapconn);
+
+/*init a soap conneciton */
+void msn_soap_init(MsnSoapConn *soapconn, char * host, int ssl,
+		   MsnSoapSslConnectCbFunction connect_cb,
+		   MsnSoapSslErrorCbFunction error_cb);
+void msn_soap_connect(MsnSoapConn *soapconn);
+void msn_soap_close(MsnSoapConn *soapconn);
+
+/*write to soap*/
+void msn_soap_write(MsnSoapConn * soapconn, char *write_buf, MsnSoapWrittenCbFunction written_cb);
+void msn_soap_post(MsnSoapConn *soapconn,MsnSoapReq *request);
+
+void msn_soap_free_read_buf(MsnSoapConn *soapconn);
+void msn_soap_free_write_buf(MsnSoapConn *soapconn);
+void msn_soap_connect_cb(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond);
+void msn_soap_read_cb(gpointer data, gint source, PurpleInputCondition cond);
+
+/*clean the unhandled requests*/
+void msn_soap_clean_unhandled_requests(MsnSoapConn *soapconn);
+
+/*check if the soap connection is connected*/
+int msn_soap_connected(MsnSoapConn *soapconn);
+void msn_soap_set_process_step(MsnSoapConn *soapconn, MsnSoapStep step);
+
+#endif/*_MSN_SOAP_H_*/
+
--- a/libpurple/protocols/msn/state.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/state.c	Fri Sep 28 16:34:43 2007 +0000
@@ -38,6 +38,197 @@
 	N_("Available")
 };
 
+/* Local Function Prototype*/
+static char *msn_build_psm(const char *psmstr,const char *mediastr,
+						   const char *guidstr);
+
+/*
+ * WLM media PSM info build prcedure
+ *
+ * Result can like:
+ *	<CurrentMedia>\0Music\01\0{0} - {1}\0Song Title\0Song Artist\0Song Album\0\0</CurrentMedia>\
+ *	<CurrentMedia>\0Games\01\0Playing {0}\0Game Name\0</CurrentMedia>\
+ *	<CurrentMedia>\0Office\01\0Office Message\0Office App Name\0</CurrentMedia>"
+ */
+static char *
+msn_build_psm(const char *psmstr,const char *mediastr, const char *guidstr)
+{
+	xmlnode *dataNode,*psmNode,*mediaNode,*guidNode;
+	char *result;
+	int length;
+
+	dataNode = xmlnode_new("Data");
+
+	psmNode = xmlnode_new("PSM");
+	if(psmstr != NULL){
+		xmlnode_insert_data(psmNode,psmstr,strlen(psmstr));
+	}
+	xmlnode_insert_child(dataNode,psmNode);
+
+	mediaNode = xmlnode_new("CurrentMedia");
+	if(mediastr != NULL){
+		xmlnode_insert_data(mediaNode,mediastr,strlen(mediastr));
+	}
+	xmlnode_insert_child(dataNode,mediaNode);
+
+	guidNode = xmlnode_new("MachineGuid");
+	if(guidstr != NULL){
+		xmlnode_insert_data(guidNode,guidstr,strlen(guidstr));
+	}
+	xmlnode_insert_child(dataNode,guidNode);
+
+	result = xmlnode_to_str(dataNode,&length);
+	xmlnode_free(dataNode);
+	return result;
+}
+
+/* parse CurrentMedia string */
+char *
+msn_parse_currentmedia(const char *cmedia)
+{
+	char **cmedia_array;
+	GString *buffer = NULL;
+	int strings;
+
+	if ((cmedia == NULL) || (*cmedia == '\0')) {
+		purple_debug_info("msn", "No currentmedia string\n");
+		return NULL;
+	}
+
+	purple_debug_info("msn", "Parsing currentmedia string: \"%s\"\n", cmedia);
+
+	cmedia_array = g_strsplit(cmedia, "\\0", 0);
+
+	strings = 0;
+	/* Yes, we want to skip the first element here, as it is empty due to
+	 * the cmedia string starting with \0 -- see the examples below. */
+	while (cmedia_array[++strings] != NULL);
+
+	/* The cmedia_array[2] field contains a 1 if enabled. */
+	if ((strings > 3) && (!strcmp(cmedia_array[2], "1"))) {
+		char *inptr = cmedia_array[3];
+
+		buffer = g_string_new(NULL);
+
+		while (*inptr != '\0') {
+			if ((*inptr == '{') && ((*(inptr + 1) != '\0') && (*(inptr+2) == '}'))) {
+				char *tmpptr;
+				int tmp;
+
+				errno = 0;
+				tmp = strtol(inptr + 1, &tmpptr, 10);
+
+				if (errno == 0 && tmpptr != inptr + 1 &&
+				    tmp + 4 < strings) {
+					/* Replace {?} tag with appropriate text only when successful.
+					 * Skip otherwise. */
+					buffer = g_string_append(buffer, cmedia_array[tmp + 4]);
+				}
+				inptr += 3; /* Skip to the next char after '}' */
+			} else {
+				buffer = g_string_append_c(buffer, *inptr++);
+			}
+		}
+		purple_debug_info("msn", "Parsed currentmedia string, result: \"%s\"\n",
+		                  buffer->str);
+	} else {
+		purple_debug_info("msn", "Current media marked disabled, not parsing.\n");
+	}
+
+	g_strfreev(cmedia_array);
+	return buffer ? g_string_free(buffer, FALSE) : NULL;
+}
+
+/* get the CurrentMedia info from the XML string */
+char *
+msn_get_currentmedia(char *xml_str, gsize len)
+{
+	xmlnode *payloadNode, *currentmediaNode;
+	char *currentmedia;
+	
+	purple_debug_info("msn","msn get CurrentMedia\n");
+	payloadNode = xmlnode_from_str(xml_str, len);
+	if (!payloadNode){
+		purple_debug_error("msn","PSM XML parse Error!\n");
+		return NULL;
+	}
+	currentmediaNode = xmlnode_get_child(payloadNode, "CurrentMedia");
+	if (currentmediaNode == NULL){
+		purple_debug_info("msn","No CurrentMedia Node");
+		xmlnode_free(payloadNode);
+		return NULL;
+	}
+	currentmedia = xmlnode_get_data(currentmediaNode);
+
+	xmlnode_free(payloadNode);
+
+	return currentmedia;
+}
+
+/*get the PSM info from the XML string*/
+char *
+msn_get_psm(char *xml_str, gsize len)
+{
+	xmlnode *payloadNode, *psmNode;
+	char *psm;
+	
+	purple_debug_info("MSNP14","msn get PSM\n");
+	payloadNode = xmlnode_from_str(xml_str, len);
+	if (!payloadNode){
+		purple_debug_error("MSNP14","PSM XML parse Error!\n");
+		return NULL;
+	}
+	psmNode = xmlnode_get_child(payloadNode, "PSM");
+	if (psmNode == NULL){
+		purple_debug_info("MSNP14","No PSM status Node");
+		xmlnode_free(payloadNode);
+		return NULL;
+	}
+	psm = xmlnode_get_data(psmNode);
+
+	xmlnode_free(payloadNode);
+
+	return psm;
+}
+
+/* set the MSN's PSM info,Currently Read from the status Line 
+ * Thanks for Cris Code
+ */
+void
+msn_set_psm(MsnSession *session)
+{
+	PurpleAccount *account = session->account;
+	PurplePresence *presence;
+	PurpleStatus *status;
+	MsnCmdProc *cmdproc;
+	MsnTransaction *trans;
+	char *payload;
+	const char *statusline;
+	gchar *unescapedstatusline;
+
+	g_return_if_fail(session != NULL);
+	g_return_if_fail(session->notification != NULL);
+
+	cmdproc = session->notification->cmdproc;
+	/*prepare PSM info*/
+	if(session->psm){
+		g_free(session->psm);
+	}
+	/*Get the PSM string from Purple's Status Line*/
+	presence = purple_account_get_presence(account);
+	status = purple_presence_get_active_status(presence);
+	statusline = purple_status_get_attr_string(status, "message");
+	unescapedstatusline = purple_unescape_html(statusline);
+	session->psm = msn_build_psm(unescapedstatusline, NULL, NULL);
+	g_free(unescapedstatusline);
+	payload = session->psm;
+
+	purple_debug_misc("MSNP14","Sending UUX command with payload: %s\n",payload);
+	trans = msn_transaction_new(cmdproc, "UUX","%d",strlen(payload));
+	msn_transaction_set_payload(trans, payload, strlen(payload));
+	msn_cmdproc_send_trans(cmdproc, trans);
+}
+
 void
 msn_change_status(MsnSession *session)
 {
@@ -79,6 +270,7 @@
 
 		g_free(msnobj_str);
 	}
+	msn_set_psm(session);
 }
 
 const char *
--- a/libpurple/protocols/msn/state.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/state.h	Fri Sep 28 16:34:43 2007 +0000
@@ -59,6 +59,17 @@
 
 const char *msn_state_get_text(MsnAwayType state);
 
+void msn_set_psm(MsnSession *session);
+
+/* Parse CurrentMedia string */
+char * msn_parse_currentmedia(const char *cmedia);
+
+/* Get the CurrentMedia info from the XML string */
+char * msn_get_currentmedia(char *xml_str,gsize len);
+
+/*get the PSM info from the XML string*/
+char * msn_get_psm(char *xml_str,gsize len);
+
 MsnAwayType msn_state_from_account(PurpleAccount *account);
 
 #endif /* _MSN_STATE_H_ */
--- a/libpurple/protocols/msn/switchboard.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/switchboard.c	Fri Sep 28 16:34:43 2007 +0000
@@ -25,7 +25,7 @@
 #include "prefs.h"
 #include "switchboard.h"
 #include "notification.h"
-#include "msn-utils.h"
+#include "msnutils.h"
 
 #include "error.h"
 
@@ -534,6 +534,7 @@
 	payload = msn_message_gen_payload(msg, &payload_len);
 
 #ifdef MSN_DEBUG_SB
+	purple_debug_info("MSNP14","SB length:{%d}",payload_len);
 	msn_message_show_readable(msg, "SB SEND", FALSE);
 #endif
 
@@ -621,6 +622,7 @@
 	g_return_if_fail(swboard != NULL);
 	g_return_if_fail(msg     != NULL);
 
+	purple_debug_info("MSNP14","switchboard send msg..\n");
 	if (msn_switchboard_can_send(swboard))
 		release_msg(swboard, msg);
 	else if (queue)
@@ -727,7 +729,8 @@
 
 	msg = msn_message_new_from_cmd(cmdproc->session, cmd);
 
-	msn_message_parse_payload(msg, payload, len);
+	msn_message_parse_payload(msg, payload, len,
+					MSG_LINE_DEM,MSG_BODY_DEM);
 #ifdef MSN_DEBUG_SB
 	msn_message_show_readable(msg, "SB RECV", FALSE);
 #endif
@@ -749,6 +752,14 @@
 }
 
 static void
+ubm_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_misc("MSNP14","get UBM...\n");
+	cmdproc->servconn->payload_len = atoi(cmd->params[4]);
+	cmdproc->last_cmd->payload_cb = msg_cmd_post;
+}
+
+static void
 nak_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnMessage *msg;
@@ -1095,6 +1106,8 @@
 cal_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
 {
 	int reason = MSN_SB_ERROR_UNKNOWN;
+	MsnMessage *msg;
+	MsnSwitchBoard *swboard = trans->data;
 
 	if (error == 215)
 	{
@@ -1107,7 +1120,19 @@
 	}
 
 	purple_debug_warning("msn", "cal_error: command %s gave error %i\n", trans->command, error);
+	purple_debug_warning("msn", "Will Use Offline Message to sendit\n");
 
+//	cal_error_helper(trans, reason);
+	/*offline Message send Process*/
+
+	while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL){
+		purple_debug_warning("MSNP14","offline msg to send:{%s}\n",msg->body);
+		/* The messages could not be sent due to a switchboard error */
+		swboard->error = MSN_SB_ERROR_USER_OFFLINE;
+		msg_error_helper(swboard->cmdproc, msg,
+							 MSN_MSG_ERROR_SB);
+		msn_message_unref(msg);
+	}
 	cal_error_helper(trans, reason);
 }
 
@@ -1151,6 +1176,7 @@
 		/* The conversation window was closed. */
 		return;
 
+	purple_debug_info("MSNP14","Switchboard:auth:{%s} socket:{%s}\n",cmd->params[4],cmd->params[2]);
 	msn_switchboard_set_auth_key(swboard, cmd->params[4]);
 
 	msn_parse_socket(cmd->params[2], &host, &port);
@@ -1263,6 +1289,7 @@
 	msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd);
 
 	msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "UBM", ubm_cmd);
 	msn_table_add_cmd(cbs_table, NULL, "JOI", joi_cmd);
 	msn_table_add_cmd(cbs_table, NULL, "BYE", bye_cmd);
 	msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd);
--- a/libpurple/protocols/msn/sync.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/sync.c	Fri Sep 28 16:34:43 2007 +0000
@@ -90,9 +90,9 @@
 {
 	MsnSession *session = cmdproc->session;
 	const char *name;
-	int group_id;
+	const char *group_id;
 
-	group_id = atoi(cmd->params[0]);
+	group_id = cmd->params[0];
 	name = purple_url_decode(cmd->params[1]);
 
 	msn_group_new(session->userlist, group_id, name);
@@ -156,10 +156,10 @@
 
 		for (c = tokens; *c != NULL; c++)
 		{
-			int id;
+			char *id;
 
-			id = atoi(*c);
-			group_ids = g_slist_append(group_ids, GINT_TO_POINTER(id));
+			id = *c;
+			group_ids = g_slist_append(group_ids, g_strdup(id));
 		}
 
 		g_strfreev(tokens);
--- a/libpurple/protocols/msn/user.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/user.c	Fri Sep 28 16:34:43 2007 +0000
@@ -25,6 +25,7 @@
 #include "user.h"
 #include "slp.h"
 
+/*new a user object*/
 MsnUser *
 msn_user_new(MsnUserList *userlist, const char *passport,
 			 const char *store_name)
@@ -50,6 +51,7 @@
 	return user;
 }
 
+/*destroy a user object*/
 void
 msn_user_destroy(MsnUser *user)
 {
@@ -59,7 +61,14 @@
 		g_hash_table_destroy(user->clientcaps);
 
 	if (user->group_ids != NULL)
+	{
+		GList *l;
+		for (l = user->group_ids; l != NULL; l = l->next)
+		{
+			g_free(l->data);
+		}
 		g_list_free(user->group_ids);
+	}
 
 	if (user->msnobj != NULL)
 		msn_object_destroy(user->msnobj);
@@ -67,6 +76,7 @@
 	g_free(user->passport);
 	g_free(user->friendly_name);
 	g_free(user->store_name);
+	g_free(user->uid);
 	g_free(user->phone.home);
 	g_free(user->phone.work);
 	g_free(user->phone.mobile);
@@ -81,7 +91,18 @@
 
 	account = user->userlist->session->account;
 
-	if (user->status != NULL) {
+	if (user->statusline != NULL && user->currentmedia != NULL) {
+		purple_prpl_got_user_status(account, user->passport, user->status,
+		                          "message", user->statusline,
+		                          "currentmedia", user->currentmedia, NULL);
+	} else if (user->currentmedia != NULL) {
+		purple_prpl_got_user_status(account, user->passport, user->status, "currentmedia",
+		                          user->currentmedia, NULL);
+	} else if (user->statusline != NULL) {
+		//char *status = g_strdup_printf("%s - %s", user->status, user->statusline);
+		purple_prpl_got_user_status(account, user->passport, user->status,
+		                          "message", user->statusline, NULL);
+	} else if (user->status != NULL) {
 		if (!strcmp(user->status, "offline") && user->mobile) {
 			purple_prpl_got_user_status(account, user->passport, "offline", NULL);
 			purple_prpl_got_user_status(account, user->passport, "mobile", NULL);
@@ -142,12 +163,66 @@
 }
 
 void
+msn_user_set_statusline(MsnUser *user, const char *statusline)
+{
+	g_return_if_fail(user != NULL);
+
+	g_free(user->statusline);
+	user->statusline = g_strdup(statusline);
+}
+
+void
+msn_user_set_currentmedia(MsnUser *user, const char *currentmedia)
+{
+	g_return_if_fail(user != NULL);
+
+	g_free(user->currentmedia);
+	user->currentmedia = g_strdup(currentmedia);
+}
+
+void
 msn_user_set_store_name(MsnUser *user, const char *name)
 {
 	g_return_if_fail(user != NULL);
 
-	g_free(user->store_name);
-	user->store_name = g_strdup(name);
+	if (name != NULL)
+	{
+		g_free(user->store_name);
+		user->store_name = g_strdup(name);
+	}
+}
+
+void
+msn_user_set_uid(MsnUser *user, const char *uid)
+{
+	g_return_if_fail(user != NULL);
+
+	g_free(user->uid);
+	user->uid = g_strdup(uid);
+}
+
+void
+msn_user_set_type(MsnUser *user, MsnUserType type)
+{
+	g_return_if_fail(user != NULL);
+
+	user->type = type;
+}
+
+void
+msn_user_set_op(MsnUser *user, int list_op)
+{
+	g_return_if_fail(user != NULL);
+
+	user->list_op |= list_op;
+}
+
+void
+msn_user_unset_op(MsnUser *user, int list_op)
+{
+	g_return_if_fail(user != NULL);
+	
+	user->list_op &= ~list_op;
 }
 
 void
@@ -218,54 +293,97 @@
 	}
 }
 
+/*add group id to User object*/
 void
-msn_user_add_group_id(MsnUser *user, int id)
+msn_user_add_group_id(MsnUser *user, const char* id)
 {
 	MsnUserList *userlist;
 	PurpleAccount *account;
 	PurpleBuddy *b;
 	PurpleGroup *g;
 	const char *passport;
+	char *group_id;
 	const char *group_name;
 
 	g_return_if_fail(user != NULL);
-	g_return_if_fail(id >= 0);
+	g_return_if_fail(id != NULL);
 
-	user->group_ids = g_list_append(user->group_ids, GINT_TO_POINTER(id));
+	group_id = g_strdup(id);
+	user->group_ids = g_list_append(user->group_ids, group_id);
 
 	userlist = user->userlist;
 	account = userlist->session->account;
 	passport = msn_user_get_passport(user);
 
-	group_name = msn_userlist_find_group_name(userlist, id);
+	group_name = msn_userlist_find_group_name(userlist, group_id);
+
+	purple_debug_info("User","group id:%s,name:%s,user:%s\n", group_id, group_name, passport);
 
 	g = purple_find_group(group_name);
 
-	if ((id == 0) && (g == NULL))
+	if ((id == NULL) && (g == NULL))
 	{
 		g = purple_group_new(group_name);
 		purple_blist_add_group(g, NULL);
 	}
 
 	b = purple_find_buddy_in_group(account, passport, g);
-
 	if (b == NULL)
 	{
 		b = purple_buddy_new(account, passport, NULL);
-
 		purple_blist_add_buddy(b, NULL, g, NULL);
 	}
+	b->proto_data = user;
+	/*Update the blist Node info*/
+//	purple_blist_node_set_string(&(b->node), "", "");
+}
 
-	b->proto_data = user;
+/*check if the msn user is online*/
+gboolean
+msn_user_is_online(PurpleAccount *account, const char *name)
+{
+	PurpleBuddy *buddy;
+
+	buddy =purple_find_buddy(account,name);
+	return PURPLE_BUDDY_IS_ONLINE(buddy);
+}
+
+gboolean
+msn_user_is_yahoo(PurpleAccount *account, const char *name)
+{
+	MsnSession *session = NULL;
+	MsnUser *user;
+	PurpleConnection *gc;
+
+	gc = purple_account_get_connection(account);
+	if (gc != NULL)
+		session = gc->proto_data;
+
+	if ((session != NULL) && (session->protocol_ver == WLM_PROT_VER))
+		return FALSE;
+
+	if ((session != NULL) && (user = msn_userlist_find_user(session->userlist, name)) != NULL)
+	{
+		return (user->type == MSN_USER_TYPE_YAHOO);
+	}
+	return (strstr(name,"@yahoo.") != NULL);
 }
 
 void
-msn_user_remove_group_id(MsnUser *user, int id)
+msn_user_remove_group_id(MsnUser *user, const char *id)
 {
+	GList *l;
+
 	g_return_if_fail(user != NULL);
-	g_return_if_fail(id >= 0);
+	g_return_if_fail(id != NULL);
+
+	l = g_list_find_custom(user->group_ids, id, (GCompareFunc)strcmp);
 
-	user->group_ids = g_list_remove(user->group_ids, GINT_TO_POINTER(id));
+	if (l == NULL)
+		return;
+
+	g_free(l->data);
+	user->group_ids = g_list_remove_link(user->group_ids, l);
 }
 
 void
--- a/libpurple/protocols/msn/user.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/user.h	Fri Sep 28 16:34:43 2007 +0000
@@ -31,6 +31,17 @@
 
 #include "userlist.h"
 
+typedef enum
+{
+	MSN_USER_TYPE_UNKNOWN  = 0x00,
+	MSN_USER_TYPE_PASSPORT = 0x01,
+	MSN_USER_TYPE_UNKNOWN1 = 0x02,
+	MSN_USER_TYPE_MOBILE   = 0x04,
+	MSN_USER_TYPE_UNKNOWN2 = 0x08,
+	MSN_USER_TYPE_UNKNOWN3 = 0x10,
+	MSN_USER_TYPE_YAHOO    = 0x20
+} MsnUserType;
+
 /**
  * A user.
  */
@@ -45,7 +56,12 @@
 	char *store_name;       /**< The name stored in the server. */
 	char *friendly_name;    /**< The friendly name.             */
 
+	char * uid;				/*< User Id							*/
+
 	const char *status;     /**< The state of the user.         */
+	char *statusline;       /**< The state of the user.         */	
+	char *currentmedia;     /**< The current media of the user. */
+
 	gboolean idle;          /**< The idle state of the user.    */
 
 	struct
@@ -65,7 +81,12 @@
 
 	GHashTable *clientcaps; /**< The client's capabilities.     */
 
-	int list_op;
+	MsnUserType type;       /**< The user type                  */
+
+	int list_op;            /**< Which lists the user is in     */
+
+	guint membership_id[5];	/**< The membershipId sent by the contacts server,
+				     indexed by the list it belongs to		*/
 };
 
 /**************************************************************************/
@@ -102,6 +123,22 @@
  */
 void msn_user_update(MsnUser *user);
 
+ /**
+  *  Sets the new statusline of user.
+  * 
+  *  @param user The user.
+  *  @param state The statusline string.
+  */
+void msn_user_set_statusline(MsnUser *user, const char *statusline);
+
+ /**
+  *  Sets the current media of user.
+  * 
+  *  @param user The user.
+  *  @param state The statusline string.
+  */
+void msn_user_set_currentmedia(MsnUser *user, const char *currentmedia);
+
 /**
  * Sets the new state of user.
  *
@@ -156,7 +193,7 @@
  * @param user The user.
  * @param id   The group ID.
  */
-void msn_user_add_group_id(MsnUser *user, int id);
+void msn_user_add_group_id(MsnUser *user, const char * id);
 
 /**
  * Removes the group ID from a user.
@@ -164,7 +201,7 @@
  * @param user The user.
  * @param id   The group ID.
  */
-void msn_user_remove_group_id(MsnUser *user, int id);
+void msn_user_remove_group_id(MsnUser *user, const char * id);
 
 /**
  * Sets the home phone number for a user.
@@ -182,6 +219,9 @@
  */
 void msn_user_set_work_phone(MsnUser *user, const char *number);
 
+void msn_user_set_uid(MsnUser *user, const char *uid);
+void msn_user_set_type(MsnUser *user, MsnUserType type);
+
 /**
  * Sets the mobile phone number for a user.
  *
@@ -279,6 +319,22 @@
  */
 GHashTable *msn_user_get_client_caps(const MsnUser *user);
 
+/**
+ * check to see if user is online
+ */
+gboolean
+msn_user_is_online(PurpleAccount *account, const char *name);
+
+/**
+ * check to see if user is Yahoo User
+ */
+gboolean
+msn_user_is_yahoo(PurpleAccount *account ,const char *name);
+
+void msn_user_set_op(MsnUser *user, int list_op);
+void msn_user_unset_op(MsnUser *user, int list_op);
+
 /*@}*/
 
+
 #endif /* _MSN_USER_H_ */
--- a/libpurple/protocols/msn/userlist.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/userlist.c	Fri Sep 28 16:34:43 2007 +0000
@@ -43,8 +43,15 @@
 	MsnPermitAdd *pa = data;
 	MsnSession *session = pa->gc->proto_data;
 	MsnUserList *userlist = session->userlist;
+	MsnUser *user = msn_userlist_find_add_user(userlist, pa->who, pa->who);
+	
+	purple_debug_misc("MSN Userlist", "Accepted the new buddy: %s\n", pa->who);
 
-	msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_AL, NULL);
+	msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_AL);
+
+	if (msn_userlist_user_is_in_list(user, MSN_LIST_FL)) {
+		msn_del_contact_from_list(session->contact, NULL, pa->who, MSN_LIST_PL);
+	}
 
 	g_free(pa->who);
 	g_free(pa->friendly);
@@ -55,10 +62,20 @@
 msn_cancel_add_cb(gpointer data)
 {
 	MsnPermitAdd *pa = data;
-	MsnSession *session = pa->gc->proto_data;
-	MsnUserList *userlist = session->userlist;
+
+	purple_debug_misc("MSN Userlist", "Deniedthe new buddy: %s\n", pa->who);
 
-	msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_BL, NULL);
+	if (g_list_find(purple_connections_get_all(), pa->gc) != NULL)
+	{
+		MsnSession *session = pa->gc->proto_data;
+		MsnUserList *userlist = session->userlist;
+		MsnCallbackState *state = msn_callback_state_new();
+	
+		msn_callback_state_set_action(state, MSN_DENIED_BUDDY);
+
+		msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_BL);
+		msn_del_contact_from_list(session->contact, state, pa->who, MSN_LIST_PL);
+	}
 
 	g_free(pa->who);
 	g_free(pa->friendly);
@@ -78,49 +95,45 @@
 	purple_account_request_authorization(purple_connection_get_account(gc), passport, NULL, friendly, NULL,
 					   purple_find_buddy(purple_connection_get_account(gc), passport) != NULL,
 					   msn_accept_add_cb, msn_cancel_add_cb, pa);
+
 }
 
 /**************************************************************************
  * Utility functions
  **************************************************************************/
 
-static gboolean
-user_is_in_group(MsnUser *user, int group_id)
+gboolean
+msn_userlist_user_is_in_group(MsnUser *user, const char * group_id)
 {
 	if (user == NULL)
 		return FALSE;
 
-	if (group_id < 0)
+	if (group_id == NULL)
 		return FALSE;
 
-	if (g_list_find(user->group_ids, GINT_TO_POINTER(group_id)))
+	if (g_list_find_custom(user->group_ids, group_id, (GCompareFunc)strcmp))
 		return TRUE;
 
 	return FALSE;
 }
 
-static gboolean
-user_is_there(MsnUser *user, int list_id, int group_id)
+gboolean
+msn_userlist_user_is_in_list(MsnUser *user, MsnListId list_id)
 {
 	int list_op;
 
 	if (user == NULL)
 		return FALSE;
-
+	
 	list_op = 1 << list_id;
 
-	if (!(user->list_op & list_op))
+	if (user->list_op & list_op)
+		return TRUE;
+	else
 		return FALSE;
-
-	if (list_id == MSN_LIST_FL)
-	{
-		if (group_id >= 0)
-			return user_is_in_group(user, group_id);
-	}
-
-	return TRUE;
 }
 
+#if 0
 static const char*
 get_store_name(MsnUser *user)
 {
@@ -148,31 +161,7 @@
 
 	return store_name;
 }
-
-static void
-msn_request_add_group(MsnUserList *userlist, const char *who,
-					  const char *old_group_name, const char *new_group_name)
-{
-	MsnCmdProc *cmdproc;
-	MsnTransaction *trans;
-	MsnMoveBuddy *data;
-
-	cmdproc = userlist->session->notification->cmdproc;
-	data = g_new0(MsnMoveBuddy, 1);
-
-	data->who = g_strdup(who);
-
-	if (old_group_name)
-		data->old_group_name = g_strdup(old_group_name);
-
-	trans = msn_transaction_new(cmdproc, "ADG", "%s %d",
-								purple_url_encode(new_group_name),
-								0);
-
-	msn_transaction_set_data(trans, data);
-
-	msn_cmdproc_send_trans(cmdproc, trans);
-}
+#endif
 
 /**************************************************************************
  * Server functions
@@ -193,14 +182,16 @@
 	return -1;
 }
 
+/* this function msn_got_add_user isn't called anywhere */
 void
 msn_got_add_user(MsnSession *session, MsnUser *user,
-				 MsnListId list_id, int group_id)
+				 MsnListId list_id, const char * group_id)
 {
 	PurpleAccount *account;
 	const char *passport;
 	const char *friendly;
 
+	purple_debug_info("MSNP14","got add user...\n");
 	account = session->account;
 
 	passport = msn_user_get_passport(user);
@@ -214,7 +205,7 @@
 
 		serv_got_alias(gc, passport, friendly);
 
-		if (group_id >= 0)
+		if (group_id != NULL)
 		{
 			msn_user_add_group_id(user, group_id);
 		}
@@ -263,7 +254,7 @@
 			 *       looked at this.  Maybe we should use the store
 			 *       name instead? --KingAnt
 			 */
-			got_new_entry(gc, passport, friendly);
+//			got_new_entry(gc, passport, friendly);
 		}
 	}
 
@@ -273,7 +264,7 @@
 
 void
 msn_got_rem_user(MsnSession *session, MsnUser *user,
-				 MsnListId list_id, int group_id)
+				 MsnListId list_id, const char * group_id)
 {
 	PurpleAccount *account;
 	const char *passport;
@@ -285,7 +276,7 @@
 	if (list_id == MSN_LIST_FL)
 	{
 		/* TODO: When is the user totally removed? */
-		if (group_id >= 0)
+		if (group_id != NULL)
 		{
 			msn_user_remove_group_id(user, group_id);
 			return;
@@ -333,7 +324,6 @@
 	{
 		purple_debug_info("msn", "Buddy '%s' shall be deleted?.\n",
 						passport);
-
 	}
 }
 
@@ -351,14 +341,16 @@
 
 	passport = msn_user_get_passport(user);
 	store = msn_user_get_store_name(user);
+	
+	msn_user_set_op(user, list_op);
 
 	if (list_op & MSN_LIST_FL_OP)
 	{
 		GSList *c;
 		for (c = group_ids; c != NULL; c = g_slist_next(c))
 		{
-			int group_id;
-			group_id = GPOINTER_TO_INT(c->data);
+			char *group_id;
+			group_id = c->data;
 			msn_user_add_group_id(user, group_id);
 		}
 
@@ -393,11 +385,14 @@
 
 		if (!(list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP)))
 		{
-			got_new_entry(gc, passport, store);
+//			got_new_entry(gc, passport, store);
 		}
 	}
 
-	user->list_op = list_op;
+	if (list_op & MSN_LIST_PL_OP)
+	{
+		got_new_entry(gc, passport, store);
+	}
 }
 
 /**************************************************************************
@@ -427,18 +422,18 @@
 {
 	GList *l;
 
+	/*destroy userlist*/
 	for (l = userlist->users; l != NULL; l = l->next)
 	{
 		msn_user_destroy(l->data);
 	}
-
 	g_list_free(userlist->users);
 
+	/*destroy group list*/
 	for (l = userlist->groups; l != NULL; l = l->next)
 	{
 		msn_group_destroy(l->data);
 	}
-
 	g_list_free(userlist->groups);
 
 	g_queue_free(userlist->buddy_icon_requests);
@@ -449,6 +444,22 @@
 	g_free(userlist);
 }
 
+MsnUser *
+msn_userlist_find_add_user(MsnUserList *userlist,const char *passport,const char *userName)
+{
+	MsnUser *user;
+
+	user = msn_userlist_find_user(userlist, passport);
+	if (user == NULL)
+	{
+		user = msn_user_new(userlist, passport, userName);
+		msn_userlist_add_user(userlist, user);
+	} else {
+		msn_user_set_store_name(user, userName);
+	}
+	return user;
+}
+
 void
 msn_userlist_add_user(MsnUserList *userlist, MsnUser *user)
 {
@@ -472,10 +483,36 @@
 	{
 		MsnUser *user = (MsnUser *)l->data;
 
+//		purple_debug_info("MsnUserList","user passport:%s,passport:%s\n",user->passport,passport);
 		g_return_val_if_fail(user->passport != NULL, NULL);
 
-		if (!strcmp(passport, user->passport))
+		if (!g_strcasecmp(passport, user->passport)){
+//			purple_debug_info("MsnUserList","return:%p\n",user);
 			return user;
+		}
+	}
+
+	return NULL;
+}
+
+MsnUser *
+msn_userlist_find_user_with_id(MsnUserList *userlist, const char *uid)
+{
+ 	GList *l;
+
+        g_return_val_if_fail(uid != NULL, NULL);
+
+        for (l = userlist->users; l != NULL; l = l->next)
+        {
+                MsnUser *user = (MsnUser *)l->data;
+
+		if (user->uid == NULL) {
+			continue;
+		}
+
+		if ( !g_strcasecmp(uid, user->uid) ) {
+			return user;
+		}
 	}
 
 	return NULL;
@@ -494,18 +531,18 @@
 }
 
 MsnGroup *
-msn_userlist_find_group_with_id(MsnUserList *userlist, int id)
+msn_userlist_find_group_with_id(MsnUserList *userlist, const char * id)
 {
 	GList *l;
 
 	g_return_val_if_fail(userlist != NULL, NULL);
-	g_return_val_if_fail(id       >= 0,    NULL);
+	g_return_val_if_fail(id       != NULL, NULL);
 
 	for (l = userlist->groups; l != NULL; l = l->next)
 	{
 		MsnGroup *group = l->data;
 
-		if (group->id == id)
+		if (!g_strcasecmp(group->id,id))
 			return group;
 	}
 
@@ -524,14 +561,14 @@
 	{
 		MsnGroup *group = l->data;
 
-		if ((group->name != NULL) && !g_ascii_strcasecmp(name, group->name))
+		if ((group->name != NULL) && !g_strcasecmp(name, group->name))
 			return group;
 	}
 
 	return NULL;
 }
 
-int
+const char *
 msn_userlist_find_group_id(MsnUserList *userlist, const char *group_name)
 {
 	MsnGroup *group;
@@ -541,11 +578,11 @@
 	if (group != NULL)
 		return msn_group_get_id(group);
 	else
-		return -1;
+		return NULL;
 }
 
 const char *
-msn_userlist_find_group_name(MsnUserList *userlist, int group_id)
+msn_userlist_find_group_name(MsnUserList *userlist, const char * group_id)
 {
 	MsnGroup *group;
 
@@ -558,7 +595,7 @@
 }
 
 void
-msn_userlist_rename_group_id(MsnUserList *userlist, int group_id,
+msn_userlist_rename_group_id(MsnUserList *userlist, const char * group_id,
 							 const char *new_name)
 {
 	MsnGroup *group;
@@ -570,7 +607,7 @@
 }
 
 void
-msn_userlist_remove_group_id(MsnUserList *userlist, int group_id)
+msn_userlist_remove_group_id(MsnUserList *userlist, const char * group_id)
 {
 	MsnGroup *group;
 
@@ -584,116 +621,293 @@
 }
 
 void
-msn_userlist_rem_buddy(MsnUserList *userlist,
-					   const char *who, int list_id, const char *group_name)
+msn_userlist_rem_buddy(MsnUserList *userlist, const char *who)
+{
+	MsnUser *user = NULL;
+	
+	g_return_if_fail(userlist != NULL);
+	g_return_if_fail(userlist->session != NULL);
+	g_return_if_fail(userlist->session->contact != NULL);
+	g_return_if_fail(who != NULL);
+	
+	user = msn_userlist_find_user(userlist, who);
+
+	msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_FL);
+
+	/* delete the contact from address book via soap action */
+	if (user != NULL) {
+		msn_delete_contact(userlist->session->contact, user->uid);
+	}
+}
+
+void
+msn_userlist_rem_buddy_from_list(MsnUserList *userlist, const char *who,
+				 MsnListId list_id)
 {
 	MsnUser *user;
-	int group_id;
-	const char *list;
+	const gchar *list;
+	MsnListOp list_op = 1 << list_id;
 
 	user = msn_userlist_find_user(userlist, who);
-	group_id = -1;
-
-	if (group_name != NULL)
-	{
-		group_id = msn_userlist_find_group_id(userlist, group_name);
-
-		if (group_id < 0)
-		{
-			/* Whoa, there is no such group. */
-			purple_debug_error("msn", "Group doesn't exist: %s\n", group_name);
-			return;
-		}
-	}
-
-	/* First we're going to check if not there. */
-	if (!(user_is_there(user, list_id, group_id)))
-	{
+	
+	g_return_if_fail(user != NULL);
+	
+	if ( !msn_userlist_user_is_in_list(user, list_id)) {
 		list = lists[list_id];
-		purple_debug_error("msn", "User '%s' is not there: %s\n",
-						 who, list);
+		purple_debug_info("MSN Userlist", "User %s is not in list %s, not removing.\n", who, list);
 		return;
 	}
 
-	/* Then request the rem to the server. */
-	list = lists[list_id];
+	msn_user_unset_op(user, list_op);
 
-	msn_notification_rem_buddy(userlist->session->notification, list, who, group_id);
+	msn_notification_rem_buddy_from_list(userlist->session->notification, list_id, who);
 }
 
+/*add buddy*/
 void
-msn_userlist_add_buddy(MsnUserList *userlist,
-					   const char *who, int list_id,
-					   const char *group_name)
+msn_userlist_add_buddy(MsnUserList *userlist, const char *who, const char *group_name)
 {
 	MsnUser *user;
-	int group_id;
-	const char *list;
-	const char *store_name;
+	MsnCallbackState *state = NULL;
+	const char *group_id = NULL, *new_group_name;
+	
+	new_group_name = group_name == NULL ? MSN_INDIVIDUALS_GROUP_NAME : group_name;
 
-	group_id = -1;
+	
+	g_return_if_fail(userlist != NULL);
+	g_return_if_fail(userlist->session != NULL);
+
+	
+	purple_debug_info("MSN Userlist", "Add user: %s to group: %s\n", who, new_group_name);
+
+	state = msn_callback_state_new();
+	msn_callback_state_set_who(state, who);
+	msn_callback_state_set_new_group_name(state, new_group_name);
 
 	if (!purple_email_is_valid(who))
 	{
 		/* 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 */
-		if (list_id == MSN_LIST_FL)
-		{
-			char *str = g_strdup_printf(_("Unable to add \"%s\"."), who);
-			purple_notify_error(NULL, NULL, str,
-							  _("The screen name specified is invalid."));
-			g_free(str);
-		}
+		
+		char *str = g_strdup_printf(_("Unable to add \"%s\"."), who);
+		
+		purple_notify_error(NULL, NULL, str,
+				  _("The screen name specified is invalid."));
+		g_free(str);
 
 		return;
 	}
 
-	if (group_name != NULL)
+	group_id = msn_userlist_find_group_id(userlist, new_group_name);
+
+	if (group_id == NULL)
 	{
-		group_id = msn_userlist_find_group_id(userlist, group_name);
+		/* Whoa, we must add that group first. */
+		purple_debug_info("MSN Userlist", "Adding user %s to a new group, creating group %s first\n", who, new_group_name);
+		
+		msn_callback_state_set_action(state, MSN_ADD_BUDDY);
 
-		if (group_id < 0)
-		{
-			/* Whoa, we must add that group first. */
-			msn_request_add_group(userlist, who, NULL, group_name);
+		msn_add_group(userlist->session, state, new_group_name);
+		return;
+	} else {
+		msn_callback_state_set_guid(state, group_id);
+	}
+	
+	/* XXX: adding user here may not be correct (should add them in the
+ 	 * ACK to the ADL command), but for now we need to make sure they exist  
+	 * early enough that the ILN command doesn't screw us up */
+
+	user = msn_userlist_find_add_user(userlist, who, who);
+
+	if ( msn_userlist_user_is_in_list(user, MSN_LIST_FL) ) {
+
+		purple_debug_info("MSN Userlist", "User %s already exists\n", who);
+
+		msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL);
+
+		if (msn_userlist_user_is_in_group(user, group_id)) {
+			purple_debug_info("MSN Userlist", "User %s is already in group %s, returning\n", who, new_group_name);
 			return;
 		}
 	}
+			
+	purple_debug_info("MSN Userlist", "Adding user: %s to group id: %s\n", who, group_id);
 
-	user = msn_userlist_find_user(userlist, who);
+	msn_callback_state_set_action(state, MSN_ADD_BUDDY);
+
+	/* Add contact in the Contact server with a SOAP request and if
+	   successful, send ADL with MSN_LIST_AL and MSN_LIST_FL and a FQY */
+	msn_add_contact_to_group(userlist->session->contact, state, who, group_id);
+}
 
+void
+msn_userlist_add_buddy_to_list(MsnUserList *userlist, const char *who, 
+							MsnListId list_id)
+{
+	MsnUser *user = NULL;
+	const gchar *list;
+	MsnListOp list_op = 1 << list_id;
+
+	g_return_if_fail(userlist != NULL);
+	
+	user = msn_userlist_find_add_user(userlist, who, who);
+	
 	/* First we're going to check if it's already there. */
-	if (user_is_there(user, list_id, group_id))
+	if (msn_userlist_user_is_in_list(user, list_id))
 	{
 		list = lists[list_id];
-		purple_debug_error("msn", "User '%s' is already there: %s\n", who, list);
+		purple_debug_info("MSN Userlist", "User '%s' is already in list: %s\n", who, list);
 		return;
 	}
+	
+	//store_name = (user != NULL) ? get_store_name(user) : who;
+	
+	//purple_debug_info("MSN Userlist", "store_name = %s\n", store_name);
+	
+	/* XXX: see XXX above, this should really be done when we get the response from
+		the server */
+	
+	msn_user_set_op(user, list_op);
+	
+	msn_notification_add_buddy_to_list(userlist->session->notification, list_id, who);
+}
+
+gboolean
+msn_userlist_add_buddy_to_group(MsnUserList *userlist, const char *who,
+				const char *group_name)
+{
+	MsnUser *user;
+	gchar * group_id;
+	
+	g_return_val_if_fail(userlist != NULL, FALSE);
+	g_return_val_if_fail(group_name != NULL, FALSE);
+	g_return_val_if_fail(who != NULL, FALSE);
+
+	purple_debug_info("MSN Userlist","Adding buddy with passport %s to group %s\n", who, group_name);
+
+	if ( (group_id = (gchar *)msn_userlist_find_group_id(userlist, group_name)) == NULL) {
+		purple_debug_error("MSN Userlist", "Group %s has no guid!\n", group_name);
+		return FALSE;
+	}
 
-	store_name = (user != NULL) ? get_store_name(user) : who;
+	if ( (user = msn_userlist_find_user(userlist, who)) == NULL) {
+		purple_debug_error("MSN Userlist", "User %s not found!", who);
+		return FALSE;
+	}
+	
+	msn_user_add_group_id(user, group_id);
+
+	return TRUE;
+}
+
+
+gboolean
+msn_userlist_rem_buddy_from_group(MsnUserList *userlist, const char *who,
+				const char *group_name)
+{
+	const gchar * group_id;
+	MsnUser *user;
 
-	/* Then request the add to the server. */
-	list = lists[list_id];
+	g_return_val_if_fail(userlist != NULL, FALSE);
+	g_return_val_if_fail(group_name != NULL, FALSE);
+	g_return_val_if_fail(who != NULL, FALSE);
+	
+	purple_debug_info("MSN Userlist","Removing buddy with passport %s from group %s\n", who, group_name);
 
-	msn_notification_add_buddy(userlist->session->notification, list, who,
-							   store_name, group_id);
+	if ( (group_id = msn_userlist_find_group_id(userlist, group_name)) == NULL) {
+		purple_debug_error("MSN Userlist", "Group %s has no guid!\n", group_name);
+		return FALSE;
+	}
+
+	if ( (user = msn_userlist_find_user(userlist, who)) == NULL) {
+		purple_debug_error("MSN Userlist", "User %s not found!", who);
+		return FALSE;
+	}
+
+	msn_user_remove_group_id(user, group_id);
+
+	return TRUE;
 }
 
 void
 msn_userlist_move_buddy(MsnUserList *userlist, const char *who,
-						const char *old_group_name, const char *new_group_name)
+			const char *old_group_name, const char *new_group_name)
 {
-	int new_group_id;
+	const char *new_group_id;
+	MsnCallbackState *state;
+	
+	g_return_if_fail(userlist != NULL);
+	g_return_if_fail(userlist->session != NULL);
+	g_return_if_fail(userlist->session->contact != NULL);
+
+	state = msn_callback_state_new();
+	msn_callback_state_set_who(state, who);
+	msn_callback_state_set_action(state, MSN_MOVE_BUDDY);
+	msn_callback_state_set_old_group_name(state, old_group_name);
+	msn_callback_state_set_new_group_name(state, new_group_name);
 
 	new_group_id = msn_userlist_find_group_id(userlist, new_group_name);
 
-	if (new_group_id < 0)
-	{
-		msn_request_add_group(userlist, who, old_group_name, new_group_name);
+	if (new_group_id == NULL)
+	{		
+		msn_add_group(userlist->session, state, new_group_name);
 		return;
 	}
+	
+	/* add the contact to the new group, and remove it from the old one in
+	 * the callback
+	*/
+	msn_add_contact_to_group(userlist->session->contact, state, who, new_group_id);
+}
 
-	msn_userlist_add_buddy(userlist, who, MSN_LIST_FL, new_group_name);
-	msn_userlist_rem_buddy(userlist, who, MSN_LIST_FL, old_group_name);
+/*load userlist from the Blist file cache*/
+void
+msn_userlist_load(MsnSession *session)
+{
+	PurpleBlistNode *gnode, *cnode, *bnode;
+	PurpleConnection *gc = purple_account_get_connection(session->account);
+	GSList *l;
+	MsnUser * user;
+
+	g_return_if_fail(gc != NULL);
+
+	for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next)
+	{
+		if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
+			continue;
+		for (cnode = gnode->child; cnode; cnode = cnode->next)
+		{
+			if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
+				continue;
+			for (bnode = cnode->child; bnode; bnode = bnode->next)
+			{
+				PurpleBuddy *b;
+				if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
+					continue;
+				b = (PurpleBuddy *)bnode;
+				if (b->account == gc->account)
+				{
+					user = msn_userlist_find_add_user(session->userlist,
+						b->name,NULL);
+					b->proto_data = user;
+					msn_user_set_op(user, MSN_LIST_FL_OP);
+				}
+			}
+		}
+	}
+	for (l = session->account->permit; l != NULL; l = l->next)
+	{
+		user = msn_userlist_find_add_user(session->userlist,
+						(char *)l->data,NULL);
+		msn_user_set_op(user, MSN_LIST_AL_OP);
+	}
+	for (l = session->account->deny; l != NULL; l = l->next)
+	{
+		user = msn_userlist_find_add_user(session->userlist,
+						(char *)l->data,NULL);
+		msn_user_set_op(user, MSN_LIST_BL_OP);
+	}
+	
 }
+
--- a/libpurple/protocols/msn/userlist.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/msn/userlist.h	Fri Sep 28 16:34:43 2007 +0000
@@ -35,16 +35,11 @@
 	MSN_LIST_FL,
 	MSN_LIST_AL,
 	MSN_LIST_BL,
-	MSN_LIST_RL
+	MSN_LIST_RL,
+	MSN_LIST_PL
 
 } MsnListId;
 
-typedef struct
-{
-	char *who;
-	char *old_group_name;
-
-} MsnMoveBuddy;
 
 struct _MsnUserList
 {
@@ -64,40 +59,57 @@
 
 };
 
+gboolean msn_userlist_user_is_in_group(MsnUser *user, const char * group_id);
+gboolean msn_userlist_user_is_in_list(MsnUser *user, MsnListId list_id);
 MsnListId msn_get_list_id(const char *list);
 
 void msn_got_add_user(MsnSession *session, MsnUser *user,
-					  MsnListId list_id, int group_id);
+					  MsnListId list_id, const char *group_id);
 void msn_got_rem_user(MsnSession *session, MsnUser *user,
-					  MsnListId list_id, int group_id);
+					  MsnListId list_id, const char *group_id);
 void msn_got_lst_user(MsnSession *session, MsnUser *user,
 					  int list_op, GSList *group_ids);
 
 MsnUserList *msn_userlist_new(MsnSession *session);
 void msn_userlist_destroy(MsnUserList *userlist);
+
 void msn_userlist_add_user(MsnUserList *userlist, MsnUser *user);
 void msn_userlist_remove_user(MsnUserList *userlist, MsnUser *user);
-MsnUser *msn_userlist_find_user(MsnUserList *userlist,
-								const char *passport);
+
+MsnUser * msn_userlist_find_user(MsnUserList *userlist, const char *passport);
+MsnUser * msn_userlist_find_add_user(MsnUserList *userlist,
+				const char *passport, const char *userName);
+MsnUser * msn_userlist_find_user_with_id(MsnUserList *userlist, const char *uid);
+
 void msn_userlist_add_group(MsnUserList *userlist, MsnGroup *group);
 void msn_userlist_remove_group(MsnUserList *userlist, MsnGroup *group);
-MsnGroup *msn_userlist_find_group_with_id(MsnUserList *userlist, int id);
-MsnGroup *msn_userlist_find_group_with_name(MsnUserList *userlist,
-											const char *name);
-int msn_userlist_find_group_id(MsnUserList *userlist,
-							   const char *group_name);
-const char *msn_userlist_find_group_name(MsnUserList *userlist,
-										 int group_id);
-void msn_userlist_rename_group_id(MsnUserList *userlist, int group_id,
-								  const char *new_name);
-void msn_userlist_remove_group_id(MsnUserList *userlist, int group_id);
+MsnGroup *msn_userlist_find_group_with_id(MsnUserList *userlist, const char *id);
+MsnGroup *msn_userlist_find_group_with_name(MsnUserList *userlist, const char *name);
+const char * msn_userlist_find_group_id(MsnUserList *userlist,
+					const char *group_name);
+const char *msn_userlist_find_group_name(MsnUserList *userlist, const char *group_id);
+void msn_userlist_rename_group_id(MsnUserList *userlist, const char *group_id,
+				  const char *new_name);
+void msn_userlist_remove_group_id(MsnUserList *userlist, const char *group_id);
 
-void msn_userlist_rem_buddy(MsnUserList *userlist, const char *who,
-							int list_id, const char *group_name);
-void msn_userlist_add_buddy(MsnUserList *userlist, const char *who,
-							int list_id, const char *group_name);
+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_move_buddy(MsnUserList *userlist, const char *who,
-							 const char *old_group_name,
-							 const char *new_group_name);
+						    const char *old_group_name,
+						    const char *new_group_name);
+
+gboolean msn_userlist_add_buddy_to_group(MsnUserList *userlist, const char *who,
+					 const char *group_name);
+gboolean msn_userlist_rem_buddy_from_group(MsnUserList *userlist,
+					   const char *who,
+					   const char *group_name);
+
+void msn_userlist_add_buddy_to_list(MsnUserList *userlist, const char *who, 
+				    MsnListId list_id);
+void msn_userlist_rem_buddy_from_list(MsnUserList *userlist, const char *who,
+				      MsnListId list_id);
+
+void msn_userlist_load(MsnSession *session);
 
 #endif /* _MSN_USERLIST_H_ */
--- a/libpurple/protocols/myspace/markup.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/myspace/markup.c	Fri Sep 28 16:34:43 2007 +0000
@@ -426,13 +426,14 @@
 html_tag_to_msim_markup(MsimSession *session, xmlnode *root, gchar **begin, 
 		gchar **end)
 {
+	if (!purple_utf8_strcasecmp(root->name, "root") ||
+	    !purple_utf8_strcasecmp(root->name, "html")) {
+		*begin = g_strdup("");
+		*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 
 	 * applied to the text. */
-	if (!purple_utf8_strcasecmp(root->name, "root")) {
-		*begin = g_strdup("");
-		*end = g_strdup("");
 	} else if (!purple_utf8_strcasecmp(root->name, "b")) {
 		*begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_BOLD);
 		*end = g_strdup("</f>");
@@ -503,8 +504,21 @@
 
 		/* TODO: color (bg uses <body>), emoticons */
 	} else {
+		gchar *err;
+
+#ifdef MSIM_MARKUP_SHOW_UNKNOWN_TAGS
 		*begin = g_strdup_printf("[%s]", root->name);
 		*end = g_strdup_printf("[/%s]", root->name);
+#else
+		*begin = g_strdup("");
+		*end = g_strdup("");
+#endif
+
+		err = g_strdup_printf("html_tag_to_msim_markup: unrecognized "
+			"HTML tag %s was sent by the IM client; ignoring", 
+			root->name ? root->name : "(NULL)");
+		msim_unrecognized(NULL, NULL, err);
+		g_free(err);
 	}
 }
 
--- a/libpurple/protocols/myspace/markup.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/myspace/markup.h	Fri Sep 28 16:34:43 2007 +0000
@@ -1,27 +1,27 @@
-/* MySpaceIM Protocol Plugin - markup
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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  02111-1301  USA
- */
-
-#ifndef _MYSPACE_MARKUP_H
-#define _MYSPACE_MARKUP_H
-
-/* High-level msim markup <=> Purple html conversion functions. */
-gchar *msim_markup_to_html(MsimSession *, const gchar *raw);
-gchar *html_to_msim_markup(MsimSession *, const gchar *raw);
-
-#endif /* !_MYSPACE_MARKUP_H */
+/* MySpaceIM Protocol Plugin - markup
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * 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  02111-1301  USA
+ */
+
+#ifndef _MYSPACE_MARKUP_H
+#define _MYSPACE_MARKUP_H
+
+/* High-level msim markup <=> Purple html conversion functions. */
+gchar *msim_markup_to_html(MsimSession *, const gchar *raw);
+gchar *html_to_msim_markup(MsimSession *, const gchar *raw);
+
+#endif /* !_MYSPACE_MARKUP_H */
--- a/libpurple/protocols/myspace/myspace.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Fri Sep 28 16:34:43 2007 +0000
@@ -291,9 +291,10 @@
 		/* Notify an error message also, because this is important! */
 		purple_notify_error(acct, g_strdup(_("MySpaceIM Error")), str, NULL);
 
+		gc->wants_to_die = TRUE;
 		purple_connection_error(gc, str);
-		
 		g_free(str);
+		return;
 	}
 #endif
 
@@ -458,6 +459,7 @@
 	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 = ");
@@ -1039,7 +1041,7 @@
 	PurpleStatusType *type;
 	MsimSession *session;
 	guint status_code;
-	const gchar *statstring;
+	gchar *statstring;
 
 	session = (MsimSession *)account->gc->proto_data;
 
@@ -1073,7 +1075,7 @@
 			break;
 	}
 
-	statstring = purple_status_get_attr_string(status, "message");
+	statstring = (gchar *)purple_status_get_attr_string(status, "message");
 
 	if (!statstring) {
 		statstring = "";
@@ -1082,7 +1084,7 @@
 	/* Status strings are plain text. */
 	statstring = purple_markup_strip_html(statstring);
 
-	msim_set_status_code(session, status_code, g_strdup(statstring));
+	msim_set_status_code(session, status_code, statstring);
 }
 
 /** Go idle. */
@@ -1213,7 +1215,7 @@
 		if (uid == wanted_uid)
 		{
 			ret = g_strdup(name);
-            break;
+			break;
 		}
 	}
 
@@ -1790,11 +1792,13 @@
 	/* Destroy session if fatal. */
 	if (msim_msg_get(msg, "fatal")) {
 		purple_debug_info("msim", "fatal error, closing\n");
-		if (err == 260) {
-			/* Incorrect password */
-			session->gc->wants_to_die = TRUE;
-			if (!purple_account_get_remember_password(session->account))
-				purple_account_set_password(session->account, NULL);
+		switch (err) {
+			case 260: /* Incorrect password */
+			case 6: /* Logged in elsewhere */
+				session->gc->wants_to_die = TRUE;
+				if (!purple_account_get_remember_password(session->account))
+					purple_account_set_password(session->account, NULL);
+				break;
 		}
 		purple_connection_error(session->gc, full_errmsg);
 	} else {
@@ -1867,6 +1871,7 @@
 		purple_blist_add_buddy(buddy, NULL, NULL, NULL);
 
 		user = msim_get_user_from_buddy(buddy);
+		/* TODO: free user. memory leak? */
 
 		/* All buddies on list should have 'uid' integer associated with them. */
 		purple_blist_node_set_int(&buddy->node, "UserID", msim_msg_get_integer(msg, "f"));
@@ -2863,7 +2868,7 @@
 }
 
 /** Callbacks called by Purple, to access this plugin. */
-PurplePluginProtocolInfo prpl_info = {
+static PurplePluginProtocolInfo prpl_info = {
 	/* options */
 	  OPT_PROTO_USE_POINTSIZE        /* specify font size in sane point size */
 	| OPT_PROTO_MAIL_CHECK,
--- a/libpurple/protocols/myspace/myspace.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/myspace/myspace.h	Fri Sep 28 16:34:43 2007 +0000
@@ -67,6 +67,10 @@
 /*#define MSIM_DEBUG_LOGIN_CHALLENGE*/
 /*#define MSIM_DEBUG_RXBUF            */
 
+/* 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 
  * run with 'pidgin -d' to see the output. Don't define if
--- a/libpurple/protocols/myspace/session.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/myspace/session.c	Fri Sep 28 16:34:43 2007 +0000
@@ -1,95 +1,95 @@
-/* MySpaceIM Protocol Plugin, session
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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  02111-1301  USA
- */
-
-
-#include "myspace.h"
-
-/* Session methods */
-
-/**
- * Create a new MSIM session.
- *
- * @param acct The account to create the session from.
- *
- * @return Pointer to a new session. Free with msim_session_destroy.
- */
-MsimSession *
-msim_session_new(PurpleAccount *acct)
-{
-	MsimSession *session;
-
-	g_return_val_if_fail(acct != NULL, NULL);
-
-	session = g_new0(MsimSession, 1);
-
-	session->magic = MSIM_SESSION_STRUCT_MAGIC;
-	session->account = acct;
-	session->gc = purple_account_get_connection(acct);
-	session->sesskey = 0;
-	session->userid = 0;
-	session->username = NULL;
-	session->fd = -1;
-
-	/* TODO: Remove. */
-	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, 
-			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.
-											 Figure this out, once free cache. */
-
-	/* Created in msim_process_server_info() */
-	session->server_info = NULL;
-
-	session->rxoff = 0;
-	session->rxbuf = g_new0(gchar, MSIM_READ_BUF_SIZE);
-	session->next_rid = 1;
-	session->last_comm = time(NULL);
-	session->inbox_status = 0;
-	
-	return session;
-}
-
-/**
- * Free a session.
- *
- * @param session The session to destroy.
- */
-void 
-msim_session_destroy(MsimSession *session)
-{
-	g_return_if_fail(MSIM_SESSION_VALID(session));
-	
-	session->magic = -1;
-
-	g_free(session->rxbuf);
-	g_free(session->username);
-
-	/* TODO: Remove. */
-	g_hash_table_destroy(session->user_lookup_cb);
-	g_hash_table_destroy(session->user_lookup_cb_data);
-
-	if (session->server_info) {
-		msim_msg_free(session->server_info);
-	}
-	
-	g_free(session);
-}
-
+/* MySpaceIM Protocol Plugin, session
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * 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  02111-1301  USA
+ */
+
+
+#include "myspace.h"
+
+/* Session methods */
+
+/**
+ * Create a new MSIM session.
+ *
+ * @param acct The account to create the session from.
+ *
+ * @return Pointer to a new session. Free with msim_session_destroy.
+ */
+MsimSession *
+msim_session_new(PurpleAccount *acct)
+{
+	MsimSession *session;
+
+	g_return_val_if_fail(acct != NULL, NULL);
+
+	session = g_new0(MsimSession, 1);
+
+	session->magic = MSIM_SESSION_STRUCT_MAGIC;
+	session->account = acct;
+	session->gc = purple_account_get_connection(acct);
+	session->sesskey = 0;
+	session->userid = 0;
+	session->username = NULL;
+	session->fd = -1;
+
+	/* TODO: Remove. */
+	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, 
+			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.
+											 Figure this out, once free cache. */
+
+	/* Created in msim_process_server_info() */
+	session->server_info = NULL;
+
+	session->rxoff = 0;
+	session->rxbuf = g_new0(gchar, MSIM_READ_BUF_SIZE);
+	session->next_rid = 1;
+	session->last_comm = time(NULL);
+	session->inbox_status = 0;
+	
+	return session;
+}
+
+/**
+ * Free a session.
+ *
+ * @param session The session to destroy.
+ */
+void 
+msim_session_destroy(MsimSession *session)
+{
+	g_return_if_fail(MSIM_SESSION_VALID(session));
+	
+	session->magic = -1;
+
+	g_free(session->rxbuf);
+	g_free(session->username);
+
+	/* TODO: Remove. */
+	g_hash_table_destroy(session->user_lookup_cb);
+	g_hash_table_destroy(session->user_lookup_cb_data);
+
+	if (session->server_info) {
+		msim_msg_free(session->server_info);
+	}
+	
+	g_free(session);
+}
+
--- a/libpurple/protocols/myspace/session.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/myspace/session.h	Fri Sep 28 16:34:43 2007 +0000
@@ -1,57 +1,57 @@
-/* MySpaceIM Protocol Plugin, session
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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  02111-1301  USA
- */
-
-#ifndef _MYSPACE_SESSION_H
-#define _MYSPACE_SESSION_H
-
-/* Random number in every MsimSession, to ensure it is valid. */
-#define MSIM_SESSION_STRUCT_MAGIC       0xe4a6752b
-
-/* Everything needed to keep track of a session (proto_data field in PurpleConnection) */
-typedef struct _MsimSession
-{
-	guint magic;                        /**< MSIM_SESSION_STRUCT_MAGIC */
-	PurpleAccount *account;
-	PurpleConnection *gc;
-	guint sesskey;                      /**< Session key from server */
-	guint userid;                       /**< This user's numeric user ID */
-	gchar *username;                    /**< This user's unique username */
-	gint fd;                            /**< File descriptor to/from server */
-
-	/* TODO: Remove. */
-	GHashTable *user_lookup_cb;         /**< Username -> userid lookup callback */
-	GHashTable *user_lookup_cb_data;    /**< Username -> userid lookup callback data */
-
-	MsimMessage *server_info;           /**< Parameters from server */
-
-	gchar *rxbuf;                       /**< Receive buffer */
-	guint rxoff;                        /**< Receive buffer offset */
-	guint next_rid;                     /**< Next request/response ID */
-	time_t last_comm;                   /**< Time received last communication */
-	guint inbox_status;                 /**< Bit field of inbox notifications */
-} MsimSession;
-
-/* 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);
-
-#endif /* !_MYSPACE_SESSION_H */
+/* MySpaceIM Protocol Plugin, session
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * 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  02111-1301  USA
+ */
+
+#ifndef _MYSPACE_SESSION_H
+#define _MYSPACE_SESSION_H
+
+/* Random number in every MsimSession, to ensure it is valid. */
+#define MSIM_SESSION_STRUCT_MAGIC       0xe4a6752b
+
+/* Everything needed to keep track of a session (proto_data field in PurpleConnection) */
+typedef struct _MsimSession
+{
+	guint magic;                        /**< MSIM_SESSION_STRUCT_MAGIC */
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	guint sesskey;                      /**< Session key from server */
+	guint userid;                       /**< This user's numeric user ID */
+	gchar *username;                    /**< This user's unique username */
+	gint fd;                            /**< File descriptor to/from server */
+
+	/* TODO: Remove. */
+	GHashTable *user_lookup_cb;         /**< Username -> userid lookup callback */
+	GHashTable *user_lookup_cb_data;    /**< Username -> userid lookup callback data */
+
+	MsimMessage *server_info;           /**< Parameters from server */
+
+	gchar *rxbuf;                       /**< Receive buffer */
+	guint rxoff;                        /**< Receive buffer offset */
+	guint next_rid;                     /**< Next request/response ID */
+	time_t last_comm;                   /**< Time received last communication */
+	guint inbox_status;                 /**< Bit field of inbox notifications */
+} MsimSession;
+
+/* 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);
+
+#endif /* !_MYSPACE_SESSION_H */
--- a/libpurple/protocols/myspace/user.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/myspace/user.c	Fri Sep 28 16:34:43 2007 +0000
@@ -1,437 +1,454 @@
-/* MySpaceIM Protocol Plugin, header file
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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  02111-1301  USA
- */
-
-#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(gchar *band, gchar *song);
-static void msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text,
-		gsize len, const gchar *error_message);
-
-/** Format the "now playing" indicator, showing the artist and song.
- * @return Return a new string (must be g_free()'d), or NULL.
- */
-static gchar *
-msim_format_now_playing(gchar *band, gchar *song)
-{
-	if ((band && strlen(band)) || (song && strlen(song))) {
-		return g_strdup_printf("%s - %s",
-			(band && strlen(band)) ? band : "Unknown Artist",
-			(song && strlen(song)) ? song : "Unknown Song");
-	} else {
-		return NULL;
-	}
-}
-/** Get the MsimUser from a PurpleBuddy, creating it if needed. */
-MsimUser *
-msim_get_user_from_buddy(PurpleBuddy *buddy)
-{
-	MsimUser *user;
-
-	if (!buddy) {
-		return NULL;
-	}
-
-	if (!buddy->proto_data) {
-		/* No MsimUser for this buddy; make one. */
-
-		/* TODO: where is this freed? */
-		user = g_new0(MsimUser, 1);
-		user->buddy = buddy;
-		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. */
-MsimUser *
-msim_find_user(MsimSession *session, const gchar *username)
-{
-	PurpleBuddy *buddy;
-	MsimUser *user;
-
-	buddy = purple_find_buddy(session->account, username);
-	if (!buddy) {
-		return NULL;
-	}
-
-	user = msim_get_user_from_buddy(buddy);
-
-	return user;
-}
-
-/** 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
-msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full)
-{
-	gchar *str;
-	guint uid;
-	guint cv;
-
-	/* 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 */
-		purple_notify_user_info_add_pair(user_info, _("Profile"),
-				g_strdup_printf("<a href=\"http://myspace.com/%d\">http://myspace.com/%d</a>",
-					uid, uid));
-	}
-
-
-	/* a/s/l...the vitals */
-	if (user->age) {
-		purple_notify_user_info_add_pair(user_info, _("Age"),
-				g_strdup_printf("%d", user->age));
-	}
-
-	if (user->gender && strlen(user->gender)) {
-		purple_notify_user_info_add_pair(user_info, _("Gender"), user->gender);
-	}
-
-	if (user->location && strlen(user->location)) {
-		purple_notify_user_info_add_pair(user_info, _("Location"), user->location);
-	}
-
-	/* Other information */
-	if (user->headline && strlen(user->headline)) {
-		purple_notify_user_info_add_pair(user_info, _("Headline"), user->headline);
-	}
-
-	str = msim_format_now_playing(user->band_name, user->song_name);
-	if (str && strlen(str)) {
-		purple_notify_user_info_add_pair(user_info, _("Song"), str);
-	}
-
-	/* Note: total friends only available if looked up by uid, not username. */
-	if (user->total_friends) {
-		purple_notify_user_info_add_pair(user_info, _("Total Friends"),
-			g_strdup_printf("%d", user->total_friends));
-	}
-
-	if (full) {
-		/* Client information */
-
-		str = user->client_info;
-		cv = user->client_cv;
-
-		if (str && cv != 0) {
-			purple_notify_user_info_add_pair(user_info, _("Client Version"),
-					g_strdup_printf("%s (build %d)", str, cv));
-		} else if (str) {
-			purple_notify_user_info_add_pair(user_info, _("Client Version"),
-					g_strdup(str));
-		} else if (cv) {
-			purple_notify_user_info_add_pair(user_info, _("Client Version"),
-					g_strdup_printf("Build %d", cv));
-		}
-	}
-}
-
-/** Store a field of information about a buddy. */
-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(). */
-		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));
-		}
-		/* Need to store in MsimUser, too? What if not on blist? */
-	} else if (g_str_equal(key_str, "Age")) {
-		user->age = atol(value_str);
-	} else if (g_str_equal(key_str, "Gender")) {
-		user->gender = g_strdup(value_str);
-	} else if (g_str_equal(key_str, "Location")) {
-		user->location = g_strdup(value_str);
-	} else if (g_str_equal(key_str, "TotalFriends")) {
-		user->total_friends = atol(value_str);
-	} else if (g_str_equal(key_str, "DisplayName")) {
-		user->display_name = g_strdup(value_str);
-	} else if (g_str_equal(key_str, "BandName")) {
-		user->band_name = g_strdup(value_str);
-	} else if (g_str_equal(key_str, "SongName")) {
-		user->song_name = g_strdup(value_str);
-	} else if (g_str_equal(key_str, "UserName") || g_str_equal(key_str, "IMName") || g_str_equal(key_str, "NickName")) {
-		/* Ignore because PurpleBuddy knows this already */
-		;
-	} else if (g_str_equal(key_str, "ImageURL") || g_str_equal(key_str, "AvatarURL")) {
-		const gchar *previous_url;
-
-		user->image_url = g_strdup(value_str);
-
-		/* Instead of showing 'no photo' picture, show nothing. */
-		if (g_str_equal(user->image_url, "http://x.myspace.com/images/no_pic.gif"))
-		{
-			purple_buddy_icons_set_for_user(user->buddy->account,
-				user->buddy->name,
-				NULL, 0, NULL);
-			return;
-		}
-	
-		/* TODO: use ETag for checksum */
-		previous_url = purple_buddy_icons_get_checksum_for_user(user->buddy);
-
-		/* Only download if URL changed */
-		if (!previous_url || !g_str_equal(previous_url, user->image_url)) {
-			purple_util_fetch_url(user->image_url, TRUE, NULL, TRUE, msim_downloaded_buddy_icon, (gpointer)user);
-		}
-	} else if (g_str_equal(key_str, "LastImageUpdated")) {
-		/* TODO: use somewhere */
-		user->last_image_updated = atol(value_str);
-	} else if (g_str_equal(key_str, "Headline")) {
-		user->headline = g_strdup(value_str);
-	} else {
-		/* TODO: other fields in MsimUser */
-		gchar *msg;
-
-		msg = g_strdup_printf("msim_store_user_info_each: unknown field %s=%s",
-				key_str, value_str);
-
-		msim_unrecognized(NULL, NULL, msg);
-
-		g_free(msg);
-	}
-}
-
-/** 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.
- * @param user The structure to save to, or NULL to save in PurpleBuddy->proto_data.
- *
- * Variable information is saved to the passed MsimUser structure. Permanent
- * information (UserID) is stored in the blist node of the buddy list (and
- * ends up in blist.xml, persisted to disk) if it exists.
- *
- * If the function has no buddy information, this function
- * is a no-op (and returns FALSE).
- *
- */
-gboolean 
-msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user)
-{
-	gchar *username;
-	MsimMessage *body, *body_node;
-
-	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
-	g_return_val_if_fail(msg != NULL, FALSE);
-
-	body = msim_msg_get_dictionary(msg, "body");
-	if (!body) {
-		return FALSE;
-	}
-
-	username = msim_msg_get_string(body, "UserName");
-
-	if (!username) {
-		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);
-		if (!user) {
-			msim_msg_free(body);
-			g_free(username);
-			return FALSE;
-		}
-	}
-
-	/* TODO: make looping over MsimMessage's easier. */
-	for (body_node = body; 
-		body_node != NULL; 
-		body_node = msim_msg_get_next_element_node(body_node))
-	{
-		const gchar *key_str;
-		gchar *value_str;
-		MsimMessageElement *elem;
-
-		elem = (MsimMessageElement *)body_node->data;
-		key_str = elem->name;
-
-		value_str = msim_msg_get_string_from_element(elem);
-		msim_store_user_info_each(key_str, value_str, user);
-		g_free(value_str);
-	}
-
-	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);
-
-	return TRUE;
-}
-
-/**
- * Asynchronously lookup user information, calling callback when receive result.
- *
- * @param session
- * @param user The user id, email address, or username. Not freed.
- * @param cb Callback, called with user information when available.
- * @param data An arbitray data pointer passed to the callback.
- */
-/* TODO: change to not use callbacks */
-void 
-msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data)
-{
-	MsimMessage *body;
-	gchar *field_name;
-	guint rid, cmd, dsn, lid;
-
-	g_return_if_fail(MSIM_SESSION_VALID(session));
-	g_return_if_fail(user != NULL);
-	/* Callback can be null to not call anything, just lookup & store information. */
-	/*g_return_if_fail(cb != NULL);*/
-
-	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);
-
-	/* Send request */
-
-	cmd = MSIM_CMD_GET;
-
-	if (msim_is_userid(user)) {
-		field_name = "UserID";
-		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;
-		lid = MG_MYSPACE_INFO_BY_STRING_LID;
-	} else {
-		field_name = "UserName";
-		dsn = MG_MYSPACE_INFO_BY_STRING_DSN;
-		lid = MG_MYSPACE_INFO_BY_STRING_LID;
-	}
-
-	body = msim_msg_new(
-			field_name, MSIM_TYPE_STRING, g_strdup(user),
-			NULL);
-
-	g_return_if_fail(msim_send(session,
-			"persist", MSIM_TYPE_INTEGER, 1,
-			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
-			"cmd", MSIM_TYPE_INTEGER, 1,
-			"dsn", MSIM_TYPE_INTEGER, dsn,
-			"uid", MSIM_TYPE_INTEGER, session->userid,
-			"lid", MSIM_TYPE_INTEGER, lid,
-			"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);
-}
-
-/**
- * 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)
-{
-	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 %d 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 */
-}
-
-
+/* MySpaceIM Protocol Plugin, header file
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * 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  02111-1301  USA
+ */
+
+#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(gchar *band, gchar *song);
+static void msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text,
+		gsize len, const gchar *error_message);
+
+/** Format the "now playing" indicator, showing the artist and song.
+ * @return Return a new string (must be g_free()'d), or NULL.
+ */
+static gchar *
+msim_format_now_playing(gchar *band, gchar *song)
+{
+	if ((band && strlen(band)) || (song && strlen(song))) {
+		return g_strdup_printf("%s - %s",
+			(band && strlen(band)) ? band : "Unknown Artist",
+			(song && strlen(song)) ? song : "Unknown Song");
+	} else {
+		return NULL;
+	}
+}
+/** Get the MsimUser from a PurpleBuddy, creating it if needed. */
+MsimUser *
+msim_get_user_from_buddy(PurpleBuddy *buddy)
+{
+	MsimUser *user;
+
+	if (!buddy) {
+		return NULL;
+	}
+
+	if (!buddy->proto_data) {
+		/* No MsimUser for this buddy; make one. */
+
+		/* TODO: where is this freed? */
+		user = g_new0(MsimUser, 1);
+		user->buddy = buddy;
+		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. */
+MsimUser *
+msim_find_user(MsimSession *session, const gchar *username)
+{
+	PurpleBuddy *buddy;
+	MsimUser *user;
+
+	buddy = purple_find_buddy(session->account, username);
+	if (!buddy) {
+		return NULL;
+	}
+
+	user = msim_get_user_from_buddy(buddy);
+
+	return user;
+}
+
+/** 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
+msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full)
+{
+	gchar *str;
+	guint uid;
+	guint cv;
+
+	/* 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 */
+		purple_notify_user_info_add_pair(user_info, _("Profile"),
+				g_strdup_printf("<a href=\"http://myspace.com/%d\">http://myspace.com/%d</a>",
+					uid, uid));
+	}
+
+
+	/* a/s/l...the vitals */
+	if (user->age) {
+		purple_notify_user_info_add_pair(user_info, _("Age"),
+				g_strdup_printf("%d", user->age));
+	}
+
+	if (user->gender && strlen(user->gender)) {
+		purple_notify_user_info_add_pair(user_info, _("Gender"), user->gender);
+	}
+
+	if (user->location && strlen(user->location)) {
+		purple_notify_user_info_add_pair(user_info, _("Location"), user->location);
+	}
+
+	/* Other information */
+	if (user->headline && strlen(user->headline)) {
+		purple_notify_user_info_add_pair(user_info, _("Headline"), user->headline);
+	}
+
+	str = msim_format_now_playing(user->band_name, user->song_name);
+	if (str && strlen(str)) {
+		purple_notify_user_info_add_pair(user_info, _("Song"), str);
+	}
+
+	/* Note: total friends only available if looked up by uid, not username. */
+	if (user->total_friends) {
+		purple_notify_user_info_add_pair(user_info, _("Total Friends"),
+			g_strdup_printf("%d", user->total_friends));
+	}
+
+	if (full) {
+		/* Client information */
+
+		str = user->client_info;
+		cv = user->client_cv;
+
+		if (str && cv != 0) {
+			purple_notify_user_info_add_pair(user_info, _("Client Version"),
+					g_strdup_printf("%s (build %d)", str, cv));
+		} else if (str) {
+			purple_notify_user_info_add_pair(user_info, _("Client Version"),
+					g_strdup(str));
+		} else if (cv) {
+			purple_notify_user_info_add_pair(user_info, _("Client Version"),
+					g_strdup_printf("Build %d", cv));
+		}
+	}
+}
+
+/** 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 
+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(). */
+		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));
+		}
+		/* Need to store in MsimUser, too? What if not on blist? */
+	} else if (g_str_equal(key_str, "Age")) {
+		user->age = atol(value_str);
+		g_free(value_str);
+	} else if (g_str_equal(key_str, "Gender")) {
+		g_free(user->gender);
+		user->gender = value_str;
+	} else if (g_str_equal(key_str, "Location")) {
+		g_free(user->location);
+		user->location = value_str;
+	} else if (g_str_equal(key_str, "TotalFriends")) {
+		user->total_friends = atol(value_str);
+	} else if (g_str_equal(key_str, "DisplayName")) {
+		g_free(user->display_name);
+		user->display_name = value_str;
+	} else if (g_str_equal(key_str, "BandName")) {
+		g_free(user->band_name);
+		user->band_name = value_str;
+	} else if (g_str_equal(key_str, "SongName")) {
+		g_free(user->song_name);
+		user->song_name = value_str;
+	} else if (g_str_equal(key_str, "UserName") || g_str_equal(key_str, "IMName") || g_str_equal(key_str, "NickName")) {
+		/* Ignore because PurpleBuddy knows this already */
+		g_free(value_str);
+	} else if (g_str_equal(key_str, "ImageURL") || g_str_equal(key_str, "AvatarURL")) {
+		const gchar *previous_url;
+
+		g_free(user->image_url);
+
+		user->image_url = value_str;
+
+		/* Instead of showing 'no photo' picture, show nothing. */
+		if (g_str_equal(user->image_url, "http://x.myspace.com/images/no_pic.gif"))
+		{
+			purple_buddy_icons_set_for_user(user->buddy->account,
+				user->buddy->name,
+				NULL, 0, NULL);
+			return;
+		}
+	
+		/* TODO: use ETag for checksum */
+		previous_url = purple_buddy_icons_get_checksum_for_user(user->buddy);
+
+		/* Only download if URL changed */
+		if (!previous_url || !g_str_equal(previous_url, user->image_url)) {
+			purple_util_fetch_url(user->image_url, TRUE, NULL, TRUE, msim_downloaded_buddy_icon, (gpointer)user);
+		}
+	} else if (g_str_equal(key_str, "LastImageUpdated")) {
+		/* TODO: use somewhere */
+		user->last_image_updated = atol(value_str);
+		g_free(value_str);
+	} else if (g_str_equal(key_str, "Headline")) {
+		g_free(user->headline);
+		user->headline = value_str;
+	} else {
+		/* TODO: other fields in MsimUser */
+		gchar *msg;
+
+		msg = g_strdup_printf("msim_store_user_info_each: unknown field %s=%s",
+				key_str, value_str);
+		g_free(value_str);
+
+		msim_unrecognized(NULL, NULL, msg);
+
+		g_free(msg);
+	}
+}
+
+/** 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.
+ * @param user The structure to save to, or NULL to save in PurpleBuddy->proto_data.
+ *
+ * Variable information is saved to the passed MsimUser structure. Permanent
+ * information (UserID) is stored in the blist node of the buddy list (and
+ * ends up in blist.xml, persisted to disk) if it exists.
+ *
+ * If the function has no buddy information, this function
+ * is a no-op (and returns FALSE).
+ *
+ */
+gboolean 
+msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user)
+{
+	gchar *username;
+	MsimMessage *body, *body_node;
+
+	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+	g_return_val_if_fail(msg != NULL, FALSE);
+
+	body = msim_msg_get_dictionary(msg, "body");
+	if (!body) {
+		return FALSE;
+	}
+
+	username = msim_msg_get_string(body, "UserName");
+
+	if (!username) {
+		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);
+		if (!user) {
+			msim_msg_free(body);
+			g_free(username);
+			return FALSE;
+		}
+	}
+
+	/* TODO: make looping over MsimMessage's easier. */
+	for (body_node = body; 
+		body_node != NULL; 
+		body_node = msim_msg_get_next_element_node(body_node))
+	{
+		const gchar *key_str;
+		gchar *value_str;
+		MsimMessageElement *elem;
+
+		elem = (MsimMessageElement *)body_node->data;
+		key_str = elem->name;
+
+		value_str = msim_msg_get_string_from_element(elem);
+		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;
+}
+
+/**
+ * Asynchronously lookup user information, calling callback when receive result.
+ *
+ * @param session
+ * @param user The user id, email address, or username. Not freed.
+ * @param cb Callback, called with user information when available.
+ * @param data An arbitray data pointer passed to the callback.
+ */
+/* TODO: change to not use callbacks */
+void 
+msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data)
+{
+	MsimMessage *body;
+	gchar *field_name;
+	guint rid, cmd, dsn, lid;
+
+	g_return_if_fail(MSIM_SESSION_VALID(session));
+	g_return_if_fail(user != NULL);
+	/* Callback can be null to not call anything, just lookup & store information. */
+	/*g_return_if_fail(cb != NULL);*/
+
+	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);
+
+	/* Send request */
+
+	cmd = MSIM_CMD_GET;
+
+	if (msim_is_userid(user)) {
+		field_name = "UserID";
+		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;
+		lid = MG_MYSPACE_INFO_BY_STRING_LID;
+	} else {
+		field_name = "UserName";
+		dsn = MG_MYSPACE_INFO_BY_STRING_DSN;
+		lid = MG_MYSPACE_INFO_BY_STRING_LID;
+	}
+
+	body = msim_msg_new(
+			field_name, MSIM_TYPE_STRING, g_strdup(user),
+			NULL);
+
+	g_return_if_fail(msim_send(session,
+			"persist", MSIM_TYPE_INTEGER, 1,
+			"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+			"cmd", MSIM_TYPE_INTEGER, 1,
+			"dsn", MSIM_TYPE_INTEGER, dsn,
+			"uid", MSIM_TYPE_INTEGER, session->userid,
+			"lid", MSIM_TYPE_INTEGER, lid,
+			"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);
+}
+
+/**
+ * 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)
+{
+	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 %d 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 */
+}
+
+
--- a/libpurple/protocols/myspace/user.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/myspace/user.h	Fri Sep 28 16:34:43 2007 +0000
@@ -1,55 +1,55 @@
-/* MySpaceIM Protocol Plugin, header file
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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  02111-1301  USA
- */
-
-#ifndef _MYSPACE_USER_H
-#define _MYSPACE_USER_H
-
-/* Hold ephemeral information about buddies, for proto_data of PurpleBuddy. */
-/* GHashTable? */
-typedef struct _MsimUser
-{
-	PurpleBuddy *buddy;
-	guint client_cv;
-	gchar *client_info;
-	guint age;
-	gchar *gender;
-	gchar *location;
-	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;
-	guint last_image_updated;
-} MsimUser;
-
-/* 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);
-
-MsimUser *msim_get_user_from_buddy(PurpleBuddy *buddy);
-MsimUser *msim_find_user(MsimSession *session, const gchar *username);
-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);
-void msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data);
-
-#endif /* !_MYSPACE_USER_H */
+/* MySpaceIM Protocol Plugin, header file
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * 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  02111-1301  USA
+ */
+
+#ifndef _MYSPACE_USER_H
+#define _MYSPACE_USER_H
+
+/* Hold ephemeral information about buddies, for proto_data of PurpleBuddy. */
+/* GHashTable? */
+typedef struct _MsimUser
+{
+	PurpleBuddy *buddy;
+	guint client_cv;
+	gchar *client_info;
+	guint age;
+	gchar *gender;
+	gchar *location;
+	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;
+	guint last_image_updated;
+} MsimUser;
+
+/* 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);
+
+MsimUser *msim_get_user_from_buddy(PurpleBuddy *buddy);
+MsimUser *msim_find_user(MsimSession *session, const gchar *username);
+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);
+void msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data);
+
+#endif /* !_MYSPACE_USER_H */
--- a/libpurple/protocols/myspace/zap.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/myspace/zap.c	Fri Sep 28 16:34:43 2007 +0000
@@ -1,208 +1,208 @@
-/* MySpaceIM Protocol Plugin - zap support
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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  02111-1301  USA
- */
-
-#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)
-{
-	static GList *types = NULL;
-	MsimAttentionType* attn;
-
-	if (!types) {
-#define _MSIM_ADD_NEW_ATTENTION(icn, nme, incoming, outgoing)              \
-		attn = g_new0(MsimAttentionType, 1);                       \
-		attn->icon_name = icn;                                     \
-		attn->name = nme;                                          \
-		attn->incoming_description = incoming;                     \
-		attn->outgoing_description = outgoing;                     \
-		types = g_list_append(types, attn);
-
-		/* TODO: icons for each zap */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Zap"), _("%s has zapped you!"), _("Zapping %s..."));
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Whack"), _("%s has whacked you!"), _("Whacking %s..."));
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Torch"), _("%s has torched you!"), _("Torching %s..."));
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Smooch"), _("%s has smooched you!"), _("Smooching %s..."));
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Hug"), _("%s has hugged you!"), _("Hugging %s..."));
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Slap"), _("%s has slapped you!"), _("Slapping %s..."));
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Goose"), _("%s has goosed you!"), _("Goosing %s..."));
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("High-five"), _("%s has high-fived you!"), _("High-fiving %s..."));
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Punk"), _("%s has punk'd you!"), _("Punking %s..."));
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Raspberry"), _("%s has raspberried you!"), _("Raspberrying %s..."));
-	}
-
-	return types;
-}
-
-/** Send a zap */
-gboolean
-msim_send_attention(PurpleConnection *gc, const gchar *username, guint code)
-{
-	GList *types;
-	MsimSession *session;
-	MsimAttentionType *attn;
-	PurpleBuddy *buddy;
-
-	session = (MsimSession *)gc->proto_data;
-
-	/* Look for this attention type, by the code index given. */
-	types = msim_attention_types(gc->account);
-	attn = (MsimAttentionType *)g_list_nth_data(types, code);
-
-	if (!attn) {
-		purple_debug_info("msim_send_attention", "got invalid zap code %d\n", code);
-		return FALSE;
-	}
-
-	buddy = purple_find_buddy(session->account, username);
-	if (!buddy) {
-		return FALSE;
-	}
-
-	msim_send_zap(session, username, code);
-
-	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)
-{
-	PurpleBuddy *buddy;
-	PurpleAccount *account;
-	PurpleConnection *gc;
-	MsimSession *session;
-	guint zap;
-
-	if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) {
-		/* Only know about buddies for now. */
-		return;
-	}
-
-	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *)node;
-
-	/* Find the session */
-	account = buddy->account;
-	gc = purple_account_get_connection(account);
-	session = (MsimSession *)gc->proto_data;
-
-	zap = GPOINTER_TO_INT(zap_num_ptr);
-
-	serv_send_attention(session->gc, buddy->name, zap);
-}
-
-/** Return menu, if any, for a buddy list node. */
-GList *
-msim_blist_node_menu(PurpleBlistNode *node)
-{
-	GList *menu, *zap_menu;
-	GList *types;
-	PurpleMenuAction *act;
-	guint i;
-
-	if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) {
-		/* Only know about buddies for now. */
-		return NULL;
-	}
-
-	zap_menu = NULL;
-
-	/* TODO: get rid of once is accessible directly in GUI */
-	types = msim_attention_types(NULL);
-	i = 0;
-	do
-	{
-		MsimAttentionType *attn;
-
-		attn = (MsimAttentionType *)types->data;
-
-		act = purple_menu_action_new(attn->name, PURPLE_CALLBACK(msim_send_zap_from_menu),
-				GUINT_TO_POINTER(i), NULL);
-		zap_menu = g_list_append(zap_menu, act);
-
-		++i;
-	} while ((types = g_list_next(types)));
-
-	act = purple_menu_action_new(_("Zap"), NULL, NULL, zap_menu);
-	menu = g_list_append(NULL, act);
-
-	return menu;
-}
-
-/** Process an incoming zap. */
-gboolean
-msim_incoming_zap(MsimSession *session, MsimMessage *msg)
-{
-	gchar *msg_text, *username;
-	gint zap;
-
-	msg_text = msim_msg_get_string(msg, "msg");
-	username = msim_msg_get_string(msg, "_username");
-
-	g_return_val_if_fail(msg_text != NULL, FALSE);
-	g_return_val_if_fail(username != NULL, FALSE);
-
-	g_return_val_if_fail(sscanf(msg_text, "!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", &zap) == 1, FALSE);
-
-	zap = CLAMP(zap, 0, 9);
-
-	serv_got_attention(session->gc, username, zap);
-
-	g_free(msg_text);
-	g_free(username);
-
-	return TRUE;
-}
-
-
+/* MySpaceIM Protocol Plugin - zap support
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * 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  02111-1301  USA
+ */
+
+#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)
+{
+	static GList *types = NULL;
+	MsimAttentionType* attn;
+
+	if (!types) {
+#define _MSIM_ADD_NEW_ATTENTION(icn, nme, incoming, outgoing)              \
+		attn = g_new0(MsimAttentionType, 1);                       \
+		attn->icon_name = icn;                                     \
+		attn->name = nme;                                          \
+		attn->incoming_description = incoming;                     \
+		attn->outgoing_description = outgoing;                     \
+		types = g_list_append(types, attn);
+
+		/* TODO: icons for each zap */
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("Zap"), _("%s has zapped you!"), _("Zapping %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("Whack"), _("%s has whacked you!"), _("Whacking %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("Torch"), _("%s has torched you!"), _("Torching %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("Smooch"), _("%s has smooched you!"), _("Smooching %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("Hug"), _("%s has hugged you!"), _("Hugging %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("Slap"), _("%s has slapped you!"), _("Slapping %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("Goose"), _("%s has goosed you!"), _("Goosing %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("High-five"), _("%s has high-fived you!"), _("High-fiving %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("Punk"), _("%s has punk'd you!"), _("Punking %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("Raspberry"), _("%s has raspberried you!"), _("Raspberrying %s..."));
+	}
+
+	return types;
+}
+
+/** Send a zap */
+gboolean
+msim_send_attention(PurpleConnection *gc, const gchar *username, guint code)
+{
+	GList *types;
+	MsimSession *session;
+	MsimAttentionType *attn;
+	PurpleBuddy *buddy;
+
+	session = (MsimSession *)gc->proto_data;
+
+	/* Look for this attention type, by the code index given. */
+	types = msim_attention_types(gc->account);
+	attn = (MsimAttentionType *)g_list_nth_data(types, code);
+
+	if (!attn) {
+		purple_debug_info("msim_send_attention", "got invalid zap code %d\n", code);
+		return FALSE;
+	}
+
+	buddy = purple_find_buddy(session->account, username);
+	if (!buddy) {
+		return FALSE;
+	}
+
+	msim_send_zap(session, username, code);
+
+	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)
+{
+	PurpleBuddy *buddy;
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	MsimSession *session;
+	guint zap;
+
+	if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) {
+		/* Only know about buddies for now. */
+		return;
+	}
+
+	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
+
+	buddy = (PurpleBuddy *)node;
+
+	/* Find the session */
+	account = buddy->account;
+	gc = purple_account_get_connection(account);
+	session = (MsimSession *)gc->proto_data;
+
+	zap = GPOINTER_TO_INT(zap_num_ptr);
+
+	serv_send_attention(session->gc, buddy->name, zap);
+}
+
+/** Return menu, if any, for a buddy list node. */
+GList *
+msim_blist_node_menu(PurpleBlistNode *node)
+{
+	GList *menu, *zap_menu;
+	GList *types;
+	PurpleMenuAction *act;
+	guint i;
+
+	if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) {
+		/* Only know about buddies for now. */
+		return NULL;
+	}
+
+	zap_menu = NULL;
+
+	/* TODO: get rid of once is accessible directly in GUI */
+	types = msim_attention_types(NULL);
+	i = 0;
+	do
+	{
+		MsimAttentionType *attn;
+
+		attn = (MsimAttentionType *)types->data;
+
+		act = purple_menu_action_new(attn->name, PURPLE_CALLBACK(msim_send_zap_from_menu),
+				GUINT_TO_POINTER(i), NULL);
+		zap_menu = g_list_append(zap_menu, act);
+
+		++i;
+	} while ((types = g_list_next(types)));
+
+	act = purple_menu_action_new(_("Zap"), NULL, NULL, zap_menu);
+	menu = g_list_append(NULL, act);
+
+	return menu;
+}
+
+/** Process an incoming zap. */
+gboolean
+msim_incoming_zap(MsimSession *session, MsimMessage *msg)
+{
+	gchar *msg_text, *username;
+	gint zap;
+
+	msg_text = msim_msg_get_string(msg, "msg");
+	username = msim_msg_get_string(msg, "_username");
+
+	g_return_val_if_fail(msg_text != NULL, FALSE);
+	g_return_val_if_fail(username != NULL, FALSE);
+
+	g_return_val_if_fail(sscanf(msg_text, "!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", &zap) == 1, FALSE);
+
+	zap = CLAMP(zap, 0, 9);
+
+	serv_got_attention(session->gc, username, zap);
+
+	g_free(msg_text);
+	g_free(username);
+
+	return TRUE;
+}
+
+
--- a/libpurple/protocols/myspace/zap.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/myspace/zap.h	Fri Sep 28 16:34:43 2007 +0000
@@ -1,28 +1,28 @@
-/* MySpaceIM Protocol Plugin - zap support
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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  02111-1301  USA
- */
-
-#ifndef _MYSPACE_ZAP_H
-#define _MYSPACE_ZAP_H
-
-GList *msim_attention_types(PurpleAccount *acct);
-gboolean msim_send_attention(PurpleConnection *gc, const gchar *username, guint code);
-GList *msim_blist_node_menu(PurpleBlistNode *node);
-gboolean msim_incoming_zap(MsimSession *session, MsimMessage *msg);
-
-#endif /* !_MYSPACE_ZAP_H */
+/* MySpaceIM Protocol Plugin - zap support
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * 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  02111-1301  USA
+ */
+
+#ifndef _MYSPACE_ZAP_H
+#define _MYSPACE_ZAP_H
+
+GList *msim_attention_types(PurpleAccount *acct);
+gboolean msim_send_attention(PurpleConnection *gc, const gchar *username, guint code);
+GList *msim_blist_node_menu(PurpleBlistNode *node);
+gboolean msim_incoming_zap(MsimSession *session, MsimMessage *msg);
+
+#endif /* !_MYSPACE_ZAP_H */
--- a/libpurple/protocols/novell/novell.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/novell/novell.c	Fri Sep 28 16:34:43 2007 +0000
@@ -130,6 +130,8 @@
 		if (ret_code == NMERR_AUTHENTICATION_FAILED ||
 			ret_code == NMERR_CREDENTIALS_MISSING ||
 			ret_code == NMERR_PASSWORD_INVALID) {
+			if (!purple_account_get_remember_password(gc->account))
+				purple_account_set_password(gc->account, NULL);
 			gc->wants_to_die = TRUE;
 		}
 		purple_connection_error(gc, err);
@@ -2004,11 +2006,14 @@
 _evt_user_disconnect(NMUser * user, NMEvent * event)
 {
 	PurpleConnection *gc;
-
-	gc = purple_account_get_connection((PurpleAccount *) user->client_data);
+	PurpleAccount *account = user->client_data;
+
+	gc = purple_account_get_connection(account);
 	if (gc)
 	{
 		gc->wants_to_die = TRUE; /* we don't want to reconnect in this case */
+		if (!purple_account_get_remember_password(account))
+			purple_account_set_password(account, NULL);
 		purple_connection_error(gc, _("You have been logged out because you"
 									" logged in at another workstation."));
 	}
@@ -2799,7 +2804,7 @@
 	const char *text = NULL;
 
 	if (buddy == NULL)
-		return; 
+		return;
 
 	gc = purple_account_get_connection(buddy->account);
 	if (gc == NULL || (user = gc->proto_data) == NULL)
--- a/libpurple/protocols/oscar/flap_connection.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/oscar/flap_connection.c	Fri Sep 28 16:34:43 2007 +0000
@@ -382,6 +382,8 @@
 		gchar *tmp;
 		if (conn->disconnect_code == 0x0001) {
 			tmp = g_strdup(_("You have signed on from another location."));
+			if (!purple_account_get_remember_password(account))
+				purple_account_set_password(account, NULL);
 			od->gc->wants_to_die = TRUE;
 		} else if (conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_CLOSED)
 			tmp = g_strdup(_("Server closed the connection."));
--- a/libpurple/protocols/oscar/oscar.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Fri Sep 28 16:34:43 2007 +0000
@@ -5523,6 +5523,8 @@
 			return "hiptop";
 		if (userinfo->capabilities & OSCAR_CAPABILITY_SECUREIM)
 			return "secure";
+		if (userinfo->icqinfo.status & AIM_ICQ_STATE_BIRTHDAY)
+			return "birthday";
 	}
 	return NULL;
 }
--- a/libpurple/protocols/qq/login_logout.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/qq/login_logout.c	Fri Sep 28 16:34:43 2007 +0000
@@ -480,6 +480,8 @@
 	switch (ret) {
 	case QQ_LOGIN_REPLY_PWD_ERROR:
 		gc->wants_to_die = TRUE;
+		if (!purple_account_get_remember_password(gc->account))
+			purple_account_set_password(gc->account, NULL);
 		purple_connection_error(gc, _("Incorrect password."));
 		break;
 	case QQ_LOGIN_REPLY_MISC_ERROR:
--- a/libpurple/protocols/simple/simple.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/simple/simple.c	Fri Sep 28 16:34:43 2007 +0000
@@ -695,7 +695,7 @@
 static void do_register_exp(struct simple_account_data *sip, int expire) {
 	char *uri, *to, *contact, *hdr;
 
-	/* Set our default expiration to 900, 
+	/* Set our default expiration to 900,
 	 * as done in the initialization of the simple_account_data
 	 * structure.
 	 */
@@ -1042,6 +1042,8 @@
 				if(sip->registrar.retries > SIMPLE_REGISTER_RETRY_MAX) {
 					purple_debug_info("simple", "Setting wants_to_die to true.\n");
 					sip->gc->wants_to_die = TRUE;
+					if (!purple_account_get_remember_password(sip->gc->account))
+						purple_account_set_password(sip->gc->account, NULL);
 					purple_connection_error(sip->gc, _("Incorrect password."));
 					return TRUE;
 				}
--- a/libpurple/protocols/yahoo/yahoo.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Fri Sep 28 16:34:43 2007 +0000
@@ -202,6 +202,8 @@
 
 	if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {
 		gc->wants_to_die = TRUE;
+		if (!purple_account_get_remember_password(account))
+			purple_account_set_password(account, NULL);
 		purple_connection_error(gc, _("You have signed on from another location."));
 		return;
 	}
@@ -4087,12 +4089,12 @@
 {
 	return TRUE;
 }
-	
+
 gboolean yahoo_send_attention(PurpleConnection *gc, const char *username, guint type)
 {
 	PurpleConversation *c;
 
-	c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, 
+	c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
 			username, gc->account);
 
 	g_return_val_if_fail(c != NULL, FALSE);
@@ -4117,7 +4119,7 @@
 		attn->incoming_description = _("%s has buzzed you!");
 		attn->outgoing_description = _("Buzzing %s...");
 		list = g_list_append(list, attn);
-	} 
+	}
 
 	return list;
 }
--- a/libpurple/server.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/server.c	Fri Sep 28 16:34:43 2007 +0000
@@ -543,7 +543,7 @@
 				 PurpleMessageFlags flags, time_t mtime)
 {
 	PurpleAccount *account;
-	PurpleConversation *cnv;
+	PurpleConversation *conv;
 	char *message, *name;
 	char *angel, *buffy;
 	int plugin_return;
@@ -562,22 +562,19 @@
 	 * We should update the conversation window buttons and menu,
 	 * if it exists.
 	 */
-	cnv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, gc->account);
+	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, gc->account);
 
 	/*
-	 * Plugin stuff. we pass a char ** but we don't want to pass what's
-	 * been given us by the prpls. So we create temp holders and pass
-	 * those instead. It's basically just to avoid segfaults.
+	 * Make copies of the message and the sender in case plugins want
+	 * to free these strings and replace them with a modifed version.
 	 */
-	/* TODO: MAX(message, BUF_LONG) is pretty ugly. */
-	buffy = g_malloc(MAX(strlen(msg) + 1, BUF_LONG));
-	strcpy(buffy, msg);
+	buffy = g_strdup(msg);
 	angel = g_strdup(who);
 
 	plugin_return = GPOINTER_TO_INT(
 		purple_signal_emit_return_1(purple_conversations_get_handle(),
 								  "receiving-im-msg", gc->account,
-								  &angel, &buffy, cnv, &flags));
+								  &angel, &buffy, conv, &flags));
 
 	if (!buffy || !angel || plugin_return) {
 		g_free(buffy);
@@ -589,21 +586,21 @@
 	message = buffy;
 
 	purple_signal_emit(purple_conversations_get_handle(), "received-im-msg", gc->account,
-					 name, message, cnv, flags);
+					 name, message, conv, flags);
 
 	/* search for conversation again in case it was created by received-im-msg handler */
-	if (cnv == NULL)
-		cnv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, gc->account);
+	if (conv == NULL)
+		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, gc->account);
 
 	/*
 	 * XXX: Should we be setting this here, or relying on prpls to set it?
 	 */
 	flags |= PURPLE_MESSAGE_RECV;
 
-	if (cnv == NULL)
-		cnv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name);
+	if (conv == NULL)
+		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name);
 
-	purple_conv_im_write(PURPLE_CONV_IM(cnv), NULL, message, flags, mtime);
+	purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, message, flags, mtime);
 	g_free(message);
 
 	/*
@@ -670,7 +667,7 @@
 				{
 					serv_send_im(gc, name, away_msg, PURPLE_MESSAGE_AUTO_RESP);
 
-					purple_conv_im_write(PURPLE_CONV_IM(cnv), NULL, away_msg,
+					purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, away_msg,
 									   PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_AUTO_RESP,
 									   mtime);
 				}
@@ -892,15 +889,10 @@
 		return;
 
 	/*
-	 * Plugin stuff. We pass a char ** but we don't want to pass what's
-	 * been given us by the prpls. so we create temp holders and pass those
-	 * instead. It's basically just to avoid segfaults. Of course, if the
-	 * data is binary, plugins don't see it. Bitch all you want; i really
-	 * don't want you to be dealing with it.
+	 * Make copies of the message and the sender in case plugins want
+	 * to free these strings and replace them with a modifed version.
 	 */
-	/* TODO: MAX(message, BUF_LONG) is pretty ugly. */
-	buffy = g_malloc(MAX(strlen(message) + 1, BUF_LONG));
-	strcpy(buffy, message);
+	buffy = g_strdup(message);
 	angel = g_strdup(who);
 
 	plugin_return = GPOINTER_TO_INT(
@@ -913,6 +905,7 @@
 		g_free(angel);
 		return;
 	}
+
 	who = angel;
 	message = buffy;
 
--- a/libpurple/sslconn.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/sslconn.h	Fri Sep 28 16:34:43 2007 +0000
@@ -31,6 +31,7 @@
 
 #define PURPLE_SSL_DEFAULT_PORT 443
 
+/** Possible SSL errors. */
 typedef enum
 {
 	PURPLE_SSL_HANDSHAKE_FAILED = 1,
@@ -86,39 +87,48 @@
 typedef struct
 {
 	/** Initializes the SSL system provided.
-     *  @return TRUE if initialization succeeded
-     */
+	 *  @return @a TRUE if initialization succeeded
+	 *  @see purple_ssl_init
+	 */
 	gboolean (*init)(void);
-	/** Unloads the SSL system. Inverse of init. */
+	/** Unloads the SSL system. Inverse of PurpleSslOps::init.
+	 *  @see purple_ssl_uninit
+	 */
 	void (*uninit)(void);
-	/** Sets up the SSL connection for a PurpleSslConnection once
-     *  the TCP connection has been established */
+	/** Sets up the SSL connection for a #PurpleSslConnection once
+	 *  the TCP connection has been established
+	 *  @see purple_ssl_connect
+	 */
 	void (*connectfunc)(PurpleSslConnection *gsc);
 	/** Destroys the internal data of the SSL connection provided.
 	 *  Freeing gsc itself is left to purple_ssl_close()
-	 *
+	 *  @see purple_ssl_close
 	 */
 	void (*close)(PurpleSslConnection *gsc);
 	/** Reads data from a connection (like POSIX read())
-	 * @param gsc	Connection context
-	 * @param data	Pointer to buffer to drop data into
-	 * @param len	Maximum number of bytes to read
-	 * @return	Number of bytes actually written into the buffer, or <0 on error
+	 * @param gsc   Connection context
+	 * @param data  Pointer to buffer to drop data into
+	 * @param len   Maximum number of bytes to read
+	 * @return      Number of bytes actually written into @a data (which may be
+	 *              less than @a len), or <0 on error
+	 * @see purple_ssl_read
 	*/
 	size_t (*read)(PurpleSslConnection *gsc, void *data, size_t len);
 	/** Writes data to a connection (like POSIX send())
-	* @param gsc	Connection context
-	* @param data	Data buffer to send data from
-	* @param len	Number of bytes to send from buffer
-	* @return	The number of bytes written (may be less than len) or <0 on error
+	* @param gsc    Connection context
+	* @param data   Data buffer to send data from
+	* @param len    Number of bytes to send from buffer
+	* @return       The number of bytes written to @a data (may be less than
+	*               @a len) or <0 on error
+	* @see purple_ssl_write
 	*/
 	size_t (*write)(PurpleSslConnection *gsc, const void *data, size_t len);
 	/** Obtains the certificate chain provided by the peer
 	 *
 	 * @param gsc   Connection context
-	 * @return      A newly allocated list containing the certificates
-	 *              the peer provided.
-	 * @see PurpleCertificate
+	 * @return      A newly allocated list of #PurpleCertificate containing the
+	 *              certificates the peer provided.
+	 * @see purple_ssl_get_peer_certificates
 	 * @todo        Decide whether the ordering of certificates in this
 	 *              list can be guaranteed.
 	 */
@@ -141,12 +151,12 @@
 /**
  * Returns whether or not SSL is currently supported.
  *
- * @return TRUE if SSL is supported, or FALSE otherwise.
+ * @return @a TRUE if SSL is supported, or @a FALSE otherwise.
  */
 gboolean purple_ssl_is_supported(void);
 
 /**
- * Returns a human-readable string for an SSL error
+ * Returns a human-readable string for an SSL error.
  *
  * @param error      Error code
  * @return Human-readable error explanation
@@ -163,8 +173,8 @@
  * @param port       The destination port.
  * @param func       The SSL input handler function.
  * @param error_func The SSL error handler function.  This function
- *                   should NOT call purple_ssl_close().  In the event
- *                   of an error the PurpleSslConnection will be
+ *                   should <strong>NOT</strong> call purple_ssl_close().  In
+ *                   the event of an error the #PurpleSslConnection will be
  *                   destroyed for you.
  * @param data       User-defined data.
  *
@@ -177,7 +187,8 @@
 
 /**
  * Makes a SSL connection using an already open file descriptor.
- * DEPRECATED. Use purple_ssl_connect_with_host_fd instead.
+ *
+ * @deprecated Use purple_ssl_connect_with_host_fd() instead.
  *
  * @param account    The account making the connection.
  * @param fd         The file descriptor.
@@ -256,7 +267,7 @@
  * @param gsc    The SSL connection handle
  *
  * @return The peer certificate chain, in the order of certificate, issuer,
- *         issuer's issuer, etc. NULL if no certificates have been provided,
+ *         issuer's issuer, etc. @a NULL if no certificates have been provided,
  */
 GList * purple_ssl_get_peer_certificates(PurpleSslConnection *gsc);
 
--- a/libpurple/status.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/status.c	Fri Sep 28 16:34:43 2007 +0000
@@ -601,7 +601,7 @@
 	{
 		time_t current_time = time(NULL);
 		const char *buddy_alias = purple_buddy_get_alias(buddy);
-		char *tmp;
+		char *tmp, *logtmp;
 		PurpleLog *log;
 
 		if (old_status != NULL)
@@ -609,6 +609,10 @@
 			tmp = g_strdup_printf(_("%s changed status from %s to %s"), buddy_alias,
 			                      purple_status_get_name(old_status),
 			                      purple_status_get_name(new_status));
+			logtmp = g_strdup_printf(_("%s (%s) changed status from %s to %s"), buddy_alias, buddy->name,
+			                      purple_status_get_name(old_status),
+			                      purple_status_get_name(new_status));
+
 		}
 		else
 		{
@@ -618,11 +622,16 @@
 			{
 				tmp = g_strdup_printf(_("%s is now %s"), buddy_alias,
 				                      purple_status_get_name(new_status));
+				logtmp = g_strdup_printf(_("%s (%s) is now %s"), buddy_alias, buddy->name,
+				                      purple_status_get_name(new_status));
+
 			}
 			else
 			{
 				tmp = g_strdup_printf(_("%s is no longer %s"), buddy_alias,
 				                      purple_status_get_name(new_status));
+				logtmp = g_strdup_printf(_("%s (%s) is no longer %s"), buddy_alias, buddy->name,
+				                      purple_status_get_name(new_status));
 			}
 		}
 
@@ -630,10 +639,11 @@
 		if (log != NULL)
 		{
 			purple_log_write(log, PURPLE_MESSAGE_SYSTEM, buddy_alias,
-			               current_time, tmp);
+			               current_time, logtmp);
 		}
 
 		g_free(tmp);
+		g_free(logtmp);
 	}
 }
 
--- a/libpurple/util.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/util.c	Fri Sep 28 16:34:43 2007 +0000
@@ -68,7 +68,7 @@
 };
 
 static char *custom_user_dir = NULL;
-static char *home_dir = NULL;
+static char *user_dir = NULL;
 
 PurpleMenuAction *
 purple_menu_action_new(const char *label, PurpleCallback callback, gpointer data,
@@ -515,23 +515,6 @@
  * Date/Time Functions
  **************************************************************************/
 
-#ifdef _WIN32
-static long win32_get_tz_offset() {
-	TIME_ZONE_INFORMATION tzi;
-	DWORD ret;
-	long off = -1;
-
-	if ((ret = GetTimeZoneInformation(&tzi)) != TIME_ZONE_ID_INVALID)
-	{
-		off = -(tzi.Bias * 60);
-		if (ret == TIME_ZONE_ID_DAYLIGHT)
-			off -= tzi.DaylightBias * 60;
-	}
-
-	return off;
-}
-#endif
-
 const char *purple_get_tzoff_str(const struct tm *tm, gboolean iso)
 {
 	static char buf[7];
@@ -546,7 +529,7 @@
 		g_return_val_if_reached("");
 
 #ifdef _WIN32
-	if ((off = win32_get_tz_offset()) == -1)
+	if ((off = wpurple_get_tz_offset()) == -1)
 		return "";
 #else
 # ifdef HAVE_TM_GMTOFF
@@ -854,7 +837,7 @@
 #endif
 
 #ifdef _WIN32
-				if ((sys_tzoff = win32_get_tz_offset()) == -1)
+				if ((sys_tzoff = wpurple_get_tz_offset()) == -1)
 					tzoff = PURPLE_NO_TZ_OFF;
 				else
 					tzoff += sys_tzoff;
@@ -2465,10 +2448,10 @@
 {
 	if (custom_user_dir != NULL)
 		return custom_user_dir;
-	else if (!home_dir)
-		home_dir = g_build_filename(purple_home_dir(), ".purple", NULL);
-
-	return home_dir;
+	else if (!user_dir)
+		user_dir = g_build_filename(purple_home_dir(), ".purple", NULL);
+
+	return user_dir;
 }
 
 void purple_util_set_user_dir(const char *dir)
--- a/libpurple/win32/win32dep.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/win32/win32dep.c	Fri Sep 28 16:34:43 2007 +0000
@@ -575,6 +575,22 @@
 	libpurpledll_hInstance = NULL;
 }
 
+long
+wpurple_get_tz_offset() {
+	TIME_ZONE_INFORMATION tzi;
+	DWORD ret;
+	long off = -1;
+
+	if ((ret = GetTimeZoneInformation(&tzi)) != TIME_ZONE_ID_INVALID)
+	{
+		off = -(tzi.Bias * 60);
+		if (ret == TIME_ZONE_ID_DAYLIGHT)
+			off -= tzi.DaylightBias * 60;
+	}
+
+	return off;
+}
+
 /* DLL initializer */
 /* suppress gcc "no previous prototype" warning */
 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
--- a/libpurple/win32/win32dep.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/win32/win32dep.h	Fri Sep 28 16:34:43 2007 +0000
@@ -60,6 +60,7 @@
 void wpurple_init(void);
 void wpurple_cleanup(void);
 
+long wpurple_get_tz_offset(void);
 
 /*
  *  MACROS
--- a/libpurple/xmlnode.h	Fri Sep 28 16:32:28 2007 +0000
+++ b/libpurple/xmlnode.h	Fri Sep 28 16:34:43 2007 +0000
@@ -129,7 +129,7 @@
  *
  * @param node The node to get data from.
  *
- * @return The data from the node.  This data is in raw escaped format.
+ * @return The data from the node or NULL. This data is in raw escaped format.
  *         You must g_free this string when finished using it.
  */
 char *xmlnode_get_data(xmlnode *node);
--- a/pidgin/gtkblist.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/gtkblist.c	Fri Sep 28 16:34:43 2007 +0000
@@ -88,6 +88,8 @@
 	GtkWidget *group_combo;
 	GtkWidget *entries_box;
 	GtkSizeGroup *sg;
+	GtkWidget *autojoin;
+	GtkWidget *persistent;
 
 	GList *entries;
 
@@ -138,13 +140,23 @@
 static void redo_buddy_list(PurpleBuddyList *list, gboolean remove, gboolean rerender);
 static void pidgin_blist_collapse_contact_cb(GtkWidget *w, PurpleBlistNode *node);
 static char *pidgin_get_group_title(PurpleBlistNode *gnode, gboolean expanded);
-
-struct _pidgin_blist_node {
+static void pidgin_blist_expand_contact_cb(GtkWidget *w, PurpleBlistNode *node);
+
+typedef enum {
+	PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE    =  1 << 0,  /* Whether there's pending message in a conversation */
+} PidginBlistNodeFlags;
+
+typedef struct _pidgin_blist_node {
 	GtkTreeRowReference *row;
 	gboolean contact_expanded;
 	gboolean recent_signonoff;
 	gint recent_signonoff_timer;
-};
+	struct {
+		PurpleConversation *conv;
+		time_t last_message;          /* timestamp for last displayed message */
+		PidginBlistNodeFlags flags;
+	} conv;
+} PidginBlistNode;
 
 static char dim_grey_string[8] = "";
 static char *dim_grey()
@@ -306,12 +318,36 @@
 	serv_send_file(b->account->gc, b->name, NULL);
 }
 
+static void gtk_blist_menu_move_to_cb(GtkWidget *w, PurpleBlistNode *node)
+{
+	PurpleGroup *group = g_object_get_data(G_OBJECT(w), "groupnode");
+	purple_blist_add_contact((PurpleContact *)node, group, NULL);
+
+}
+
 static void gtk_blist_menu_autojoin_cb(GtkWidget *w, PurpleChat *chat)
 {
 	purple_blist_node_set_bool((PurpleBlistNode*)chat, "gtk-autojoin",
 			gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
 }
 
+static void gtk_blist_menu_persistent_cb(GtkWidget *w, PurpleChat *chat)
+{
+	purple_blist_node_set_bool((PurpleBlistNode*)chat, "gtk-persistent",
+			gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
+}
+
+static PurpleConversation *
+find_conversation_with_buddy(PurpleBuddy *buddy)
+{
+	PidginBlistNode *ui = buddy->node.ui_data;
+	if (ui)
+		return ui->conv.conv;
+	return purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
+									     purple_buddy_get_name(buddy),
+									     purple_buddy_get_account(buddy));
+}
+
 static void gtk_blist_join_chat(PurpleChat *chat)
 {
 	PurpleConversation *conv;
@@ -395,6 +431,105 @@
 }
 #endif
 
+static void
+gtk_blist_do_personize(GList *merges)
+{
+	PurpleBlistNode *contact = NULL;
+	int max = 0;
+	GList *tmp;
+
+	/* First, we find the contact to merge the rest of the buddies into.
+ 	 * This will be the contact with the most buddies in it; ties are broken
+ 	 * by which contact is higher in the list
+ 	 */
+	for (tmp = merges; tmp; tmp = tmp->next) {
+		PurpleBlistNode *node = tmp->data;
+		PurpleBlistNode *b;
+		int i = 0;
+
+		if (node->type == PURPLE_BLIST_BUDDY_NODE)
+			node = node->parent;
+
+		if (node->type != PURPLE_BLIST_CONTACT_NODE)
+			continue;
+		
+
+		for (b = node->child; b; b = b->next)
+			i++;
+		if (i > max) {
+			contact = node;
+			max = i;
+		}
+	}
+
+	if (contact == NULL)
+		return;
+
+	/* Merge all those buddies into this contact */
+	for (tmp = merges; tmp; tmp = tmp->next) {
+		PurpleBlistNode *node = tmp->data;
+		if (node->type == PURPLE_BLIST_BUDDY_NODE)
+			node = node->parent;
+
+		if (node == contact)
+			continue;
+
+		purple_blist_merge_contact((PurpleContact *)node, contact);
+	}
+
+	/* And show the expanded contact, so the people know what's going on */
+	pidgin_blist_expand_contact_cb(NULL, contact);
+	g_list_free(merges);
+}
+
+static void
+gtk_blist_auto_personize(PurpleBlistNode *group, const char *alias)
+{
+	PurpleBlistNode *contact;
+	PurpleBlistNode *buddy;
+	GList *merges = NULL;
+	int i = 0;
+	char *a = g_utf8_casefold(alias, -1);
+
+	for (contact = group->child; contact; contact = contact->next) {
+		char *node_alias;
+		if (contact->type != PURPLE_BLIST_CONTACT_NODE)
+			continue;
+
+		node_alias = g_utf8_casefold(purple_contact_get_alias((PurpleContact *)contact), -1);
+		if (node_alias && !g_utf8_collate(node_alias, a)) {
+			merges = g_list_append(merges, contact);
+			i++;
+			g_free(node_alias);
+			continue;
+		}
+		g_free(node_alias);
+
+		for (buddy = contact->child; buddy; buddy = buddy->next) {
+			if (buddy->type != PURPLE_BLIST_BUDDY_NODE)
+				continue;
+
+			node_alias = g_utf8_casefold(purple_buddy_get_alias((PurpleBuddy *)buddy), -1);
+			if (node_alias && !g_utf8_collate(node_alias, a)) {
+				merges = g_list_append(merges, buddy);
+				i++;
+			}
+			g_free(node_alias);
+		}
+	}
+	g_free(a);
+	
+	if (i > 1)
+	{
+		char *msg = g_strdup_printf(ngettext("You have %d contact named %s. Would you like to merge them?", "You currently have %d contacts named %s. Would you like to merge them?", i), i, alias);
+		purple_request_action(NULL, NULL, msg, _("Merging these contacts will cause them to share a single entry on the buddy list and use a single conversation window. "
+							 "You can separate them again by choosing 'Expand' from the contact's context menu"), 0, NULL, NULL, NULL,
+				      merges, 2, _("_Merge"), PURPLE_CALLBACK(gtk_blist_do_personize), _("_Cancel"), PURPLE_CALLBACK(g_list_free));
+		g_free(msg);
+	} else
+		g_list_free(merges);
+}
+
 static void gtk_blist_renderer_edited_cb(GtkCellRendererText *text_rend, char *arg1,
 					 char *arg2, PurpleBuddyList *list)
 {
@@ -421,13 +556,14 @@
 				PurpleContact *contact = (PurpleContact *)node;
 				struct _pidgin_blist_node *gtknode = (struct _pidgin_blist_node *)node->ui_data;
 
-				if (contact->alias || gtknode->contact_expanded)
+				if (contact->alias || gtknode->contact_expanded) {
 					purple_blist_alias_contact(contact, arg2);
-				else
-				{
+					gtk_blist_auto_personize(node->parent, arg2);
+				} else {
 					PurpleBuddy *buddy = purple_contact_get_priority_buddy(contact);
 					purple_blist_alias_buddy(buddy, arg2);
 					serv_alias_buddy(buddy);
+					gtk_blist_auto_personize(node->parent, arg2);
 				}
 			}
 			break;
@@ -435,6 +571,7 @@
 		case PURPLE_BLIST_BUDDY_NODE:
 			purple_blist_alias_buddy((PurpleBuddy*)node, arg2);
 			serv_alias_buddy((PurpleBuddy *)node);
+			gtk_blist_auto_personize(node->parent->parent, arg2);
 			break;
 		case PURPLE_BLIST_GROUP_NODE:
 			dest = purple_find_group(arg2);
@@ -525,6 +662,26 @@
 	}
 }
 
+static void gtk_blist_menu_showoffline_cb(GtkWidget *w, PurpleBlistNode *node)
+{
+	if (PURPLE_BLIST_NODE_IS_BUDDY(node))
+	{
+		purple_blist_node_set_bool(node, "show_offline",
+		                           !purple_blist_node_get_bool(node, "show_offline"));
+	}
+	else if (PURPLE_BLIST_NODE_IS_CONTACT(node))
+	{
+		PurpleBlistNode *bnode;
+		gboolean setting = !purple_blist_node_get_bool(node, "show_offline");
+
+		purple_blist_node_set_bool(node, "show_offline", setting);
+		for (bnode = node->child; bnode != NULL; bnode = bnode->next) {
+			purple_blist_node_set_bool(bnode, "show_offline", setting);
+		}
+	}
+	pidgin_blist_update(purple_get_blist(), node);
+}
+
 static void gtk_blist_show_systemlog_cb()
 {
 	pidgin_syslog_show();
@@ -1119,17 +1276,49 @@
 	g_list_free(ll);
 }
 
+
+
+static void
+pidgin_append_blist_node_move_to_menu(GtkWidget *menu, PurpleBlistNode *node)
+{
+	GtkWidget *submenu;
+	GtkWidget *menuitem;
+	PurpleBlistNode *group;
+
+	menuitem = gtk_menu_item_new_with_label(_("Move to"));
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+	gtk_widget_show(menuitem);
+
+	submenu = gtk_menu_new();
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
+
+	for (group = purple_blist_get_root(); group; group = group->next) {
+		if (group->type != PURPLE_BLIST_GROUP_NODE)
+			continue;
+		if (group == node->parent)
+			continue;
+		menuitem = pidgin_new_item_from_stock(submenu, purple_group_get_name((PurpleGroup *)group), NULL,
+						      G_CALLBACK(gtk_blist_menu_move_to_cb), node, 0, 0, NULL);
+		g_object_set_data(G_OBJECT(menuitem), "groupnode", group);
+	}
+	gtk_widget_show_all(submenu);
+}
+
 void
 pidgin_blist_make_buddy_menu(GtkWidget *menu, PurpleBuddy *buddy, gboolean sub) {
 	PurplePluginProtocolInfo *prpl_info;
 	PurpleContact *contact;
+	PurpleBlistNode *node;
 	gboolean contact_expanded = FALSE;
+	gboolean show_offline = FALSE;
 
 	g_return_if_fail(menu);
 	g_return_if_fail(buddy);
 
 	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(buddy->account->gc->prpl);
 
+	node = (PurpleBlistNode*)buddy;
+
 	contact = purple_buddy_get_contact(buddy);
 	if (contact) {
 		contact_expanded = ((struct _pidgin_blist_node *)(((PurpleBlistNode*)contact)->ui_data))->contact_expanded;
@@ -1145,17 +1334,17 @@
 		if (!prpl_info->can_receive_file ||
 			prpl_info->can_receive_file(buddy->account->gc, buddy->name))
 		{
-			pidgin_new_item_from_stock(menu, _("_Send File"),
+			pidgin_new_item_from_stock(menu, _("_Send File..."),
 									 PIDGIN_STOCK_TOOLBAR_SEND_FILE,
 									 G_CALLBACK(gtk_blist_menu_send_file_cb),
 									 buddy, 0, 0, NULL);
 		}
 	}
 
-	pidgin_new_item_from_stock(menu, _("Add Buddy _Pounce"), NULL,
+	pidgin_new_item_from_stock(menu, _("Add Buddy _Pounce..."), NULL,
 			G_CALLBACK(gtk_blist_menu_bp_cb), buddy, 0, 0, NULL);
 
-	if (((PurpleBlistNode*)buddy)->parent && ((PurpleBlistNode*)buddy)->parent->child->next && 
+	if (node->parent && node->parent->child->next && 
 	      !sub && !contact_expanded) {
 		pidgin_new_item_from_stock(menu, _("View _Log"), NULL,
 				G_CALLBACK(gtk_blist_menu_showlog_cb),
@@ -1165,15 +1354,22 @@
 				G_CALLBACK(gtk_blist_menu_showlog_cb), buddy, 0, 0, NULL);
 	}
 
-
-	pidgin_append_blist_node_proto_menu(menu, buddy->account->gc,
-										  (PurpleBlistNode *)buddy);
-	pidgin_append_blist_node_extended_menu(menu, (PurpleBlistNode *)buddy);
-
-	if (((PurpleBlistNode*)buddy)->parent && ((PurpleBlistNode*)buddy)->parent->child->next && 
+	if (!(purple_blist_node_get_flags(node) & PURPLE_BLIST_NODE_FLAG_NO_SAVE)) {
+		show_offline = purple_blist_node_get_bool(node, "show_offline");
+		pidgin_new_item_from_stock(menu, show_offline ? _("Hide when offline") : _("Show when offline"),
+				NULL, G_CALLBACK(gtk_blist_menu_showoffline_cb), node, 0, 0, NULL);
+	}
+
+	pidgin_append_blist_node_proto_menu(menu, buddy->account->gc, node);
+	pidgin_append_blist_node_extended_menu(menu, node);
+
+	if (!contact_expanded)
+		pidgin_append_blist_node_move_to_menu(menu, (PurpleBlistNode *)contact);
+
+	if (node->parent && node->parent->child->next && 
               !sub && !contact_expanded) {
 		pidgin_separator(menu);
-		pidgin_append_blist_node_privacy_menu(menu, (PurpleBlistNode *)buddy);
+		pidgin_append_blist_node_privacy_menu(menu, node);
 		pidgin_new_item_from_stock(menu, _("_Alias..."), PIDGIN_STOCK_ALIAS,
 				G_CALLBACK(gtk_blist_menu_alias_cb),
 				contact, 0, 0, NULL);
@@ -1182,7 +1378,7 @@
 				contact, 0, 0, NULL);
 	} else if (!sub || contact_expanded) {
 		pidgin_separator(menu);
-		pidgin_append_blist_node_privacy_menu(menu, (PurpleBlistNode *)buddy);
+		pidgin_append_blist_node_privacy_menu(menu, node);
 		pidgin_new_item_from_stock(menu, _("_Alias..."), PIDGIN_STOCK_ALIAS,
 				G_CALLBACK(gtk_blist_menu_alias_cb), buddy, 0, 0, NULL);
 		pidgin_new_item_from_stock(menu, _("_Remove"), GTK_STOCK_REMOVE,
@@ -1235,10 +1431,10 @@
 	GtkWidget *item;
 
 	menu = gtk_menu_new();
-	item = pidgin_new_item_from_stock(menu, _("Add a _Buddy"), GTK_STOCK_ADD,
+	item = pidgin_new_item_from_stock(menu, _("Add _Buddy..."), GTK_STOCK_ADD,
 				 G_CALLBACK(pidgin_blist_add_buddy_cb), node, 0, 0, NULL);
 	gtk_widget_set_sensitive(item, purple_connections_get_all() != NULL);
-	item = pidgin_new_item_from_stock(menu, _("Add a C_hat"), GTK_STOCK_ADD,
+	item = pidgin_new_item_from_stock(menu, _("Add C_hat..."), GTK_STOCK_ADD,
 				 G_CALLBACK(pidgin_blist_add_chat_cb), node, 0, 0, NULL);
 	gtk_widget_set_sensitive(item, pidgin_blist_joinchat_is_showable());
 	pidgin_new_item_from_stock(menu, _("_Delete Group"), GTK_STOCK_REMOVE,
@@ -1256,16 +1452,19 @@
 create_chat_menu(PurpleBlistNode *node, PurpleChat *c)
 {
 	GtkWidget *menu;
-	gboolean autojoin;
+	gboolean autojoin, persistent;
 
 	menu = gtk_menu_new();
 	autojoin = (purple_blist_node_get_bool(node, "gtk-autojoin") ||
 			(purple_blist_node_get_string(node, "gtk-autojoin") != NULL));
+	persistent = purple_blist_node_get_bool(node, "gtk-persistent");
 
 	pidgin_new_item_from_stock(menu, _("_Join"), PIDGIN_STOCK_CHAT,
 			G_CALLBACK(gtk_blist_menu_join_cb), node, 0, 0, NULL);
 	pidgin_new_check_item(menu, _("Auto-Join"),
 			G_CALLBACK(gtk_blist_menu_autojoin_cb), node, autojoin);
+	pidgin_new_check_item(menu, _("Persistent"),
+			G_CALLBACK(gtk_blist_menu_persistent_cb), node, persistent);
 	pidgin_new_item_from_stock(menu, _("View _Log"), NULL,
 			G_CALLBACK(gtk_blist_menu_showlog_cb), node, 0, 0, NULL);
 
@@ -1307,7 +1506,6 @@
 				 node, 0, 0, NULL);
 
 	pidgin_append_blist_node_extended_menu(menu, node);
-
 	return menu;
 }
 
@@ -2888,7 +3086,7 @@
 
 	/* Accounts menu */
 	{ N_("/_Accounts"), NULL, NULL, 0, "<Branch>", NULL },
-	{ N_("/Accounts/Add\\/Edit"), "<CTL>A", pidgin_accounts_window_show, 0, "<Item>", NULL },
+	{ N_("/Accounts/Manage"), "<CTL>A", pidgin_accounts_window_show, 0, "<Item>", NULL },
 
 	/* Tools */
 	{ N_("/_Tools"), NULL, NULL, 0, "<Branch>", NULL },
@@ -3145,8 +3343,6 @@
 	GdkPixbuf *ret;
 	PurplePresence *p;
 
-
-
 	if(PURPLE_BLIST_NODE_IS_CONTACT(node)) {
 		if(!gtknode->contact_expanded) {
 			buddy = purple_contact_get_priority_buddy((PurpleContact*)node);
@@ -3188,6 +3384,13 @@
 		return ret;
 	}
 
+	if (purple_status_get_attr_string(purple_presence_get_active_status(p), PURPLE_TUNE_TITLE)) {
+		path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "music.png", NULL);
+		ret = gdk_pixbuf_new_from_file(path, NULL);
+		g_free(path);
+		return ret;
+	}
+
 	prpl = purple_find_prpl(purple_account_get_protocol_id(buddy->account));
 	if (!prpl)
 		return NULL;
@@ -3261,17 +3464,17 @@
 	}
 
 	if(buddy) {
-	  	PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
-									     purple_buddy_get_name(buddy),
-									     purple_buddy_get_account(buddy));
+	  	PurpleConversation *conv = find_conversation_with_buddy(buddy);
 		PurplePresence *p;
 		gboolean trans;
 
 		if(conv != NULL) {
 			PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
-			if((gtkconv == NULL || pidgin_conv_is_hidden(gtkconv)) && size == PIDGIN_STATUS_ICON_SMALL) {
-				return gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_MESSAGE,
-							       icon_size, "GtkTreeView");
+			if (gtkconv == NULL && size == PIDGIN_STATUS_ICON_SMALL) {
+				PidginBlistNode *ui = buddy->node.ui_data;
+				if (ui == NULL || (ui->conv.flags & PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE))
+					return gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview),
+							PIDGIN_STOCK_STATUS_MESSAGE, icon_size, "GtkTreeView");
 			}
 		}
 
@@ -3327,16 +3530,17 @@
 	struct _pidgin_blist_node *gtkcontactnode = NULL;
 	char *idletime = NULL, *statustext = NULL;
 	time_t t;
-	PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
-								     purple_buddy_get_name(b),
-								     purple_buddy_get_account(b));
-	PidginConversation *gtkconv;
+	PurpleConversation *conv = find_conversation_with_buddy(b);
 	gboolean hidden_conv = FALSE;
 
-	if(conv != NULL) {
-		gtkconv = PIDGIN_CONVERSATION(conv);
-		if(gtkconv == NULL || pidgin_conv_is_hidden(gtkconv)) {
-			hidden_conv = TRUE;
+	if (conv != NULL) {
+		PidginBlistNode *ui = b->node.ui_data;
+		if (ui) {
+			if (ui->conv.flags & PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE)
+				hidden_conv = TRUE;
+		} else {
+			if (PIDGIN_CONVERSATION(conv) == NULL)
+				hidden_conv = TRUE;
 		}
 	}
 
@@ -3671,7 +3875,7 @@
 		menu = NULL;
 	}
 
-	convs = pidgin_conversations_find_unseen_list(PURPLE_CONV_TYPE_IM, PIDGIN_UNSEEN_TEXT, TRUE, 0);
+	convs = pidgin_conversations_find_unseen_list(PURPLE_CONV_TYPE_ANY, PIDGIN_UNSEEN_TEXT, TRUE, 0);
 	if (!convs)
 		/* no conversations added, don't show the menu */
 		return;
@@ -3727,7 +3931,7 @@
 		gtkblist->menutrayicon = NULL;
 	}
 
-	convs = pidgin_conversations_find_unseen_list(PURPLE_CONV_TYPE_IM, PIDGIN_UNSEEN_TEXT, TRUE, 0);
+	convs = pidgin_conversations_find_unseen_list(PURPLE_CONV_TYPE_ANY, PIDGIN_UNSEEN_TEXT, TRUE, 0);
 	if (convs) {
 		GtkWidget *img = NULL;
 		GString *tooltip_text = NULL;
@@ -3735,14 +3939,10 @@
 		tooltip_text = g_string_new("");
 		l = convs;
 		while (l != NULL) {
-			if (PIDGIN_IS_PIDGIN_CONVERSATION(l->data)) {
-				PidginConversation *gtkconv = PIDGIN_CONVERSATION((PurpleConversation *)l->data);
-
-				g_string_append_printf(tooltip_text,
-						ngettext("%d unread message from %s\n", "%d unread messages from %s\n", gtkconv->unseen_count),
-						gtkconv->unseen_count,
-						gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)));
-			}
+			int count = GPOINTER_TO_INT(purple_conversation_get_data(l->data, "unseen-count"));
+			g_string_append_printf(tooltip_text,
+					ngettext("%d unread message from %s\n", "%d unread messages from %s\n", count),
+					count, purple_conversation_get_name(l->data));
 			l = l->next;
 		}
 		if(tooltip_text->len > 0) {
@@ -3770,6 +3970,88 @@
 	conversation_updated_cb(conv, PURPLE_CONV_UPDATE_UNSEEN, gtkblist);
 }
 
+static void
+conversation_deleted_update_ui_cb(PurpleConversation *conv, struct _pidgin_blist_node *ui)
+{
+	if (ui->conv.conv != conv)
+		return;
+	ui->conv.conv = NULL;
+	ui->conv.flags = 0;
+	ui->conv.last_message = 0;
+}
+
+static void
+written_msg_update_ui_cb(PurpleAccount *account, const char *who, const char *message,
+		PurpleConversation *conv, PurpleMessageFlags flag, PurpleBlistNode *node)
+{
+	PidginBlistNode *ui = node->ui_data;
+	if (ui->conv.conv != conv || PIDGIN_CONVERSATION(conv) ||
+			!(flag & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)))
+		return;
+	ui->conv.flags |= PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE;
+	ui->conv.last_message = time(NULL);    /* XXX: for lack of better data */
+	pidgin_blist_update(purple_get_blist(), node);
+}
+
+static void
+displayed_msg_update_ui_cb(PurpleAccount *account, const char *who, const char *message,
+		PurpleConversation *conv, PurpleMessageFlags flag, PurpleBlistNode *node)
+{
+	PidginBlistNode *ui = node->ui_data;
+	if (ui->conv.conv != conv)
+		return;
+	ui->conv.flags &= ~PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE;
+	pidgin_blist_update(purple_get_blist(), node);
+}
+
+static void
+conversation_created_cb(PurpleConversation *conv, PidginBuddyList *gtkblist)
+{
+	switch (conv->type) {
+		case PURPLE_CONV_TYPE_IM:
+			{
+				GSList *buddies = purple_find_buddies(conv->account, conv->name);
+				while (buddies) {
+					PurpleBlistNode *buddy = buddies->data;
+					struct _pidgin_blist_node *ui = buddy->ui_data;
+					buddies = g_slist_delete_link(buddies, buddies);
+					if (!ui)
+						continue;
+					ui->conv.conv = conv;
+					ui->conv.flags = 0;
+					ui->conv.last_message = 0;
+					purple_signal_connect(purple_conversations_get_handle(), "deleting-conversation",
+							ui, PURPLE_CALLBACK(conversation_deleted_update_ui_cb), ui);
+					purple_signal_connect(purple_conversations_get_handle(), "wrote-im-msg",
+							ui, PURPLE_CALLBACK(written_msg_update_ui_cb), buddy);
+					purple_signal_connect(pidgin_conversations_get_handle(), "displayed-im-msg",
+							ui, PURPLE_CALLBACK(displayed_msg_update_ui_cb), buddy);
+				}
+			}
+		case PURPLE_CONV_TYPE_CHAT:
+			{
+				PurpleChat *chat = purple_blist_find_chat(conv->account, conv->name);
+				struct _pidgin_blist_node *ui;
+				if (!chat)
+					break;
+				ui = chat->node.ui_data;
+				if (!ui)
+					break;
+				ui->conv.conv = conv;
+				ui->conv.flags = 0;
+				ui->conv.last_message = 0;
+				purple_signal_connect(purple_conversations_get_handle(), "deleting-conversation",
+						ui, PURPLE_CALLBACK(conversation_deleted_update_ui_cb), ui);
+				purple_signal_connect(purple_conversations_get_handle(), "wrote-chat-msg",
+						ui, PURPLE_CALLBACK(written_msg_update_ui_cb), chat);
+				purple_signal_connect(pidgin_conversations_get_handle(), "displayed-chat-msg",
+						ui, PURPLE_CALLBACK(displayed_msg_update_ui_cb), chat);
+			}
+		default:
+			break;
+	}
+}
+
 /**********************************************************************************
  * Public API Functions                                                           *
  **********************************************************************************/
@@ -4334,7 +4616,7 @@
 	tmp = g_strdup_printf(_("<span weight='bold' size='larger'>Welcome to %s!</span>\n\n"
 
 					       "You have no accounts enabled. Enable your IM accounts from the "
-					       "<b>Accounts</b> window at <b>Accounts->Add/Edit</b>. Once you "
+					       "<b>Accounts</b> window at <b>Accounts->Manage</b>. Once you "
 					       "enable accounts, you'll be able to sign on, set your status, "
 					       "and talk to your friends."), PIDGIN_NAME);
 	pretty = pidgin_make_pretty_arrows(tmp);
@@ -4683,6 +4965,9 @@
 	purple_signal_connect(purple_conversations_get_handle(), "deleting-conversation",
 						gtkblist, PURPLE_CALLBACK(conversation_deleting_cb),
 						gtkblist);
+	purple_signal_connect(purple_conversations_get_handle(), "conversation-created",
+			gtkblist, PURPLE_CALLBACK(conversation_created_cb),
+			gtkblist);
 
 	gtk_widget_hide(gtkblist->headline_hbox);
 	gtk_widget_hide(gtkblist->error_buttons);
@@ -4789,6 +5074,7 @@
 		if(gtknode->recent_signonoff_timer > 0)
 			purple_timeout_remove(gtknode->recent_signonoff_timer);
 
+		purple_signals_disconnect_by_handle(node->ui_data);
 		g_free(node->ui_data);
 		node->ui_data = NULL;
 	}
@@ -4953,7 +5239,7 @@
 				   STATUS_ICON_COLUMN, NULL,
 				   NAME_COLUMN, title,
 				   NODE_COLUMN, gnode,
-				   BGCOLOR_COLUMN, &bgcolor,
+	/* 			   BGCOLOR_COLUMN, &bgcolor,     */
 				   GROUP_EXPANDER_COLUMN, TRUE,
 				   GROUP_EXPANDER_VISIBLE_COLUMN, TRUE,
 				   CONTACT_EXPANDER_VISIBLE_COLUMN, FALSE,
@@ -5213,14 +5499,17 @@
 		GdkPixbuf *emblem;
 		char *mark;
 		gboolean showicons = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
-		const char *name = purple_chat_get_name(chat);
-		PurpleConversation *conv =
-				purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, name, chat->account);
-		gboolean hidden = (conv && !PIDGIN_CONVERSATION(conv));
-
-		if(!insert_node(list, node, &iter))
+		PidginBlistNode *ui;
+		PurpleConversation *conv;
+		gboolean hidden;
+
+		if (!insert_node(list, node, &iter))
 			return;
 
+		ui = node->ui_data;
+		conv = ui->conv.conv;
+		hidden = (conv && (ui->conv.flags & PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE));
+
 		status = pidgin_blist_get_status_icon(node,
 				 PIDGIN_STATUS_ICON_SMALL);
 		emblem = pidgin_blist_get_emblem(node);
@@ -5527,7 +5816,7 @@
 	gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
 
 	/* Set up stuff for the account box */
-	label = gtk_label_new_with_mnemonic(_("_Account:"));
+	label = gtk_label_new_with_mnemonic(_("A_ccount:"));
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 	gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
 
@@ -5644,6 +5933,12 @@
 		purple_blist_add_chat(chat, group, NULL);
 	}
 
+	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->autojoin)))
+		purple_blist_node_set_bool((PurpleBlistNode*)chat, "gtk-autojoin", TRUE);
+
+	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->persistent)))
+		purple_blist_node_set_bool((PurpleBlistNode*)chat, "gtk-persistent", TRUE);
+
 	gtk_widget_destroy(data->window);
 	g_free(data->default_chat_name);
 	g_list_free(data->entries);
@@ -5938,6 +6233,11 @@
 	gtk_label_set_mnemonic_widget(GTK_LABEL(label), GTK_BIN(data->group_combo)->child);
 	pidgin_set_accessible_label (data->group_combo, label);
 	gtk_box_pack_end(GTK_BOX(rowbox), data->group_combo, TRUE, TRUE, 0);
+	
+	data->autojoin = gtk_check_button_new_with_mnemonic(_("Autojoin when account becomes online."));
+	data->persistent = gtk_check_button_new_with_mnemonic(_("Hide chat when the window is closed."));
+	gtk_box_pack_start(GTK_BOX(vbox), data->autojoin, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), data->persistent, FALSE, FALSE, 0);
 
 	g_signal_connect(G_OBJECT(data->window), "response",
 					 G_CALLBACK(add_chat_resp_cb), data);
@@ -6586,7 +6886,7 @@
 	for (l = gtk_container_get_children(GTK_CONTAINER(accountmenu)); l; l = g_list_delete_link(l, l)) {
 		menuitem = l->data;
 
-		if (menuitem != gtk_item_factory_get_widget(gtkblist->ift, N_("/Accounts/Add\\/Edit")))
+		if (menuitem != gtk_item_factory_get_widget(gtkblist->ift, N_("/Accounts/Manage")))
 			gtk_widget_destroy(menuitem);
 	}
 
--- a/pidgin/gtkcellrendererexpander.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/gtkcellrendererexpander.c	Fri Sep 28 16:34:43 2007 +0000
@@ -270,6 +270,9 @@
 			    cell_area->x + cell->xpad + (width / 2),
 			    cell_area->y + cell->ypad + (height / 2),
 			    cell->is_expanded ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED);
+	if (cell->is_expanded)
+		gtk_paint_hline (widget->style, window, state, NULL, widget, NULL, 0, 
+				 widget->allocation.width, cell_area->y + cell_area->height);
 }
 
 static gboolean pidgin_cell_renderer_expander_activate(GtkCellRenderer *r,
--- a/pidgin/gtkconn.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/gtkconn.c	Fri Sep 28 16:34:43 2007 +0000
@@ -53,7 +53,7 @@
  * The key is a pointer to the PurpleAccount and the
  * value is a pointer to a PidginAutoRecon.
  */
-static GHashTable *hash = NULL;
+static GHashTable *auto_reconns = NULL;
 
 static void
 pidgin_connection_connect_progress(PurpleConnection *gc,
@@ -80,7 +80,7 @@
 		pidgin_status_box_set_connecting(PIDGIN_STATUS_BOX(gtkblist->statusbox),
 					   (purple_connections_get_connecting() != NULL));
 
-	g_hash_table_remove(hash, account);
+	g_hash_table_remove(auto_reconns, account);
 
 	pidgin_blist_update_account_error_state(account, NULL);
 }
@@ -120,7 +120,7 @@
 
 	purple_debug_info("autorecon", "do_signon called\n");
 	g_return_val_if_fail(account != NULL, FALSE);
-	info = g_hash_table_lookup(hash, account);
+	info = g_hash_table_lookup(auto_reconns, account);
 
 	if (info)
 		info->timeout = 0;
@@ -141,15 +141,16 @@
 {
 	PurpleAccount *account = NULL;
 	PidginAutoRecon *info;
+	GList *list;
 
 	account = purple_connection_get_account(gc);
-	info = g_hash_table_lookup(hash, account);
+	info = g_hash_table_lookup(auto_reconns, account);
 
 	pidgin_blist_update_account_error_state(account, text);
 	if (!gc->wants_to_die) {
 		if (info == NULL) {
 			info = g_new0(PidginAutoRecon, 1);
-			g_hash_table_insert(hash, account, info);
+			g_hash_table_insert(auto_reconns, account, info);
 			info->delay = g_random_int_range(INITIAL_RECON_DELAY_MIN, INITIAL_RECON_DELAY_MAX);
 		} else {
 			info->delay = MIN(2 * info->delay, MAX_RECON_DELAY);
@@ -160,7 +161,7 @@
 	} else {
 		char *p, *s, *n=NULL ;
 		if (info != NULL)
-			g_hash_table_remove(hash, account);
+			g_hash_table_remove(auto_reconns, account);
 
 		if (purple_account_get_alias(account))
 		{
@@ -192,6 +193,17 @@
 		 */
 		purple_account_set_enabled(account, PIDGIN_UI, FALSE);
 	}
+
+	/* If we have any open chats, we probably want to rejoin when we get back online. */
+	list = purple_get_chats();
+	while (list) {
+		PurpleConversation *conv = list->data;
+		list = list->next;
+		if (conv->account != account ||
+				purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv)))
+			continue;
+		purple_conversation_set_data(conv, "want-to-rejoin", GINT_TO_POINTER(TRUE));
+	}
 }
 
 static void pidgin_connection_network_connected ()
@@ -204,7 +216,7 @@
 
 	while (list) {
 		PurpleAccount *account = (PurpleAccount*)list->data;
-		g_hash_table_remove(hash, account);
+		g_hash_table_remove(auto_reconns, account);
 		if (purple_account_is_disconnected(account))
 			do_signon(account);
 		list = list->next;
@@ -265,7 +277,7 @@
 static void
 account_removed_cb(PurpleAccount *account, gpointer user_data)
 {
-	g_hash_table_remove(hash, account);
+	g_hash_table_remove(auto_reconns, account);
 
 	pidgin_blist_update_account_error_state(account, NULL);
 }
@@ -286,7 +298,7 @@
 void
 pidgin_connection_init(void)
 {
-	hash = g_hash_table_new_full(
+	auto_reconns = g_hash_table_new_full(
 							g_direct_hash, g_direct_equal,
 							NULL, free_auto_recon);
 
@@ -300,5 +312,5 @@
 {
 	purple_signals_disconnect_by_handle(pidgin_connection_get_handle());
 
-	g_hash_table_destroy(hash);
+	g_hash_table_destroy(auto_reconns);
 }
--- a/pidgin/gtkconv.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/gtkconv.c	Fri Sep 28 16:34:43 2007 +0000
@@ -70,6 +70,8 @@
 
 #include "gtknickcolors.h"
 
+#define CLOSE_CONV_TIMEOUT_SECS  (10 * 60)
+
 #define AUTO_RESPONSE "&lt;AUTO-REPLY&gt; : "
 
 typedef  enum
@@ -123,7 +125,6 @@
 static GtkWidget *invite_dialog = NULL;
 static GtkWidget *warn_close_dialog = NULL;
 
-static PidginWindow *hidden_convwin = NULL;
 static GList *window_list = NULL;
 
 /* Lists of status icons at all available sizes for use as window icons */
@@ -161,6 +162,7 @@
 static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv);
 static gboolean pidgin_userlist_motion_cb (GtkWidget *w, GdkEventMotion *event, PidginConversation *gtkconv);
 static void pidgin_conv_leave_cb (GtkWidget *w, GdkEventCrossing *e, PidginConversation *gtkconv);
+static void hide_conv(PidginConversation *gtkconv, gboolean closetimer);
 
 static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y,
 		int width, int height);
@@ -208,12 +210,49 @@
  **************************************************************************/
 
 static gboolean
-close_conv_cb(GtkWidget *w, GdkEventButton *event, PidginConversation *gtkconv)
-{
+close_this_sucker(gpointer data)
+{
+	PidginConversation *gtkconv = data;
 	GList *list = g_list_copy(gtkconv->convs);
-
 	g_list_foreach(list, (GFunc)purple_conversation_destroy, NULL);
 	g_list_free(list);
+	return FALSE;
+}
+
+static gboolean
+close_conv_cb(GtkWidget *w, GdkEventButton *dontuse, PidginConversation *gtkconv)
+{
+	/* We are going to destroy the conversations immediately only if the 'close immediately'
+	 * preference is selected. Otherwise, close the conversation after a reasonable timeout
+	 * (I am going to consider 10 minutes as a 'reasonable timeout' here.
+	 * For chats, close immediately if the chat is not in the buddylist, or if the chat is
+	 * not marked 'Persistent' */
+	PurpleConversation *conv = gtkconv->active_conv;
+	PurpleAccount *account = purple_conversation_get_account(conv);
+	const char *name = purple_conversation_get_name(conv);
+
+	switch (purple_conversation_get_type(conv)) {
+		case PURPLE_CONV_TYPE_IM:
+		{
+			if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately"))
+				close_this_sucker(gtkconv);
+			else
+				hide_conv(gtkconv, TRUE);
+			break;
+		}
+		case PURPLE_CONV_TYPE_CHAT:
+		{
+			PurpleChat *chat = purple_blist_find_chat(account, name);
+			if (!chat ||
+					!purple_blist_node_get_bool(&chat->node, "gtk-persistent"))
+				close_this_sucker(gtkconv);
+			else
+				hide_conv(gtkconv, FALSE);
+			break;
+		}
+		default:
+			;
+	}
 
 	return TRUE;
 }
@@ -337,10 +376,13 @@
 static void clear_conversation_scrollback(PurpleConversation *conv)
 {
 	PidginConversation *gtkconv = NULL;
+	GList *iter;
 
 	gtkconv = PIDGIN_CONVERSATION(conv);
 
 	gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml));
+	for (iter = gtkconv->convs; iter; iter = iter->next)
+		purple_conversation_clear_message_history(iter->data);
 }
 
 static PurpleCmdRet
@@ -348,7 +390,6 @@
                  const char *cmd, char **args, char **error, void *data)
 {
 	clear_conversation_scrollback(conv);
-	purple_conversation_clear_message_history(conv);
 	return PURPLE_CMD_STATUS_OK;
 }
 
@@ -1060,12 +1101,9 @@
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv;
-	PidginConversation *gtkconv;
 
 	conv = pidgin_conv_window_get_active_conversation(win);
-	gtkconv = PIDGIN_CONVERSATION(conv);
-
-	gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml));
+	clear_conversation_scrollback(conv);
 }
 
 struct _search {
@@ -1315,18 +1353,33 @@
 	add_remove_cb(NULL, PIDGIN_CONVERSATION(conv));
 }
 
-#if 0
-static void
-menu_hide_conv_cb(gpointer data, guint action, GtkWidget *widget)
-{
-	PidginWindow *win = data;
-	PidginConversation *gtkconv = pidgin_conv_window_get_active_gtkconv(win);
-	PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win);
+static gboolean
+close_already(gpointer data)
+{
+	purple_conversation_destroy(data);
+	return FALSE;
+}
+
+static void
+hide_conv(PidginConversation *gtkconv, gboolean closetimer)
+{
+	GList *list;
+
 	purple_signal_emit(pidgin_conversations_get_handle(),
 			"conversation-hiding", gtkconv);
-	purple_conversation_set_ui_ops(conv, NULL);
-}
-#endif
+
+	for (list = g_list_copy(gtkconv->convs); list; list = g_list_delete_link(list, list)) {
+		PurpleConversation *conv = list->data;
+		if (closetimer) {
+			guint timer = GPOINTER_TO_INT(purple_conversation_get_data(conv, "close-timer"));
+			if (timer)
+				purple_timeout_remove(timer);
+			timer = purple_timeout_add_seconds(CLOSE_CONV_TIMEOUT_SECS, close_already, conv);
+			purple_conversation_set_data(conv, "close-timer", GINT_TO_POINTER(timer));
+		}
+		purple_conversation_set_ui_ops(conv, NULL);
+	}
+}
 
 static void
 menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget)
@@ -2343,63 +2396,69 @@
 	return get_prpl_icon_list(account);
 }
 
-GdkPixbuf *
-pidgin_conv_get_tab_icon(PurpleConversation *conv, gboolean small_icon)
-{
-        PurpleAccount *account = NULL;
-        const char *name = NULL;
-        GdkPixbuf *status = NULL;
-        PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
-	const char *icon_size = small_icon ? PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC : PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL;
-        g_return_val_if_fail(conv != NULL, NULL);
-
-        account = purple_conversation_get_account(conv);
-        name = purple_conversation_get_name(conv);
-
-        g_return_val_if_fail(account != NULL, NULL);
-        g_return_val_if_fail(name != NULL, NULL);
-
-        /* Use the buddy icon, if possible */
-        if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
-                PurpleBuddy *b = purple_find_buddy(account, name);
-                if (b != NULL) {
+static GdkPixbuf *
+pidgin_conv_get_icon(PurpleConversation *conv, GtkWidget *parent, const char *icon_size)
+{
+	PurpleAccount *account = NULL;
+	const char *name = NULL;
+	GdkPixbuf *status = NULL;
+	PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+	g_return_val_if_fail(conv != NULL, NULL);
+
+	account = purple_conversation_get_account(conv);
+	name = purple_conversation_get_name(conv);
+
+	g_return_val_if_fail(account != NULL, NULL);
+	g_return_val_if_fail(name != NULL, NULL);
+
+	/* Use the buddy icon, if possible */
+	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
+		PurpleBuddy *b = purple_find_buddy(account, name);
+		if (b != NULL) {
 			PurplePresence *p = purple_buddy_get_presence(b);
-                        /* I hate this hack.  It fixes a bug where the pending message icon
-                          * displays in the conv tab even though it shouldn't.
-                          * A better solution would be great. */
-                        if (ops && ops->update)
-                                ops->update(NULL, (PurpleBlistNode*)b);
+			/* I hate this hack.  It fixes a bug where the pending message icon
+			 * displays in the conv tab even though it shouldn't.
+			 * A better solution would be great. */
+			if (ops && ops->update)
+				ops->update(NULL, (PurpleBlistNode*)b);
 
 			/* XXX Seanegan: We really need a util function to return a pixbuf for a Presence to avoid all this switching */	
 			if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AWAY))
-	                        status = pidgin_create_status_icon(PURPLE_STATUS_AWAY, PIDGIN_CONVERSATION(conv)->icon, icon_size);
+				status = pidgin_create_status_icon(PURPLE_STATUS_AWAY, parent, icon_size);
 			else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_EXTENDED_AWAY))
-	                        status = pidgin_create_status_icon(PURPLE_STATUS_EXTENDED_AWAY, PIDGIN_CONVERSATION(conv)->icon, icon_size);
- 			else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_OFFLINE))
-	                        status = pidgin_create_status_icon(PURPLE_STATUS_OFFLINE, PIDGIN_CONVERSATION(conv)->icon, icon_size);
- 			else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AVAILABLE))
-	                        status = pidgin_create_status_icon(PURPLE_STATUS_AVAILABLE, PIDGIN_CONVERSATION(conv)->icon, icon_size);
- 			else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_INVISIBLE))
-	                        status = pidgin_create_status_icon(PURPLE_STATUS_INVISIBLE, PIDGIN_CONVERSATION(conv)->icon, icon_size);
- 			else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_UNAVAILABLE))
-	                        status = pidgin_create_status_icon(PURPLE_STATUS_UNAVAILABLE, PIDGIN_CONVERSATION(conv)->icon, icon_size);
-                }
-        }
-
-        /* If they don't have a buddy icon, then use the PRPL icon */
-        if (status == NULL) {
+				status = pidgin_create_status_icon(PURPLE_STATUS_EXTENDED_AWAY, parent, icon_size);
+			else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_OFFLINE))
+				status = pidgin_create_status_icon(PURPLE_STATUS_OFFLINE, parent, icon_size);
+			else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AVAILABLE))
+				status = pidgin_create_status_icon(PURPLE_STATUS_AVAILABLE, parent, icon_size);
+			else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_INVISIBLE))
+				status = pidgin_create_status_icon(PURPLE_STATUS_INVISIBLE, parent, icon_size);
+			else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_UNAVAILABLE))
+				status = pidgin_create_status_icon(PURPLE_STATUS_UNAVAILABLE, parent, icon_size);
+		}
+	}
+
+	/* If they don't have a buddy icon, then use the PRPL icon */
+	if (status == NULL) {
 		GtkIconSize size = gtk_icon_size_from_name(icon_size);
 		if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
-        		status = gtk_widget_render_icon (PIDGIN_CONVERSATION(conv)->icon, PIDGIN_STOCK_STATUS_PERSON,
-                                                 size, "GtkWidget");
+			status = gtk_widget_render_icon (parent, PIDGIN_STOCK_STATUS_PERSON,
+					size, "GtkWidget");
 		} else {
-	        		status = gtk_widget_render_icon (PIDGIN_CONVERSATION(conv)->icon, PIDGIN_STOCK_STATUS_CHAT,
-                                                 size, "GtkWidget");
+			status = gtk_widget_render_icon (parent, PIDGIN_STOCK_STATUS_CHAT,
+					size, "GtkWidget");
 		}
 	}	
 	return status;
 }
 
+GdkPixbuf *
+pidgin_conv_get_tab_icon(PurpleConversation *conv, gboolean small_icon)
+{
+	const char *icon_size = small_icon ? PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC : PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL;
+	return pidgin_conv_get_icon(conv, PIDGIN_CONVERSATION(conv)->icon, icon_size);
+}
+
 
 static void
 update_tab_icon(PurpleConversation *conv)
@@ -2751,9 +2810,9 @@
 	PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
 	GdkModifierType state;
 
-	if(gtkconv->win==hidden_convwin) {
-		pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv);
-		pidgin_conv_placement_place(gtkconv);
+	if (gtkconv == NULL) {
+		pidgin_conv_attach_to_conversation(conv);
+		gtkconv = PIDGIN_CONVERSATION(conv);
 	}
 
 	pidgin_conv_switch_active_conversation(conv);
@@ -2786,15 +2845,19 @@
 		PurpleConversation *conv = (PurpleConversation*)l->data;
 		PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
 
-		if(gtkconv == NULL || gtkconv->active_conv != conv)
+		if (gtkconv != NULL && gtkconv->active_conv != conv)
 			continue;
-
-		if (gtkconv->unseen_state >= min_state
-			&& (!hidden_only ||
-				(hidden_only && gtkconv->win == hidden_convwin))) {
-
+		if (gtkconv == NULL) {
+			if (!hidden_only ||
+					!purple_conversation_get_data(conv, "unseen-count"))
+				continue;
 			r = g_list_prepend(r, conv);
 			c++;
+		} else {
+			if (gtkconv->unseen_state >= min_state && !hidden_only) {
+				r = g_list_prepend(r, conv);
+				c++;
+			}
 		}
 	}
 
@@ -2834,11 +2897,11 @@
 		PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
 
 		GtkWidget *icon = gtk_image_new();
-		GdkPixbuf *pbuf = pidgin_conv_get_tab_icon(conv, TRUE);
+		GdkPixbuf *pbuf = pidgin_conv_get_icon(conv, icon, PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC);
 		GtkWidget *item;
 		gchar *text = g_strdup_printf("%s (%d)",
-				gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)),
-				gtkconv->unseen_count);
+				gtkconv ? gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)) : purple_conversation_get_name(conv),
+				gtkconv ? gtkconv->unseen_count : GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count")));
 
 		gtk_image_set_from_pixbuf(GTK_IMAGE(icon), pbuf);
 		g_object_unref(pbuf);
@@ -3096,7 +3159,7 @@
 	PurpleConversation *conv;
 	GtkWidget *item;
 
-	if (win->window == NULL || win == hidden_convwin)
+	if (win->window == NULL)
 		return;
 
 	gtkconv = pidgin_conv_window_get_active_gtkconv(win);
@@ -3571,7 +3634,7 @@
 		gtk_widget_destroy(win->menu.send_to);
 
 	/* Build the Send To menu */
-	win->menu.send_to = gtk_menu_item_new_with_mnemonic(_("_Send To"));
+	win->menu.send_to = gtk_menu_item_new_with_mnemonic(_("S_end To"));
 	gtk_widget_show(win->menu.send_to);
 
 	menu = gtk_menu_new();
@@ -4943,6 +5006,9 @@
 	GtkWidget *tab_cont;
 	PurpleBlistNode *convnode;
 
+	if (hidden)
+		return;
+
 	if (conv_type == PURPLE_CONV_TYPE_IM && (gtkconv = pidgin_conv_find_gtkconv(conv))) {
 		conv->ui_data = gtkconv;
 		if (!g_list_find(gtkconv->convs, conv))
@@ -5042,10 +5108,7 @@
 	                         G_CALLBACK(gtk_widget_grab_focus),
 	                         gtkconv->entry);
 
-	if (hidden)
-		pidgin_conv_window_add_gtkconv(hidden_convwin, gtkconv);
-	else
-		pidgin_conv_placement_place(gtkconv);
+	pidgin_conv_placement_place(gtkconv);
 
 	if (nick_colors == NULL) {
 		nbr_nick_colors = NUM_NICK_COLORS;
@@ -5053,11 +5116,13 @@
 	}
 }
 
+#if 0
 static void
 pidgin_conv_new_hidden(PurpleConversation *conv)
 {
 	private_gtkconv_new(conv, TRUE);
 }
+#endif
 
 void
 pidgin_conv_new(PurpleConversation *conv)
@@ -5070,26 +5135,22 @@
 				   PurpleConversation *conv, PurpleMessageFlags flags)
 {
 	PurpleConversationUiOps *ui_ops = pidgin_conversations_get_conv_ui_ops();
-	if (conv != NULL)
-		return;
 
 	/* create hidden conv if hide_new pref is always */
-	if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always") == 0)
-	{
-		ui_ops->create_conversation = pidgin_conv_new_hidden;
-		purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
-		ui_ops->create_conversation = pidgin_conv_new;
-		return;
-	}
-
-	/* create hidden conv if hide_new pref is away and account is away */
-	if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away") == 0 &&
-	    !purple_status_is_available(purple_account_get_active_status(account)))
-	{
-		ui_ops->create_conversation = pidgin_conv_new_hidden;
-		purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
-		ui_ops->create_conversation = pidgin_conv_new;
-		return;
+	/* or if hide_new pref is away and account is away */
+	if ((strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always") == 0) ||
+		(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away") == 0 &&
+		 !purple_status_is_available(purple_account_get_active_status(account)))) {
+		if (!conv) {
+			ui_ops->create_conversation = NULL;
+			conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
+			purple_conversation_set_ui_ops(conv, NULL);
+			ui_ops->create_conversation = pidgin_conv_new;
+		}
+	} else {
+		/* new message for an IM */
+		if (conv && conv->type == PURPLE_CONV_TYPE_IM)
+			pidgin_conv_attach_to_conversation(conv);
 	}
 }
 
@@ -5098,6 +5159,9 @@
 {
 	PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
 
+	if (!gtkconv)
+		return;
+
 	gtkconv->convs = g_list_remove(gtkconv->convs, conv);
 	/* Don't destroy ourselves until all our convos are gone */
 	if (gtkconv->convs) {
@@ -6575,6 +6639,19 @@
 	pidgin_conv_update_fields(conv, flags);
 }
 
+static void
+wrote_msg_update_unseen_cb(PurpleAccount *account, const char *who, const char *message,
+		PurpleConversation *conv, PurpleMessageFlags flag, gpointer null)
+{
+	if (conv == NULL || PIDGIN_IS_PIDGIN_CONVERSATION(conv))
+		return;
+	if (flag & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)) {
+		purple_conversation_set_data(conv, "unseen-count",
+				GINT_TO_POINTER(GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count")) + 1));
+		purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN);
+	}
+}
+
 static PurpleConversationUiOps conversation_ui_ops =
 {
 	pidgin_conv_new,
@@ -7072,6 +7149,7 @@
 account_status_changed_cb(PurpleAccount *account, PurpleStatus *oldstatus,
                           PurpleStatus *newstatus)
 {
+#if 0
 	GList *l;
 	PurpleConversation *conv = NULL;
 	PidginConversation *gtkconv;
@@ -7081,27 +7159,7 @@
 
 	if(purple_status_is_available(oldstatus) || !purple_status_is_available(newstatus))
 		return;
-
-	while ((l = hidden_convwin->gtkconvs) != NULL)
-	{
-		gtkconv = l->data;
-
-		conv = gtkconv->active_conv;
-
-		while(l && !purple_status_is_available(
-					purple_account_get_active_status(
-					purple_conversation_get_account(conv))))
-			l = l->next;
-		if (!l)
-			break;
-
-		pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv);
-		pidgin_conv_placement_place(gtkconv);
-
-		/* TODO: do we need to do anything for any other conversations that are in the same gtkconv here?
-		 * I'm a little concerned that not doing so will cause the "pending" indicator in the gtkblist not to be cleared. -DAA*/
-		purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN);
-	}
+#endif
 }
 
 static void
@@ -7109,32 +7167,25 @@
 				 gconstpointer value, gpointer data)
 {
 	GList *l;
-	PurpleConversation *conv = NULL;
-	PidginConversation *gtkconv;
 	gboolean when_away = FALSE;
 
-	if(!hidden_convwin)
-		return;
-
 	if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always")==0)
 		return;
 
 	if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")==0)
 		when_away = TRUE;
 
-	while ((l = hidden_convwin->gtkconvs) != NULL)
+	for (l = purple_get_conversations(); l; l = l->next)
 	{
-		gtkconv = l->data;
-
-		conv = gtkconv->active_conv;
-
+		PurpleConversation *conv = l->data;
+		PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
+		if (gtkconv)
+			continue;
 		if(when_away && !purple_status_is_available(
 							purple_account_get_active_status(
 							purple_conversation_get_account(conv))))
 			continue;
-
-		pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv);
-		pidgin_conv_placement_place(gtkconv);
+		pidgin_conv_attach_to_conversation(conv);
 	}
 }
 
@@ -7190,6 +7241,23 @@
 		/* if (purple_conversation_get_account(conv) == account) */
 			pidgin_conv_update_fields(conv, PIDGIN_CONV_TAB_ICON |
 							PIDGIN_CONV_MENU | PIDGIN_CONV_COLORIZE_TITLE);
+
+		if (PURPLE_CONNECTION_IS_CONNECTED(gc) &&
+				conv->type == PURPLE_CONV_TYPE_CHAT &&
+				conv->account == gc->account &&
+				purple_conversation_get_data(conv, "want-to-rejoin")) {
+			GHashTable *comps = NULL;
+			PurpleChat *chat = purple_blist_find_chat(conv->account, conv->name);
+			if (chat == NULL) {
+				if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL)
+					comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, conv->name);
+			} else {
+				comps = chat->components;
+			}
+			serv_join_chat(gc, comps);
+			if (chat == NULL && comps != NULL)
+				g_hash_table_destroy(comps);
+		}
 	}
 }
 
@@ -7317,9 +7385,15 @@
 	PidginConversation *gtkconv = data;
 	int count = 0;
 	int timer = gtkconv->attach.timer;
+	time_t when = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(gtkconv->entry), "attach-start-time"));
+
 	gtkconv->attach.timer = 0;
 	while (gtkconv->attach.current && count < 100) {  /* XXX: 100 is a random value here */
 		PurpleConvMessage *msg = gtkconv->attach.current->data;
+		if (when && when < msg->when) {
+			gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0);
+			g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);
+		}
 		pidgin_conv_write_conv(gtkconv->active_conv, msg->who, msg->who, msg->what, msg->flags, msg->when);
 		gtkconv->attach.current = gtkconv->attach.current->prev;
 		count++;
@@ -7328,6 +7402,7 @@
 	if (gtkconv->attach.current)
 		return TRUE;
 
+	g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);
 	purple_signal_emit(pidgin_conversations_get_handle(),
 			"conversation-displayed", gtkconv);
 	g_source_remove(gtkconv->attach.timer);
@@ -7339,18 +7414,21 @@
 {
 	GList *list;
 	PidginConversation *gtkconv;
+	int timer;
 
 	if (PIDGIN_IS_PIDGIN_CONVERSATION(conv))
 		return FALSE;
 
+	purple_conversation_set_data(conv, "unseen-count", NULL);
 	purple_conversation_set_ui_ops(conv, pidgin_conversations_get_conv_ui_ops());
 	private_gtkconv_new(conv, FALSE);
 	gtkconv = PIDGIN_CONVERSATION(conv);
 
 	list = purple_conversation_get_message_history(conv);
 	if (list) {
-		list = g_list_last(list);
-		gtkconv->attach.current = list;
+		g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time",
+				GINT_TO_POINTER(((PurpleConvMessage*)(list->data))->when));
+		gtkconv->attach.current = g_list_last(list);
 		gtkconv->attach.timer = g_idle_add(add_message_history_to_gtkconv, gtkconv);
 	} else {
 		purple_signal_emit(pidgin_conversations_get_handle(),
@@ -7362,6 +7440,9 @@
 		pidgin_conv_chat_add_users(conv, PURPLE_CONV_CHAT(conv)->in_room, TRUE);
 	}
 
+	timer = GPOINTER_TO_INT(purple_conversation_get_data(conv, "close-timer"));
+	if (timer)
+		purple_timeout_remove(timer);
 	return TRUE;
 }
 
@@ -7427,6 +7508,7 @@
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", TRUE);
 
 	purple_prefs_add_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "never");
+	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately", FALSE);
 
 #ifdef _WIN32
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", FALSE);
@@ -7590,9 +7672,6 @@
 
 	purple_conversations_set_ui_ops(&conversation_ui_ops);
 
-	hidden_convwin = pidgin_conv_window_new();
-	window_list = g_list_remove(window_list, hidden_convwin);
-
 	purple_signal_connect(purple_accounts_get_handle(), "account-status-changed",
                         handle, PURPLE_CALLBACK(account_status_changed_cb), NULL);
 
@@ -7628,6 +7707,10 @@
 	purple_signal_connect_priority(purple_conversations_get_handle(), "conversation-updated", handle,
 						PURPLE_CALLBACK(pidgin_conv_updated), NULL,
 						PURPLE_SIGNAL_PRIORITY_LOWEST);
+	purple_signal_connect(purple_conversations_get_handle(), "wrote-im-msg", handle,
+			PURPLE_CALLBACK(wrote_msg_update_unseen_cb), NULL);
+	purple_signal_connect(purple_conversations_get_handle(), "wrote-chat-msg", handle,
+			PURPLE_CALLBACK(wrote_msg_update_unseen_cb), NULL);
 }
 
 void
@@ -7636,8 +7719,6 @@
 	purple_prefs_disconnect_by_handle(pidgin_conversations_get_handle());
 	purple_signals_disconnect_by_handle(pidgin_conversations_get_handle());
 	purple_signals_unregister_by_instance(pidgin_conversations_get_handle());
-	pidgin_conv_window_destroy(hidden_convwin);
-	hidden_convwin=NULL;
 }
 
 
@@ -8019,7 +8100,7 @@
 		sub = gtk_menu_item_get_submenu(GTK_MENU_ITEM(gtkconv->win->menu.send_to));
 
 		if (sub && GTK_WIDGET_IS_SENSITIVE(gtkconv->win->menu.send_to)) {
-			GtkWidget *item = gtk_menu_item_new_with_mnemonic(_("_Send To"));
+			GtkWidget *item = gtk_menu_item_new_with_mnemonic(_("S_end To"));
 			if (populated)
 				pidgin_separator(menu);
 			gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
@@ -8769,15 +8850,10 @@
 
 	if (win->gtkconvs) {
 		while (win->gtkconvs) {
-			GList *nextgtk = win->gtkconvs->next;
-			PidginConversation *gtkconv = win->gtkconvs->data;
-			GList *nextcore = gtkconv->convs->next;
-			PurpleConversation *conv = gtkconv->convs->data;
-			purple_conversation_destroy(conv);
-			if (!nextgtk && !nextcore)
-			/* we'll end up invoking ourselves when we destroy our last child */
-			/* so don't destroy ourselves right now */
-				return;
+			gboolean last = (win->gtkconvs->next == NULL);
+			close_conv_cb(NULL, NULL, win->gtkconvs->data);
+			if (last)
+				break;
 		}
 		return;
 	}
@@ -9054,7 +9130,7 @@
 	if (win->gtkconvs && win->gtkconvs->next == NULL)
 		pidgin_conv_tab_pack(win, win->gtkconvs->data);
 
-	if (!win->gtkconvs && win != hidden_convwin)
+	if (!win->gtkconvs)
 		pidgin_conv_window_destroy(win);
 }
 
@@ -9593,9 +9669,7 @@
 gboolean
 pidgin_conv_is_hidden(PidginConversation *gtkconv)
 {
-	g_return_val_if_fail(gtkconv != NULL, FALSE);
-
-	return (gtkconv->win == hidden_convwin);
+	return (gtkconv == NULL);
 }
 
 
@@ -9696,3 +9770,4 @@
 
 	return colors;
 }
+
--- a/pidgin/gtkdocklet.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/gtkdocklet.c	Fri Sep 28 16:34:43 2007 +0000
@@ -532,7 +532,7 @@
 	g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(docklet_toggle_mute), NULL);
 	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
 
-	menuitem = gtk_check_menu_item_new_with_label(_("Blink on new message"));
+	menuitem = gtk_check_menu_item_new_with_label(_("Blink on New Message"));
 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/blink"));
 	g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(docklet_toggle_blink), NULL);
 	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
--- a/pidgin/gtkimhtmltoolbar.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/gtkimhtmltoolbar.c	Fri Sep 28 16:34:43 2007 +0000
@@ -1166,6 +1166,7 @@
 	GtkWidget *label;
 	GtkWidget *insert_button;
 	GtkWidget *font_button;
+	GtkWidget *smiley_button;
 	GtkWidget *font_menu;
 	GtkWidget *insert_menu;
 	GtkWidget *menuitem;
@@ -1267,12 +1268,6 @@
 	insert_menu = gtk_menu_new();
 	g_object_set_data(G_OBJECT(toolbar), "insert_menu", insert_menu);
 
-	menuitem = gtk_menu_item_new_with_mnemonic(_("_Smiley"));
-	g_signal_connect_swapped(G_OBJECT(menuitem), "activate", G_CALLBACK(gtk_button_clicked), toolbar->smiley);
-	gtk_menu_shell_append(GTK_MENU_SHELL(insert_menu), menuitem);
-	g_signal_connect(G_OBJECT(toolbar->smiley), "notify::sensitive",
-			G_CALLBACK(button_sensitiveness_changed), menuitem);
-
 	menuitem = gtk_menu_item_new_with_mnemonic(_("_Image"));
 	g_signal_connect_swapped(G_OBJECT(menuitem), "activate", G_CALLBACK(gtk_button_clicked), toolbar->image);
 	gtk_menu_shell_append(GTK_MENU_SHELL(insert_menu), menuitem);
@@ -1294,6 +1289,24 @@
 	g_signal_connect(G_OBJECT(insert_button), "activate", G_CALLBACK(pidgin_menu_clicked), insert_menu);
 	g_signal_connect(G_OBJECT(insert_menu), "deactivate", G_CALLBACK(pidgin_menu_deactivate), insert_button);
 	toolbar->sml = NULL;
+	
+	/* Sep */
+	sep = gtk_vseparator_new();
+	gtk_box_pack_start(GTK_BOX(box), sep, FALSE, FALSE, 0);
+	gtk_widget_show_all(sep);
+
+	/* Smiley */
+	smiley_button = gtk_button_new();
+	gtk_button_set_relief(GTK_BUTTON(smiley_button), GTK_RELIEF_NONE);
+	bbox = gtk_hbox_new(FALSE, 3);
+	gtk_container_add(GTK_CONTAINER(smiley_button), bbox);
+	image = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_SMILEY, gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL));
+	gtk_box_pack_start(GTK_BOX(bbox), image, FALSE, FALSE, 0);
+	label = gtk_label_new_with_mnemonic(_("_Smile!"));
+	gtk_box_pack_start(GTK_BOX(bbox), label, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(box), smiley_button, FALSE, FALSE, 0);
+	g_signal_connect_swapped(G_OBJECT(smiley_button), "clicked", G_CALLBACK(gtk_button_clicked), toolbar->smiley);
+	gtk_widget_show_all(smiley_button);
 
 	gtk_box_pack_start(GTK_BOX(hbox), box, FALSE, FALSE, 0);
 	g_object_set_data(G_OBJECT(hbox), "lean-view", box);
--- a/pidgin/gtkmain.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/gtkmain.c	Fri Sep 28 16:34:43 2007 +0000
@@ -394,6 +394,9 @@
 		       "  -n, --nologin       don't automatically login\n"
 		       "  -l, --login[=NAME]  automatically login (optional argument NAME specifies\n"
 		       "                      account(s) to use, separated by commas)\n"
+#ifndef WIN32
+		       "  --display=DISPLAY   X display to use\n"
+#endif
 		       "  -v, --version       display the current version and exit\n"), PIDGIN_NAME, VERSION, name);
 	}
 
@@ -481,6 +484,7 @@
 		{"nologin",  no_argument,       NULL, 'n'},
 		{"session",  required_argument, NULL, 's'},
 		{"version",  no_argument,       NULL, 'v'},
+		{"display",  required_argument, NULL, 'D'},
 		{0, 0, 0, 0}
 	};
 
@@ -626,6 +630,9 @@
 		case 'm':   /* do not ensure single instance. */
 			opt_si = FALSE;
 			break;
+		case 'D':   /* --display */
+			/* handled by gtk_init_check below */
+			break;
 		case '?':	/* show terse help */
 		default:
 			show_usage(argv[0], TRUE);
--- a/pidgin/gtknotify.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/gtknotify.c	Fri Sep 28 16:34:43 2007 +0000
@@ -559,8 +559,8 @@
 	if (!GTK_WIDGET_VISIBLE(dialog)) {
 		GdkPixbuf *pixbuf = gtk_widget_render_icon(dialog, PIDGIN_STOCK_DIALOG_MAIL,
 							   gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL), NULL);
-		char *label_text = g_strdup_printf(ngettext("<b>You have %d new e-mail.</b>",
-							    "<b>You have %d new e-mails.</b>",
+		char *label_text = g_strdup_printf(ngettext("<b>%d new e-mail.</b>",
+							    "<b>%d new e-mails.</b>",
 							    mail_dialog->total_count), mail_dialog->total_count);
 		mail_dialog->in_use = TRUE;     /* So that _set_headline doesn't accidentally
 										   remove the notifications when replacing an
@@ -690,30 +690,30 @@
 	GtkTreeIter iter;
 	GdkPixbuf *pixbuf;
 	guint col_num;
-	guint i;
-	guint j;
+	GList *row, *column;
+	guint n;
 
 	gtk_list_store_clear(data->model);
 
 	pixbuf = pidgin_create_prpl_icon(purple_connection_get_account(gc), 0.5);
 
 	/* +1 is for the automagically created Status column. */
-	col_num = purple_notify_searchresults_get_columns_count(results) + 1;
+	col_num = g_list_length(results->columns) + 1;
 
-	for (i = 0; i < purple_notify_searchresults_get_rows_count(results); i++) {
-		GList *row = purple_notify_searchresults_row_get(results, i);
+	for (row = results->rows; row != NULL; row = row->next) {
 
 		gtk_list_store_append(model, &iter);
 		gtk_list_store_set(model, &iter, 0, pixbuf, -1);
 
-		for (j = 1; j < col_num; j++) {
+		n = 1;
+		for (column = row->data; column != NULL; column = column->next) {
 			GValue v;
-			char *data = g_list_nth_data(row, j - 1);
 
 			v.g_type = 0;
 			g_value_init(&v, G_TYPE_STRING);
-			g_value_set_string(&v, data);
-			gtk_list_store_set_value(model, &iter, j, &v);
+			g_value_set_string(&v, column->data);
+			gtk_list_store_set_value(model, &iter, n, &v);
+			n++;
 		}
 	}
 
@@ -733,6 +733,7 @@
 	GtkListStore *model;
 	GtkCellRenderer *renderer;
 	guint col_num;
+	GList *column;
 	guint i;
 
 	GtkWidget *vbox;
@@ -780,7 +781,7 @@
 	g_free(label_text);
 
 	/* +1 is for the automagically created Status column. */
-	col_num = purple_notify_searchresults_get_columns_count(results) + 1;
+	col_num = g_list_length(results->columns) + 1;
 
 	/* Setup the list model */
 	col_types = g_new0(GType, col_num);
@@ -815,12 +816,13 @@
 	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
 					-1, "", renderer, "pixbuf", 0, NULL);
 
-	for (i = 1; i < col_num; i++) {
+	i = 1;
+	for (column = results->columns; column != NULL; column = column->next) {
 		renderer = gtk_cell_renderer_text_new();
 
 		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), -1,
-				purple_notify_searchresults_column_get_title(results, i-1),
-				renderer, "text", i, NULL);
+				column->data, renderer, "text", i, NULL);
+		i++;
 	}
 
 	for (i = 0; i < g_list_length(results->buttons); i++) {
--- a/pidgin/gtkprefs.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/gtkprefs.c	Fri Sep 28 16:34:43 2007 +0000
@@ -994,6 +994,8 @@
 
 	pidgin_prefs_checkbox(_("Show _formatting on incoming messages"),
 				PIDGIN_PREFS_ROOT "/conversations/show_incoming_formatting", vbox);
+	pidgin_prefs_checkbox(_("Close IMs immediately when the tab is closed"),
+				PIDGIN_PREFS_ROOT "/conversations/im/close_immediately", vbox);
 
 	iconpref1 = pidgin_prefs_checkbox(_("Show _detailed information"),
 			PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", vbox);
--- a/pidgin/gtksession.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/gtksession.c	Fri Sep 28 16:34:43 2007 +0000
@@ -36,6 +36,7 @@
 #include <gdk/gdkx.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <gdk/gdk.h>
 
 #define ERROR_LENGTH 512
 
@@ -141,7 +142,7 @@
 /* my magic utility function */
 
 static gchar **session_make_command(gchar *client_id, gchar *config_dir) {
-	gint i = 2;
+	gint i = 4;
 	gint j = 0;
 	gchar **ret;
 
@@ -161,6 +162,9 @@
 		ret[j++] = g_strdup(config_dir);
 	}
 
+	ret[j++] = g_strdup("--display");
+	ret[j++] = g_strdup((gchar *)gdk_display_get_name(gdk_display_get_default()));
+
 	ret[j++] = NULL;
 
 	return ret;
Binary file pidgin/pixmaps/dialogs/64/cool.png has changed
Binary file pidgin/pixmaps/dialogs/64/error.png has changed
Binary file pidgin/pixmaps/dialogs/64/info.png has changed
Binary file pidgin/pixmaps/dialogs/64/mail.png has changed
Binary file pidgin/pixmaps/dialogs/64/question.png has changed
--- a/pidgin/pixmaps/dialogs/64/scalable/cool.svg	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/pixmaps/dialogs/64/scalable/cool.svg	Fri Sep 28 16:34:43 2007 +0000
@@ -7,101 +7,25 @@
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="64"
-   height="64"
+   width="48"
+   height="48"
    id="svg2"
    sodipodi:version="0.32"
-   inkscape:version="0.43"
+   inkscape:version="0.45"
    version="1.0"
-   sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/dialogs"
+   sodipodi:docbase="/home/hbons/Desktop/2.1.1/dialogs"
    sodipodi:docname="dialog-cool.svg"
-   inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/dialogs/dialog-cool.png"
+   inkscape:export-filename="/home/hbons/Desktop/newstyle.png"
    inkscape:export-xdpi="90"
-   inkscape:export-ydpi="90">
+   inkscape:export-ydpi="90"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
   <defs
      id="defs4">
     <linearGradient
        inkscape:collect="always"
-       id="linearGradient2351">
-      <stop
-         style="stop-color:#eeeeec;stop-opacity:1;"
-         offset="0"
-         id="stop2353" />
-      <stop
-         style="stop-color:#eeeeec;stop-opacity:0;"
-         offset="1"
-         id="stop2355" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient2351"
-       id="linearGradient2357"
-       x1="12.488563"
-       y1="5.8544211"
-       x2="12.488563"
-       y2="19.066195"
-       gradientUnits="userSpaceOnUse"
-       gradientTransform="translate(60.97357,13.05831)" />
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient2343">
-      <stop
-         style="stop-color:#babdb6;stop-opacity:1;"
-         offset="0"
-         id="stop2345" />
-      <stop
-         style="stop-color:#babdb6;stop-opacity:0;"
-         offset="1"
-         id="stop2347" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient2343"
-       id="linearGradient2349"
-       x1="12.515625"
-       y1="8.7261219"
-       x2="12.515625"
-       y2="0.68458056"
-       gradientUnits="userSpaceOnUse"
-       gradientTransform="matrix(0.99284,0,0,1,61.04756,13.09375)" />
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient3121">
-      <stop
-         style="stop-color:#d3d7cf;stop-opacity:1;"
-         offset="0"
-         id="stop3123" />
-      <stop
-         style="stop-color:#d3d7cf;stop-opacity:0;"
-         offset="1"
-         id="stop3125" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient3816">
-      <stop
-         style="stop-color:#000000;stop-opacity:1;"
-         offset="0"
-         id="stop3818" />
-      <stop
-         style="stop-color:#000000;stop-opacity:0;"
-         offset="1"
-         id="stop3820" />
-    </linearGradient>
-    <radialGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient3816"
-       id="radialGradient3822"
-       cx="31.112698"
-       cy="19.008621"
-       fx="31.112698"
-       fy="19.008621"
-       r="8.6620579"
-       gradientUnits="userSpaceOnUse" />
-    <linearGradient
-       inkscape:collect="always"
        id="linearGradient3104">
       <stop
          style="stop-color:#eeeeec;stop-opacity:1;"
@@ -123,15 +47,380 @@
        r="9.975256"
        gradientUnits="userSpaceOnUse"
        gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <filter
+       inkscape:collect="always"
+       x="-0.27879593"
+       width="1.5575919"
+       y="-0.78248727"
+       height="2.5649745"
+       id="filter3405">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="1.5438116"
+         id="feGaussianBlur3407" />
+    </filter>
+    <radialGradient
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient2247"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3263">
+      <stop
+         style="stop-color:#555753;stop-opacity:1;"
+         offset="0"
+         id="stop3265" />
+      <stop
+         style="stop-color:#555753;stop-opacity:0;"
+         offset="1"
+         id="stop3267" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2216"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3263"
+       id="linearGradient3269"
+       x1="12.845698"
+       y1="16.037401"
+       x2="10.698112"
+       y2="15.449714"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3191"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3150">
+      <stop
+         style="stop-color:#2e3436;stop-opacity:1;"
+         offset="0"
+         id="stop3152" />
+      <stop
+         style="stop-color:#2e3436;stop-opacity:0;"
+         offset="1"
+         id="stop3154" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3175"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3150"
+       id="radialGradient3156"
+       cx="10.748654"
+       cy="10.457643"
+       fx="10.748654"
+       fy="10.457643"
+       r="6.6449099"
+       gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       id="radialGradient2214"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2255"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3313"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <radialGradient
+       r="2.5781252"
+       fy="11.083743"
+       fx="17.911736"
+       cy="11.083743"
+       cx="17.911736"
+       gradientTransform="matrix(-1.591138,1.574803,-1.783257,-1.76495,68.854751,-2.8442229)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient2259"
+       xlink:href="#linearGradient2382"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2867">
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:1;"
+         offset="0"
+         id="stop2869" />
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:0;"
+         offset="1"
+         id="stop2871" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2847">
+      <stop
+         style="stop-color:#888a85;stop-opacity:1;"
+         offset="0"
+         id="stop2849" />
+      <stop
+         style="stop-color:#888a85;stop-opacity:0;"
+         offset="1"
+         id="stop2851" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2382">
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:1;"
+         offset="0"
+         id="stop2384" />
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:0;"
+         offset="1"
+         id="stop2386" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2230"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2847"
+       id="linearGradient2853"
+       x1="12.5"
+       y1="18.202251"
+       x2="12.746171"
+       y2="20.761486"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2867"
+       id="linearGradient2873"
+       x1="12.720216"
+       y1="20.952612"
+       x2="12.720216"
+       y2="17.682426"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient2303"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2349"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient2233"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2264"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient3771"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       r="8.6620579"
+       fy="19.008621"
+       fx="31.112698"
+       cy="19.008621"
+       cx="31.112698"
+       id="radialGradient3822"
+       xlink:href="#linearGradient3816"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient3816"
+       inkscape:collect="always">
+      <stop
+         id="stop3818"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop3820"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3121"
+       inkscape:collect="always">
+      <stop
+         id="stop3123"
+         offset="0"
+         style="stop-color:#d3d7cf;stop-opacity:1;" />
+      <stop
+         id="stop3125"
+         offset="1"
+         style="stop-color:#d3d7cf;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       gradientTransform="matrix(0.99284,0,0,1,61.04756,13.09375)"
+       gradientUnits="userSpaceOnUse"
+       y2="0.68458056"
+       x2="12.515625"
+       y1="8.7261219"
+       x1="12.515625"
+       id="linearGradient2349"
+       xlink:href="#linearGradient2343"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2343"
+       inkscape:collect="always">
+      <stop
+         id="stop2345"
+         offset="0"
+         style="stop-color:#babdb6;stop-opacity:1;" />
+      <stop
+         id="stop2347"
+         offset="1"
+         style="stop-color:#babdb6;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       gradientTransform="translate(60.97357,13.05831)"
+       gradientUnits="userSpaceOnUse"
+       y2="19.066195"
+       x2="12.488563"
+       y1="5.8544211"
+       x1="12.488563"
+       id="linearGradient2357"
+       xlink:href="#linearGradient2351"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2351"
+       inkscape:collect="always">
+      <stop
+         id="stop2353"
+         offset="0"
+         style="stop-color:#eeeeec;stop-opacity:1;" />
+      <stop
+         id="stop2355"
+         offset="1"
+         style="stop-color:#eeeeec;stop-opacity:0;" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3794"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
     <linearGradient
        inkscape:collect="always"
        xlink:href="#linearGradient3121"
-       id="linearGradient1551"
+       id="linearGradient3802"
        gradientUnits="userSpaceOnUse"
        x1="42.925175"
        y1="40.136646"
        x2="42.925175"
        y2="15.474488" />
+    <filter
+       inkscape:collect="always"
+       x="-0.47282609"
+       width="1.9456522"
+       y="-0.47282609"
+       height="1.9456522"
+       id="filter4019">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="1.552286"
+         id="feGaussianBlur4021" />
+    </filter>
   </defs>
   <sodipodi:namedview
      id="base"
@@ -140,17 +429,19 @@
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="12.003863"
-     inkscape:cx="43.074856"
-     inkscape:cy="35.626159"
+     inkscape:zoom="15.839192"
+     inkscape:cx="40.272536"
+     inkscape:cy="20.18158"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="true"
-     fill="#555753"
-     inkscape:window-width="1267"
-     inkscape:window-height="971"
-     inkscape:window-x="6"
-     inkscape:window-y="21" />
+     fill="#fce94f"
+     inkscape:window-width="1440"
+     inkscape:window-height="847"
+     inkscape:window-x="3"
+     inkscape:window-y="25"
+     width="48px"
+     height="48px" />
   <metadata
      id="metadata7">
     <rdf:RDF>
@@ -167,25 +458,25 @@
      inkscape:groupmode="layer"
      id="layer1">
     <path
-       d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1  22.45064,19.008621 A 8.6620579 8.6620579 0 1 1  39.774755 19.008621 z"
-       sodipodi:ry="8.6620579"
-       sodipodi:rx="8.6620579"
-       sodipodi:cy="19.008621"
-       sodipodi:cx="31.112698"
-       id="path4318"
-       style="opacity:0.5;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
        sodipodi:type="arc"
-       transform="matrix(2.383972,0,0,1.117487,-53.5217,33.04541)" />
+       style="opacity:0.64044949;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3405)"
+       id="path3140"
+       sodipodi:cx="10.748654"
+       sodipodi:cy="10.457643"
+       sodipodi:rx="6.6449099"
+       sodipodi:ry="2.3675451"
+       d="M 17.393564 10.457643 A 6.6449099 2.3675451 0 1 1  4.1037445,10.457643 A 6.6449099 2.3675451 0 1 1  17.393564 10.457643 z"
+       transform="matrix(2.2723916,0,0,1.6905173,-0.1758194,23.510748)" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#f57900;stroke-width:0.53913006;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#cc6400;stroke-width:0.55559433;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path1307"
        sodipodi:cx="11.806158"
        sodipodi:cy="10.983024"
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.854646,0,0,1.855034,-0.899768,22.62707)" />
+       transform="matrix(1.8043406,0,0,1.8043406,3.1976696,7.6828846)" />
     <path
        sodipodi:type="arc"
        style="opacity:0.79545456;fill:url(#radialGradient3114);fill-opacity:1;stroke:none;stroke-width:1.05274069;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
@@ -195,98 +486,215 @@
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.704217,0,0,1.704217,0.879746,24.28255)" />
+       transform="matrix(1.6958412,0,0,1.6958412,4.3182736,9.0348912)" />
     <path
        sodipodi:type="arc"
-       style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.57006598;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.58677971;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path2184"
        sodipodi:cx="11.806158"
        sodipodi:cy="10.983024"
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.75441,0,0,1.753957,0.28417,23.73792)" />
+       transform="matrix(1.7042169,0,0,1.7042169,4.3797455,8.7825453)" />
+    <path
+       style="fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1"
+       d="M 23.500001,23.5 C 23.500001,26.26 21.260002,28.500001 18.500001,28.500001 C 15.740001,28.500001 13.5,26.26 13.5,23.5 C 13.5,20.74 15.740001,18.5 18.500001,18.5 C 21.260002,18.5 23.500001,20.74 23.500001,23.5 z "
+       id="path3154" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2172"
+       sodipodi:cx="9.7069349"
+       sodipodi:cy="9.6526775"
+       sodipodi:rx="1.0259361"
+       sodipodi:ry="1.9413869"
+       d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1  8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1  10.732871 9.6526775 z"
+       transform="matrix(1.9494387,0,0,1.2877392,1.0769258,12.069869)" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:0.282258;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3152"
+       sodipodi:cx="9.7069349"
+       sodipodi:cy="9.6526775"
+       sodipodi:rx="1.0259361"
+       sodipodi:ry="1.9413869"
+       d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1  8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1  10.732871 9.6526775 z"
+       transform="matrix(4.8735976,0,0,2.5754783,-16.807694,-1.3602618)" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3148"
+       sodipodi:cx="9.7069349"
+       sodipodi:cy="9.6526775"
+       sodipodi:rx="1.0259361"
+       sodipodi:ry="1.9413869"
+       d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1  8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1  10.732871 9.6526775 z"
+       transform="matrix(1.9494393,0,0,1.2877392,10.076919,12.069869)" />
+    <path
+       style="opacity:1;fill:#ce5c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 36,31 C 35.958854,34.901861 33.103799,38.559709 28.776926,39.671439 C 24.450054,40.78317 20.070187,38.984235 18,35.624852 C 24.906148,40.499205 32.307884,37.963138 36,31 z "
+       id="path2186"
+       sodipodi:nodetypes="cscc" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2259"
+       sodipodi:cx="8.3258924"
+       sodipodi:cy="9.2232141"
+       sodipodi:rx="1.2276785"
+       sodipodi:ry="1.7410715"
+       d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499"
+       transform="matrix(3.5277688,0.705265,-0.6665314,1.855957,7.1597185,-7.1449202)"
+       sodipodi:start="3.5782199"
+       sodipodi:end="5.6135639"
+       sodipodi:open="true" />
     <path
-       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="M 32,46 C 30.709742,51.13847 26.288403,55 21.000001,55 C 15.7116,55 11.290259,51.13847 10,46 C 12.318243,49.327326 16.389775,52.419284 21.000001,52.419284 C 25.610224,52.419285 29.681757,49.327326 32,46 z "
-       id="path2186"
+       sodipodi:type="arc"
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2261"
+       sodipodi:cx="8.3258924"
+       sodipodi:cy="9.2232141"
+       sodipodi:rx="1.2276785"
+       sodipodi:ry="1.7410715"
+       d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499"
+       transform="matrix(-3.5277688,0.705265,0.6665314,1.855957,41.208475,-4.1630498)"
+       sodipodi:start="3.5782199"
+       sodipodi:end="5.6135639"
+       sodipodi:open="true" />
+    <path
+       d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1  22.45064,19.008621 A 8.6620579 8.6620579 0 1 1  39.774755 19.008621 z"
+       sodipodi:ry="8.6620579"
+       sodipodi:rx="8.6620579"
+       sodipodi:cy="19.008621"
+       sodipodi:cx="31.112698"
+       id="path4318"
+       style="opacity:0.5;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       sodipodi:type="arc"
+       transform="matrix(2.383972,0,0,1.117487,-126.51617,-6.51091)" />
+    <path
+       sodipodi:type="arc"
+       style="fill:#edd400;fill-opacity:1;stroke:#f57900;stroke-width:0.53913003;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3777"
+       sodipodi:cx="11.806158"
+       sodipodi:cy="10.983024"
+       sodipodi:rx="9.975256"
+       sodipodi:ry="9.975256"
+       d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
+       transform="matrix(1.854646,0,0,1.855034,-73.894233,-16.92925)" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.79545456;fill:url(#radialGradient3794);fill-opacity:1;stroke:none;stroke-width:1.05274069;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3779"
+       sodipodi:cx="11.806158"
+       sodipodi:cy="10.983024"
+       sodipodi:rx="9.975256"
+       sodipodi:ry="9.975256"
+       d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
+       transform="matrix(1.704217,0,0,1.704217,-72.114719,-15.27377)" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.57006598;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3781"
+       sodipodi:cx="11.806158"
+       sodipodi:cy="10.983024"
+       sodipodi:rx="9.975256"
+       sodipodi:ry="9.975256"
+       d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
+       transform="matrix(1.75441,0,0,1.753957,-72.710295,-15.8184)" />
+    <path
+       style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M -40.994465,6.44368 C -42.284723,11.58215 -46.706062,15.44368 -51.994464,15.44368 C -57.282865,15.44368 -61.704206,11.58215 -62.994465,6.44368 C -60.676222,9.771006 -56.60469,12.862964 -51.994464,12.862964 C -47.384241,12.862965 -43.312708,9.771006 -40.994465,6.44368 z "
+       id="path3783"
        sodipodi:nodetypes="cscsc" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path2191"
        sodipodi:cx="9.0598059"
        sodipodi:cy="8.7845774"
        sodipodi:rx="1.1679889"
        sodipodi:ry="1.4520943"
        d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1  7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1  10.227795 8.7845774 z"
-       transform="matrix(1.712345,0,0,2.754643,1.486487,14.80163)" />
+       transform="matrix(1.712345,0,0,2.754643,-71.507978,-24.75469)" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path2193"
        sodipodi:cx="9.0598059"
        sodipodi:cy="8.7845774"
        sodipodi:rx="1.1679889"
        sodipodi:ry="1.4520943"
        d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1  7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1  10.227795 8.7845774 z"
-       transform="matrix(1.712345,0,0,2.754643,9.486483,14.80163)" />
+       transform="matrix(1.712345,0,0,2.754643,-63.507982,-24.75469)" />
     <path
-       style="opacity:0.78977272;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1.66300178;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="M 6,37 C 6,41.951923 9.359998,46 13.499999,46 C 17.413598,46 20.659892,42.352213 21,37.773438 C 21.340107,42.352213 24.586402,46 28.499999,46 C 32.640004,46 36,41.951923 36,37 L 21,37 L 6,37 z "
-       id="path2264" />
-    <path
-       style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;stroke-dasharray:none"
-       d="M 44.078659,9.5112136 C 34.84342,9.8834971 27.500059,15.977362 27.500059,23.405814 C 27.500059,27.671183 29.253586,32.180745 33.0662,34.729626 C 33.874807,38.292011 31.54507,41.058776 31.141507,41.494102 C 31.871844,41.290557 37.643487,39.670532 39.808221,37.260561 C 41.990193,37.168054 43.23089,37.300418 44.997262,37.300418 C 54.649949,37.300418 62.494467,31.073895 62.494465,23.405814 C 62.494465,15.737733 54.649949,9.5112136 44.997262,9.5112136 C 44.695616,9.5112136 44.37657,9.4992035 44.078659,9.5112136 z "
+       style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M -28.915806,-30.045106 C -38.151045,-29.672823 -45.494406,-23.578958 -45.494406,-16.150506 C -45.494406,-11.885137 -43.740879,-7.375575 -39.928265,-4.826694 C -39.119658,-1.264309 -41.449395,1.502456 -41.852958,1.937782 C -41.122621,1.734237 -35.350978,0.114212 -33.186244,-2.295759 C -31.004272,-2.388266 -29.763575,-2.255902 -27.997203,-2.255902 C -18.344516,-2.255902 -10.499998,-8.482425 -10.5,-16.150506 C -10.5,-23.818587 -18.344516,-30.045106 -27.997203,-30.045106 C -28.298849,-30.045106 -28.617895,-30.057116 -28.915806,-30.045106 z "
        id="path13316"
        sodipodi:nodetypes="cscccsssc" />
     <path
        sodipodi:type="inkscape:offset"
        inkscape:radius="-1.0020103"
-       inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z "
+       inkscape:original="M -28.90625 -30.03125 C -38.141489 -29.658966 -45.5 -23.584702 -45.5 -16.15625 C -45.499998 -11.890882 -43.750114 -7.361381 -39.9375 -4.8125 C -39.128893 -1.250115 -41.440187 1.502174 -41.84375 1.9375 C -41.113412 1.733955 -35.352234 0.128721 -33.1875 -2.28125 C -31.005527 -2.373757 -29.766372 -2.25 -28 -2.25 C -18.347312 -2.2499999 -10.499998 -8.488169 -10.5 -16.15625 C -10.5 -23.824332 -18.347313 -30.03125 -28 -30.03125 C -28.301645 -30.031249 -28.608339 -30.04326 -28.90625 -30.03125 z "
        xlink:href="#path13316"
        style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
        id="path13323"
        inkscape:href="#path13316"
-       d="M 43.9375,10.5 C 35.082559,10.856667 28.28125,16.643774 28.28125,23.4375 C 28.28125,27.441186 29.946384,31.636673 33.4375,33.96875 C 33.648247,34.117093 33.793739,34.340928 33.84375,34.59375 C 34.305353,36.625753 33.873291,38.418899 33.28125,39.75 C 33.741286,39.588469 33.859625,39.584381 34.375,39.375 C 36.123726,38.664548 38.008731,37.651133 38.875,36.6875 C 39.056781,36.478508 39.316956,36.354077 39.59375,36.34375 C 41.847992,36.248256 43.128683,36.40625 44.84375,36.40625 C 54.103198,36.406251 61.406252,30.447219 61.40625,23.4375 C 61.406249,16.427779 54.105354,10.5 44.84375,10.5 C 44.5143,10.499999 44.179676,10.490245 43.9375,10.5 z " />
+       d="M 44.125,10.5 C 35.308909,10.855387 28.5,16.639515 28.5,23.40625 C 28.5,27.397567 30.147439,31.550115 33.625,33.875 C 33.835747,34.023343 33.981239,34.247178 34.03125,34.5 C 34.490803,36.524599 34.051533,38.324325 33.46875,39.65625 C 33.930328,39.493414 34.045022,39.492531 34.5625,39.28125 C 36.305088,38.56977 38.200088,37.553862 39.0625,36.59375 C 39.244281,36.384758 39.504456,36.260327 39.78125,36.25 C 42.026592,36.154804 43.292249,36.3125 45,36.3125 C 54.22098,36.312499 61.500002,30.39071 61.5,23.40625 C 61.5,16.421791 54.220979,10.5 45,10.5 C 44.671757,10.5 44.368389,10.490188 44.125,10.5 z "
+       transform="translate(-72.994465,-39.55632)" />
     <path
        sodipodi:type="inkscape:offset"
        inkscape:radius="-1.0109046"
-       inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z "
+       inkscape:original="M -28.90625 -30.03125 C -38.141489 -29.658966 -45.5 -23.584702 -45.5 -16.15625 C -45.499998 -11.890882 -43.750114 -7.361381 -39.9375 -4.8125 C -39.128893 -1.250115 -41.440187 1.502174 -41.84375 1.9375 C -41.113412 1.733955 -35.352234 0.128721 -33.1875 -2.28125 C -31.005527 -2.373757 -29.766372 -2.25 -28 -2.25 C -18.347312 -2.2499999 -10.499998 -8.488169 -10.5 -16.15625 C -10.5 -23.824332 -18.347313 -30.03125 -28 -30.03125 C -28.301645 -30.031249 -28.608339 -30.04326 -28.90625 -30.03125 z "
        xlink:href="#path13316"
-       style="opacity:1;color:#000000;fill:url(#linearGradient1551);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;stroke-dasharray:none"
+       style="color:#000000;fill:url(#linearGradient3802);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
        id="path1336"
        inkscape:href="#path13316"
-       d="M 43.9375,10.5 C 35.086269,10.856517 28.28125,16.649624 28.28125,23.4375 C 28.28125,27.43874 29.949375,31.638672 33.4375,33.96875 C 33.659358,34.111954 33.816384,34.336276 33.875,34.59375 C 34.337119,36.628026 33.873842,38.417659 33.28125,39.75 C 33.741161,39.588512 33.859781,39.584317 34.375,39.375 C 36.123195,38.664763 38.010688,37.617706 38.875,36.65625 C 39.06282,36.459679 39.321894,36.347038 39.59375,36.34375 C 41.848554,36.248232 43.129202,36.40625 44.84375,36.40625 C 54.099359,36.406251 61.406252,30.441153 61.40625,23.4375 C 61.406249,16.433845 54.101534,10.5 44.84375,10.5 C 44.514064,10.499999 44.17917,10.490265 43.9375,10.5 z " />
+       d="M 44.125,10.5 C 35.31263,10.855237 28.5,16.645389 28.5,23.40625 C 28.5,27.395135 30.150413,31.552103 33.625,33.875 C 33.846858,34.018204 34.003884,34.242526 34.0625,34.5 C 34.519684,36.514161 34.077673,38.294264 33.5,39.625 C 33.948389,39.466107 34.062909,39.485228 34.5625,39.28125 C 36.304559,38.569986 38.202041,37.520438 39.0625,36.5625 C 39.25032,36.365929 39.509394,36.253288 39.78125,36.25 C 42.027154,36.154781 43.29277,36.3125 45,36.3125 C 54.217148,36.312499 61.500002,30.384642 61.5,23.40625 C 61.5,16.427859 54.217147,10.5 45,10.5 C 44.671521,10.5 44.367905,10.490207 44.125,10.5 z "
+       transform="translate(-72.994465,-39.55632)" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path1397"
        sodipodi:cx="9.0598059"
        sodipodi:cy="8.7845774"
        sodipodi:rx="1.1679889"
        sodipodi:ry="1.4520943"
        d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1  7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1  10.227795 8.7845774 z"
-       transform="matrix(0.856174,0,0,0.688661,33.24323,22.95041)" />
+       transform="matrix(0.856174,0,0,0.688661,-39.751235,-16.60591)" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path1403"
        sodipodi:cx="9.0598059"
        sodipodi:cy="8.7845774"
        sodipodi:rx="1.1679889"
        sodipodi:ry="1.4520943"
        d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1  7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1  10.227795 8.7845774 z"
-       transform="matrix(0.856172,0,0,0.688662,37.24325,22.9504)" />
+       transform="matrix(0.856172,0,0,0.688662,-35.751215,-16.60592)" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path1405"
        sodipodi:cx="9.0598059"
        sodipodi:cy="8.7845774"
        sodipodi:rx="1.1679889"
        sodipodi:ry="1.4520943"
        d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1  7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1  10.227795 8.7845774 z"
-       transform="matrix(0.856173,0,0,0.688662,41.24324,22.95039)" />
+       transform="matrix(0.856173,0,0,0.688662,-31.751225,-16.60593)" />
+    <path
+       style="opacity:0.78977272;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1.66300178;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 6.9375 23 C 6.6605 23 6.4375 23.223 6.4375 23.5 C 6.4375 23.777 6.6605 24 6.9375 24 L 11.0625 24 C 11.531404 27.382552 14.351819 30 17.75 30 C 21.272241 30 24.193903 27.155019 24.5 23.59375 C 24.806096 27.15502 27.727762 30 31.25 30 C 34.648185 30 37.468596 27.382552 37.9375 24 L 42.0625 24 C 42.3395 24 42.5625 23.777 42.5625 23.5 C 42.5625 23.223 42.3395 23 42.0625 23 L 38 23 L 24.5 23 L 11.5 23 L 11 23 L 6.9375 23 z "
+       id="path2264" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter4019)"
+       id="path3813"
+       sodipodi:cx="13.826463"
+       sodipodi:cy="24.19828"
+       sodipodi:rx="3.2829957"
+       sodipodi:ry="3.2829957"
+       d="M 17.109458 24.19828 A 3.2829957 3.2829957 0 1 1  10.543467,24.19828 A 3.2829957 3.2829957 0 1 1  17.109458 24.19828 z"
+       transform="matrix(0.9137996,0,0,0.9137994,-1.6346163,0.8876255)" />
   </g>
 </svg>
--- a/pidgin/pixmaps/dialogs/64/scalable/error.svg	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/pixmaps/dialogs/64/scalable/error.svg	Fri Sep 28 16:34:43 2007 +0000
@@ -7,101 +7,25 @@
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="64"
-   height="64"
+   width="48"
+   height="48"
    id="svg2"
    sodipodi:version="0.32"
-   inkscape:version="0.43"
+   inkscape:version="0.45"
    version="1.0"
-   sodipodi:docbase="/home/hbons/Desktop"
-   sodipodi:docname="dialog-error.svg"
-   inkscape:export-filename="/home/hbons/Desktop/dialog-warning.png"
+   sodipodi:docbase="/home/hbons/Desktop/2.1.1/dialogs"
+   sodipodi:docname="dialog--error.svg"
+   inkscape:export-filename="/home/hbons/Desktop/newstyle.png"
    inkscape:export-xdpi="90"
-   inkscape:export-ydpi="90">
+   inkscape:export-ydpi="90"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
   <defs
      id="defs4">
     <linearGradient
        inkscape:collect="always"
-       id="linearGradient2239">
-      <stop
-         style="stop-color:#ffffff;stop-opacity:1;"
-         offset="0"
-         id="stop2241" />
-      <stop
-         style="stop-color:#ffffff;stop-opacity:0;"
-         offset="1"
-         id="stop2243" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient2239"
-       id="linearGradient2245"
-       x1="15.535398"
-       y1="1.8014067"
-       x2="15.535398"
-       y2="48.674999"
-       gradientUnits="userSpaceOnUse"
-       gradientTransform="matrix(0.667328,0,0,0.667328,34.82201,12.82201)" />
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient2186">
-      <stop
-         style="stop-color:#ffffff;stop-opacity:1;"
-         offset="0"
-         id="stop2188" />
-      <stop
-         style="stop-color:#ffffff;stop-opacity:0;"
-         offset="1"
-         id="stop2190" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient2186"
-       id="linearGradient2194"
-       x1="11.226587"
-       y1="-5.4832759"
-       x2="11.226587"
-       y2="17.697369"
-       gradientUnits="userSpaceOnUse"
-       gradientTransform="matrix(0.946132,0,0,0.946123,34.14115,12.15018)" />
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient3121">
-      <stop
-         style="stop-color:#d3d7cf;stop-opacity:1;"
-         offset="0"
-         id="stop3123" />
-      <stop
-         style="stop-color:#d3d7cf;stop-opacity:0;"
-         offset="1"
-         id="stop3125" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient3816">
-      <stop
-         style="stop-color:#000000;stop-opacity:1;"
-         offset="0"
-         id="stop3818" />
-      <stop
-         style="stop-color:#000000;stop-opacity:0;"
-         offset="1"
-         id="stop3820" />
-    </linearGradient>
-    <radialGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient3816"
-       id="radialGradient3822"
-       cx="31.112698"
-       cy="19.008621"
-       fx="31.112698"
-       fy="19.008621"
-       r="8.6620579"
-       gradientUnits="userSpaceOnUse" />
-    <linearGradient
-       inkscape:collect="always"
        id="linearGradient3104">
       <stop
          style="stop-color:#eeeeec;stop-opacity:1;"
@@ -123,15 +47,462 @@
        r="9.975256"
        gradientUnits="userSpaceOnUse"
        gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <filter
+       inkscape:collect="always"
+       x="-0.27879593"
+       width="1.5575919"
+       y="-0.78248727"
+       height="2.5649745"
+       id="filter3405">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="1.5438116"
+         id="feGaussianBlur3407" />
+    </filter>
+    <radialGradient
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient2247"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3263">
+      <stop
+         style="stop-color:#555753;stop-opacity:1;"
+         offset="0"
+         id="stop3265" />
+      <stop
+         style="stop-color:#555753;stop-opacity:0;"
+         offset="1"
+         id="stop3267" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2216"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3263"
+       id="linearGradient3269"
+       x1="12.845698"
+       y1="16.037401"
+       x2="10.698112"
+       y2="15.449714"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3191"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3150">
+      <stop
+         style="stop-color:#2e3436;stop-opacity:1;"
+         offset="0"
+         id="stop3152" />
+      <stop
+         style="stop-color:#2e3436;stop-opacity:0;"
+         offset="1"
+         id="stop3154" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3175"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3150"
+       id="radialGradient3156"
+       cx="10.748654"
+       cy="10.457643"
+       fx="10.748654"
+       fy="10.457643"
+       r="6.6449099"
+       gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       id="radialGradient2214"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2255"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3313"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <radialGradient
+       r="2.5781252"
+       fy="11.083743"
+       fx="17.911736"
+       cy="11.083743"
+       cx="17.911736"
+       gradientTransform="matrix(-1.591138,1.574803,-1.783257,-1.76495,68.854751,-2.8442229)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient2259"
+       xlink:href="#linearGradient2382"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2867">
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:1;"
+         offset="0"
+         id="stop2869" />
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:0;"
+         offset="1"
+         id="stop2871" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2847">
+      <stop
+         style="stop-color:#888a85;stop-opacity:1;"
+         offset="0"
+         id="stop2849" />
+      <stop
+         style="stop-color:#888a85;stop-opacity:0;"
+         offset="1"
+         id="stop2851" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2382">
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:1;"
+         offset="0"
+         id="stop2384" />
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:0;"
+         offset="1"
+         id="stop2386" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2230"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2847"
+       id="linearGradient2853"
+       x1="12.5"
+       y1="18.202251"
+       x2="12.746171"
+       y2="20.761486"
+       gradientUnits="userSpaceOnUse" />
     <linearGradient
        inkscape:collect="always"
-       xlink:href="#linearGradient3121"
-       id="linearGradient1551"
+       xlink:href="#linearGradient2867"
+       id="linearGradient2873"
+       x1="12.720216"
+       y1="20.952612"
+       x2="12.720216"
+       y2="17.682426"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient2303"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2349"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient2233"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2264"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
+    <radialGradient
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3456"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3454"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <radialGradient
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3452"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3450"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <linearGradient
+       gradientUnits="userSpaceOnUse"
+       y2="17.682426"
+       x2="12.720216"
+       y1="20.952612"
+       x1="12.720216"
+       id="linearGradient3448"
+       xlink:href="#linearGradient2867"
+       inkscape:collect="always" />
+    <linearGradient
+       gradientUnits="userSpaceOnUse"
+       y2="20.761486"
+       x2="12.746171"
+       y1="18.202251"
+       x1="12.5"
+       id="linearGradient3446"
+       xlink:href="#linearGradient2847"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
        gradientUnits="userSpaceOnUse"
-       x1="42.925175"
-       y1="40.136646"
-       x2="42.925175"
-       y2="15.474488" />
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient3444"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2382"
+       id="radialGradient3424"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1.591138,1.574803,-1.783257,-1.76495,68.854751,-2.8442229)"
+       cx="17.911736"
+       cy="11.083743"
+       fx="17.911736"
+       fy="11.083743"
+       r="2.5781252" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient3422"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3420"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3418"
+       cx="8.7359829"
+       cy="18.005522"
+       fx="8.7359829"
+       fy="18.005522"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)"
+       r="6.6449099"
+       fy="10.457643"
+       fx="10.748654"
+       cy="10.457643"
+       cx="10.748654"
+       id="radialGradient3416"
+       xlink:href="#linearGradient3150"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient3414"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3406"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       cx="8.7359829"
+       cy="18.005522"
+       fx="8.7359829"
+       fy="18.005522"
+       r="9.975256" />
+    <linearGradient
+       gradientUnits="userSpaceOnUse"
+       y2="15.449714"
+       x2="10.698112"
+       y1="16.037401"
+       x1="12.845698"
+       id="linearGradient3404"
+       xlink:href="#linearGradient3263"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient3402"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3394"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       cx="8.7359829"
+       cy="18.005522"
+       fx="8.7359829"
+       fy="18.005522"
+       r="9.975256" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient3388"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3479"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
   </defs>
   <sodipodi:namedview
      id="base"
@@ -140,17 +511,19 @@
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="29.556978"
-     inkscape:cx="52.766638"
-     inkscape:cy="42.047904"
+     inkscape:zoom="11.2"
+     inkscape:cx="49.816631"
+     inkscape:cy="24.376627"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="true"
-     fill="#cc0000"
-     inkscape:window-width="1267"
-     inkscape:window-height="971"
-     inkscape:window-x="6"
-     inkscape:window-y="21" />
+     fill="#fce94f"
+     inkscape:window-width="1440"
+     inkscape:window-height="847"
+     inkscape:window-x="3"
+     inkscape:window-y="25"
+     width="48px"
+     height="48px" />
   <metadata
      id="metadata7">
     <rdf:RDF>
@@ -167,25 +540,25 @@
      inkscape:groupmode="layer"
      id="layer1">
     <path
-       d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1  22.45064,19.008621 A 8.6620579 8.6620579 0 1 1  39.774755 19.008621 z"
-       sodipodi:ry="8.6620579"
-       sodipodi:rx="8.6620579"
-       sodipodi:cy="19.008621"
-       sodipodi:cx="31.112698"
-       id="path4318"
-       style="opacity:0.5;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
        sodipodi:type="arc"
-       transform="matrix(2.383972,0,0,1.117487,-53.5217,33.04541)" />
+       style="opacity:0.64044949;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3405)"
+       id="path3140"
+       sodipodi:cx="10.748654"
+       sodipodi:cy="10.457643"
+       sodipodi:rx="6.6449099"
+       sodipodi:ry="2.3675451"
+       d="M 17.393564 10.457643 A 6.6449099 2.3675451 0 1 1  4.1037445,10.457643 A 6.6449099 2.3675451 0 1 1  17.393564 10.457643 z"
+       transform="matrix(2.2723916,0,0,1.6905173,-0.1758194,23.510748)" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#f57900;stroke-width:0.53913006;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#cc6400;stroke-width:0.55559433;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path1307"
        sodipodi:cx="11.806158"
        sodipodi:cy="10.983024"
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.854646,0,0,1.855034,-0.899768,22.62707)" />
+       transform="matrix(1.8043406,0,0,1.8043406,3.1976696,7.6828846)" />
     <path
        sodipodi:type="arc"
        style="opacity:0.79545456;fill:url(#radialGradient3114);fill-opacity:1;stroke:none;stroke-width:1.05274069;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
@@ -195,93 +568,55 @@
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.704217,0,0,1.704217,0.879746,24.28255)" />
+       transform="matrix(1.6958412,0,0,1.6958412,4.3182736,9.0348912)" />
     <path
        sodipodi:type="arc"
-       style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.57006598;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.58677971;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path2184"
        sodipodi:cx="11.806158"
        sodipodi:cy="10.983024"
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.75441,0,0,1.753957,0.28417,23.73792)" />
-    <path
-       style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;stroke-dasharray:none"
-       d="M 44.078659,9.5112136 C 34.84342,9.8834971 27.500059,15.977362 27.500059,23.405814 C 27.500059,27.671183 29.253586,32.180745 33.0662,34.729626 C 33.874807,38.292011 31.54507,41.058776 31.141507,41.494102 C 31.871844,41.290557 37.643487,39.670532 39.808221,37.260561 C 41.990193,37.168054 43.23089,37.300418 44.997262,37.300418 C 54.649949,37.300418 62.494467,31.073895 62.494465,23.405814 C 62.494465,15.737733 54.649949,9.5112136 44.997262,9.5112136 C 44.695616,9.5112136 44.37657,9.4992035 44.078659,9.5112136 z "
-       id="path13316"
-       sodipodi:nodetypes="cscccsssc" />
-    <path
-       sodipodi:type="inkscape:offset"
-       inkscape:radius="-1.0020103"
-       inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z "
-       xlink:href="#path13316"
-       style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
-       id="path13323"
-       inkscape:href="#path13316"
-       d="M 43.9375,10.5 C 35.082559,10.856667 28.28125,16.643774 28.28125,23.4375 C 28.28125,27.441186 29.946384,31.636673 33.4375,33.96875 C 33.648247,34.117093 33.793739,34.340928 33.84375,34.59375 C 34.305353,36.625753 33.873291,38.418899 33.28125,39.75 C 33.741286,39.588469 33.859625,39.584381 34.375,39.375 C 36.123726,38.664548 38.008731,37.651133 38.875,36.6875 C 39.056781,36.478508 39.316956,36.354077 39.59375,36.34375 C 41.847992,36.248256 43.128683,36.40625 44.84375,36.40625 C 54.103198,36.406251 61.406252,30.447219 61.40625,23.4375 C 61.406249,16.427779 54.105354,10.5 44.84375,10.5 C 44.5143,10.499999 44.179676,10.490245 43.9375,10.5 z " />
-    <path
-       sodipodi:type="inkscape:offset"
-       inkscape:radius="-1.0109046"
-       inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z "
-       xlink:href="#path13316"
-       style="opacity:1;color:#000000;fill:url(#linearGradient1551);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;stroke-dasharray:none"
-       id="path1336"
-       inkscape:href="#path13316"
-       d="M 43.9375,10.5 C 35.086269,10.856517 28.28125,16.649624 28.28125,23.4375 C 28.28125,27.43874 29.949375,31.638672 33.4375,33.96875 C 33.659358,34.111954 33.816384,34.336276 33.875,34.59375 C 34.337119,36.628026 33.873842,38.417659 33.28125,39.75 C 33.741161,39.588512 33.859781,39.584317 34.375,39.375 C 36.123195,38.664763 38.010688,37.617706 38.875,36.65625 C 39.06282,36.459679 39.321894,36.347038 39.59375,36.34375 C 41.848554,36.248232 43.129202,36.40625 44.84375,36.40625 C 54.099359,36.406251 61.406252,30.441153 61.40625,23.4375 C 61.406249,16.433845 54.101534,10.5 44.84375,10.5 C 44.514064,10.499999 44.17917,10.490265 43.9375,10.5 z " />
+       transform="matrix(1.7042169,0,0,1.7042169,4.3797455,8.7825453)" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path2193"
-       sodipodi:cx="9.0598059"
-       sodipodi:cy="8.7845774"
-       sodipodi:rx="1.1679889"
-       sodipodi:ry="1.4520943"
-       d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1  7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1  10.227795 8.7845774 z"
-       transform="matrix(1.712345,0,0,2.754643,9.486483,14.80163)" />
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2259"
+       sodipodi:cx="8.3258924"
+       sodipodi:cy="9.2232141"
+       sodipodi:rx="1.2276785"
+       sodipodi:ry="1.7410715"
+       d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499"
+       transform="matrix(3.5277688,0.705265,-0.6665314,1.855957,7.2901885,-4.1630498)"
+       sodipodi:start="3.5782199"
+       sodipodi:end="5.6135639"
+       sodipodi:open="true" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path2191"
-       sodipodi:cx="9.0598059"
-       sodipodi:cy="8.7845774"
-       sodipodi:rx="1.1679889"
-       sodipodi:ry="1.4520943"
-       d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1  7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1  10.227795 8.7845774 z"
-       transform="matrix(1.712345,0,0,2.754643,1.486487,14.80163)" />
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2261"
+       sodipodi:cx="8.3258924"
+       sodipodi:cy="9.2232141"
+       sodipodi:rx="1.2276785"
+       sodipodi:ry="1.7410715"
+       d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499"
+       transform="matrix(-3.5277688,0.705265,0.6665314,1.855957,41.208475,-4.1630498)"
+       sodipodi:start="3.5782199"
+       sodipodi:end="5.6135639"
+       sodipodi:open="true" />
     <path
        style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="M 32,55 C 30.709742,49.86153 26.288403,46 21.000001,46 C 15.7116,46 11.290259,49.86153 10,55 C 12.318243,51.672674 16.389775,48.580716 21.000001,48.580716 C 25.610224,48.580715 29.681757,51.672674 32,55 z "
-       id="path2186"
-       sodipodi:nodetypes="cscsc" />
-    <path
-       sodipodi:type="arc"
-       style="opacity:1;color:#000000;fill:#ef2929;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36561811px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
-       id="path1311"
-       sodipodi:cx="15.590227"
-       sodipodi:cy="16.57217"
-       sodipodi:rx="14.345175"
-       sodipodi:ry="14.345175"
-       d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1  1.2450523,16.57217 A 14.345175 14.345175 0 1 1  29.935402 16.57217 z"
-       transform="matrix(0.732268,0,0,0.732268,34.07926,11.36022)" />
+       d="M 17,21 L 17,22 L 18,22 L 18,21 L 17,21 z M 18,22 L 18,23 L 19,23 L 19,22 L 18,22 z M 19,23 L 19,24 L 20,24 L 20,23 L 19,23 z M 20,23 L 21,23 L 21,22 L 20,22 L 20,23 z M 21,22 L 22,22 L 22,21 L 21,21 L 21,22 z M 20,24 L 20,25 L 21,25 L 21,24 L 20,24 z M 21,25 L 21,26 L 22,26 L 22,25 L 21,25 z M 19,24 L 18,24 L 18,25 L 19,25 L 19,24 z M 18,25 L 17,25 L 17,26 L 18,26 L 18,25 z "
+       id="rect3307" />
     <path
-       sodipodi:type="arc"
-       style="opacity:1;color:#000000;fill:#ef2929;fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:1.4342562px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
-       id="path1339"
-       sodipodi:cx="15.590227"
-       sodipodi:cy="16.57217"
-       sodipodi:rx="14.345175"
-       sodipodi:ry="14.345175"
-       d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1  1.2450523,16.57217 A 14.345175 14.345175 0 1 1  29.935402 16.57217 z"
-       transform="matrix(0.697225,0,0,0.697224,34.63061,11.94498)" />
+       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 27,21 L 27,22 L 28,22 L 28,21 L 27,21 z M 28,22 L 28,23 L 29,23 L 29,22 L 28,22 z M 29,23 L 29,24 L 30,24 L 30,23 L 29,23 z M 30,23 L 31,23 L 31,22 L 30,22 L 30,23 z M 31,22 L 32,22 L 32,21 L 31,21 L 31,22 z M 30,24 L 30,25 L 31,25 L 31,24 L 30,24 z M 31,25 L 31,26 L 32,26 L 32,25 L 31,25 z M 29,24 L 28,24 L 28,25 L 29,25 L 29,24 z M 28,25 L 27,25 L 27,26 L 28,26 L 28,25 z "
+       id="path3326" />
     <path
-       style="opacity:0.6;color:#000000;fill:url(#linearGradient2194);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2245);stroke-width:1.00000024px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
-       d="M 54.501284,23.499216 C 54.501284,28.468337 50.46837,32.501247 45.499243,32.501247 C 40.530116,32.501247 36.497202,28.468337 36.497202,23.499216 C 36.497202,18.530098 40.530116,14.497189 45.499243,14.497189 C 50.46837,14.497189 54.501284,18.530098 54.501284,23.499216 z "
-       id="path2220" />
-    <path
-       style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:0.99999881px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
-       d="M 53.472399,23.373021 C 53.472399,25.828104 51.776345,25.485533 45.279112,25.485533 C 38.811218,25.485533 37.51405,25.897351 37.51405,23.485931 C 37.51405,21.235525 38.820793,21.494116 45.34652,21.494116 C 51.901652,21.494116 53.472399,20.942767 53.472399,23.373021 z "
-       id="path1341"
-       sodipodi:nodetypes="czczz" />
+       style="fill:#ce5c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 34,39 C 32.885686,35.003412 29.067255,32 24.5,32 C 19.932746,32 16.114315,35.003412 15,39 C 17.00212,36.412082 20.518441,33.850868 24.5,33.850868 C 28.481556,33.850866 31.99788,36.412082 34,39 z "
+       id="path3492"
+       sodipodi:nodetypes="cscsc" />
   </g>
 </svg>
--- a/pidgin/pixmaps/dialogs/64/scalable/info.svg	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/pixmaps/dialogs/64/scalable/info.svg	Fri Sep 28 16:34:43 2007 +0000
@@ -7,147 +7,25 @@
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="64"
-   height="64"
+   width="48"
+   height="48"
    id="svg2"
    sodipodi:version="0.32"
-   inkscape:version="0.43"
+   inkscape:version="0.45"
    version="1.0"
    sodipodi:docbase="/home/hbons/Desktop"
-   sodipodi:docname="dialog-info.svg"
-   inkscape:export-filename="/home/hbons/Desktop/dialog-info.png"
+   sodipodi:docname="dialog.svg"
+   inkscape:export-filename="/home/hbons/Desktop/newstyle.png"
    inkscape:export-xdpi="90"
-   inkscape:export-ydpi="90">
+   inkscape:export-ydpi="90"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
   <defs
      id="defs4">
     <linearGradient
        inkscape:collect="always"
-       id="linearGradient2226">
-      <stop
-         style="stop-color:#729fcf;stop-opacity:1;"
-         offset="0"
-         id="stop2228" />
-      <stop
-         style="stop-color:#729fcf;stop-opacity:0;"
-         offset="1"
-         id="stop2230" />
-    </linearGradient>
-    <radialGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient2226"
-       id="radialGradient2232"
-       cx="6.8598728"
-       cy="12.836589"
-       fx="6.8598728"
-       fy="12.836589"
-       r="6"
-       gradientTransform="matrix(-1.535401,1.457479,-1.350253,-1.281728,72.86699,21.2066)"
-       gradientUnits="userSpaceOnUse" />
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient3150">
-      <stop
-         style="stop-color:#2e3436;stop-opacity:1;"
-         offset="0"
-         id="stop3152" />
-      <stop
-         style="stop-color:#2e3436;stop-opacity:0;"
-         offset="1"
-         id="stop3154" />
-    </linearGradient>
-    <radialGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient3150"
-       id="radialGradient3156"
-       cx="10.748654"
-       cy="10.457643"
-       fx="10.748654"
-       fy="10.457643"
-       r="6.6449099"
-       gradientTransform="matrix(-0.842757,5.698892e-16,-4.565819e-9,-0.35721,19.80716,14.19321)"
-       gradientUnits="userSpaceOnUse" />
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient2351">
-      <stop
-         style="stop-color:#eeeeec;stop-opacity:1;"
-         offset="0"
-         id="stop2353" />
-      <stop
-         style="stop-color:#eeeeec;stop-opacity:0;"
-         offset="1"
-         id="stop2355" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient2351"
-       id="linearGradient2357"
-       x1="12.488563"
-       y1="5.8544211"
-       x2="12.488563"
-       y2="19.066195"
-       gradientUnits="userSpaceOnUse"
-       gradientTransform="matrix(1,0,0,1.005826,31.99641,10.9359)" />
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient2343">
-      <stop
-         style="stop-color:#babdb6;stop-opacity:1;"
-         offset="0"
-         id="stop2345" />
-      <stop
-         style="stop-color:#babdb6;stop-opacity:0;"
-         offset="1"
-         id="stop2347" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient2343"
-       id="linearGradient2349"
-       x1="12.515625"
-       y1="8.7261219"
-       x2="12.515625"
-       y2="0.68458056"
-       gradientUnits="userSpaceOnUse"
-       gradientTransform="matrix(0.993429,0,0,1.004681,32.05868,11.024)" />
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient3121">
-      <stop
-         style="stop-color:#d3d7cf;stop-opacity:1;"
-         offset="0"
-         id="stop3123" />
-      <stop
-         style="stop-color:#d3d7cf;stop-opacity:0;"
-         offset="1"
-         id="stop3125" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient3816">
-      <stop
-         style="stop-color:#000000;stop-opacity:1;"
-         offset="0"
-         id="stop3818" />
-      <stop
-         style="stop-color:#000000;stop-opacity:0;"
-         offset="1"
-         id="stop3820" />
-    </linearGradient>
-    <radialGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient3816"
-       id="radialGradient3822"
-       cx="31.112698"
-       cy="19.008621"
-       fx="31.112698"
-       fy="19.008621"
-       r="8.6620579"
-       gradientUnits="userSpaceOnUse" />
-    <linearGradient
-       inkscape:collect="always"
        id="linearGradient3104">
       <stop
          style="stop-color:#eeeeec;stop-opacity:1;"
@@ -169,15 +47,259 @@
        r="9.975256"
        gradientUnits="userSpaceOnUse"
        gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <filter
+       inkscape:collect="always"
+       x="-0.27879593"
+       width="1.5575919"
+       y="-0.78248727"
+       height="2.5649745"
+       id="filter3405">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="1.5438116"
+         id="feGaussianBlur3407" />
+    </filter>
+    <radialGradient
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient2247"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3263">
+      <stop
+         style="stop-color:#555753;stop-opacity:1;"
+         offset="0"
+         id="stop3265" />
+      <stop
+         style="stop-color:#555753;stop-opacity:0;"
+         offset="1"
+         id="stop3267" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2216"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3263"
+       id="linearGradient3269"
+       x1="12.845698"
+       y1="16.037401"
+       x2="10.698112"
+       y2="15.449714"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3191"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
     <linearGradient
        inkscape:collect="always"
-       xlink:href="#linearGradient3121"
-       id="linearGradient1551"
+       id="linearGradient3150">
+      <stop
+         style="stop-color:#2e3436;stop-opacity:1;"
+         offset="0"
+         id="stop3152" />
+      <stop
+         style="stop-color:#2e3436;stop-opacity:0;"
+         offset="1"
+         id="stop3154" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3175"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3150"
+       id="radialGradient3156"
+       cx="10.748654"
+       cy="10.457643"
+       fx="10.748654"
+       fy="10.457643"
+       r="6.6449099"
+       gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       id="radialGradient2214"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2255"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3313"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <radialGradient
+       r="2.5781252"
+       fy="11.083743"
+       fx="17.911736"
+       cy="11.083743"
+       cx="17.911736"
+       gradientTransform="matrix(-1.591138,1.574803,-1.783257,-1.76495,68.854751,-2.8442229)"
        gradientUnits="userSpaceOnUse"
-       x1="42.925175"
-       y1="40.136646"
-       x2="42.925175"
-       y2="15.474488" />
+       id="radialGradient2259"
+       xlink:href="#linearGradient2382"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2867">
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:1;"
+         offset="0"
+         id="stop2869" />
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:0;"
+         offset="1"
+         id="stop2871" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2847">
+      <stop
+         style="stop-color:#888a85;stop-opacity:1;"
+         offset="0"
+         id="stop2849" />
+      <stop
+         style="stop-color:#888a85;stop-opacity:0;"
+         offset="1"
+         id="stop2851" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2382">
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:1;"
+         offset="0"
+         id="stop2384" />
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:0;"
+         offset="1"
+         id="stop2386" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2230"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2847"
+       id="linearGradient2853"
+       x1="12.5"
+       y1="18.202251"
+       x2="12.746171"
+       y2="20.761486"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2867"
+       id="linearGradient2873"
+       x1="12.720216"
+       y1="20.952612"
+       x2="12.720216"
+       y2="17.682426"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient2303"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2349"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient2233"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2264"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
   </defs>
   <sodipodi:namedview
      id="base"
@@ -186,17 +308,19 @@
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="6.0019314"
-     inkscape:cx="46.66506"
-     inkscape:cy="27.955978"
+     inkscape:zoom="11.2"
+     inkscape:cx="49.304407"
+     inkscape:cy="24.325832"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="true"
-     fill="#2e3436"
-     inkscape:window-width="1267"
-     inkscape:window-height="971"
-     inkscape:window-x="6"
-     inkscape:window-y="21" />
+     fill="#fce94f"
+     inkscape:window-width="1440"
+     inkscape:window-height="845"
+     inkscape:window-x="3"
+     inkscape:window-y="25"
+     width="48px"
+     height="48px" />
   <metadata
      id="metadata7">
     <rdf:RDF>
@@ -213,25 +337,25 @@
      inkscape:groupmode="layer"
      id="layer1">
     <path
-       d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1  22.45064,19.008621 A 8.6620579 8.6620579 0 1 1  39.774755 19.008621 z"
-       sodipodi:ry="8.6620579"
-       sodipodi:rx="8.6620579"
-       sodipodi:cy="19.008621"
-       sodipodi:cx="31.112698"
-       id="path4318"
-       style="opacity:0.5;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
        sodipodi:type="arc"
-       transform="matrix(2.383972,0,0,1.117487,-53.5217,33.04541)" />
+       style="opacity:0.64044949;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3405)"
+       id="path3140"
+       sodipodi:cx="10.748654"
+       sodipodi:cy="10.457643"
+       sodipodi:rx="6.6449099"
+       sodipodi:ry="2.3675451"
+       d="M 17.393564 10.457643 A 6.6449099 2.3675451 0 1 1  4.1037445,10.457643 A 6.6449099 2.3675451 0 1 1  17.393564 10.457643 z"
+       transform="matrix(2.2723916,0,0,1.6905173,-0.1758194,23.510748)" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#f57900;stroke-width:0.53913006;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#cc6400;stroke-width:0.55559433;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path1307"
        sodipodi:cx="11.806158"
        sodipodi:cy="10.983024"
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.854646,0,0,1.855034,-0.899768,22.62707)" />
+       transform="matrix(1.8043406,0,0,1.8043406,3.1976696,7.6828846)" />
     <path
        sodipodi:type="arc"
        style="opacity:0.79545456;fill:url(#radialGradient3114);fill-opacity:1;stroke:none;stroke-width:1.05274069;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
@@ -241,161 +365,81 @@
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.704217,0,0,1.704217,0.879746,24.28255)" />
+       transform="matrix(1.6958412,0,0,1.6958412,4.3182736,9.0348912)" />
     <path
        sodipodi:type="arc"
-       style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.57006598;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.58677971;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path2184"
        sodipodi:cx="11.806158"
        sodipodi:cy="10.983024"
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.75441,0,0,1.753957,0.28417,23.73792)" />
+       transform="matrix(1.7042169,0,0,1.7042169,4.3797455,8.7825453)" />
+    <path
+       style="fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1"
+       d="M 23.500001,23.5 C 23.500001,26.26 21.260002,28.500001 18.500001,28.500001 C 15.740001,28.500001 13.5,26.26 13.5,23.5 C 13.5,20.74 15.740001,18.5 18.500001,18.5 C 21.260002,18.5 23.500001,20.74 23.500001,23.5 z "
+       id="path3154" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2172"
+       sodipodi:cx="9.7069349"
+       sodipodi:cy="9.6526775"
+       sodipodi:rx="1.0259361"
+       sodipodi:ry="1.9413869"
+       d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1  8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1  10.732871 9.6526775 z"
+       transform="matrix(1.9494387,0,0,1.2877392,1.0769249,12.069869)" />
     <path
-       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="M 32,46 C 30.709742,51.13847 26.288403,55 21.000001,55 C 15.7116,55 11.290259,51.13847 10,46 C 12.318243,49.327326 16.389775,52.419284 21.000001,52.419284 C 25.610224,52.419285 29.681757,49.327326 32,46 z "
+       sodipodi:type="arc"
+       style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:0.282258;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3152"
+       sodipodi:cx="9.7069349"
+       sodipodi:cy="9.6526775"
+       sodipodi:rx="1.0259361"
+       sodipodi:ry="1.9413869"
+       d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1  8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1  10.732871 9.6526775 z"
+       transform="matrix(4.8735976,0,0,2.5754783,-16.807694,-1.3602618)" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3148"
+       sodipodi:cx="9.7069349"
+       sodipodi:cy="9.6526775"
+       sodipodi:rx="1.0259361"
+       sodipodi:ry="1.9413869"
+       d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1  8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1  10.732871 9.6526775 z"
+       transform="matrix(1.9494393,0,0,1.2877392,10.07692,12.069869)" />
+    <path
+       style="opacity:1;fill:#ce5c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 34,32 C 32.885686,35.996588 29.067255,39 24.5,39 C 19.932746,39 16.114315,35.996588 15,32 C 17.00212,34.587918 20.518441,37.149132 24.5,37.149132 C 28.481556,37.149134 31.99788,34.587918 34,32 z "
        id="path2186"
        sodipodi:nodetypes="cscsc" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path2191"
-       sodipodi:cx="9.0598059"
-       sodipodi:cy="8.7845774"
-       sodipodi:rx="1.1679889"
-       sodipodi:ry="1.4520943"
-       d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1  7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1  10.227795 8.7845774 z"
-       transform="matrix(1.712345,0,0,2.754643,1.486487,14.80163)" />
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2259"
+       sodipodi:cx="8.3258924"
+       sodipodi:cy="9.2232141"
+       sodipodi:rx="1.2276785"
+       sodipodi:ry="1.7410715"
+       d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499"
+       transform="matrix(3.5277688,0.705265,-0.6665314,1.855957,7.2901885,-4.1630498)"
+       sodipodi:start="3.5782199"
+       sodipodi:end="5.6135639"
+       sodipodi:open="true" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path2193"
-       sodipodi:cx="9.0598059"
-       sodipodi:cy="8.7845774"
-       sodipodi:rx="1.1679889"
-       sodipodi:ry="1.4520943"
-       d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1  7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1  10.227795 8.7845774 z"
-       transform="matrix(1.712345,0,0,2.754643,9.486483,14.80163)" />
-    <path
-       style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;stroke-dasharray:none"
-       d="M 44.078659,9.5112136 C 34.84342,9.8834971 27.500059,15.977362 27.500059,23.405814 C 27.500059,27.671183 29.253586,32.180745 33.0662,34.729626 C 33.874807,38.292011 31.54507,41.058776 31.141507,41.494102 C 31.871844,41.290557 37.643487,39.670532 39.808221,37.260561 C 41.990193,37.168054 43.23089,37.300418 44.997262,37.300418 C 54.649949,37.300418 62.494467,31.073895 62.494465,23.405814 C 62.494465,15.737733 54.649949,9.5112136 44.997262,9.5112136 C 44.695616,9.5112136 44.37657,9.4992035 44.078659,9.5112136 z "
-       id="path13316"
-       sodipodi:nodetypes="cscccsssc" />
-    <path
-       sodipodi:type="inkscape:offset"
-       inkscape:radius="-1.0020103"
-       inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z "
-       xlink:href="#path13316"
-       style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
-       id="path13323"
-       inkscape:href="#path13316"
-       d="M 43.9375,10.5 C 35.082559,10.856667 28.28125,16.643774 28.28125,23.4375 C 28.28125,27.441186 29.946384,31.636673 33.4375,33.96875 C 33.648247,34.117093 33.793739,34.340928 33.84375,34.59375 C 34.305353,36.625753 33.873291,38.418899 33.28125,39.75 C 33.741286,39.588469 33.859625,39.584381 34.375,39.375 C 36.123726,38.664548 38.008731,37.651133 38.875,36.6875 C 39.056781,36.478508 39.316956,36.354077 39.59375,36.34375 C 41.847992,36.248256 43.128683,36.40625 44.84375,36.40625 C 54.103198,36.406251 61.406252,30.447219 61.40625,23.4375 C 61.406249,16.427779 54.105354,10.5 44.84375,10.5 C 44.5143,10.499999 44.179676,10.490245 43.9375,10.5 z " />
-    <path
-       sodipodi:type="inkscape:offset"
-       inkscape:radius="-1.0109046"
-       inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z "
-       xlink:href="#path13316"
-       style="opacity:1;color:#000000;fill:url(#linearGradient1551);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;stroke-dasharray:none"
-       id="path1336"
-       inkscape:href="#path13316"
-       d="M 43.9375,10.5 C 35.086269,10.856517 28.28125,16.649624 28.28125,23.4375 C 28.28125,27.43874 29.949375,31.638672 33.4375,33.96875 C 33.659358,34.111954 33.816384,34.336276 33.875,34.59375 C 34.337119,36.628026 33.873842,38.417659 33.28125,39.75 C 33.741161,39.588512 33.859781,39.584317 34.375,39.375 C 36.123195,38.664763 38.010688,37.617706 38.875,36.65625 C 39.06282,36.459679 39.321894,36.347038 39.59375,36.34375 C 41.848554,36.248232 43.129202,36.40625 44.84375,36.40625 C 54.099359,36.406251 61.406252,30.441153 61.40625,23.4375 C 61.406249,16.433845 54.101534,10.5 44.84375,10.5 C 44.514064,10.499999 44.17917,10.490265 43.9375,10.5 z " />
-    <path
-       style="opacity:1;fill:url(#radialGradient2232);fill-opacity:1;stroke:#729fcf;stroke-width:1.00000012;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="M 44.703431,14.533668 C 40.70252,14.678436 37.503421,17.811488 37.503421,21.651365 C 37.503421,24.907582 40.201737,27.911617 43.341119,28.760108 L 43.389173,30.850471 C 43.389173,30.872875 43.386855,30.909548 43.389173,30.931354 C 43.394328,30.963552 43.421848,31.022249 43.431776,31.052677 C 43.443213,31.082437 43.458677,31.146493 43.474381,31.174002 C 43.480062,31.182896 43.510872,31.20584 43.516985,31.214444 C 43.569231,31.280841 43.655052,31.37351 43.730003,31.41665 C 43.749323,31.426587 43.794808,31.448926 43.815208,31.457092 C 43.857011,31.471566 43.940397,31.49101 43.985625,31.497533 C 44.008596,31.499735 44.047229,31.497533 44.07083,31.497533 L 46.028589,31.404055 C 46.052192,31.404055 46.090827,31.406257 46.113796,31.404055 C 46.159024,31.397531 46.242411,31.378087 46.284211,31.363613 C 46.304612,31.355448 46.350096,31.333109 46.369418,31.323172 C 46.444367,31.280031 46.53019,31.187363 46.582436,31.120966 C 46.588549,31.112362 46.619359,31.089417 46.62504,31.080523 C 46.640742,31.053014 46.656207,30.988959 46.667645,30.959199 C 46.677573,30.928771 46.705092,30.870073 46.710248,30.837876 C 46.712565,30.816069 46.710248,30.779396 46.710248,30.756993 L 46.758302,28.760108 C 49.897683,27.911617 52.499887,24.907584 52.499889,21.651365 C 52.499889,17.719331 49.13652,14.533668 45.001656,14.533668 C 44.904746,14.533668 44.799454,14.530194 44.703431,14.533668 z "
-       id="path1311"
-       sodipodi:nodetypes="csccsssssssccsssssssccssc" />
-    <path
-       sodipodi:type="inkscape:offset"
-       inkscape:radius="-0.98906523"
-       inkscape:original="M 44.71875 14.53125 C 40.71784 14.676018 37.5 17.816373 37.5 21.65625 C 37.499999 24.912467 40.204368 27.901509 43.34375 28.75 L 43.375 30.84375 C 43.375001 30.866154 43.372682 30.915694 43.375 30.9375 C 43.380156 30.969697 43.427572 31.032072 43.4375 31.0625 C 43.448939 31.09226 43.453046 31.159991 43.46875 31.1875 C 43.474432 31.196394 43.525137 31.210146 43.53125 31.21875 C 43.583494 31.285148 43.643799 31.36311 43.71875 31.40625 C 43.73807 31.416186 43.7921 31.460584 43.8125 31.46875 C 43.854303 31.483224 43.954772 31.493477 44 31.5 C 44.02297 31.502201 44.038899 31.5 44.0625 31.5 L 46.03125 31.40625 C 46.054855 31.40625 46.102031 31.408452 46.125 31.40625 C 46.170228 31.399726 46.23945 31.389474 46.28125 31.375 C 46.301652 31.366835 46.355678 31.322437 46.375 31.3125 C 46.449948 31.269359 46.541504 31.191397 46.59375 31.125 C 46.599863 31.116396 46.619319 31.102644 46.625 31.09375 C 46.640704 31.066241 46.644812 30.99851 46.65625 30.96875 C 46.666178 30.938321 46.713594 30.875947 46.71875 30.84375 C 46.721068 30.821944 46.71875 30.772403 46.71875 30.75 L 46.75 28.75 C 49.889382 27.901508 52.499998 24.912469 52.5 21.65625 C 52.5 17.724216 49.134864 14.53125 45 14.53125 C 44.90309 14.53125 44.814773 14.527776 44.71875 14.53125 z "
-       xlink:href="#path1311"
-       style="opacity:0.7;fill:#ffffff;fill-opacity:0.41960784;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path2204"
-       inkscape:href="#path1311"
-       d="M 33.46875,7.46875 C 29.99276,7.595007 27.28125,10.282227 27.28125,13.5625 C 27.281251,16.268084 29.627654,18.959072 32.3125,19.6875 C 32.745246,19.795209 33.052411,20.179165 33.0625,20.625 L 33.125,22.34375 L 34.40625,22.28125 L 34.46875,20.625 C 34.478839,20.179165 34.786004,19.795209 35.21875,19.6875 C 37.89876,18.960384 40.156248,16.287128 40.15625,13.5625 C 40.15625,10.202426 37.315969,7.4687499 33.71875,7.46875 C 33.598771,7.4687498 33.517755,7.46697 33.46875,7.46875 z "
-       transform="translate(3.330669e-15,4.169556e-4)" />
-    <rect
-       style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#c4a000;stroke-width:1.00000107;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect2188"
-       width="5.0002198"
-       height="3.994288"
-       x="42.497272"
-       y="29.502851"
-       rx="0.50000107"
-       ry="0.50000083" />
-    <path
-       sodipodi:type="inkscape:offset"
-       inkscape:radius="-1.0076578"
-       inkscape:original="M 43 29.5 C 42.722999 29.5 42.5 29.723 42.5 30 L 42.5 33 C 42.5 33.277 42.723 33.5 43 33.5 L 47 33.5 C 47.277001 33.5 47.499999 33.277 47.5 33 L 47.5 30 C 47.5 29.723 47.277002 29.5 47 29.5 L 43 29.5 z "
-       xlink:href="#rect2188"
-       style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.00000083;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path1324"
-       inkscape:href="#rect2188"
-       d="M 32.21875,22.4375 L 32.21875,24.40625 L 35.1875,24.40625 L 35.1875,22.4375 L 32.21875,22.4375 z " />
-    <rect
-       style="opacity:0.7;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect2238"
-       width="1"
-       height="2"
-       x="43"
-       y="24" />
-    <rect
-       style="opacity:0.70454544;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect2240"
-       width="1.0217247"
-       height="2"
-       x="45.978275"
-       y="24" />
-    <rect
-       style="opacity:0.7;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect2242"
-       width="1"
-       height="2.0132751"
-       x="-25"
-       y="43.986725"
-       transform="matrix(0,-1,1,0,0,0)" />
-    <rect
-       style="opacity:0.7;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect2244"
-       width="1.0000002"
-       height="1"
-       x="-24"
-       y="43"
-       transform="matrix(0,-1,1,0,0,0)" />
-    <rect
-       style="opacity:0.7;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect2246"
-       width="1.0000002"
-       height="1"
-       x="-24"
-       y="45"
-       transform="matrix(0,-1,1,0,0,0)" />
-    <rect
-       style="opacity:0.5;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect2250"
-       width="1.0000002"
-       height="1.0066376"
-       x="-23"
-       y="45.993362"
-       transform="matrix(0,-1,1,0,0,0)" />
-    <rect
-       style="opacity:0.5;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect2252"
-       width="1.0000002"
-       height="1.0066376"
-       x="-23"
-       y="43.993362"
-       transform="matrix(0,-1,1,0,0,0)" />
-    <path
-       sodipodi:type="arc"
-       style="opacity:0.9;fill:#ffffff;fill-opacity:0.41960784;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path2254"
-       sodipodi:cx="8.9137974"
-       sodipodi:cy="6.046802"
-       sodipodi:rx="1.3745575"
-       sodipodi:ry="1.3329042"
-       d="M 10.288355 6.046802 A 1.3745575 1.3329042 0 1 1  7.5392399,6.046802 A 1.3745575 1.3329042 0 1 1  10.288355 6.046802 z"
-       transform="matrix(1.455014,0,0,1.500481,30.0303,10.92689)" />
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2261"
+       sodipodi:cx="8.3258924"
+       sodipodi:cy="9.2232141"
+       sodipodi:rx="1.2276785"
+       sodipodi:ry="1.7410715"
+       d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499"
+       transform="matrix(-3.5277688,0.705265,0.6665314,1.855957,41.208475,-4.1630498)"
+       sodipodi:start="3.5782199"
+       sodipodi:end="5.6135639"
+       sodipodi:open="true" />
   </g>
 </svg>
--- a/pidgin/pixmaps/dialogs/64/scalable/question.svg	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/pixmaps/dialogs/64/scalable/question.svg	Fri Sep 28 16:34:43 2007 +0000
@@ -7,57 +7,25 @@
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="64"
-   height="64"
+   width="48"
+   height="48"
    id="svg2"
    sodipodi:version="0.32"
-   inkscape:version="0.43"
+   inkscape:version="0.45"
    version="1.0"
-   sodipodi:docbase="/home/hbons/Desktop"
+   sodipodi:docbase="/home/hbons/Desktop/2.1.1/dialogs/scalable"
    sodipodi:docname="dialog-question.svg"
-   inkscape:export-filename="/home/hbons/Desktop/dialog-question.png"
+   inkscape:export-filename="/home/hbons/Desktop/newstyle.png"
    inkscape:export-xdpi="90"
-   inkscape:export-ydpi="90">
+   inkscape:export-ydpi="90"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
   <defs
      id="defs4">
     <linearGradient
        inkscape:collect="always"
-       id="linearGradient3121">
-      <stop
-         style="stop-color:#d3d7cf;stop-opacity:1;"
-         offset="0"
-         id="stop3123" />
-      <stop
-         style="stop-color:#d3d7cf;stop-opacity:0;"
-         offset="1"
-         id="stop3125" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient3816">
-      <stop
-         style="stop-color:#000000;stop-opacity:1;"
-         offset="0"
-         id="stop3818" />
-      <stop
-         style="stop-color:#000000;stop-opacity:0;"
-         offset="1"
-         id="stop3820" />
-    </linearGradient>
-    <radialGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient3816"
-       id="radialGradient3822"
-       cx="31.112698"
-       cy="19.008621"
-       fx="31.112698"
-       fy="19.008621"
-       r="8.6620579"
-       gradientUnits="userSpaceOnUse" />
-    <linearGradient
-       inkscape:collect="always"
        id="linearGradient3104">
       <stop
          style="stop-color:#eeeeec;stop-opacity:1;"
@@ -79,15 +47,259 @@
        r="9.975256"
        gradientUnits="userSpaceOnUse"
        gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <filter
+       inkscape:collect="always"
+       x="-0.27879593"
+       width="1.5575919"
+       y="-0.78248727"
+       height="2.5649745"
+       id="filter3405">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="1.5438116"
+         id="feGaussianBlur3407" />
+    </filter>
+    <radialGradient
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient2247"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3263">
+      <stop
+         style="stop-color:#555753;stop-opacity:1;"
+         offset="0"
+         id="stop3265" />
+      <stop
+         style="stop-color:#555753;stop-opacity:0;"
+         offset="1"
+         id="stop3267" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2216"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3263"
+       id="linearGradient3269"
+       x1="12.845698"
+       y1="16.037401"
+       x2="10.698112"
+       y2="15.449714"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3191"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
     <linearGradient
        inkscape:collect="always"
-       xlink:href="#linearGradient3121"
-       id="linearGradient1551"
+       id="linearGradient3150">
+      <stop
+         style="stop-color:#2e3436;stop-opacity:1;"
+         offset="0"
+         id="stop3152" />
+      <stop
+         style="stop-color:#2e3436;stop-opacity:0;"
+         offset="1"
+         id="stop3154" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3175"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3150"
+       id="radialGradient3156"
+       cx="10.748654"
+       cy="10.457643"
+       fx="10.748654"
+       fy="10.457643"
+       r="6.6449099"
+       gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       id="radialGradient2214"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2255"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3313"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <radialGradient
+       r="2.5781252"
+       fy="11.083743"
+       fx="17.911736"
+       cy="11.083743"
+       cx="17.911736"
+       gradientTransform="matrix(-1.591138,1.574803,-1.783257,-1.76495,68.854751,-2.8442229)"
        gradientUnits="userSpaceOnUse"
-       x1="42.925175"
-       y1="40.136646"
-       x2="42.925175"
-       y2="15.474488" />
+       id="radialGradient2259"
+       xlink:href="#linearGradient2382"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2867">
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:1;"
+         offset="0"
+         id="stop2869" />
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:0;"
+         offset="1"
+         id="stop2871" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2847">
+      <stop
+         style="stop-color:#888a85;stop-opacity:1;"
+         offset="0"
+         id="stop2849" />
+      <stop
+         style="stop-color:#888a85;stop-opacity:0;"
+         offset="1"
+         id="stop2851" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2382">
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:1;"
+         offset="0"
+         id="stop2384" />
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:0;"
+         offset="1"
+         id="stop2386" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2230"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2847"
+       id="linearGradient2853"
+       x1="12.5"
+       y1="18.202251"
+       x2="12.746171"
+       y2="20.761486"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2867"
+       id="linearGradient2873"
+       x1="12.720216"
+       y1="20.952612"
+       x2="12.720216"
+       y2="17.682426"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient2303"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2349"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient2233"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2264"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
   </defs>
   <sodipodi:namedview
      id="base"
@@ -96,17 +308,19 @@
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="16.976026"
-     inkscape:cx="39.201403"
-     inkscape:cy="23.251521"
+     inkscape:zoom="22.4"
+     inkscape:cx="41.793957"
+     inkscape:cy="31.031721"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="true"
-     fill="#204a87"
-     inkscape:window-width="1267"
-     inkscape:window-height="971"
-     inkscape:window-x="6"
-     inkscape:window-y="21" />
+     fill="#fce94f"
+     inkscape:window-width="1440"
+     inkscape:window-height="847"
+     inkscape:window-x="3"
+     inkscape:window-y="25"
+     width="48px"
+     height="48px" />
   <metadata
      id="metadata7">
     <rdf:RDF>
@@ -123,25 +337,25 @@
      inkscape:groupmode="layer"
      id="layer1">
     <path
-       d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1  22.45064,19.008621 A 8.6620579 8.6620579 0 1 1  39.774755 19.008621 z"
-       sodipodi:ry="8.6620579"
-       sodipodi:rx="8.6620579"
-       sodipodi:cy="19.008621"
-       sodipodi:cx="31.112698"
-       id="path4318"
-       style="opacity:0.5;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
        sodipodi:type="arc"
-       transform="matrix(2.383972,0,0,1.117487,-53.5217,33.04541)" />
+       style="opacity:0.64044949;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3405)"
+       id="path3140"
+       sodipodi:cx="10.748654"
+       sodipodi:cy="10.457643"
+       sodipodi:rx="6.6449099"
+       sodipodi:ry="2.3675451"
+       d="M 17.393564 10.457643 A 6.6449099 2.3675451 0 1 1  4.1037445,10.457643 A 6.6449099 2.3675451 0 1 1  17.393564 10.457643 z"
+       transform="matrix(2.2723916,0,0,1.6905173,-4.1758193,23.510748)" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#f57900;stroke-width:0.53913006;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#cc6400;stroke-width:0.55559433;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path1307"
        sodipodi:cx="11.806158"
        sodipodi:cy="10.983024"
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.854646,0,0,1.855034,-0.899768,22.62707)" />
+       transform="matrix(1.8043406,0,0,1.8043406,-0.8023303,7.6828845)" />
     <path
        sodipodi:type="arc"
        style="opacity:0.79545456;fill:url(#radialGradient3114);fill-opacity:1;stroke:none;stroke-width:1.05274069;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
@@ -151,81 +365,90 @@
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.704217,0,0,1.704217,0.879746,24.28255)" />
+       transform="matrix(1.6958412,0,0,1.6958412,0.3182737,9.0348911)" />
     <path
        sodipodi:type="arc"
-       style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.57006598;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.58677971;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path2184"
        sodipodi:cx="11.806158"
        sodipodi:cy="10.983024"
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.75441,0,0,1.753957,0.28417,23.73792)" />
+       transform="matrix(1.7042169,0,0,1.7042169,0.3797456,8.7825452)" />
+    <path
+       style="fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1"
+       d="M 19.500001,23.5 C 19.500001,26.26 17.260002,28.500001 14.500001,28.500001 C 11.740001,28.500001 9.5000001,26.26 9.5000001,23.5 C 9.5000001,20.74 11.740001,18.5 14.500001,18.5 C 17.260002,18.5 19.500001,20.74 19.500001,23.5 z "
+       id="path3154" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path2191"
-       sodipodi:cx="9.0598059"
-       sodipodi:cy="8.7845774"
-       sodipodi:rx="1.1679889"
-       sodipodi:ry="1.4520943"
-       d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1  7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1  10.227795 8.7845774 z"
-       transform="matrix(1.712345,0,0,2.754643,1.486487,11.80163)" />
+       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2172"
+       sodipodi:cx="9.7069349"
+       sodipodi:cy="9.6526775"
+       sodipodi:rx="1.0259361"
+       sodipodi:ry="1.9413869"
+       d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1  8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1  10.732871 9.6526775 z"
+       transform="matrix(1.9494387,0,0,1.2877392,-1.9230749,13.069869)" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:0.282258;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3152"
+       sodipodi:cx="9.7069349"
+       sodipodi:cy="9.6526775"
+       sodipodi:rx="1.0259361"
+       sodipodi:ry="1.9413869"
+       d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1  8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1  10.732871 9.6526775 z"
+       transform="matrix(4.8735976,0,0,2.5754783,-20.807694,-1.3602619)" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path2193"
-       sodipodi:cx="9.0598059"
-       sodipodi:cy="8.7845774"
-       sodipodi:rx="1.1679889"
-       sodipodi:ry="1.4520943"
-       d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1  7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1  10.227795 8.7845774 z"
-       transform="matrix(1.712345,0,0,2.754643,9.486483,11.80163)" />
+       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3148"
+       sodipodi:cx="9.7069349"
+       sodipodi:cy="9.6526775"
+       sodipodi:rx="1.0259361"
+       sodipodi:ry="1.9413869"
+       d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1  8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1  10.732871 9.6526775 z"
+       transform="matrix(1.9494393,0,0,1.2877392,9.0769201,13.069869)" />
     <path
-       style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;stroke-dasharray:none"
-       d="M 44.078659,9.5112136 C 34.84342,9.8834971 27.500059,15.977362 27.500059,23.405814 C 27.500059,27.671183 29.253586,32.180745 33.0662,34.729626 C 33.874807,38.292011 31.54507,41.058776 31.141507,41.494102 C 31.871844,41.290557 37.643487,39.670532 39.808221,37.260561 C 41.990193,37.168054 43.23089,37.300418 44.997262,37.300418 C 54.649949,37.300418 62.494467,31.073895 62.494465,23.405814 C 62.494465,15.737733 54.649949,9.5112136 44.997262,9.5112136 C 44.695616,9.5112136 44.37657,9.4992035 44.078659,9.5112136 z "
-       id="path13316"
-       sodipodi:nodetypes="cscccsssc" />
-    <path
-       sodipodi:type="inkscape:offset"
-       inkscape:radius="-1.0020103"
-       inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z "
-       xlink:href="#path13316"
-       style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
-       id="path13323"
-       inkscape:href="#path13316"
-       d="M 43.9375,10.5 C 35.082559,10.856667 28.28125,16.643774 28.28125,23.4375 C 28.28125,27.441186 29.946384,31.636673 33.4375,33.96875 C 33.648247,34.117093 33.793739,34.340928 33.84375,34.59375 C 34.305353,36.625753 33.873291,38.418899 33.28125,39.75 C 33.741286,39.588469 33.859625,39.584381 34.375,39.375 C 36.123726,38.664548 38.008731,37.651133 38.875,36.6875 C 39.056781,36.478508 39.316956,36.354077 39.59375,36.34375 C 41.847992,36.248256 43.128683,36.40625 44.84375,36.40625 C 54.103198,36.406251 61.406252,30.447219 61.40625,23.4375 C 61.406249,16.427779 54.105354,10.5 44.84375,10.5 C 44.5143,10.499999 44.179676,10.490245 43.9375,10.5 z " />
+       style="opacity:1;fill:#ce5c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 30,32 C 28.885686,35.996588 25.067255,39 20.5,39 C 15.932746,39 12.114315,35.996588 11,32 C 16.460075,38.82871 24.447577,38.177252 30,32 z "
+       id="path2186"
+       sodipodi:nodetypes="cscc" />
     <path
-       sodipodi:type="inkscape:offset"
-       inkscape:radius="-1.0109046"
-       inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z "
-       xlink:href="#path13316"
-       style="opacity:1;color:#000000;fill:url(#linearGradient1551);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;stroke-dasharray:none"
-       id="path1336"
-       inkscape:href="#path13316"
-       d="M 43.9375,10.5 C 35.086269,10.856517 28.28125,16.649624 28.28125,23.4375 C 28.28125,27.43874 29.949375,31.638672 33.4375,33.96875 C 33.659358,34.111954 33.816384,34.336276 33.875,34.59375 C 34.337119,36.628026 33.873842,38.417659 33.28125,39.75 C 33.741161,39.588512 33.859781,39.584317 34.375,39.375 C 36.123195,38.664763 38.010688,37.617706 38.875,36.65625 C 39.06282,36.459679 39.321894,36.347038 39.59375,36.34375 C 41.848554,36.248232 43.129202,36.40625 44.84375,36.40625 C 54.099359,36.406251 61.406252,30.441153 61.40625,23.4375 C 61.406249,16.433845 54.101534,10.5 44.84375,10.5 C 44.514064,10.499999 44.17917,10.490265 43.9375,10.5 z " />
-    <flowRoot
-       xml:space="preserve"
-       id="flowRoot2649"
-       style="font-size:20px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#204a87;font-family:Bitstream Charter"
-       transform="matrix(1.282232,0,0,1.31579,-8.49345,-11.44883)"><flowRegion
-         id="flowRegion2651"><rect
-           id="rect2653"
-           width="44.011906"
-           height="42.819229"
-           x="36.988094"
-           y="20.180773"
-           style="font-size:20px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#204a87;font-family:Bitstream Charter" /></flowRegion><flowPara
-         id="flowPara2655">?</flowPara></flowRoot>    <rect
-       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect2278"
-       width="16.246384"
-       height="1.4764884"
-       x="-2.760174"
-       y="54.321537"
-       ry="0.49634099"
-       rx="0.49687836"
-       transform="matrix(0.972407,-0.233292,0.286699,0.958021,0,0)" />
+       sodipodi:type="arc"
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2259"
+       sodipodi:cx="8.3258924"
+       sodipodi:cy="9.2232141"
+       sodipodi:rx="1.2276785"
+       sodipodi:ry="1.7410715"
+       d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499"
+       transform="matrix(3.5277688,0.705265,-0.6665314,1.855957,3.2901886,-4.1630499)"
+       sodipodi:start="3.5782199"
+       sodipodi:end="5.6135639"
+       sodipodi:open="true" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2261"
+       sodipodi:cx="8.3258924"
+       sodipodi:cy="9.2232141"
+       sodipodi:rx="1.2276785"
+       sodipodi:ry="1.7410715"
+       d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499"
+       transform="matrix(-3.5277688,0.705265,0.6665314,1.855957,37.208475,-4.1630499)"
+       sodipodi:start="3.5782199"
+       sodipodi:end="5.6135639"
+       sodipodi:open="true" />
+    <path
+       transform="translate(-2.96875,2.96875)"
+       style="font-size:19.03945923px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#204a87;fill-opacity:1;stroke:none;stroke-width:1.55613649px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Century Schoolbook L"
+       d="M 41.5625,0.03125 C 39.882592,0.03125 38.340312,0.45633843 37.125,1.3125 C 35.909688,2.1686616 35.03125,3.5773827 35.03125,5.15625 C 35.031248,6.9581536 36.509895,8.65625 38.375,8.65625 C 39.965182,8.6562496 41.5,7.3378655 41.5,5.65625 C 41.5,5.3071726 41.34266,4.9823536 41.21875,4.65625 C 41.387991,4.6997757 41.631962,4.7250666 41.6875,4.78125 C 41.780384,4.8752143 41.90625,5.0515022 41.90625,5.59375 C 41.90625,6.1652988 41.718827,6.6932831 41.46875,7.03125 C 40.561362,8.1855326 40.145637,8.7242892 39.8125,9.21875 C 39.479363,9.7132108 39.280996,10.139806 39.125,10.53125 C 39.124907,10.541666 39.124907,10.552084 39.125,10.5625 C 39.043286,10.775751 38.25,11.848298 38.25,13.46875 L 38.25,14.21875 C 38.248868,14.683225 38.432878,15.129003 38.761313,15.457437 C 39.089747,15.785872 39.535525,15.969882 40,15.96875 L 40.59375,15.96875 C 39.296693,16.363109 38.1875,17.335329 38.1875,18.78125 C 38.187498,20.599164 39.742417,21.96875 41.46875,21.96875 C 43.193995,21.968752 44.75,20.563489 44.75,18.78125 C 44.749996,17.191313 43.501537,16.129612 42.0625,15.84375 C 42.760608,15.593328 43.224284,14.929144 43.21875,14.1875 C 43.207309,13.142551 43.280625,12.715648 43.375,12.5 C 43.469375,12.284352 43.666112,12.036543 44.375,11.46875 C 44.385548,11.458466 44.395966,11.448048 44.40625,11.4375 C 45.640264,10.416457 46.472134,9.663013 47.09375,8.75 C 47.715366,7.836987 47.96875,6.7448903 47.96875,5.75 C 47.968751,4.1061365 47.251058,2.5766205 46.0625,1.5625 C 44.873942,0.5483795 43.29027,0.03125 41.5625,0.03125 z "
+       id="path3346" />
+    <path
+       id="text2395"
+       d="M 38.506782,17.184869 C 38.482313,14.953817 38.751472,14.339138 40.317489,13.087017 C 42.715448,11.106389 43.253768,10.332347 43.253768,8.7387398 C 43.253768,6.3710938 41.369653,4.7774818 38.580188,4.7774818 C 35.815195,4.7774818 33.808732,6.1889664 33.808732,8.1468275 C 33.808732,9.1485242 34.493866,9.8997976 35.399218,9.8997976 C 36.182227,9.8997976 36.793951,9.3534166 36.793951,8.6476754 C 36.793951,8.1923596 36.549258,7.8053395 36.08435,7.4410862 C 35.717315,7.1678961 35.692845,7.122364 35.692845,6.9402374 C 35.692845,6.3483259 36.769483,5.8019451 37.943996,5.8019451 C 39.681291,5.8019451 40.684521,6.8491761 40.684521,8.6021443 C 40.684521,9.5355437 40.390894,10.400647 39.901517,11.060855 C 38.09081,13.360205 38.090807,13.360208 37.772712,14.157012 C 37.528022,14.794454 37.034866,15.386368 37.034866,16.456362 L 37.034866,17.184869 L 38.506782,17.184869 M 38.512445,20.345536 C 37.65603,20.345536 36.970897,20.982982 36.970897,21.75702 C 36.970897,22.553823 37.65603,23.191268 38.487976,23.191268 C 39.344388,23.191268 40.029523,22.553823 40.029523,21.75702 C 40.029523,20.982982 39.344388,20.345536 38.512445,20.345536"
+       style="font-size:19.03945923px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#eeeeec;fill-opacity:1;stroke:#ffffff;stroke-width:1.55496371px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Century Schoolbook L" />
   </g>
 </svg>
--- a/pidgin/pixmaps/dialogs/64/scalable/warning.svg	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/pixmaps/dialogs/64/scalable/warning.svg	Fri Sep 28 16:34:43 2007 +0000
@@ -7,55 +7,35 @@
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="64"
-   height="64"
+   width="48"
+   height="48"
    id="svg2"
    sodipodi:version="0.32"
-   inkscape:version="0.43"
+   inkscape:version="0.45"
    version="1.0"
-   sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/dialogs"
+   sodipodi:docbase="/home/hbons/Desktop/2.1.1/dialogs"
    sodipodi:docname="dialog-warning.svg"
-   inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/dialogs/dialog-warning.png"
+   inkscape:export-filename="/home/hbons/Desktop/newstyle.png"
    inkscape:export-xdpi="90"
-   inkscape:export-ydpi="90">
+   inkscape:export-ydpi="90"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
   <defs
      id="defs4">
     <linearGradient
        inkscape:collect="always"
-       id="linearGradient3121">
-      <stop
-         style="stop-color:#d3d7cf;stop-opacity:1;"
-         offset="0"
-         id="stop3123" />
+       id="linearGradient3179">
       <stop
-         style="stop-color:#d3d7cf;stop-opacity:0;"
-         offset="1"
-         id="stop3125" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient3816">
-      <stop
-         style="stop-color:#000000;stop-opacity:1;"
+         style="stop-color:#555753;stop-opacity:1;"
          offset="0"
-         id="stop3818" />
+         id="stop3181" />
       <stop
-         style="stop-color:#000000;stop-opacity:0;"
+         style="stop-color:#555753;stop-opacity:0;"
          offset="1"
-         id="stop3820" />
+         id="stop3183" />
     </linearGradient>
-    <radialGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient3816"
-       id="radialGradient3822"
-       cx="31.112698"
-       cy="19.008621"
-       fx="31.112698"
-       fy="19.008621"
-       r="8.6620579"
-       gradientUnits="userSpaceOnUse" />
     <linearGradient
        inkscape:collect="always"
        id="linearGradient3104">
@@ -79,15 +59,268 @@
        r="9.975256"
        gradientUnits="userSpaceOnUse"
        gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <filter
+       inkscape:collect="always"
+       x="-0.27879593"
+       width="1.5575919"
+       y="-0.78248727"
+       height="2.5649745"
+       id="filter3405">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="1.5438116"
+         id="feGaussianBlur3407" />
+    </filter>
+    <radialGradient
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient2247"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3263">
+      <stop
+         style="stop-color:#555753;stop-opacity:1;"
+         offset="0"
+         id="stop3265" />
+      <stop
+         style="stop-color:#555753;stop-opacity:0;"
+         offset="1"
+         id="stop3267" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2216"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3263"
+       id="linearGradient3269"
+       x1="12.845698"
+       y1="16.037401"
+       x2="10.698112"
+       y2="15.449714"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3191"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
     <linearGradient
        inkscape:collect="always"
-       xlink:href="#linearGradient3121"
-       id="linearGradient1551"
+       id="linearGradient3150">
+      <stop
+         style="stop-color:#2e3436;stop-opacity:1;"
+         offset="0"
+         id="stop3152" />
+      <stop
+         style="stop-color:#2e3436;stop-opacity:0;"
+         offset="1"
+         id="stop3154" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3175"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3150"
+       id="radialGradient3156"
+       cx="10.748654"
+       cy="10.457643"
+       fx="10.748654"
+       fy="10.457643"
+       r="6.6449099"
+       gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="18.005522"
+       fx="8.7359829"
+       cy="18.005522"
+       cx="8.7359829"
+       id="radialGradient2214"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2255"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient3313"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <radialGradient
+       r="2.5781252"
+       fy="11.083743"
+       fx="17.911736"
+       cy="11.083743"
+       cx="17.911736"
+       gradientTransform="matrix(-1.591138,1.574803,-1.783257,-1.76495,68.854751,-2.8442229)"
        gradientUnits="userSpaceOnUse"
-       x1="42.925175"
-       y1="40.136646"
-       x2="42.925175"
-       y2="15.474488" />
+       id="radialGradient2259"
+       xlink:href="#linearGradient2382"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2867">
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:1;"
+         offset="0"
+         id="stop2869" />
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:0;"
+         offset="1"
+         id="stop2871" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2847">
+      <stop
+         style="stop-color:#888a85;stop-opacity:1;"
+         offset="0"
+         id="stop2849" />
+      <stop
+         style="stop-color:#888a85;stop-opacity:0;"
+         offset="1"
+         id="stop2851" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2382">
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:1;"
+         offset="0"
+         id="stop2384" />
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:0;"
+         offset="1"
+         id="stop2386" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2230"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2847"
+       id="linearGradient2853"
+       x1="12.5"
+       y1="18.202251"
+       x2="12.746171"
+       y2="20.761486"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2867"
+       id="linearGradient2873"
+       x1="12.720216"
+       y1="20.952612"
+       x2="12.720216"
+       y2="17.682426"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient2303"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2349"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
+    <radialGradient
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       gradientUnits="userSpaceOnUse"
+       r="9.975256"
+       fy="14.186539"
+       fx="8.3343515"
+       cy="14.186539"
+       cx="8.3343515"
+       id="radialGradient2233"
+       xlink:href="#linearGradient3104"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3104"
+       id="radialGradient2264"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)"
+       cx="8.3343515"
+       cy="14.186539"
+       fx="8.3343515"
+       fy="14.186539"
+       r="9.975256" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3179"
+       id="linearGradient3185"
+       x1="19.107143"
+       y1="33.892857"
+       x2="24.017857"
+       y2="33.892857"
+       gradientUnits="userSpaceOnUse" />
   </defs>
   <sodipodi:namedview
      id="base"
@@ -96,17 +329,19 @@
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="12.003863"
-     inkscape:cx="39.201403"
-     inkscape:cy="23.251521"
+     inkscape:zoom="11.2"
+     inkscape:cx="48.857979"
+     inkscape:cy="24.415118"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="true"
-     fill="#cc0000"
-     inkscape:window-width="1267"
-     inkscape:window-height="971"
-     inkscape:window-x="6"
-     inkscape:window-y="21" />
+     fill="#fce94f"
+     inkscape:window-width="1440"
+     inkscape:window-height="845"
+     inkscape:window-x="3"
+     inkscape:window-y="25"
+     width="48px"
+     height="48px" />
   <metadata
      id="metadata7">
     <rdf:RDF>
@@ -123,25 +358,25 @@
      inkscape:groupmode="layer"
      id="layer1">
     <path
-       d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1  22.45064,19.008621 A 8.6620579 8.6620579 0 1 1  39.774755 19.008621 z"
-       sodipodi:ry="8.6620579"
-       sodipodi:rx="8.6620579"
-       sodipodi:cy="19.008621"
-       sodipodi:cx="31.112698"
-       id="path4318"
-       style="opacity:0.5;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
        sodipodi:type="arc"
-       transform="matrix(2.383972,0,0,1.117487,-53.5217,33.04541)" />
+       style="opacity:0.64044949;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3405)"
+       id="path3140"
+       sodipodi:cx="10.748654"
+       sodipodi:cy="10.457643"
+       sodipodi:rx="6.6449099"
+       sodipodi:ry="2.3675451"
+       d="M 17.393564 10.457643 A 6.6449099 2.3675451 0 1 1  4.1037445,10.457643 A 6.6449099 2.3675451 0 1 1  17.393564 10.457643 z"
+       transform="matrix(2.2723916,0,0,1.6905173,-0.1758194,23.510748)" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#f57900;stroke-width:0.53913006;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#cc6400;stroke-width:0.55559433;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path1307"
        sodipodi:cx="11.806158"
        sodipodi:cy="10.983024"
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.854646,0,0,1.855034,-0.899768,22.62707)" />
+       transform="matrix(1.8043406,0,0,1.8043406,3.1976696,7.6828846)" />
     <path
        sodipodi:type="arc"
        style="opacity:0.79545456;fill:url(#radialGradient3114);fill-opacity:1;stroke:none;stroke-width:1.05274069;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
@@ -151,83 +386,96 @@
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.704217,0,0,1.704217,0.879746,24.28255)" />
+       transform="matrix(1.6958412,0,0,1.6958412,4.3182736,9.0348912)" />
     <path
        sodipodi:type="arc"
-       style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.57006598;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.58677971;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="path2184"
        sodipodi:cx="11.806158"
        sodipodi:cy="10.983024"
        sodipodi:rx="9.975256"
        sodipodi:ry="9.975256"
        d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1  1.8309021,10.983024 A 9.975256 9.975256 0 1 1  21.781414 10.983024 z"
-       transform="matrix(1.75441,0,0,1.753957,0.28417,23.73792)" />
+       transform="matrix(1.7042169,0,0,1.7042169,4.3797455,8.7825453)" />
     <path
-       style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;stroke-dasharray:none"
-       d="M 44.078659,9.5112136 C 34.84342,9.8834971 27.500059,15.977362 27.500059,23.405814 C 27.500059,27.671183 29.253586,32.180745 33.0662,34.729626 C 33.874807,38.292011 31.54507,41.058776 31.141507,41.494102 C 31.871844,41.290557 37.643487,39.670532 39.808221,37.260561 C 41.990193,37.168054 43.23089,37.300418 44.997262,37.300418 C 54.649949,37.300418 62.494467,31.073895 62.494465,23.405814 C 62.494465,15.737733 54.649949,9.5112136 44.997262,9.5112136 C 44.695616,9.5112136 44.37657,9.4992035 44.078659,9.5112136 z "
-       id="path13316"
-       sodipodi:nodetypes="cscccsssc" />
+       style="fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1"
+       d="M 23.500001,23.5 C 23.500001,26.26 21.260002,28.500001 18.500001,28.500001 C 15.740001,28.500001 13.5,26.26 13.5,23.5 C 13.5,20.74 15.740001,18.5 18.500001,18.5 C 21.260002,18.5 23.500001,20.74 23.500001,23.5 z "
+       id="path3154" />
     <path
-       sodipodi:type="inkscape:offset"
-       inkscape:radius="-1.0020103"
-       inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z "
-       xlink:href="#path13316"
-       style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
-       id="path13323"
-       inkscape:href="#path13316"
-       d="M 43.9375,10.5 C 35.082559,10.856667 28.28125,16.643774 28.28125,23.4375 C 28.28125,27.441186 29.946384,31.636673 33.4375,33.96875 C 33.648247,34.117093 33.793739,34.340928 33.84375,34.59375 C 34.305353,36.625753 33.873291,38.418899 33.28125,39.75 C 33.741286,39.588469 33.859625,39.584381 34.375,39.375 C 36.123726,38.664548 38.008731,37.651133 38.875,36.6875 C 39.056781,36.478508 39.316956,36.354077 39.59375,36.34375 C 41.847992,36.248256 43.128683,36.40625 44.84375,36.40625 C 54.103198,36.406251 61.406252,30.447219 61.40625,23.4375 C 61.406249,16.427779 54.105354,10.5 44.84375,10.5 C 44.5143,10.499999 44.179676,10.490245 43.9375,10.5 z " />
+       sodipodi:type="arc"
+       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2172"
+       sodipodi:cx="9.7069349"
+       sodipodi:cy="9.6526775"
+       sodipodi:rx="1.0259361"
+       sodipodi:ry="1.9413869"
+       d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1  8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1  10.732871 9.6526775 z"
+       transform="matrix(1.9494387,0,0,1.2877392,1.0769249,12.069869)" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:0.282258;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3152"
+       sodipodi:cx="9.7069349"
+       sodipodi:cy="9.6526775"
+       sodipodi:rx="1.0259361"
+       sodipodi:ry="1.9413869"
+       d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1  8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1  10.732871 9.6526775 z"
+       transform="matrix(4.8735976,0,0,2.5754783,-16.807694,-1.3602618)" />
     <path
-       sodipodi:type="inkscape:offset"
-       inkscape:radius="-1.0109046"
-       inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z "
-       xlink:href="#path13316"
-       style="opacity:1;color:#000000;fill:url(#linearGradient1551);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;stroke-dasharray:none"
-       id="path1336"
-       inkscape:href="#path13316"
-       d="M 43.9375,10.5 C 35.086269,10.856517 28.28125,16.649624 28.28125,23.4375 C 28.28125,27.43874 29.949375,31.638672 33.4375,33.96875 C 33.659358,34.111954 33.816384,34.336276 33.875,34.59375 C 34.337119,36.628026 33.873842,38.417659 33.28125,39.75 C 33.741161,39.588512 33.859781,39.584317 34.375,39.375 C 36.123195,38.664763 38.010688,37.617706 38.875,36.65625 C 39.06282,36.459679 39.321894,36.347038 39.59375,36.34375 C 41.848554,36.248232 43.129202,36.40625 44.84375,36.40625 C 54.099359,36.406251 61.406252,30.441153 61.40625,23.4375 C 61.406249,16.433845 54.101534,10.5 44.84375,10.5 C 44.514064,10.499999 44.17917,10.490265 43.9375,10.5 z " />
-    <flowRoot
-       xml:space="preserve"
-       id="flowRoot2649"
-       style="font-size:20px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#cc0000;font-family:Bitstream Charter"
-       transform="matrix(1.41844,0,0,1.343101,-12.30498,-12.66081)"><flowRegion
-         id="flowRegion2651"><rect
-           id="rect2653"
-           width="44.011906"
-           height="42.819229"
-           x="36.988094"
-           y="20.180773"
-           style="font-size:20px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#cc0000;font-family:Bitstream Charter" /></flowRegion><flowPara
-         id="flowPara2655">!</flowPara></flowRoot>    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3148"
+       sodipodi:cx="9.7069349"
+       sodipodi:cy="9.6526775"
+       sodipodi:rx="1.0259361"
+       sodipodi:ry="1.9413869"
+       d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1  8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1  10.732871 9.6526775 z"
+       transform="matrix(1.9494393,0,0,1.2877392,10.07692,12.069869)" />
+    <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path2193"
-       sodipodi:cx="9.0598059"
-       sodipodi:cy="8.7845774"
-       sodipodi:rx="1.1679889"
-       sodipodi:ry="1.4520943"
-       d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1  7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1  10.227795 8.7845774 z"
-       transform="matrix(1.712345,0,0,2.754643,9.486483,14.80163)" />
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2259"
+       sodipodi:cx="8.3258924"
+       sodipodi:cy="9.2232141"
+       sodipodi:rx="1.2276785"
+       sodipodi:ry="1.7410715"
+       d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499"
+       transform="matrix(3.5277688,0.705265,-0.6665314,1.855957,7.2901885,-4.1630498)"
+       sodipodi:start="3.5782199"
+       sodipodi:end="5.6135639"
+       sodipodi:open="true" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2261"
+       sodipodi:cx="8.3258924"
+       sodipodi:cy="9.2232141"
+       sodipodi:rx="1.2276785"
+       sodipodi:ry="1.7410715"
+       d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499"
+       transform="matrix(-3.5277688,0.705265,0.6665314,1.855957,41.208475,-4.1630498)"
+       sodipodi:start="3.5782199"
+       sodipodi:end="5.6135639"
+       sodipodi:open="true" />
     <path
        sodipodi:type="arc"
        style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path2191"
-       sodipodi:cx="9.0598059"
-       sodipodi:cy="8.7845774"
-       sodipodi:rx="1.1679889"
-       sodipodi:ry="1.4520943"
-       d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1  7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1  10.227795 8.7845774 z"
-       transform="matrix(1.712345,0,0,2.754643,1.486487,14.80163)" />
+       id="path3228"
+       sodipodi:cx="21.5625"
+       sodipodi:cy="33.892857"
+       sodipodi:rx="2.4553571"
+       sodipodi:ry="1.9642857"
+       d="M 24.017857 33.892857 A 2.4553571 1.9642857 0 1 1  19.107143,33.892857 A 2.4553571 1.9642857 0 1 1  24.017857 33.892857 z"
+       transform="matrix(3.0545454,0,0,2.2909093,-41.363636,-42.145461)" />
     <path
        sodipodi:type="arc"
-       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path2251"
-       sodipodi:cx="9.3754778"
-       sodipodi:cy="13.4881"
-       sodipodi:rx="6.1556172"
-       sodipodi:ry="6.1556172"
-       d="M 15.531095 13.4881 A 6.1556172 6.1556172 0 1 1  3.2198606,13.4881 A 6.1556172 6.1556172 0 1 1  15.531095 13.4881 z"
-       transform="matrix(0.97472,0,0,0.812266,11.86154,41.04407)"
-       inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90" />
+       style="opacity:1;fill:url(#linearGradient3185);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2206"
+       sodipodi:cx="21.5625"
+       sodipodi:cy="33.892857"
+       sodipodi:rx="2.4553571"
+       sodipodi:ry="1.9642857"
+       d="M 24.017857 33.892857 A 2.4553571 1.9642857 0 1 1  19.107143,33.892857 A 2.4553571 1.9642857 0 1 1  24.017857 33.892857 z"
+       transform="matrix(-3.0545454,0,0,2.2909093,90.363634,-42.145461)" />
   </g>
 </svg>
Binary file pidgin/pixmaps/dialogs/64/warning.png has changed
--- a/pidgin/pixmaps/emblems/16/Makefile.am	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/pixmaps/emblems/16/Makefile.am	Fri Sep 28 16:34:43 2007 +0000
@@ -1,6 +1,7 @@
 SUBDIRS = scalable
 
 EXTRA_DIST = 	aol-client.png \
+		birthday.png \
 		blocked.png \
 		bot.png \
 		external.png \
@@ -12,6 +13,7 @@
 		hiptop.png \
 		male.png \
 		mobile.png \
+		music.png \
 		not-authorized.png \
 		operator.png \
 		qq-member.png \
Binary file pidgin/pixmaps/emblems/16/birthday.png has changed
Binary file pidgin/pixmaps/emblems/16/music.png has changed
--- a/pidgin/pixmaps/emblems/16/scalable/Makefile.am	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/pixmaps/emblems/16/scalable/Makefile.am	Fri Sep 28 16:34:43 2007 +0000
@@ -7,6 +7,7 @@
 		game.svg \
 		male.svg \
 		mobile.svg \
+		music.svg \
 		not-authorized.svg \
 		qq-member.svg \
 		secure.svg \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pixmaps/emblems/16/scalable/music.svg	Fri Sep 28 16:34:43 2007 +0000
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="16"
+   height="16"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   sodipodi:modified="true"
+   version="1.0">
+  <defs
+     id="defs4">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3185">
+      <stop
+         style="stop-color:#4e9a06;stop-opacity:1;"
+         offset="0"
+         id="stop3187" />
+      <stop
+         style="stop-color:#4e9a06;stop-opacity:0"
+         offset="1"
+         id="stop3189" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3177">
+      <stop
+         style="stop-color:#4e9a06;stop-opacity:1;"
+         offset="0"
+         id="stop3179" />
+      <stop
+         style="stop-color:#4e9a06;stop-opacity:0;"
+         offset="1"
+         id="stop3181" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3153">
+      <stop
+         style="stop-color:#eeeeec;stop-opacity:1;"
+         offset="0"
+         id="stop3155" />
+      <stop
+         style="stop-color:#eeeeec;stop-opacity:0;"
+         offset="1"
+         id="stop3157" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3153"
+       id="linearGradient3159"
+       x1="2.5409546"
+       y1="10.048674"
+       x2="10.378205"
+       y2="15.928688"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3177"
+       id="radialGradient3183"
+       cx="5.2116022"
+       cy="8.4051199"
+       fx="5.2116022"
+       fy="8.4051199"
+       r="2.9404981"
+       gradientTransform="matrix(2.6050387,0,0,2.2888674,-8.415579,-10.767812)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3185"
+       id="radialGradient3191"
+       cx="5.1978397"
+       cy="8.4135866"
+       fx="5.1978397"
+       fy="8.4135866"
+       r="3.1428281"
+       gradientTransform="matrix(2.8202152,0,0,2.4999643,-9.461187,-12.455954)"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="22.4"
+     inkscape:cx="19.784002"
+     inkscape:cy="11.848"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="16px"
+     height="16px"
+     showgrid="true"
+     inkscape:window-width="1440"
+     inkscape:window-height="847"
+     inkscape:window-x="0"
+     inkscape:window-y="22" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#555753;fill-opacity:1;stroke:#222728;stroke-width:1.14297926;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2160"
+       sodipodi:cx="6.4712896"
+       sodipodi:cy="14.484771"
+       sodipodi:rx="3.5986683"
+       sodipodi:ry="2.1781414"
+       d="M 10.069958 14.484771 A 3.5986683 2.1781414 0 1 1  2.8726213,14.484771 A 3.5986683 2.1781414 0 1 1  10.069958 14.484771 z"
+       transform="matrix(0.8336417,0,0,0.918214,4.1052631,-0.8001194)" />
+    <rect
+       style="opacity:1;fill:#222728;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3143"
+       width="1"
+       height="12"
+       x="12"
+       y="1"
+       rx="0.18940361"
+       ry="0.20662212" />
+    <path
+       style="fill:#222728;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1"
+       d="M 12.006464,3.0203051 L 11.981638,1 C 13.945163,1 17.837365,1.1548232 14.996311,7.9684328 C 15.596089,2.2547574 13.743811,3.0203051 12.006464,3.0203051 z "
+       id="rect3146"
+       sodipodi:nodetypes="cccc" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#555753;fill-opacity:1;stroke:url(#linearGradient3159);stroke-width:1.97969818;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3151"
+       sodipodi:cx="6.4712896"
+       sodipodi:cy="14.484771"
+       sodipodi:rx="3.5986683"
+       sodipodi:ry="2.1781414"
+       d="M 10.069958 14.484771 A 3.5986683 2.1781414 0 1 1  2.8726213,14.484771 A 3.5986683 2.1781414 0 1 1  10.069958 14.484771 z"
+       transform="matrix(0.5557611,0,0,0.4591071,5.903509,5.8499391)" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:none;fill-opacity:1;stroke:url(#radialGradient3191);stroke-width:0.98568761;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3173"
+       sodipodi:cx="8.0970039"
+       sodipodi:cy="11.122857"
+       sodipodi:rx="4.3089318"
+       sodipodi:ry="3.5513175"
+       d="M 3.9729753,12.152015 A 4.3089318,3.5513175 0 0 1 9.0871283,7.6665672"
+       transform="matrix(1.0443424,0,0,0.9855497,-0.4560443,3.7870959e-2)"
+       sodipodi:start="2.8475788"
+       sodipodi:end="4.9442449"
+       sodipodi:open="true" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:none;fill-opacity:1;stroke:url(#radialGradient3183);stroke-width:0.58102763;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path3175"
+       sodipodi:cx="8.0970039"
+       sodipodi:cy="11.122857"
+       sodipodi:rx="4.3089318"
+       sodipodi:ry="3.5513175"
+       d="M 3.9729753,12.152015 A 4.3089318,3.5513175 0 0 1 9.0871283,7.6665672"
+       transform="matrix(1.6981233,0,0,1.7443645,-5.9310642,-8.697544)"
+       sodipodi:start="2.8475788"
+       sodipodi:end="4.9442449"
+       sodipodi:open="true" />
+  </g>
+</svg>
Binary file pidgin/pixmaps/protocols/16/myspace.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pixmaps/protocols/22/scalable/myspace.svg	Fri Sep 28 16:34:43 2007 +0000
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="24"
+   height="24"
+   id="svg2160"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   sodipodi:docname="myspace48.svg"
+   sodipodi:docbase="/home/hbons/Desktop"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true"
+   version="1.0">
+  <defs
+     id="defs2162">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3147">
+      <stop
+         style="stop-color:#eeeeec;stop-opacity:1;"
+         offset="0"
+         id="stop3149" />
+      <stop
+         style="stop-color:#eeeeec;stop-opacity:0;"
+         offset="1"
+         id="stop3151" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3172">
+      <stop
+         style="stop-color:#eeeeec;stop-opacity:1;"
+         offset="0"
+         id="stop3174" />
+      <stop
+         style="stop-color:#eeeeec;stop-opacity:0;"
+         offset="1"
+         id="stop3176" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3172"
+       id="linearGradient3178"
+       x1="10.549266"
+       y1="5.125"
+       x2="52.810349"
+       y2="49.864979"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3147"
+       id="linearGradient3153"
+       x1="6.0203052"
+       y1="1.0398448"
+       x2="26.101271"
+       y2="25.83909"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="9.8994949"
+     inkscape:cx="31.349135"
+     inkscape:cy="11.3794"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1440"
+     inkscape:window-height="847"
+     inkscape:window-x="3"
+     inkscape:window-y="25"
+     width="24px"
+     height="24px" />
+  <metadata
+     id="metadata2165">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:#888a85;stroke-width:1.00000012;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 17 1.5 C 15.068 1.5 13.5 3.0680001 13.5 5 C 13.5 6.932 15.068 8.5 17 8.5 C 18.932 8.5 20.499999 6.932 20.5 5 C 20.5 3.068 18.931999 1.4999999 17 1.5 z M 10.5 2.5 C 8.8439999 2.5 7.5000001 3.8439999 7.5 5.5 C 7.5 7.1559999 8.8439997 8.4999996 10.5 8.5 C 9.395701 8.5527352 8.4448563 9.5454035 7.875 10.4375 C 7.830859 8.7148111 7.161553 7.5791344 5.6875 7.5 C 6.7035586 7.4052513 7.5 6.5406823 7.5 5.5 C 7.5 4.396 6.604 3.5 5.5 3.5 C 4.396 3.5 3.4999999 4.396 3.5 5.5 C 3.5 6.5828941 4.3626534 7.4666427 5.4375 7.5 C 4.352857 7.6401732 3.5000005 8.6243123 3.5 9.875 L 3.5 14.53125 L 7.5625 14.53125 L 7.5625 18.53125 L 12.5 18.53125 L 12.5 22.5 L 21.5 22.5 C 21.499867 19.408873 21.5 16.303843 21.5 13.21875 C 21.5 10.634939 19.434134 8.53125 16.875 8.53125 C 15.587036 8.5312503 14.40291 9.424387 13.5625 10.28125 C 13.046577 9.1148819 11.916283 8.5 10.59375 8.5 C 12.205095 8.4489386 13.5 7.1236737 13.5 5.5 C 13.5 3.8440001 12.156 2.5 10.5 2.5 z "
+       id="path3149" />
+    <path
+       sodipodi:type="inkscape:offset"
+       inkscape:radius="-1.00878"
+       inkscape:original="M 17 1.5 C 15.068 1.5 13.5 3.0680001 13.5 5 C 13.5 6.932 15.068 8.5 17 8.5 C 18.932 8.5 20.499999 6.932 20.5 5 C 20.5 3.068 18.931999 1.4999999 17 1.5 z M 10.5 2.5 C 8.8439999 2.5 7.5000001 3.8439999 7.5 5.5 C 7.5 7.1559999 8.8439997 8.4999996 10.5 8.5 C 9.395701 8.5527352 8.4448563 9.5454035 7.875 10.4375 C 7.830859 8.7148111 7.161553 7.5791344 5.6875 7.5 C 6.7035586 7.4052513 7.5 6.5406823 7.5 5.5 C 7.5 4.396 6.604 3.5 5.5 3.5 C 4.396 3.5 3.4999999 4.396 3.5 5.5 C 3.5 6.5828941 4.3626534 7.4666427 5.4375 7.5 C 4.352857 7.6401732 3.5000005 8.6243123 3.5 9.875 L 3.5 14.53125 L 7.5625 14.53125 L 7.5625 18.53125 L 12.5 18.53125 L 12.5 22.5 L 21.5 22.5 C 21.499867 19.408873 21.5 16.303843 21.5 13.21875 C 21.5 10.634939 19.434134 8.53125 16.875 8.53125 C 15.587036 8.5312503 14.40291 9.424387 13.5625 10.28125 C 13.046577 9.1148819 11.916283 8.5 10.59375 8.5 C 12.205095 8.4489386 13.5 7.1236737 13.5 5.5 C 13.5 3.8440001 12.156 2.5 10.5 2.5 z "
+       style="opacity:1;fill:url(#linearGradient3153);fill-opacity:1.0;stroke:#ffffff;stroke-width:1.00000012;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path2174"
+       d="M 17,2.5 C 15.613813,2.5 14.5,3.6138135 14.5,5 C 14.5,6.3861867 15.613813,7.5 17,7.5 C 18.386187,7.5 19.499999,6.3861873 19.5,5 C 19.5,3.6138137 18.386185,2.4999999 17,2.5 z M 10.5,3.5 C 9.3898132,3.5 8.5000001,4.3898131 8.5,5.5 C 8.5,6.5997176 9.3733703,7.4835976 10.46875,7.5 C 10.499983,7.4985473 10.531267,7.4985473 10.5625,7.5 C 10.572807,7.4996734 10.583484,7.5004795 10.59375,7.5 C 11.655314,7.4504166 12.5,6.5769144 12.5,5.5 C 12.5,4.3898135 11.610187,3.5 10.5,3.5 z M 5.5,4.5 C 4.9418133,4.5 4.4999999,4.9418134 4.5,5.5 C 4.5,6.0471523 4.9293308,6.4832594 5.46875,6.5 C 5.4999831,6.4985473 5.5312669,6.4985473 5.5625,6.5 C 5.572916,6.4998387 5.583334,6.4998387 5.59375,6.5 C 6.0934659,6.4534009 6.5,6.0259981 6.5,5.5 C 6.5,4.9418133 6.0581867,4.5 5.5,4.5 z M 5.53125,8.5 C 4.98621,8.5848564 4.5000003,9.0959604 4.5,9.875 L 4.5,13.53125 L 7.5625,13.53125 C 8.1127746,13.536073 8.557677,13.980975 8.5625,14.53125 L 8.5625,17.53125 L 12.5,17.53125 C 13.050275,17.536073 13.495177,17.980975 13.5,18.53125 L 13.5,21.5 L 20.5,21.5 C 20.499928,18.739558 20.5,15.971417 20.5,13.21875 C 20.5,11.172647 18.881301,9.53125 16.875,9.53125 C 16.053394,9.5312502 15.035346,10.231141 14.28125,11 C 14.045303,11.244024 13.70246,11.353041 13.368907,11.290106 C 13.035354,11.227172 12.755806,11.000722 12.625,10.6875 C 12.280526,9.9087333 11.615906,9.5089368 10.625,9.5 C 10.614584,9.5001613 10.604166,9.5001613 10.59375,9.5 C 10.583334,9.5001613 10.572916,9.5001613 10.5625,9.5 C 10.033117,9.5252804 9.1973144,10.219569 8.71875,10.96875 C 8.4774641,11.327111 8.0347855,11.49207 7.6178253,11.378996 C 7.2008651,11.265922 6.9021772,10.899915 6.875,10.46875 C 6.8561284,9.7322475 6.6929787,9.2126452 6.5,8.9375 C 6.312535,8.6702161 6.1126513,8.5308317 5.65625,8.5 C 5.645834,8.5001613 5.635416,8.5001613 5.625,8.5 C 5.5937669,8.5014527 5.5624831,8.5014527 5.53125,8.5 L 5.53125,8.5 z " />
+  </g>
+</svg>
Binary file pidgin/pixmaps/protocols/48/myspace.png has changed
Binary file pidgin/pixmaps/status/16/available.png has changed
Binary file pidgin/pixmaps/status/16/away.png has changed
Binary file pidgin/pixmaps/status/16/busy.png has changed
Binary file pidgin/pixmaps/status/16/extended-away.png has changed
Binary file pidgin/pixmaps/status/16/offline.png has changed
Binary file pidgin/pixmaps/status/16/rtl/extended-away.png has changed
--- a/pidgin/pixmaps/status/16/scalable/available.svg	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/pixmaps/status/16/scalable/available.svg	Fri Sep 28 16:34:43 2007 +0000
@@ -13,13 +13,15 @@
    height="16"
    id="svg2"
    sodipodi:version="0.32"
-   inkscape:version="0.44.1"
+   inkscape:version="0.45"
    version="1.0"
    inkscape:export-filename="/home/hbons/GUI/Tango/Gaim Refresh/status/16/available.png"
    inkscape:export-xdpi="90"
    inkscape:export-ydpi="90"
-   sodipodi:docbase="/home/hbons/Desktop/experiment/status/16/scalable"
-   sodipodi:docname="available.svg">
+   sodipodi:docbase="/home/hbons/Desktop/2.1.1/status/16/scalable"
+   sodipodi:docname="available.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
   <defs
      id="defs4">
     <linearGradient
@@ -246,7 +248,7 @@
      inkscape:window-width="1274"
      inkscape:window-height="844"
      inkscape:window-x="3"
-     inkscape:window-y="0" />
+     inkscape:window-y="25" />
   <metadata
      id="metadata7">
     <rdf:RDF>
@@ -263,16 +265,6 @@
      inkscape:groupmode="layer"
      id="layer1">
     <path
-       d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1  22.45064,19.008621 A 8.6620579 8.6620579 0 1 1  39.774755 19.008621 z"
-       sodipodi:ry="8.6620579"
-       sodipodi:rx="8.6620579"
-       sodipodi:cy="19.008621"
-       sodipodi:cx="31.112698"
-       id="path2969"
-       style="color:black;fill:url(#radialGradient3025);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
-       sodipodi:type="arc"
-       transform="matrix(0.923568,0,0,0.173169,-20.73469,11.2083)" />
-    <path
        transform="matrix(0.538297,0,0,0.538297,-1.630177,-1.459246)"
        style="fill:url(#linearGradient4738);fill-opacity:1;fill-rule:evenodd;stroke:#306300;stroke-width:1.85770929;stroke-miterlimit:4;stroke-opacity:1"
        d="M 31.822886,17.572527 C 31.822886,25.263442 25.580983,31.505344 17.890068,31.505344 C 10.199153,31.505344 3.9572506,25.263442 3.9572506,17.572527 C 3.9572506,9.8816117 10.199153,3.6397095 17.890068,3.6397095 C 25.580983,3.6397095 31.822886,9.8816117 31.822886,17.572527 z "
--- a/pidgin/pixmaps/status/16/scalable/away.svg	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/pixmaps/status/16/scalable/away.svg	Fri Sep 28 16:34:43 2007 +0000
@@ -13,13 +13,15 @@
    height="16"
    id="svg2"
    sodipodi:version="0.32"
-   inkscape:version="0.44.1"
+   inkscape:version="0.45"
    version="1.0"
    inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/16/available16.png"
    inkscape:export-xdpi="90"
    inkscape:export-ydpi="90"
-   sodipodi:docbase="/home/hbons/Desktop/2.0.2/pidgin/pixmaps/status/16/scalable"
-   sodipodi:docname="away.svg">
+   sodipodi:docbase="/home/hbons/Desktop/2.1.1/status/16/scalable"
+   sodipodi:docname="away.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
   <defs
      id="defs4">
     <linearGradient
@@ -123,8 +125,8 @@
      fill="#eeeeec"
      inkscape:window-width="1434"
      inkscape:window-height="840"
-     inkscape:window-x="0"
-     inkscape:window-y="0"
+     inkscape:window-x="3"
+     inkscape:window-y="25"
      inkscape:object-paths="false"
      inkscape:grid-bbox="true"
      inkscape:guide-bbox="false"
@@ -145,16 +147,6 @@
      inkscape:groupmode="layer"
      id="layer1">
     <path
-       d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1  22.45064,19.008621 A 8.6620579 8.6620579 0 1 1  39.774755 19.008621 z"
-       sodipodi:ry="8.6620579"
-       sodipodi:rx="8.6620579"
-       sodipodi:cy="19.008621"
-       sodipodi:cx="31.112698"
-       id="path4318"
-       style="opacity:1;color:black;fill:url(#radialGradient2818);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
-       sodipodi:type="arc"
-       transform="matrix(0.923568,0,0,0.173169,-20.73469,11.2083)" />
-    <path
        sodipodi:type="arc"
        style="opacity:1;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#173867;stroke-width:1.91314828px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
        id="path1339"
--- a/pidgin/pixmaps/status/16/scalable/busy.svg	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/pixmaps/status/16/scalable/busy.svg	Fri Sep 28 16:34:43 2007 +0000
@@ -13,13 +13,15 @@
    height="16"
    id="svg2"
    sodipodi:version="0.32"
-   inkscape:version="0.44.1"
+   inkscape:version="0.45"
    version="1.0"
    inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/16/available16.png"
    inkscape:export-xdpi="90"
    inkscape:export-ydpi="90"
-   sodipodi:docbase="/home/hbons/Desktop/experiment/status/16/scalable"
-   sodipodi:docname="busy.svg">
+   sodipodi:docbase="/home/hbons/Desktop/2.1.1/status/16/scalable"
+   sodipodi:docname="busy.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
   <defs
      id="defs4">
     <linearGradient
@@ -192,8 +194,8 @@
      fill="#eeeeec"
      inkscape:window-width="1268"
      inkscape:window-height="844"
-     inkscape:window-x="6"
-     inkscape:window-y="0" />
+     inkscape:window-x="3"
+     inkscape:window-y="25" />
   <metadata
      id="metadata7">
     <rdf:RDF>
@@ -210,16 +212,6 @@
      inkscape:groupmode="layer"
      id="layer1">
     <path
-       d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1  22.45064,19.008621 A 8.6620579 8.6620579 0 1 1  39.774755 19.008621 z"
-       sodipodi:ry="8.6620579"
-       sodipodi:rx="8.6620579"
-       sodipodi:cy="19.008621"
-       sodipodi:cx="31.112698"
-       id="path2969"
-       style="color:black;fill:url(#radialGradient3025);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
-       sodipodi:type="arc"
-       transform="matrix(0.923568,0,0,0.173169,-20.73469,11.2083)" />
-    <path
        sodipodi:type="arc"
        style="opacity:1;color:#000000;fill:#ef2929;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36561811px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
        id="path1311"
--- a/pidgin/pixmaps/status/16/scalable/extended-away.svg	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/pixmaps/status/16/scalable/extended-away.svg	Fri Sep 28 16:34:43 2007 +0000
@@ -13,12 +13,14 @@
    height="16px"
    id="svg4245"
    sodipodi:version="0.32"
-   inkscape:version="0.44.1"
-   sodipodi:docbase="/home/hbons/GUI/Tango/Gaim Refresh/status/16/scalable"
+   inkscape:version="0.45"
+   sodipodi:docbase="/home/hbons/Desktop/2.1.1/status/16/scalable"
    sodipodi:docname="extended-away.svg"
    inkscape:export-filename="/home/hbons/GUI/Tango/Gaim Refresh/status/16/extended-away.png"
    inkscape:export-xdpi="90"
-   inkscape:export-ydpi="90">
+   inkscape:export-ydpi="90"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
   <defs
      id="defs4247">
     <linearGradient
@@ -53,16 +55,16 @@
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
      inkscape:zoom="22.197802"
-     inkscape:cx="8"
-     inkscape:cy="9.6246122"
+     inkscape:cx="14.39703"
+     inkscape:cy="8.273127"
      inkscape:current-layer="layer1"
      showgrid="true"
      inkscape:grid-bbox="true"
      inkscape:document-units="px"
-     inkscape:window-width="872"
-     inkscape:window-height="626"
-     inkscape:window-x="129"
-     inkscape:window-y="124" />
+     inkscape:window-width="1440"
+     inkscape:window-height="847"
+     inkscape:window-x="0"
+     inkscape:window-y="22" />
   <metadata
      id="metadata4250">
     <rdf:RDF>
@@ -79,27 +81,17 @@
      inkscape:label="Layer 1"
      inkscape:groupmode="layer">
     <path
-       sodipodi:type="arc"
-       style="fill:url(#radialGradient5300);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.81530744;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path5131"
-       sodipodi:cx="11.756953"
-       sodipodi:cy="17.588654"
-       sodipodi:rx="6.3436799"
-       sodipodi:ry="3.9753728"
-       d="M 18.100633 17.588654 A 6.3436799 3.9753728 0 1 1  5.4132733,17.588654 A 6.3436799 3.9753728 0 1 1  18.100633 17.588654 z"
-       transform="matrix(-1.024642,0,0,0.754646,19.54667,-0.273206)" />
-    <path
-       transform="matrix(-1.708738,0,0,1.647118,-1.878642,-0.867731)"
        style="fill:#fce94f;fill-opacity:1;stroke:#ce5c00;stroke-width:0.59607363;stroke-miterlimit:4;stroke-opacity:1"
        d="M -9,3.2233667 L -7.134588,1.4374993 L -2.89508,1.4374993 C -2.3096744,1.4374993 -1.9824877,1.8329068 -1.9824877,2.3263196 L -1.9824877,9.3300741 L -9,9.3300741 L -9,3.2233667 z "
        id="rect5097"
-       sodipodi:nodetypes="ccccccc" />
+       sodipodi:nodetypes="ccccccc"
+       transform="matrix(-1.708738,0,0,1.647118,-1.878642,-0.867731)" />
     <path
-       transform="matrix(-1.398059,0,0,1.342047,-8.253506e-2,0.574281)"
        style="opacity:0.5625;fill:none;fill-opacity:1;stroke:#eeeeec;stroke-width:0.7300511;stroke-miterlimit:4;stroke-opacity:1"
        d="M -8.9656284,3.1521999 L -7.1361003,1.4267646 L -1.8535964,1.4374993 L -1.8535964,9.6313422 L -9,9.6313422 L -8.9656284,3.1521999 z "
        id="rect5099"
-       sodipodi:nodetypes="cccccc" />
+       sodipodi:nodetypes="cccccc"
+       transform="matrix(-1.398059,0,0,1.342047,-8.253506e-2,0.574281)" />
     <rect
        style="opacity:0.4;fill:#ce5c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        id="rect5988"
--- a/pidgin/pixmaps/status/16/scalable/offline.svg	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/pixmaps/status/16/scalable/offline.svg	Fri Sep 28 16:34:43 2007 +0000
@@ -13,13 +13,15 @@
    height="16"
    id="svg2"
    sodipodi:version="0.32"
-   inkscape:version="0.44.1"
+   inkscape:version="0.45"
    version="1.0"
    inkscape:export-filename="/home/hbons/Desktop/offline.png"
    inkscape:export-xdpi="90"
    inkscape:export-ydpi="90"
-   sodipodi:docbase="/home/hbons/Desktop/experiment/status/16/scalable"
-   sodipodi:docname="offline.svg">
+   sodipodi:docbase="/home/hbons/Desktop/2.1.1/status/16/scalable"
+   sodipodi:docname="offline.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
   <defs
      id="defs4">
     <linearGradient
@@ -168,8 +170,8 @@
      fill="#eeeeec"
      inkscape:window-width="1434"
      inkscape:window-height="844"
-     inkscape:window-x="0"
-     inkscape:window-y="0" />
+     inkscape:window-x="3"
+     inkscape:window-y="25" />
   <metadata
      id="metadata7">
     <rdf:RDF>
@@ -186,16 +188,6 @@
      inkscape:groupmode="layer"
      id="layer1">
     <path
-       d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1  22.45064,19.008621 A 8.6620579 8.6620579 0 1 1  39.774755 19.008621 z"
-       sodipodi:ry="8.6620579"
-       sodipodi:rx="8.6620579"
-       sodipodi:cy="19.008621"
-       sodipodi:cx="31.112698"
-       id="path4318"
-       style="opacity:0.7;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
-       sodipodi:type="arc"
-       transform="matrix(0.923568,0,0,0.288615,-20.73469,8.013827)" />
-    <path
        style="fill:#888a85;fill-opacity:1;stroke:#2e3436;stroke-width:0.99999827;stroke-miterlimit:4;stroke-opacity:1"
        d="M 13.307074,13.307079 C 10.376958,16.237198 5.6213214,16.237693 2.6918157,13.308187 C -0.23769028,10.378679 -0.23719421,5.623042 2.692923,2.6929237 C 5.62304,-0.23719442 10.378675,-0.23769056 13.308181,2.6918165 C 16.237687,5.6213234 16.237192,10.376962 13.307074,13.307079 z "
        id="path2187" />
Binary file pidgin/pixmaps/toolbar/16/emote-select.png has changed
Binary file pidgin/pixmaps/toolbar/16/insert.png has changed
Binary file pidgin/pixmaps/toolbar/16/send-file.png has changed
--- a/pidgin/plugins/history.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/plugins/history.c	Fri Sep 28 16:34:43 2007 +0000
@@ -45,6 +45,9 @@
 
 	convtype = purple_conversation_get_type(c);
 	gtkconv = PIDGIN_CONVERSATION(c);
+	if (gtkconv == NULL)
+		return;
+
 	if (convtype == PURPLE_CONV_TYPE_IM && g_list_length(gtkconv->convs) < 2)
 	{
 		GSList *buddies;
@@ -163,6 +166,7 @@
 	purple_signal_connect(purple_conversations_get_handle(),
 						"conversation-created",
 						plugin, PURPLE_CALLBACK(historize), NULL);
+	/* XXX: Do we want to listen to pidgin's "conversation-displayed" signal? */
 
 	purple_prefs_connect_callback(plugin, "/purple/logging/log_ims",
 								history_prefs_cb, plugin);
--- a/pidgin/plugins/pidginrc.c	Fri Sep 28 16:32:28 2007 +0000
+++ b/pidgin/plugins/pidginrc.c	Fri Sep 28 16:34:43 2007 +0000
@@ -57,22 +57,16 @@
 
 static const gchar *font_prefs[] = {
 	"/plugins/gtk/purplerc/font/*pidgin_conv_entry",
-	"/plugins/gtk/purplerc/font/*pidgin_conv_imhtml",
-	"/plugins/gtk/purplerc/font/*pidgin_log_imhtml",
 	"/plugins/gtk/purplerc/font/*pidgin_request_imhtml",
 	"/plugins/gtk/purplerc/font/*pidgin_notify_imhtml",
 };
 static const gchar *font_prefs_set[] = {
 	"/plugins/gtk/purplerc/set/font/*pidgin_conv_entry",
-	"/plugins/gtk/purplerc/set/font/*pidgin_conv_imhtml",
-	"/plugins/gtk/purplerc/set/font/*pidgin_log_imhtml",
 	"/plugins/gtk/purplerc/set/font/*pidgin_request_imhtml",
 	"/plugins/gtk/purplerc/set/font/*pidgin_notify_imhtml",
 };
 static const gchar *font_names[] = {
 	N_("Conversation Entry"),
-	N_("Conversation History"),
-	N_("Log Viewer"),
 	N_("Request Dialog"),
 	N_("Notify Dialog")
 };
--- a/po/POTFILES.in	Fri Sep 28 16:32:28 2007 +0000
+++ b/po/POTFILES.in	Fri Sep 28 16:34:43 2007 +0000
@@ -91,11 +91,13 @@
 libpurple/protocols/jabber/usermood.c
 libpurple/protocols/jabber/usernick.c
 libpurple/protocols/jabber/xdata.c
+libpurple/protocols/msn/contact.c
 libpurple/protocols/msn/dialog.c
 libpurple/protocols/msn/error.c
 libpurple/protocols/msn/msn.c
 libpurple/protocols/msn/nexus.c
 libpurple/protocols/msn/notification.c
+libpurple/protocols/msn/oim.c
 libpurple/protocols/msn/servconn.c
 libpurple/protocols/msn/session.c
 libpurple/protocols/msn/state.c