changeset 23509:1ac5faa72c8d

explicit merge of '9d90ebdb7e38fdd77bb504bc3302a083616360d9' and '547cd65fb6e1faeb37d88730f0dbf45075a08426' to branch 'im.pidgin.cpw.qulogic.msn'
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Sat, 07 Jun 2008 03:10:15 +0000
parents 99b4470a763e (current diff) 06b491a23d19 (diff)
children 1d97298ccff5
files libpurple/protocols/msn/contact.c libpurple/protocols/msn/contact.h libpurple/protocols/msn/msn.c libpurple/protocols/msn/msnutils.c libpurple/protocols/msn/notification.c libpurple/protocols/msn/notification.h libpurple/protocols/msn/oim.c libpurple/protocols/msn/soap.c libpurple/protocols/msn/userlist.c libpurple/protocols/zephyr/zephyr.h
diffstat 17 files changed, 1125 insertions(+), 570 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/msn/contact.c	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/contact.c	Sat Jun 07 03:10:15 2008 +0000
@@ -1,5 +1,5 @@
 /**
- * @file contact.c
+ * @file contact.c 
  * 	get MSN contacts via SOAP request
  *	created by MaYuan<mayuan2006@gmail.com>
  *
@@ -29,6 +29,7 @@
 #include "xmlnode.h"
 #include "group.h"
 #include "soap2.h"
+#include "nexus.h"
 
 const char *MsnSoapPartnerScenarioText[] =
 {
@@ -49,29 +50,10 @@
 };
 
 typedef struct {
-	MsnContact *contact;
+	MsnSession *session;
 	MsnSoapPartnerScenario which;
 } GetContactListCbData;
 
-/* new a contact */
-MsnContact *
-msn_contact_new(MsnSession *session)
-{
-	MsnContact *contact;
-
-	contact = g_new0(MsnContact, 1);
-	contact->session = session;
-
-	return contact;
-}
-
-/* destroy the contact */
-void
-msn_contact_destroy(MsnContact *contact)
-{
-	g_free(contact);
-}
-
 MsnCallbackState *
 msn_callback_state_new(MsnSession *session)
 {
@@ -200,33 +182,34 @@
 static void
 msn_create_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data)
 {
-	if (resp && msn_soap_xml_get(resp->xml, "Body/Fault") == NULL) {
+	if (resp && xmlnode_get_child(resp->xml, "Body/Fault") == NULL) {
 		purple_debug_info("msnab", "Address Book successfully created!\n");
-		msn_get_address_book((MsnContact *)data, MSN_PS_INITIAL, NULL, NULL);
+		msn_get_address_book((MsnSession *)data, MSN_PS_INITIAL, NULL, NULL);
 	} else {
 		purple_debug_info("msnab", "Address Book creation failed!\n");
 	}
 }
 
 static void
-msn_create_address_book(MsnContact * contact)
+msn_create_address_book(MsnSession *session)
 {
 	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);
-
+	g_return_if_fail(session != NULL);
+	g_return_if_fail(session->user != NULL);
+	g_return_if_fail(session->user->passport != NULL);
+	
 	purple_debug_info("msnab","Creating an Address Book.\n");
 
-	body = g_strdup_printf(MSN_ADD_ADDRESSBOOK_TEMPLATE, contact->session->user->passport);
+	body = g_strdup_printf(MSN_ADD_ADDRESSBOOK_TEMPLATE,
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS),
+		session->user->passport);
 
-	msn_soap_message_send(contact->session,
+	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_ADD_ADDRESSBOOK_SOAP_ACTION,
 			xmlnode_from_str(body, -1)),
 		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, msn_create_address_cb,
-		contact);
+		session);
 
 	g_free(body);
 }
@@ -259,7 +242,7 @@
 {
 	xmlnode *type;
 
-	if ((type = msn_soap_xml_get(service, "Info/Handle/Type"))) {
+	if ((type = xmlnode_get_child(service, "Info/Handle/Type"))) {
 		char *type_str = xmlnode_get_data(type);
 
 		if (g_str_equal(type_str, "Profile")) {
@@ -273,7 +256,7 @@
 			purple_account_set_string(session->account,	"CLLastChange",
 				lastchange_str);
 
-			for (membership = msn_soap_xml_get(service,
+			for (membership = xmlnode_get_child(service,
 					"Memberships/Membership");
 				 membership; membership = xmlnode_get_next_twin(membership)) {
 
@@ -285,7 +268,7 @@
 				purple_debug_info("msncl", "MemberRole role: %s, list: %d\n",
 					role_str, list);
 
-				for (member = msn_soap_xml_get(membership, "Members/Member");
+				for (member = xmlnode_get_child(membership, "Members/Member");
 					 member; member = xmlnode_get_next_twin(member)) {
 					const char *member_type = xmlnode_get_attrib(member, "type");
 					if (g_str_equal(member_type, "PassportMember")) {
@@ -310,7 +293,7 @@
 
 /*parse contact list*/
 static void
-msn_parse_contact_list(MsnContact *contact, xmlnode *node)
+msn_parse_contact_list(MsnSession *session, xmlnode *node)
 {
 	xmlnode *fault, *faultnode;
 
@@ -321,18 +304,18 @@
 	 *
 	 * this is not handled yet
 	 */
-	if ((fault = msn_soap_xml_get(node, "Body/Fault"))) {
+	if ((fault = xmlnode_get_child(node, "Body/Fault"))) {
 		if ((faultnode = xmlnode_get_child(fault, "faultstring"))) {
 			char *faultstring = xmlnode_get_data(faultnode);
 			purple_debug_info("msncl", "Retrieving contact list failed: %s\n",
 				faultstring);
 			g_free(faultstring);
 		}
-		if ((faultnode = msn_soap_xml_get(fault, "detail/errorcode"))) {
+		if ((faultnode = xmlnode_get_child(fault, "detail/errorcode"))) {
 			char *errorcode = xmlnode_get_data(faultnode);
 
 			if (g_str_equal(errorcode, "ABDoesNotExist")) {
-				msn_create_address_book(contact);
+				msn_create_address_book(session);
 				g_free(errorcode);
 				return;
 			}
@@ -340,14 +323,14 @@
 			g_free(errorcode);
 		}
 
-		msn_get_contact_list(contact, MSN_PS_INITIAL, NULL);
+		msn_get_contact_list(session, MSN_PS_INITIAL, NULL);
 	} else {
 		xmlnode *service;
 
-		for (service = msn_soap_xml_get(node, "Body/FindMembershipResponse/"
+		for (service = xmlnode_get_child(node, "Body/FindMembershipResponse/"
 				"FindMembershipResult/Services/Service");
 			 service; service = xmlnode_get_next_twin(service)) {
-			msn_parse_each_service(contact->session, service);
+			msn_parse_each_service(session, service);
 		}
 	}
 }
@@ -357,8 +340,7 @@
 	gpointer data)
 {
 	GetContactListCbData *cb_data = data;
-	MsnContact *contact = cb_data->contact;
-	MsnSession *session = contact->session;
+	MsnSession *session = cb_data->session;
 
 	g_return_if_fail(session != NULL);
 
@@ -368,7 +350,7 @@
 
 		purple_debug_misc("msncl","Got the contact list!\n");
 
-		msn_parse_contact_list(cb_data->contact, resp->xml);
+		msn_parse_contact_list(session, resp->xml);
 		abLastChange = purple_account_get_string(session->account,
 			"ablastChange", NULL);
 		dynamicItemLastChange = purple_account_get_string(session->account,
@@ -379,9 +361,9 @@
 			/* 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);
+			msn_get_address_book(session, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange);
 #else
-			msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL);
+			msn_get_address_book(session, MSN_PS_INITIAL, NULL, NULL);
 #endif
 		}
 	}
@@ -391,12 +373,12 @@
 
 /*SOAP  get contact list*/
 void
-msn_get_contact_list(MsnContact * contact,
+msn_get_contact_list(MsnSession *session,
 	const MsnSoapPartnerScenario partner_scenario, const char *update_time)
 {
 	gchar *body = NULL;
 	gchar *update_str = NULL;
-	GetContactListCbData cb_data = { contact, partner_scenario };
+	GetContactListCbData cb_data = { session, partner_scenario };
 	const gchar *partner_scenario_str = MsnSoapPartnerScenarioText[partner_scenario];
 
 	purple_debug_misc("MSNCL","Getting Contact List.\n");
@@ -406,9 +388,11 @@
 		update_str = g_strdup_printf(MSN_GET_CONTACT_UPDATE_XML,update_time);
 	}
 
-	body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, update_str ? update_str : "");
+	body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str,
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS),
+		update_str ? update_str : "");
 
-	msn_soap_message_send(contact->session,
+	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_GET_CONTACT_SOAP_ACTION,
 			xmlnode_from_str(body, -1)),
 		MSN_CONTACT_SERVER, MSN_GET_CONTACT_POST_URL,
@@ -419,9 +403,8 @@
 }
 
 static void
-msn_parse_addressbook_groups(MsnContact *contact, xmlnode *node)
+msn_parse_addressbook_groups(MsnSession *session, xmlnode *node)
 {
-	MsnSession *session = contact->session;
 	xmlnode *group;
 
 	purple_debug_info("MSNAB","msn_parse_addressbook_groups()\n");
@@ -507,9 +490,8 @@
 }
 
 static void
-msn_parse_addressbook_contacts(MsnContact *contact, xmlnode *node)
+msn_parse_addressbook_contacts(MsnSession *session, xmlnode *node)
 {
-	MsnSession *session = contact->session;
 	xmlnode *contactNode;
 	char *passport = NULL, *Name = NULL, *uid = NULL, *type = NULL, *mobile_number = NULL;
 	gboolean mobile = FALSE;
@@ -655,18 +637,15 @@
 }
 
 static gboolean
-msn_parse_addressbook(MsnContact * contact, xmlnode *node)
+msn_parse_addressbook(MsnSession *session, xmlnode *node)
 {
-	MsnSession * session;
 	xmlnode *result;
 	xmlnode *groups;
 	xmlnode *contacts;
 	xmlnode *abNode;
 	xmlnode *fault;
 
-	session = contact->session;
-
-	if ((fault = msn_soap_xml_get(node, "Body/Fault"))) {
+	if ((fault = xmlnode_get_child(node, "Body/Fault"))) {
 		xmlnode *faultnode;
 
 		if ((faultnode = xmlnode_get_child(fault, "faultstring"))) {
@@ -675,7 +654,7 @@
 			g_free(faultstring);
 		}
 
-		if ((faultnode = msn_soap_xml_get(fault, "detail/errorcode"))) {
+		if ((faultnode = xmlnode_get_child(fault, "detail/errorcode"))) {
 			gchar *errorcode = xmlnode_get_data(faultnode);
 
 			purple_debug_info("MSNAB", "Error Code: %s\n", errorcode);
@@ -690,7 +669,7 @@
 		return FALSE;
 	}
 
-	result = msn_soap_xml_get(node, "Body/ABFindAllResponse/ABFindAllResult");
+	result = xmlnode_get_child(node, "Body/ABFindAllResponse/ABFindAllResult");
 	if(result == NULL){
 		purple_debug_misc("MSNAB","receive no address book update\n");
 		return TRUE;
@@ -701,7 +680,7 @@
 	/*Process Group List*/
 	groups = xmlnode_get_child(result,"groups");
 	if (groups != NULL) {
-		msn_parse_addressbook_groups(contact, groups);
+		msn_parse_addressbook_groups(session, groups);
 	}
 
 	/*add a default No group to set up the no group Membership*/
@@ -726,7 +705,7 @@
 	purple_debug_info("MSNAB","process contact list...\n");
 	contacts =xmlnode_get_child(result,"contacts");
 	if (contacts != NULL) {
-		msn_parse_addressbook_contacts(contact, contacts);
+		msn_parse_addressbook_contacts(session, contacts);
 	}
 
 	abNode =xmlnode_get_child(result,"ab");
@@ -753,19 +732,16 @@
 static void
 msn_get_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data)
 {
-	MsnContact *contact = data;
-	MsnSession *session;
+	MsnSession *session = data;
 
 	if (resp == NULL)
 		return;
 
-	g_return_if_fail(contact != NULL);
-	session = contact->session;
 	g_return_if_fail(session != NULL);
 
 	purple_debug_misc("MSNAB", "Got the Address Book!\n");
 
-	if (msn_parse_addressbook(contact, resp->xml)) {
+	if (msn_parse_addressbook(session, resp->xml)) {
 		if (!session->logged_in) {
 			msn_send_privacy(session->account->gc);
 			msn_notification_dump_contact(session);
@@ -776,7 +752,7 @@
 		  send timestamps)
 		*/
 		/*
-		msn_get_address_book(contact, NULL, NULL);
+		msn_get_address_book(session, NULL, NULL);
 		*/
 		msn_session_disconnect(session);
 		purple_connection_error_reason(session->account->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to retrieve MSN Address Book"));
@@ -785,7 +761,7 @@
 
 /*get the address book*/
 void
-msn_get_address_book(MsnContact *contact,
+msn_get_address_book(MsnSession *session,
 	MsnSoapPartnerScenario partner_scenario, const char *LastChanged,
 	const char *dynamicItemLastChange)
 {
@@ -799,13 +775,16 @@
 	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 : "");
+	body = g_strdup_printf(MSN_GET_ADDRESS_TEMPLATE,
+		MsnSoapPartnerScenarioText[partner_scenario],
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS),
+		update_str ? update_str : "");
 
-	msn_soap_message_send(contact->session,
+	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_GET_ADDRESS_SOAP_ACTION,
 			xmlnode_from_str(body, -1)),
 		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, msn_get_address_cb,
-		contact);
+		session);
 
 	g_free(update_str);
 	g_free(body);
@@ -844,7 +823,7 @@
 
 /* add a Contact in MSN_INDIVIDUALS_GROUP */
 void
-msn_add_contact(MsnContact *contact, MsnCallbackState *state, const char *passport)
+msn_add_contact(MsnSession *session, MsnCallbackState *state, const char *passport)
 {
 	gchar *body = NULL;
 	gchar *contact_xml = NULL;
@@ -864,9 +843,11 @@
 	purple_debug_info("MSNCL","Adding contact %s to contact list\n", passport);
 
 	contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport);
-	body = g_strdup_printf(MSN_ADD_CONTACT_TEMPLATE, contact_xml);
+	body = g_strdup_printf(MSN_ADD_CONTACT_TEMPLATE,
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS),
+		contact_xml);
 
-	msn_soap_message_send(contact->session,
+	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_CONTACT_ADD_SOAP_ACTION,
 			xmlnode_from_str(body, -1)),
 		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
@@ -906,14 +887,14 @@
 	        msn_notification_send_fqy(state->session, state->who);
 
 			if (msn_userlist_user_is_in_list(user, MSN_LIST_PL)) {
-				msn_del_contact_from_list(state->session->contact, NULL, state->who, MSN_LIST_PL);
+				msn_del_contact_from_list(state->session, NULL, state->who, MSN_LIST_PL);
 				msn_callback_state_free(state);
 				return;
 			}
 		}
 
 		if (state->action & MSN_MOVE_BUDDY) {
-			msn_del_contact_from_group(state->session->contact, state->who, state->old_group_name);
+			msn_del_contact_from_group(state->session, state->who, state->old_group_name);
 		}
 	}
 
@@ -921,7 +902,7 @@
 }
 
 void
-msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state,
+msn_add_contact_to_group(MsnSession *session, MsnCallbackState *state,
 			 const char *passport, const char *groupId)
 {
 	MsnUserList *userlist;
@@ -931,24 +912,22 @@
 	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);
+	g_return_if_fail(session != NULL);
 
-	userlist = contact->session->userlist;
+	userlist = 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);
+			msn_add_contact(session, 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);
+			msn_del_contact_from_group(session, passport, state->old_group_name);
 		} else {
 			msn_callback_state_free(state);
 		}
@@ -972,7 +951,9 @@
 		contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport);
 	}
 
-	body = g_strdup_printf(MSN_ADD_CONTACT_GROUP_TEMPLATE, groupId, contact_xml);
+	body = g_strdup_printf(MSN_ADD_CONTACT_GROUP_TEMPLATE,
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS),
+		groupId, contact_xml);
 
 	msn_soap_message_send(state->session,
 		msn_soap_message_new(MSN_ADD_CONTACT_GROUP_SOAP_ACTION,
@@ -1006,7 +987,7 @@
 
 /*delete a Contact*/
 void
-msn_delete_contact(MsnContact *contact, const char *contactId)
+msn_delete_contact(MsnSession *session, const char *contactId)
 {
 	gchar *body = NULL;
 	gchar *contact_id_xml = NULL ;
@@ -1015,13 +996,16 @@
 	g_return_if_fail(contactId != NULL);
 	contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, contactId);
 
-	state = msn_callback_state_new(contact->session);
+	state = msn_callback_state_new(session);
 	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);
-	msn_soap_message_send(contact->session,
+	body = g_strdup_printf(MSN_DEL_CONTACT_TEMPLATE,
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS),
+		contact_id_xml);
+
+	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_CONTACT_DEL_SOAP_ACTION,
 			xmlnode_from_str(body, -1)),
 		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
@@ -1050,7 +1034,7 @@
 }
 
 void
-msn_del_contact_from_group(MsnContact *contact, const char *passport, const char *group_name)
+msn_del_contact_from_group(MsnSession *session, const char *passport, const char *group_name)
 {
 	MsnUserList * userlist;
 	MsnUser *user;
@@ -1060,11 +1044,9 @@
 
 	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);
+	g_return_if_fail(session != NULL);
 
-	userlist = contact->session->userlist;
+	userlist = session->userlist;
 
 	groupId = msn_userlist_find_group_id(userlist, group_name);
 	if (groupId != NULL) {
@@ -1086,15 +1068,17 @@
 		return;
 	}
 
-	state = msn_callback_state_new(contact->session);
+	state = msn_callback_state_new(session);
 	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);
+	body = g_strdup_printf(MSN_CONTACT_DEL_GROUP_TEMPLATE,
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS),
+		contact_id_xml, groupId);
 
-	msn_soap_message_send(contact->session,
+	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_CONTACT_DEL_GROUP_SOAP_ACTION,
 			xmlnode_from_str(body, -1)),
 		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
@@ -1117,7 +1101,7 @@
 
 /* Update a contact's nickname */
 void
-msn_update_contact(MsnContact *contact, const char* nickname)
+msn_update_contact(MsnSession *session, const char* nickname)
 {
 	gchar *body = NULL, *escaped_nickname;
 
@@ -1125,9 +1109,11 @@
 
 	escaped_nickname = g_markup_escape_text(nickname, -1);
 
-	body = g_strdup_printf(MSN_CONTACT_UPDATE_TEMPLATE, escaped_nickname);
+	body = g_strdup_printf(MSN_CONTACT_UPDATE_TEMPLATE,
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS),
+		escaped_nickname);
 
-	msn_soap_message_send(contact->session,
+	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_CONTACT_UPDATE_SOAP_ACTION,
 			xmlnode_from_str(body, -1)),
 		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
@@ -1153,14 +1139,14 @@
 			if (user != NULL)
 				msn_user_unset_op(user, MSN_LIST_PL_OP);
 
-			msn_add_contact_to_list(session->contact, state, state->who, MSN_LIST_RL);
+			msn_add_contact_to_list(session, state, state->who, MSN_LIST_RL);
 			return;
 		} else if (state->list_id == MSN_LIST_AL) {
 			purple_privacy_permit_remove(session->account, state->who, TRUE);
-			msn_add_contact_to_list(session->contact, NULL, state->who, MSN_LIST_BL);
+			msn_add_contact_to_list(session, NULL, state->who, MSN_LIST_BL);
 		} else if (state->list_id == MSN_LIST_BL) {
 			purple_privacy_deny_remove(session->account, state->who, TRUE);
-			msn_add_contact_to_list(session->contact, NULL, state->who, MSN_LIST_AL);
+			msn_add_contact_to_list(session, NULL, state->who, MSN_LIST_AL);
 		}
 	}
 
@@ -1168,46 +1154,45 @@
 }
 
 void
-msn_del_contact_from_list(MsnContact *contact, MsnCallbackState *state,
+msn_del_contact_from_list(MsnSession *session, MsnCallbackState *state,
 			  const gchar *passport, const MsnListId list)
 {
 	gchar *body = NULL, *member = NULL;
 	MsnSoapPartnerScenario partner_scenario;
 	MsnUser *user;
 
-	g_return_if_fail(contact != NULL);
+	g_return_if_fail(session != 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(contact->session);
+		state = msn_callback_state_new(session);
 	}
 	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);
+		g_return_if_fail(session->userlist != NULL);
 
-		user = msn_userlist_find_user(contact->session->userlist, passport);
+		user = msn_userlist_find_user(session->userlist, passport);
 
 		partner_scenario = MSN_PS_CONTACT_API;
 		member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML, user->membership_id[MSN_LIST_PL]);
 	} 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);
+		MsnSoapPartnerScenarioText[partner_scenario],
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS),
+		MsnMemberRole[list], member);
 
-	msn_soap_message_send(contact->session,
+	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION,
 			xmlnode_from_str(body, -1)),
 		MSN_CONTACT_SERVER, MSN_SHARE_POST_URL,
@@ -1225,7 +1210,6 @@
 
 	g_return_if_fail(state != NULL);
 	g_return_if_fail(state->session != NULL);
-	g_return_if_fail(state->session->contact != NULL);
 
 	if (resp != NULL) {
 		purple_debug_info("MSN CL", "Contact %s added successfully to %s list on server!\n", state->who, MsnMemberRole[state->list_id]);
@@ -1239,7 +1223,7 @@
 
 			if (state->action & MSN_DENIED_BUDDY) {
 
-				msn_add_contact_to_list(state->session->contact, NULL, state->who, MSN_LIST_BL);
+				msn_add_contact_to_list(state->session, NULL, state->who, MSN_LIST_BL);
 			} else if (state->list_id == MSN_LIST_AL) {
 				purple_privacy_permit_add(state->session->account, state->who, TRUE);
 			} else if (state->list_id == MSN_LIST_BL) {
@@ -1252,20 +1236,20 @@
 }
 
 void
-msn_add_contact_to_list(MsnContact *contact, MsnCallbackState *state,
+msn_add_contact_to_list(MsnSession *session, MsnCallbackState *state,
 			const gchar *passport, const MsnListId list)
 {
 	gchar *body = NULL, *member = NULL;
 	MsnSoapPartnerScenario partner_scenario;
 
-	g_return_if_fail(contact != NULL);
+	g_return_if_fail(session != 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(contact->session);
+		state = msn_callback_state_new(session);
 	}
 	msn_callback_state_set_list_id(state, list);
 	msn_callback_state_set_who(state, passport);
@@ -1275,11 +1259,11 @@
 	member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, state->who);
 
 	body = g_strdup_printf(MSN_CONTACT_ADD_TO_LIST_TEMPLATE,
-			       MsnSoapPartnerScenarioText[partner_scenario],
-			       MsnMemberRole[list],
-			       member);
+		MsnSoapPartnerScenarioText[partner_scenario],
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS),
+		MsnMemberRole[list], member);
 
-	msn_soap_message_send(contact->session,
+	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION,
 			xmlnode_from_str(body, -1)),
 		MSN_CONTACT_SERVER, MSN_SHARE_POST_URL,
@@ -1301,16 +1285,22 @@
 
 /*get the gleams info*/
 void
-msn_get_gleams(MsnContact *contact)
+msn_get_gleams(MsnSession *session)
 {
 	MsnSoapReq *soap_request;
+	gchar *body = NULL;
 
 	purple_debug_info("MSNP14","msn get gleams info...\n");
-	msn_soap_message_send(contact->session,
+
+	body = g_strdup_printf(MSN_GLEAMS_TEMPLATE,
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS));
+
+	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_GET_GLEAMS_SOAP_ACTION,
-			xmlnode_from_str(MSN_GLEAMS_TEMPLATE, -1)),
+			xmlnode_from_str(body, -1)),
 		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
 		msn_gleams_read_cb, NULL);
+	g_free(body);
 }
 #endif
 
@@ -1328,7 +1318,6 @@
 
 	g_return_if_fail(state->session != NULL);
 	g_return_if_fail(state->session->userlist != NULL);
-	g_return_if_fail(state->session->contact != NULL);
 
 	if (resp == NULL) {
 		msn_callback_state_free(state);
@@ -1349,7 +1338,7 @@
 			/* the response is taken from
 			   http://telepathy.freedesktop.org/wiki/Pymsn/MSNP/ContactListActions
 			   should copy it to msnpiki some day */
-			xmlnode *guid_node = msn_soap_xml_get(resp->xml,
+			xmlnode *guid_node = xmlnode_get_child(resp->xml,
 				"Body/ABGroupAddResponse/ABGroupAddResult/guid");
 
 			if (guid_node) {
@@ -1364,7 +1353,7 @@
 						state->who,
 						state->new_group_name);
 				} else if (state->action & MSN_MOVE_BUDDY) {
-					msn_add_contact_to_group(session->contact, state, state->who, guid);
+					msn_add_contact_to_group(session, state, state->who, guid);
 					g_free(guid);
 					return;
 				}
@@ -1393,6 +1382,7 @@
 msn_add_group(MsnSession *session, MsnCallbackState *state, const char* group_name)
 {
 	char *body = NULL;
+	char *escaped_group_name = NULL;
 
 	g_return_if_fail(session != NULL);
 	g_return_if_fail(group_name != NULL);
@@ -1409,7 +1399,10 @@
 	/* escape group name's html special chars so it can safely be sent
 	* in a XML SOAP request
 	*/
-	body = g_markup_printf_escaped(MSN_GROUP_ADD_TEMPLATE, group_name);
+	escaped_group_name = g_markup_escape_text(group_name, -1);
+	body = g_strdup_printf(MSN_GROUP_ADD_TEMPLATE,
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS),
+		escaped_group_name);
 
 	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_GROUP_ADD_SOAP_ACTION,
@@ -1417,6 +1410,7 @@
 		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
 		msn_group_read_cb, state);
 
+	g_free(escaped_group_name);
 	g_free(body);
 }
 
@@ -1452,7 +1446,9 @@
 	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);
+	body = g_strdup_printf(MSN_GROUP_DEL_TEMPLATE,
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS),
+		guid);
 
 	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_GROUP_DEL_SOAP_ACTION,
@@ -1470,6 +1466,7 @@
 	gchar *body = NULL;
 	const gchar * guid;
 	MsnCallbackState *state;
+	char *escaped_group_name;
 
 	g_return_if_fail(session != NULL);
 	g_return_if_fail(session->userlist != NULL);
@@ -1493,8 +1490,10 @@
 
 	msn_callback_state_set_action(state, MSN_RENAME_GROUP);
 
-	body = g_markup_printf_escaped(MSN_GROUP_RENAME_TEMPLATE,
-		guid, new_group_name);
+	escaped_group_name = g_markup_escape_text(new_group_name, -1);
+	body = g_strdup_printf(MSN_GROUP_RENAME_TEMPLATE,
+		msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS),
+		guid, escaped_group_name);
 
 	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_GROUP_RENAME_SOAP_ACTION,
@@ -1502,5 +1501,6 @@
 		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
 		msn_group_read_cb, state);
 
+	g_free(escaped_group_name);
 	g_free(body);
 }
--- a/libpurple/protocols/msn/contact.h	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/contact.h	Sat Jun 07 03:10:15 2008 +0000
@@ -25,15 +25,20 @@
 #ifndef _MSN_CONTACT_H_
 #define _MSN_CONTACT_H_
 
+#include "session.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>"\
+
+#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/\">"\
@@ -44,6 +49,7 @@
 		 "</ABApplicationHeader>"\
 		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
 			"<ManagedGroupRequest xmlns=\"http://www.msn.com/webservices/AddressBook\">false</ManagedGroupRequest>"\
+			"<TicketToken>%s</TicketToken>"\
 		"</ABAuthHeader>"\
 	"</soap:Header>"\
 	"<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\
@@ -72,7 +78,11 @@
 #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: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>"\
@@ -81,6 +91,7 @@
 		"</ABApplicationHeader>"\
 		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
 			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+			"<TicketToken>%s</TicketToken>"\
 		"</ABAuthHeader>"\
 	"</soap:Header>"\
 	"<soap:Body>"\
@@ -98,7 +109,8 @@
 /* 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>"\
+#define MSN_GET_ADDRESS_UPDATE_XML \
+	"<deltasOnly>true</deltasOnly>"\
 	"<lastChange>%s</lastChange>"
 
 #define MSN_GET_GLEAM_UPDATE_XML \
@@ -107,7 +119,11 @@
 	"<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: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>"\
@@ -116,6 +132,7 @@
 		"</ABApplicationHeader>"\
 		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
 			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+			"<TicketToken>%s</TicketToken>"\
 		"</ABAuthHeader>"\
 	"</soap:Header>"\
 	"<soap:Body>"\
@@ -131,7 +148,11 @@
 /*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: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>"\
@@ -140,6 +161,7 @@
 		"</ABApplicationHeader>"\
 		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
 			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+			"<TicketToken>%s</TicketToken>"\
 		"</ABAuthHeader>"\
 	"</soap:Header>"\
 	"<soap:Body>"\
@@ -157,26 +179,40 @@
  * Contact Management SOAP actions
  *******************************************************/
 
-/* Add a new contact t*/
+/* Add a new contact */
 #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_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_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>"
+#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>"
 
-/* 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/\">"\
+#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>"\
@@ -185,6 +221,36 @@
 		"</ABApplicationHeader>"\
 		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
 			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+			"<TicketToken>%s</TicketToken>"\
+		"</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>"\
+			"<TicketToken>%s</TicketToken>"\
 		"</ABAuthHeader>"\
 	"</soap:Header>"\
 	"<soap:Body>"\
@@ -207,17 +273,12 @@
 /* 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/\">"\
+#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>"\
@@ -226,6 +287,67 @@
 		"</ABApplicationHeader>"\
 		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
 			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+			"<TicketToken>%s</TicketToken>"\
+		"</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>"\
+			"<TicketToken>%s</TicketToken>"\
+		"</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>"\
+			"<TicketToken>%s</TicketToken>"\
 		"</ABAuthHeader>"\
 	"</soap:Header>"\
 	"<soap:Body>"\
@@ -255,22 +377,28 @@
 #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_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>"
+#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: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>"\
@@ -279,6 +407,7 @@
 		"</ABApplicationHeader>"\
 		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
 			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+			"<TicketToken>%s</TicketToken>"\
 		"</ABAuthHeader>"\
 	"</soap:Header>"\
 	"<soap:Body>"\
@@ -301,7 +430,11 @@
 "</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: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>"\
@@ -310,6 +443,7 @@
 		"</ABApplicationHeader>"\
 		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
 			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+			"<TicketToken>%s</TicketToken>"\
 		"</ABAuthHeader>"\
 	"</soap:Header>"\
 	"<soap:Body>"\
@@ -339,15 +473,111 @@
 
 /* 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>"
+#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>"\
+			"<TicketToken>%s</TicketToken>"\
+		"</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>"
+#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>"\
+			"<TicketToken>%s</TicketToken>"\
+		"</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>"
+#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>"\
+			"<TicketToken>%s</TicketToken>"\
+		"</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
 {
@@ -360,15 +590,6 @@
 	MSN_RENAME_GROUP		= 0x40,
 } MsnCallbackAction;
 
-typedef struct _MsnContact MsnContact;
-
-struct _MsnContact
-{
-	MsnSession *session;
-
-	MsnSoapConn *soapconn;
-};
-
 typedef struct _MsnCallbackState MsnCallbackState;
 
 struct _MsnCallbackState
@@ -395,9 +616,6 @@
 /************************************************
  * function prototype
  ************************************************/
-MsnContact * msn_contact_new(MsnSession *session);
-void msn_contact_destroy(MsnContact *contact);
-
 MsnCallbackState * msn_callback_state_new(MsnSession *session);
 void msn_callback_state_free(MsnCallbackState *state);
 void msn_callback_state_set_who(MsnCallbackState *state, const gchar *who);
@@ -411,24 +629,24 @@
 void msn_callback_state_set_action(MsnCallbackState *state,
 				   MsnCallbackAction action);
 
-void msn_contact_connect(MsnContact *contact);
-void msn_get_contact_list(MsnContact * contact,
+void msn_contact_connect(MsnSession *session);
+void msn_get_contact_list(MsnSession *session,
 			  const MsnSoapPartnerScenario partner_scenario,
 			  const char *update);
-void msn_get_address_book(MsnContact *contact,
+void msn_get_address_book(MsnSession *session,
 			  const MsnSoapPartnerScenario partner_scenario,
 			  const char * update, const char * gupdate);
 
 /* contact SOAP operations */
-void msn_update_contact(MsnContact *contact, const char* nickname);
+void msn_update_contact(MsnSession *session, const char* nickname);
 
-void msn_add_contact(MsnContact *contact, MsnCallbackState *state,
+void msn_add_contact(MsnSession *session, MsnCallbackState *state,
 		     const char *passport);
-void msn_delete_contact(MsnContact *contact, const char *contactId);
+void msn_delete_contact(MsnSession *session, const char *contactId);
 
-void msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state,
+void msn_add_contact_to_group(MsnSession *session, MsnCallbackState *state,
 			      const char *passport, const char *groupId);
-void msn_del_contact_from_group(MsnContact *contact, const char *passport,
+void msn_del_contact_from_group(MsnSession *session, const char *passport,
 				const char *group_name);
 /* group operations */
 void msn_add_group(MsnSession *session, MsnCallbackState *state,
@@ -438,9 +656,9 @@
 						   const char *new_group_name);
 
 /* lists operations */
-void msn_add_contact_to_list(MsnContact *contact, MsnCallbackState *state,
+void msn_add_contact_to_list(MsnSession *session, MsnCallbackState *state,
 			     const gchar *passport, const MsnListId list);
-void msn_del_contact_from_list(MsnContact *contact, MsnCallbackState *state,
+void msn_del_contact_from_list(MsnSession *session, MsnCallbackState *state,
 			       const gchar *passport, const MsnListId list);
 
 void msn_contact_connect_init(MsnSoapConn *soapconn);
--- a/libpurple/protocols/msn/msn.c	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/msn.c	Sat Jun 07 03:10:15 2008 +0000
@@ -27,6 +27,7 @@
 
 #include "msn.h"
 #include "accountopt.h"
+#include "contact.h"
 #include "msg.h"
 #include "page.h"
 #include "pluginpref.h"
@@ -1062,7 +1063,10 @@
 	}
 
 	msn_import_html(message, &msgformat, &msgtext);
-	if(msn_user_is_online(account, who)||
+	/* this is incorrect, we should try to initiate a connection to the
+	   buddy first, and only falls back if that fails. Otherwise we can
+	   only send offline message to invisible buddies */
+	if (msn_user_is_online(account, who)||
 		msn_user_is_yahoo(account, who)){
 		/*User online,then send Online Instant Message*/
 
@@ -1145,7 +1149,7 @@
 		}
 
 		msn_message_destroy(msg);
-	}else	{
+	} else {
 		/*send Offline Instant Message,only to MSN Passport User*/
 		MsnSession *session;
 		char *friendname;
@@ -1156,8 +1160,11 @@
 		friendname = msn_encode_mime(account->username);
 		msn_oim_prep_send_msg_info(session->oim,
 			purple_account_get_username(account),
-			friendname, who,	message);
+			friendname, who, msgtext);
 		msn_oim_send_msg(session->oim);
+
+		g_free(msgformat);
+		g_free(msgtext);
 		g_free(friendname);
 	}
 
@@ -1369,10 +1376,10 @@
 		msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL);
 
 		/* 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);
+		msn_del_contact_from_list(session, 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_add_contact_to_list(session, NULL, who, MSN_LIST_AL);
 	}
 
 
@@ -1397,10 +1404,10 @@
 		msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_AL);
 
 		/* 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);
+		msn_del_contact_from_list(session, 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_add_contact_to_list(session, NULL, who, MSN_LIST_BL);
 	}
 
 	msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_BL);
@@ -1423,7 +1430,7 @@
 
 	msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_AL);
 
-	msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_AL);
+	msn_del_contact_from_list(session, NULL, who, MSN_LIST_AL);
 
 	if (user != NULL && user->list_op & MSN_LIST_RL_OP)
 		msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_BL);
@@ -1446,7 +1453,7 @@
 
 	msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL);
 
-	msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_BL);
+	msn_del_contact_from_list(session, NULL, who, MSN_LIST_BL);
 
 	if (user != NULL && user->list_op & MSN_LIST_RL_OP)
 		msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_AL);
--- a/libpurple/protocols/msn/msn.h	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/msn.h	Sat Jun 07 03:10:15 2008 +0000
@@ -66,12 +66,10 @@
 /* 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_PROT_VER		15
 
-#define WLM_MAX_PROTOCOL	14
-#define WLM_MIN_PROTOCOL	13
+#define WLM_MAX_PROTOCOL	15
+#define WLM_MIN_PROTOCOL	15
 
 #define MSN_TYPING_RECV_TIMEOUT 6
 #define MSN_TYPING_SEND_TIMEOUT	4
--- a/libpurple/protocols/msn/msnutils.c	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/msnutils.c	Sat Jun 07 03:10:15 2008 +0000
@@ -514,8 +514,8 @@
 {
 		PurpleCipher *cipher;
 		PurpleCipherContext *context;
-		char *productKey = MSNP13_WLM_PRODUCT_KEY,
-			 *productID  = MSNP13_WLM_PRODUCT_ID,
+		char *productKey = MSNP15_WLM_PRODUCT_KEY,
+			 *productID  = MSNP15_WLM_PRODUCT_ID,
 			 *hexChars   = "0123456789abcdef",
 			 buf[BUFSIZE];
 		unsigned char md5Hash[16], *newHash;
--- a/libpurple/protocols/msn/nexus.c	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/nexus.c	Sat Jun 07 03:10:15 2008 +0000
@@ -26,7 +26,24 @@
 #include "nexus.h"
 #include "notification.h"
 
-#undef NEXUS_LOGIN_TWN
+
+/**************************************************************************
+ * Valid Ticket Tokens
+ **************************************************************************/
+
+#define SSO_VALID_TICKET_DOMAIN 0
+#define SSO_VALID_TICKET_POLICY 1
+static char *ticket_domains[][2] = {
+	/* http://msnpiki.msnfanatic.com/index.php/MSNP15:SSO */
+	/* {"Domain", "Policy Ref URI"}, Purpose */
+	{"messengerclear.live.com", NULL},       /* Authentication for messenger. */
+	{"messenger.msn.com", "?id=507"},        /* Authentication for receiving OIMs. */
+	{"contacts.msn.com", "MBI"},             /* Authentication for the Contact server. */
+	{"messengersecure.live.com", "MBI_SSL"}, /* Authentication for sending OIMs. */
+	{"spaces.live.com", "MBI"},              /* Authentication for the Windows Live Spaces */
+	{"livecontacts.live.com", "MBI"},        /* Live Contacts API, a simplified version of the Contacts SOAP service */
+	{"storage.live.com", "MBI"},             /* Storage REST API */
+};
 
 /**************************************************************************
  * Main
@@ -36,12 +53,17 @@
 msn_nexus_new(MsnSession *session)
 {
 	MsnNexus *nexus;
+	int i;
 
 	nexus = g_new0(MsnNexus, 1);
 	nexus->session = session;
 
-	nexus->challenge_data = g_hash_table_new_full(g_str_hash,
-		g_str_equal, g_free, g_free);
+	nexus->token_len = sizeof(ticket_domains) / sizeof(char *[2]);
+	nexus->tokens = g_new0(MsnTicketToken, nexus->token_len);
+
+	for (i = 0; i < nexus->token_len; i++)
+		nexus->tokens[i].token = g_hash_table_new_full(g_str_hash, g_str_equal,
+		                                               g_free, g_free);
 
 	return nexus;
 }
@@ -49,48 +71,199 @@
 void
 msn_nexus_destroy(MsnNexus *nexus)
 {
-	if (nexus->challenge_data != NULL)
-		g_hash_table_destroy(nexus->challenge_data);
+	int i;
+	for (i = 0; i < nexus->token_len; i++) {
+		g_hash_table_destroy(nexus->tokens[i].token);
+		g_free(nexus->tokens[i].secret);
+	}
+
+	g_free(nexus->tokens);
+	g_free(nexus->policy);
+	g_free(nexus->nonce);
+	g_free(nexus);
+}
+
+/**************************************************************************
+ * RPS/SSO Authentication
+ **************************************************************************/
+
+static char *
+sha1_hmac(const char *key, int key_len, const char *message, int msg_len)
+{
+	PurpleCipherContext *context;
+	char *result;
+	gboolean ret;
+
+	context = purple_cipher_context_new_by_name("hmac", NULL);
+	purple_cipher_context_set_option(context, "hash", "sha1");
+	purple_cipher_context_set_key_with_len(context, (guchar *)key, key_len);
+
+	purple_cipher_context_append(context, (guchar *)message, msg_len);
+	result = g_malloc(20);
+	ret = purple_cipher_context_digest(context, 20, (guchar *)result, NULL);
+
+	purple_cipher_context_destroy(context);
+
+	return result;
+}
+
+static char *
+rps_create_key(const char *key, int key_len, const char *data, size_t data_len)
+{
+	char *hash1, *hash2, *hash3, *hash4;
+	char *result;
+
+	hash1 = sha1_hmac(key, key_len, data, data_len);
+	hash1 = g_realloc(hash1, 20 + data_len);
+	memcpy(hash1 + 20, data, data_len);
+	hash2 = sha1_hmac(key, key_len, hash1, 20 + data_len);
+
+	hash3 = sha1_hmac(key, key_len, hash1, 20);
+
+	hash3 = g_realloc(hash3, 20 + data_len);
+	memcpy(hash3 + 20, data, data_len);
+	hash4 = sha1_hmac(key, key_len, hash3, 20 + data_len);
+
+	result = g_malloc(24);
+	memcpy(result, hash2, 20);
+	memcpy(result + 20, hash4, 4);
+
+	g_free(hash1);
+	g_free(hash2);
+	g_free(hash3);
+	g_free(hash4);
+
+	return result;
+}
+
+static char *
+des3_cbc(const char *key, const char *iv, const char *data, int len)
+{
+	PurpleCipherContext *des3;
+	char *out;
+	size_t outlen;
 
-	g_free(nexus->challenge_data_str);
-	g_free(nexus);
+	des3 = purple_cipher_context_new_by_name("des3", NULL);
+	purple_cipher_context_set_key(des3, (guchar *)key);
+	purple_cipher_context_set_batch_mode(des3, PURPLE_CIPHER_BATCH_MODE_CBC);
+	purple_cipher_context_set_iv(des3, (guchar *)iv, 8);
+
+	out = g_malloc(len);
+	purple_cipher_context_encrypt(des3, (guchar *)data, len, (guchar *)out, &outlen);
+
+	purple_cipher_context_destroy(des3);
+
+	return out;
+}
+
+#define CRYPT_MODE_CBC 1
+#define CIPHER_TRIPLE_DES 0x6603
+#define HASH_SHA1 0x8004
+static char *
+msn_rps_encrypt(MsnNexus *nexus)
+{
+	MsnUsrKey *usr_key;
+	const char *magic1 = "WS-SecureConversationSESSION KEY HASH";
+	const char *magic2 = "WS-SecureConversationSESSION KEY ENCRYPTION";
+	size_t len;
+	char *hash;
+	char *key1, *key2, *key3;
+	gsize key1_len;
+	char *nonce_fixed;
+	char *cipher;
+	char *response;
+
+	usr_key = g_malloc(sizeof(MsnUsrKey));
+	usr_key->size = GUINT32_TO_LE(28);
+	usr_key->crypt_mode = GUINT32_TO_LE(CRYPT_MODE_CBC);
+	usr_key->cipher_type = GUINT32_TO_LE(CIPHER_TRIPLE_DES);
+	usr_key->hash_type = GUINT32_TO_LE(HASH_SHA1);
+	usr_key->iv_len = GUINT32_TO_LE(8);
+	usr_key->hash_len = GUINT32_TO_LE(20);
+	usr_key->cipher_len = GUINT32_TO_LE(72);
+
+	key1 = (char *)purple_base64_decode((const char *)nexus->tokens[MSN_AUTH_MESSENGER].secret, &key1_len);
+	len = strlen(magic1);
+	key2 = rps_create_key(key1, key1_len, magic1, len);
+	len = strlen(magic2);
+	key3 = rps_create_key(key1, key1_len, magic2, len);
+
+	usr_key->iv[0] = 0x46; //rand() % 256;
+	usr_key->iv[1] = 0xC4;
+	usr_key->iv[2] = 0x14;
+	usr_key->iv[3] = 0x9F;
+	usr_key->iv[4] = 0xFF;
+	usr_key->iv[5] = 0xFC;
+	usr_key->iv[6] = 0x91;
+	usr_key->iv[7] = 0x61;
+
+	len = strlen(nexus->nonce);
+	hash = sha1_hmac(key2, 24, nexus->nonce, len);
+
+	/* We need to pad this to 72 bytes, apparently */
+	nonce_fixed = g_malloc(len + 8);
+	memcpy(nonce_fixed, nexus->nonce, len);
+	memset(nonce_fixed + len, 0x08, 8);
+	cipher = des3_cbc(key3, usr_key->iv, nonce_fixed, len + 8);
+	g_free(nonce_fixed);
+
+	memcpy(usr_key->hash, hash, 20);
+	memcpy(usr_key->cipher, cipher, 72);
+
+	g_free(key1);
+	g_free(key2);
+	g_free(key3);
+	g_free(hash);
+	g_free(cipher);
+
+	response = purple_base64_encode((guchar *)usr_key, sizeof(MsnUsrKey));
+
+	g_free(usr_key);
+
+	return response;
 }
 
 /**************************************************************************
  * Login
  **************************************************************************/
 
-static void
-nexus_got_response_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data)
+static gboolean
+nexus_parse_response(MsnNexus *nexus, xmlnode *xml)
 {
-	MsnNexus *nexus = data;
-	MsnSession *session = nexus->session;
 	xmlnode *node;
+	gboolean result = FALSE;
 
-	if (resp == NULL) {
-		msn_session_set_error(session, MSN_ERROR_SERVCONN, _("Windows Live ID authentication:Unable to connect"));
-		return;
-	}
+	node = xmlnode_get_child(xml, "Body/RequestSecurityTokenResponseCollection/RequestSecurityTokenResponse");
 
-	node = msn_soap_xml_get(resp->xml,	"Body/"
-		"RequestSecurityTokenResponseCollection/RequestSecurityTokenResponse");
+	if (node)
+		node = node->next;	/* The first one is not useful */
+	else
+		return FALSE;
 
 	for (; node; node = node->next) {
-		xmlnode *token = msn_soap_xml_get(node,
-			"RequestedSecurityToken/BinarySecurityToken");
+		xmlnode *token = xmlnode_get_child(node, "RequestedSecurityToken/BinarySecurityToken");
+		xmlnode *secret = xmlnode_get_child(node, "RequestedProofToken/BinarySecret");
+		xmlnode *expires = xmlnode_get_child(node, "LifeTime/Expires");
 
 		if (token) {
-			char *token_str = xmlnode_get_data(token);
+			char *token_str, *expiry_str;
+			const char *id_str = xmlnode_get_attrib(token, "Id");
 			char **elems, **cur, **tokens;
-			char *msn_twn_t, *msn_twn_p, *cert_str;
+			int id;
+
+			if (id_str == NULL) continue;
 
+			id = atol(id_str + 7) - 1;	/* 'Compact#' or 'PPToken#' */
+			if (id >= nexus->token_len)
+				continue;	/* Where did this come from? */
+
+			token_str = xmlnode_get_data(token);
 			if (token_str == NULL) continue;
-
 			elems = g_strsplit(token_str, "&", 0);
 
 			for (cur = elems; *cur != NULL; cur++){
 				tokens = g_strsplit(*cur, "=", 2);
-				g_hash_table_insert(nexus->challenge_data, tokens[0], tokens[1]);
+				g_hash_table_insert(nexus->tokens[id].token, tokens[0], tokens[1]);
 				/* Don't free each of the tokens, only the array. */
 				g_free(tokens);
 			}
@@ -98,30 +271,59 @@
 			g_free(token_str);
 			g_strfreev(elems);
 
-			msn_twn_t = g_hash_table_lookup(nexus->challenge_data, "t");
-			msn_twn_p = g_hash_table_lookup(nexus->challenge_data, "p");
+			if (secret)
+				nexus->tokens[id].secret = xmlnode_get_data(secret);
+			else
+				nexus->tokens[id].secret = NULL;
 
-			/*setup the t and p parameter for session*/
-			g_free(session->passport_info.t);
-			session->passport_info.t = g_strdup(msn_twn_t);
-
-			g_free(session->passport_info.p);
-			session->passport_info.p = g_strdup(msn_twn_p);
+			/* Yay for MS using ISO-8601 */
+			expiry_str = xmlnode_get_data(expires);
 
-			cert_str = g_strdup_printf("t=%s&p=%s",msn_twn_t,msn_twn_p);
-			msn_got_login_params(session, cert_str);
+			nexus->tokens[id].expiry = purple_str_to_time(expiry_str,
+				FALSE, NULL, NULL, NULL);
 
-			purple_debug_info("MSN Nexus","Close nexus connection!\n");
-			g_free(cert_str);
-			msn_nexus_destroy(nexus);
-			session->nexus = NULL;
+			g_free(expiry_str);
 
-			return;
+			purple_debug_info("msnp15", "Updated ticket for domain '%s'\n",
+			                  ticket_domains[id][SSO_VALID_TICKET_DOMAIN]);
+			result = TRUE;
 		}
 	}
 
-	/* we must have failed! */
-	msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication: cannot find authenticate token in server response"));
+	return result;
+}
+
+static void
+nexus_got_response_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data)
+{
+	MsnNexus *nexus = data;
+	MsnSession *session = nexus->session;
+	char *msn_twn_t, *msn_twn_p, *ticket;
+	char *response;
+
+	if (resp == NULL) {
+		msn_session_set_error(session, MSN_ERROR_SERVCONN, _("Windows Live ID authentication:Unable to connect"));
+		return;
+	}
+
+	if (!nexus_parse_response(nexus, resp->xml)) {
+		msn_session_set_error(session, MSN_ERROR_SERVCONN, _("Windows Live ID authentication:Invalid response"));
+		return;
+	}
+
+	/*setup the t and p parameter for session*/
+	msn_twn_t = g_hash_table_lookup(nexus->tokens[MSN_AUTH_MESSENGER].token, "t");
+	msn_twn_p = g_hash_table_lookup(nexus->tokens[MSN_AUTH_MESSENGER].token, "p");
+	g_free(session->passport_info.t);
+	session->passport_info.t = g_strdup(msn_twn_t);
+	g_free(session->passport_info.p);
+	session->passport_info.p = g_strdup(msn_twn_p);
+
+	ticket = g_strdup_printf("t=%s&p=%s", msn_twn_t, msn_twn_p);
+	response = msn_rps_encrypt(nexus);
+	msn_got_login_params(session, ticket, response);
+	g_free(ticket);
+	g_free(response);
 }
 
 /*when connect, do the SOAP Style windows Live ID authentication */
@@ -129,92 +331,119 @@
 msn_nexus_connect(MsnNexus *nexus)
 {
 	MsnSession *session = nexus->session;
-	char *ru,*lc,*id,*tw,*ct,*kpp,*kv,*ver,*rn,*tpf;
-	char *fs0,*fs;
-	const char *username;
-	char *password;
-	char *tail;
-#ifdef NEXUS_LOGIN_TWN
-	char *challenge_str;
-#else
-	char *rst1_str,*rst2_str,*rst3_str;
-#endif
+	char *username, *password;
+	GString *domains;
+	char *request;
+	int i;
+
+	MsnSoapMessage *soap;
+
+	msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE);
+
+	username = g_strdup(purple_account_get_username(session->account));
+	password = g_strndup(purple_connection_get_password(session->account->gc), 16);
+
+	purple_debug_info("msnp15", "Logging on %s, with policy '%s', nonce '%s'\n",
+	                  username, nexus->policy, nexus->nonce);
+
+	domains = g_string_new(NULL);
+	for (i = 0; i < nexus->token_len; i++) {
+		g_string_append_printf(domains, MSN_SSO_RST_TEMPLATE,
+		                       i+1,
+		                       ticket_domains[i][SSO_VALID_TICKET_DOMAIN],
+		                       ticket_domains[i][SSO_VALID_TICKET_POLICY] != NULL ?
+		                           ticket_domains[i][SSO_VALID_TICKET_POLICY] :
+		                           nexus->policy);
+	}
+
+	request = g_strdup_printf(MSN_SSO_TEMPLATE, username, password, domains->str);
+	g_free(username);
+	g_free(password);
+	g_string_free(domains, TRUE);
+
+	soap = msn_soap_message_new(NULL, xmlnode_from_str(request, -1));
+	g_free(request);
+	msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL,
+	                      nexus_got_response_cb, nexus);
+}
+
+static void
+nexus_got_update_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data)
+{
+	MsnNexus *nexus = data;
+
+	nexus_parse_response(nexus, resp->xml);
+}
+
+static void
+msn_nexus_update_token(MsnNexus *nexus, int id)
+{
+	MsnSession *session = nexus->session;
+	char *username, *password;
+	char *domain;
+	char *request;
 
 	MsnSoapMessage *soap;
 
-	purple_debug_info("MSN Nexus","Starting Windows Live ID authentication\n");
-	msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE);
-
-	/*prepare the Windows Live ID authentication token*/
-	username = purple_account_get_username(session->account);
+	username = g_strdup(purple_account_get_username(session->account));
 	password = g_strndup(purple_connection_get_password(session->account->gc), 16);
 
-	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");
-
-	/*
-	 * 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(password);
-		msn_nexus_destroy(nexus);
-		session->nexus = NULL;
-		return;
-	}
+	purple_debug_info("msnp15", "Updating ticket for user '%s' on domain '%s'\n",
+	                  username, ticket_domains[id][SSO_VALID_TICKET_DOMAIN]);
 
-	/*
-	 * 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");
-	}
-
-#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
-		);
+	/* TODO: This really assumes if we send RSTn, the server responds with
+	 Compactn, even if there is no RST(n-1). This needs checking.
+	*/
+	domain = g_strdup_printf(MSN_SSO_RST_TEMPLATE,
+		                       id,
+		                       ticket_domains[id][SSO_VALID_TICKET_DOMAIN],
+		                       ticket_domains[id][SSO_VALID_TICKET_POLICY] != NULL ?
+		                           ticket_domains[id][SSO_VALID_TICKET_POLICY] :
+		                           nexus->policy);
 
-	/*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);
+	request = g_strdup_printf(MSN_SSO_TEMPLATE, username, password, domain);
+	g_free(username);
 	g_free(password);
+	g_free(domain);
 
-	soap = msn_soap_message_new(NULL, xmlnode_from_str(tail, -1));
-	g_free(tail);
-	msn_soap_message_send(nexus->session, soap, MSN_TWN_SERVER, TWN_POST_URL,
-		nexus_got_response_cb, nexus);
+	soap = msn_soap_message_new(NULL, xmlnode_from_str(request, -1));
+	g_free(request);
+	msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL,
+	                      nexus_got_update_cb, nexus);
 }
 
+GHashTable *
+msn_nexus_get_token(MsnNexus *nexus, MsnAuthDomains id)
+{
+	g_return_val_if_fail(nexus != NULL, NULL);
+	g_return_val_if_fail(id < nexus->token_len, NULL);
+
+	if (time(NULL) > nexus->tokens[id].expiry)
+		msn_nexus_update_token(nexus, id);
+
+	return nexus->tokens[id].token;
+}
+
+const char *
+msn_nexus_get_token_str(MsnNexus *nexus, MsnAuthDomains id)
+{
+	static char buf[1024];
+	GHashTable *token = msn_nexus_get_token(nexus, id);
+	const char *msn_t;
+	const char *msn_p;
+	gint ret;
+
+	g_return_val_if_fail(token != NULL, NULL);
+
+	msn_t = g_hash_table_lookup(token, "t");
+	msn_p = g_hash_table_lookup(token, "p");
+
+	g_return_val_if_fail(msn_t != NULL, NULL);
+	g_return_val_if_fail(msn_p != NULL, NULL);
+
+	ret = g_snprintf(buf, sizeof(buf) - 1, "t=%s&amp;p=%s", msn_t, msn_p);
+	g_return_val_if_fail(ret != -1, NULL);
+
+	return buf;
+}
+
--- a/libpurple/protocols/msn/nexus.h	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/nexus.h	Sat Jun 07 03:10:15 2008 +0000
@@ -26,125 +26,115 @@
 
 #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>"
+/* Index into ticket_tokens in nexus.c Keep updated! */
+typedef enum
+{
+	MSN_AUTH_MESSENGER     = 0,
+	MSN_AUTH_MESSENGER_WEB = 1,
+	MSN_AUTH_CONTACTS      = 2,
+	MSN_AUTH_LIVE_SECURE   = 3,
+	MSN_AUTH_SPACES        = 4,
+	MSN_AUTH_LIVE_CONTACTS = 5,
+	MSN_AUTH_STORAGE       = 6
+} MsnAuthDomains;
 
-#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 MSN_SSO_SERVER	"login.live.com"
+#define SSO_POST_URL	"/RST.srf"
+
+#define MSN_SSO_RST_TEMPLATE \
+"<wst:RequestSecurityToken Id=\"RST%d\">"\
+	"<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\
+	"<wsp:AppliesTo>"\
+		"<wsa:EndpointReference>"\
+			"<wsa:Address>%s</wsa:Address>"\
+		"</wsa:EndpointReference>"\
+	"</wsp:AppliesTo>"\
+	"<wsse:PolicyReference URI=\"%s\"></wsse:PolicyReference>"\
+"</wst:RequestSecurityToken>"
 
-#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>"\
+#define MSN_SSO_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>AQAAAAIAAABsYwQAAAAxMDMz</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>"\
+			"%s"	/* Other RSTn tokens */\
+		"</ps:RequestMultipleSecurityTokens>"\
+	"</Body>"\
 "</Envelope>"
 
+typedef struct _MsnUsrKey MsnUsrKey;
+struct _MsnUsrKey
+{
+	int size; // 28. Does not count data
+	int crypt_mode; // CRYPT_MODE_CBC (1)
+	int cipher_type; // TripleDES (0x6603)
+	int hash_type; // SHA1 (0x8004)
+	int iv_len;    // 8
+	int hash_len;  // 20
+	int cipher_len; // 72
+	// Data
+	char iv[8];
+	char hash[20];
+	char cipher[72];
+};
+
+typedef struct _MsnTicketToken MsnTicketToken;
+struct _MsnTicketToken {
+	GHashTable *token;
+	char *secret;
+	time_t expiry;
+};
+
 typedef struct _MsnNexus MsnNexus;
 
 struct _MsnNexus
 {
 	MsnSession *session;
-	char * challenge_data_str;
-	GHashTable *challenge_data;
+	char *policy;
+	char *nonce;
+
+	MsnTicketToken *tokens;
+	int token_len;
 };
 
 void msn_nexus_connect(MsnNexus *nexus);
 MsnNexus *msn_nexus_new(MsnSession *session);
 void msn_nexus_destroy(MsnNexus *nexus);
+GHashTable *msn_nexus_get_token(MsnNexus *session, MsnAuthDomains id);
+const char *msn_nexus_get_token_str(MsnNexus *session, MsnAuthDomains id);
 
 #endif /* _MSN_NEXUS_H_ */
+
--- a/libpurple/protocols/msn/notification.c	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/notification.c	Sat Jun 07 03:10:15 2008 +0000
@@ -23,6 +23,7 @@
  */
 #include "msn.h"
 #include "notification.h"
+#include "contact.h"
 #include "state.h"
 #include "error.h"
 #include "msnutils.h"
@@ -34,6 +35,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
  **************************************************************************/
@@ -195,7 +205,7 @@
  **************************************************************************/
 
 void
-msn_got_login_params(MsnSession *session, const char *login_params)
+msn_got_login_params(MsnSession *session, const char *ticket, const char *response)
 {
 	MsnCmdProc *cmdproc;
 
@@ -203,7 +213,7 @@
 
 	msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_END);
 
-	msn_cmdproc_send(cmdproc, "USR", "TWN S %s", login_params);
+	msn_cmdproc_send(cmdproc, "USR", "SSO S %s %s", ticket, response);
 }
 
 static void
@@ -212,8 +222,8 @@
 	PurpleAccount *account;
 
 	account = cmdproc->session->account;
-	msn_cmdproc_send(cmdproc, "USR", "TWN I %s",
-					 purple_account_get_username(account));
+
+	msn_cmdproc_send(cmdproc, "USR", "SSO I %s", purple_account_get_username(account));
 }
 
 static void
@@ -239,32 +249,14 @@
 //		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"))
+	else if (!g_ascii_strcasecmp(cmd->params[1], "SSO"))
 	{
-		/* Passport authentication */
-		char **elems, **cur, **tokens;
+		/* RPS authentication */
 
 		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);
-			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);
-			} else
-				g_strfreev(tokens);
-		}
-
-		g_strfreev(elems);
+		session->nexus->policy = g_strdup(cmd->params[3]);
+		session->nexus->nonce = g_strdup(cmd->params[4]);
 
 		msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_START);
 
@@ -327,14 +319,15 @@
 	}
 
 	/*
-	 * Windows Live Messenger 8.0
+	 * Windows Live Messenger 8.5
 	 * 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 MSG80BETA 8.0.0689 msmsgs %s",
-					"0x0804 winnt 5.1 i386 MSNMSGR 8.0.0792 msmsgs %s",
+//					"0x0804 winnt 5.1 i386 MSNMSGR 8.0.0792 msmsgs %s",
+					"0x0409 winnt 5.1 i386 MSNMSGR 8.5.1288 msmsgs %s",
 					 purple_account_get_username(account));
 }
 
@@ -545,7 +538,7 @@
 	context = purple_cipher_context_new(cipher, NULL);
 	purple_cipher_context_append(context, (const guchar *)cmd->params[1],
 							   strlen(cmd->params[1]));
-	challenge_resp = MSNP13_WLM_PRODUCT_KEY;
+	challenge_resp = MSNP15_WLM_PRODUCT_KEY;
 
 	purple_cipher_context_append(context, (const guchar *)challenge_resp,
 							   strlen(challenge_resp));
@@ -560,7 +553,7 @@
 	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);
+	trans = msn_transaction_new(cmdproc, "QRY", "%s 32", MSNP15_WLM_PRODUCT_ID);
 
 	msn_transaction_set_payload(trans, buf, 32);
 
@@ -640,7 +633,7 @@
 {
 	MsnTransaction *trans;
 	purple_debug_info("MSN Notification","Sending ADL with payload: %s\n", payload);
-	trans = msn_transaction_new(cmdproc, "ADL", "%i", payload_len);
+	trans = msn_transaction_new(cmdproc, "ADL","%" G_GSIZE_FORMAT, payload_len);
 	msn_transaction_set_payload(trans, payload, payload_len);
 	msn_cmdproc_send_trans(cmdproc, trans);
 }
@@ -782,7 +775,7 @@
 			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);
+				msn_get_contact_list(cmdproc->session, MSN_PS_PENDING_LIST, NULL);
 			}
 
 //			g_free(decoded_friendly_name);
@@ -839,9 +832,8 @@
 {
 	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);
+//	msn_get_address_book(cmdproc->session, MSN_AB_SAVE_CONTACT, NULL, NULL);
 }
 
 static void
@@ -1292,7 +1284,7 @@
 			if (!strcmp(type, "MFN")) {
 				friendlyname = purple_url_decode(cmd->params[2]);
 
-				msn_update_contact(session->contact, friendlyname);
+				msn_update_contact(session, friendlyname);
 
 				purple_connection_set_display_name(
 					purple_account_get_connection(session->account),
@@ -1774,17 +1766,16 @@
 
 	/*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);
+	msn_get_contact_list(session, MSN_PS_INITIAL, clLastChange);
 #else
 	/* always get the full list? */
-	msn_get_contact_list(session->contact, MSN_PS_INITIAL, NULL);
+	msn_get_contact_list(session, MSN_PS_INITIAL, NULL);
 #endif
 #if 0
-	msn_contact_connect(session->contact);
+	msn_contact_connect(session);
 #endif
 }
 
@@ -2172,3 +2163,21 @@
 	msn_table_destroy(cbs_table);
 }
 
+	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);
+}
+
+void
+msn_notification_end(void)
+{
+	msn_table_destroy(cbs_table);
+}
+
--- a/libpurple/protocols/msn/notification.h	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/notification.h	Sat Jun 07 03:10:15 2008 +0000
@@ -25,6 +25,11 @@
 #define _MSN_NOTIFICATION_H_
 
 /*MSN protocol challenge info*/
+
+/*MSNP15 challenge: WLM 8.5.1288.816*/
+#define MSNP15_WLM_PRODUCT_KEY "ILTXC!4IXB5FB*PX"
+#define MSNP15_WLM_PRODUCT_ID "PROD0119GSJUC$18"
+
 /*MSNP13 challenge*/
 #define MSNP13_WLM_PRODUCT_KEY	"O4BG@C7BWLYQX?5G"
 #define MSNP13_WLM_PRODUCT_ID	"PROD01065C%ZFN6F"
@@ -76,6 +81,6 @@
  */
 void msn_notification_close(MsnNotification *notification);
 
-void msn_got_login_params(MsnSession *session, const char *login_params);
+void msn_got_login_params(MsnSession *session, const char *ticket, const char *response);
 
 #endif /* _MSN_NOTIFICATION_H_ */
--- a/libpurple/protocols/msn/oim.c	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/oim.c	Sat Jun 07 03:10:15 2008 +0000
@@ -41,6 +41,7 @@
 } MsnOimRecvData;
 
 /*Local Function Prototype*/
+static void msn_parse_oim_xml(MsnOim *oim, xmlnode *node);
 static void msn_oim_post_single_get_msg(MsnOim *oim, char *msgid);
 static MsnOimSendReq *msn_oim_new_send_req(const char *from_member,
 										   const char *friendname,
@@ -114,6 +115,50 @@
 }
 
 /****************************************
+ * OIM GetMetadata request
+ * **************************************/
+static void
+msn_oim_get_metadata_cb(MsnSoapMessage *request, MsnSoapMessage *response,
+	gpointer data)
+{
+	MsnOim *oim = data;
+
+	if (response) {
+		msn_parse_oim_xml(oim,
+			xmlnode_get_child(response->xml, "Body/GetMetadataResponse/MD"));
+	}
+}
+
+/* Post to get the OIM Metadata */
+static void
+msn_oim_get_metadata(MsnOim *oim)
+{
+	char *soap_body;
+	GHashTable *token;
+	const char *msn_t;
+	const char *msn_p;
+
+	token = msn_nexus_get_token(oim->session->nexus, MSN_AUTH_MESSENGER_WEB);
+	g_return_if_fail(token != NULL);
+
+	msn_t = g_hash_table_lookup(token, "t");
+	msn_p = g_hash_table_lookup(token, "p");
+
+	g_return_if_fail(msn_t != NULL);
+	g_return_if_fail(msn_p != NULL);
+
+	soap_body = g_strdup_printf(MSN_OIM_GET_METADATA_TEMPLATE, msn_t, msn_p);
+
+	msn_soap_message_send(oim->session,
+		msn_soap_message_new(MSN_OIM_GET_METADATA_ACTION,
+			xmlnode_from_str(soap_body, -1)),
+		MSN_OIM_RETRIEVE_HOST, MSN_OIM_RETRIEVE_URL,
+		msn_oim_get_metadata_cb, oim);
+
+	g_free(soap_body);
+}
+
+/****************************************
  * OIM send SOAP request
  * **************************************/
 /*encode the message to OIM Message Format*/
@@ -148,7 +193,7 @@
 	if (response == NULL) {
 		purple_debug_info("MSNP14", "cannot send OIM: %s\n", msg->oim_msg);
 	} else {
-		xmlnode	*faultNode = msn_soap_xml_get(response->xml, "Body/Fault");
+		xmlnode	*faultNode = xmlnode_get_child(response->xml, "Body/Fault");
 
 		if (faultNode == NULL) {
 			/*Send OK! return*/
@@ -160,9 +205,11 @@
 				char *faultcode_str = xmlnode_get_data(faultcode);
 
 				if (g_str_equal(faultcode_str, "q0:AuthenticationFailed")) {
-					xmlnode *challengeNode = msn_soap_xml_get(faultNode,
+					xmlnode *challengeNode = xmlnode_get_child(faultNode,
 						"detail/LockKeyChallenge");
 
+					g_free(faultcode_str);
+
 					if (challengeNode == NULL) {
 						if (oim->challenge) {
 							g_free(oim->challenge);
@@ -217,7 +264,7 @@
 msn_oim_send_msg(MsnOim *oim)
 {
 	MsnOimSendReq *oim_request;
-	char *soap_body,*mspauth;
+	char *soap_body;
 	char *msg_body;
 
 	g_return_if_fail(oim != NULL);
@@ -225,16 +272,12 @@
 	g_return_if_fail(oim_request != NULL);
 
 	purple_debug_info("MSNP14","sending OIM: %s\n", oim_request->oim_msg);
-	mspauth = g_strdup_printf("t=%s&amp;p=%s",
-		oim->session->passport_info.t,
-		oim->session->passport_info.p
-		);
 
 	/* if we got the challenge lock key, we compute it
 	 * else we go for the SOAP fault and resend it.
 	 */
 	if(oim->challenge == NULL){
-		purple_debug_info("MSNP14","no lock key challenge,wait for SOAP Fault and Resend\n");
+		purple_debug_info("MSNP14","no lock key challenge, wait for SOAP Fault and Resend\n");
 	}
 
 	msg_body = msn_oim_msg_to_str(oim, oim_request->oim_msg);
@@ -242,8 +285,8 @@
 					oim_request->from_member,
 					oim_request->friendname,
 					oim_request->to_member,
-					mspauth,
-					MSNP13_WLM_PRODUCT_ID,
+		msn_nexus_get_token_str(oim->session->nexus, MSN_AUTH_LIVE_SECURE),
+					MSNP15_WLM_PRODUCT_ID,
 					oim->challenge ? oim->challenge : "",
 					oim->send_seq,
 					msg_body);
@@ -258,7 +301,6 @@
 		oim->send_seq++;
 	}
 
-	g_free(mspauth);
 	g_free(msg_body);
 	g_free(soap_body);
 }
@@ -272,7 +314,7 @@
 {
 	MsnOimRecvData *rdata = data;
 
-	if (response && msn_soap_xml_get(response->xml, "Body/Fault") == NULL) {
+	if (response && xmlnode_get_child(response->xml, "Body/Fault") == NULL) {
 		purple_debug_info("msnoim", "delete OIM success\n");
 		rdata->oim->oim_list = g_list_remove(rdata->oim->oim_list,
 			rdata->msg_id);
@@ -291,11 +333,22 @@
 	MsnOim *oim = rdata->oim;
 	char *msgid = rdata->msg_id;
 	char *soap_body;
+	GHashTable *token;
+	const char *msn_t;
+	const char *msn_p;
 
 	purple_debug_info("MSNP14","Delete single OIM Message {%s}\n",msgid);
 
-	soap_body = g_strdup_printf(MSN_OIM_DEL_TEMPLATE,
-		oim->session->passport_info.t, oim->session->passport_info.p, msgid);
+	token = msn_nexus_get_token(oim->session->nexus, MSN_AUTH_MESSENGER_WEB);
+	g_return_if_fail(token != NULL);
+
+	msn_t = g_hash_table_lookup(token, "t");
+	msn_p = g_hash_table_lookup(token, "p");
+
+	g_return_if_fail(msn_t != NULL);
+	g_return_if_fail(msn_p != NULL);
+
+	soap_body = g_strdup_printf(MSN_OIM_DEL_TEMPLATE, msn_t, msn_p, msgid);
 
 	msn_soap_message_send(oim->session,
 		msn_soap_message_new(MSN_OIM_DEL_SOAP_ACTION,
@@ -445,7 +498,7 @@
 	MsnOimRecvData *rdata = data;
 
 	if (response != NULL) {
-		xmlnode *msg_node = msn_soap_xml_get(response->xml,
+		xmlnode *msg_node = xmlnode_get_child(response->xml,
 			"Body/GetMessageResponse/GetMessageResult");
 
 		if (msg_node) {
@@ -468,20 +521,37 @@
 void
 msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg)
 {
-	xmlnode *node, *mNode;
-	xmlnode *iu_node;
-	MsnSession *session = oim->session;
+	xmlnode *node;
 
 	purple_debug_info("MSNP14:OIM", "%s\n", xmlmsg);
 
-	node = xmlnode_from_str(xmlmsg, -1);
+	if (!strcmp(xmlmsg, "too-large")) {
+		/* Too many OIM's to send via NS, so we need to request them via SOAP. */
+		msn_oim_get_metadata(oim);
+	} else {
+		node = xmlnode_from_str(xmlmsg, -1);
+		msn_parse_oim_xml(oim, node);
+		xmlnode_free(node);
+	}
+}
+
+static void
+msn_parse_oim_xml(MsnOim *oim, xmlnode *node)
+{
+	xmlnode *mNode;
+	xmlnode *iu_node;
+	MsnSession *session = oim->session;
+
+	g_return_if_fail(node != NULL);
+
 	if (strcmp(node->name, "MD") != 0) {
+		char *xmlmsg = xmlnode_to_str(node, NULL);
 		purple_debug_info("msnoim", "WTF is this? %s\n", xmlmsg);
-		xmlnode_free(node);
+		g_free(xmlmsg);
 		return;
 	}
 
-	iu_node = msn_soap_xml_get(node, "E/IU");
+	iu_node = xmlnode_get_child(node, "E/IU");
 
 	if (iu_node != NULL && purple_account_get_check_mail(session->account))
 	{
@@ -528,8 +598,6 @@
 		g_free(rtime);
 		g_free(nickname);
 	}
-
-	xmlnode_free(node);
 }
 
 /*Post to get the Offline Instant Message*/
@@ -538,14 +606,24 @@
 {
 	char *soap_body;
 	MsnOimRecvData *data = g_new0(MsnOimRecvData, 1);
+	GHashTable *token;
+	const char *msn_t;
+	const char *msn_p;
 
 	purple_debug_info("MSNP14","Get single OIM Message\n");
 
+	token = msn_nexus_get_token(oim->session->nexus, MSN_AUTH_MESSENGER_WEB);
+	g_return_if_fail(token != NULL);
+
+	msn_t = g_hash_table_lookup(token, "t");
+	msn_p = g_hash_table_lookup(token, "p");
+	g_return_if_fail(msn_t != NULL);
+	g_return_if_fail(msn_p != NULL);
+
 	data->oim = oim;
 	data->msg_id = msgid;
 
-	soap_body = g_strdup_printf(MSN_OIM_GET_TEMPLATE,
-		oim->session->passport_info.t, oim->session->passport_info.p, msgid);
+	soap_body = g_strdup_printf(MSN_OIM_GET_TEMPLATE, msn_t, msn_p, msgid);
 
 	msn_soap_message_send(oim->session,
 		msn_soap_message_new(MSN_OIM_GET_SOAP_ACTION,
--- a/libpurple/protocols/msn/oim.h	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/oim.h	Sat Jun 07 03:10:15 2008 +0000
@@ -25,13 +25,37 @@
 #ifndef _MSN_OIM_H_
 #define _MSN_OIM_H_
 
-/*OIM Retrieve SOAP Template*/
+/* OIM Retrieval Info */
 #define MSN_OIM_RETRIEVE_HOST	"rsi.hotmail.com"
 #define MSN_OIM_RETRIEVE_URL	"/rsi/rsi.asmx"
+
+/* OIM GetMetadata SOAP Template */
+#define MSN_OIM_GET_METADATA_ACTION "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMetadata"
+
+#define MSN_OIM_GET_METADATA_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>"\
+		"<GetMetadata xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\" />"\
+	"</soap:Body>"\
+"</soap:Envelope>"
+
+/*OIM GetMessage SOAP Template*/
 #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: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>"\
@@ -46,15 +70,18 @@
 	"</soap:Body>"\
 "</soap:Envelope>"
 
-/*OIM Delete SOAP Template*/
+/*OIM DeleteMessages 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: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>"\
+			"<p>%s</p>"\
 		"</PassportCookie>"\
 	"</soap:Header>"\
 	"<soap:Body>"\
@@ -77,11 +104,21 @@
 
 #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_SOAP_ACTION	"http://messenger.live.com/ws/2006/09/oim/Store2"
 #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: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\"/>"\
+		"<From"\
+			" memberName=\"%s\""\
+			" friendlyName=\"%s\""\
+			" xml:lang=\"en-US\""\
+			" proxy=\"MSNMSGR\""\
+			" xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\""\
+			" msnpVer=\"MSNP15\""\
+			" buildVer=\"8.5.1288\"/>"\
 		"<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\">"\
--- a/libpurple/protocols/msn/session.c	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/session.c	Sat Jun 07 03:10:15 2008 +0000
@@ -45,8 +45,6 @@
 								 purple_account_get_username(account), NULL);
 	session->oim = msn_oim_new(session);
 
-	/*if you want to chat with Yahoo Messenger*/
-	//session->protocol_ver = WLM_YAHOO_PROT_VER;
 	session->protocol_ver = WLM_PROT_VER;
 
 	return session;
@@ -93,15 +91,13 @@
 	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);
 
-	if (session->soap_table)
+	if (session->soap_table != NULL)
 		g_hash_table_destroy(session->soap_table);
 
 	if (session->soap_cleanup_handle)
--- a/libpurple/protocols/msn/session.h	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/session.h	Sat Jun 07 03:10:15 2008 +0000
@@ -38,7 +38,6 @@
 #include "cmdproc.h"
 #include "nexus.h"
 #include "httpconn.h"
-#include "contact.h"
 #include "oim.h"
 
 #include "userlist.h"
@@ -96,7 +95,6 @@
 
 	MsnNotification *notification;
 	MsnNexus *nexus;
-	MsnContact *contact;
 	MsnOim		*oim;
 	MsnSync *sync;
 
--- a/libpurple/protocols/msn/soap.c	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/soap.c	Sat Jun 07 03:10:15 2008 +0000
@@ -841,7 +841,6 @@
 					"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"
@@ -851,7 +850,6 @@
 					"%s",
 					request->login_path,
 					request->soap_action,
-					soapconn->session->passport_info.mspauth,
 					request->login_host,
 					strlen(request->body),
 					request->body
--- a/libpurple/protocols/msn/soap2.c	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/soap2.c	Sat Jun 07 03:10:15 2008 +0000
@@ -82,6 +82,7 @@
 
 static void msn_soap_request_destroy(MsnSoapRequest *req);
 static void msn_soap_connection_sanitize(MsnSoapConnection *conn, gboolean disconnect);
+static gboolean msn_soap_write_cb_internal(gpointer data, gint fd, PurpleInputCondition cond, gboolean initial);
 
 static gboolean
 msn_soap_cleanup_each(gpointer key, gpointer value, gpointer data)
@@ -231,6 +232,7 @@
 				}
 
 				g_free(faultdata);
+				msn_soap_message_destroy(response);
 				return TRUE;
 			} else if (g_str_equal(faultdata, "wsse:FailedAuthentication")) {
 				xmlnode *reason = xmlnode_get_child(body, "faultstring");
@@ -242,6 +244,7 @@
 
 				g_free(reasondata);
 				g_free(faultdata);
+				msn_soap_message_destroy(response);
 				return FALSE;
 			}
 
@@ -254,6 +257,7 @@
 		conn->current_request = NULL;
 		request->cb(request->message, response,
 			request->cb_data);
+		msn_soap_message_destroy(response);
 		msn_soap_request_destroy(request);
 	}
 
@@ -397,10 +401,8 @@
 				message->xml = node;
 
 				if (!msn_soap_handle_body(conn, message)) {
-					msn_soap_message_destroy(message);
 					return;
 				}
-				msn_soap_message_destroy(message);
 			}
 
 			msn_soap_connection_handle_next(conn);
@@ -417,27 +419,34 @@
 static void
 msn_soap_write_cb(gpointer data, gint fd, PurpleInputCondition cond)
 {
+	msn_soap_write_cb_internal(data, fd, cond, FALSE);
+}
+
+static gboolean
+msn_soap_write_cb_internal(gpointer data, gint fd, PurpleInputCondition cond,
+		gboolean initial)
+{
 	MsnSoapConnection *conn = data;
 	int written;
 
-	g_return_if_fail(cond == PURPLE_INPUT_WRITE);
+	if (cond != PURPLE_INPUT_WRITE) return TRUE;
 
 	written = purple_ssl_write(conn->ssl, conn->buf->str + conn->handled_len,
 		conn->buf->len - conn->handled_len);
 
 	if (written < 0 && errno == EAGAIN)
-		return;
+		return TRUE;
 	else if (written <= 0) {
 		purple_ssl_close(conn->ssl);
 		conn->ssl = NULL;
-		msn_soap_connection_handle_next(conn);
-		return;
+		if (!initial) msn_soap_connection_handle_next(conn);
+		return FALSE;
 	}
 
 	conn->handled_len += written;
 
 	if (conn->handled_len < conn->buf->len)
-		return;
+		return TRUE;
 
 	/* we are done! */
 	g_string_free(conn->buf, TRUE);
@@ -451,6 +460,7 @@
 	purple_input_remove(conn->event_handle);
 	conn->event_handle = purple_input_add(conn->ssl->fd, PURPLE_INPUT_READ,
 		msn_soap_read_cb, conn);
+	return TRUE;
 }
 
 static gboolean
@@ -469,22 +479,15 @@
 			int len = -1;
 			char *body = xmlnode_to_str(req->message->xml, &len);
 			GSList *iter;
-			char *authstr = NULL;
 
 			g_queue_pop_head(conn->queue);
 
 			conn->buf = g_string_new("");
 
-			if (conn->session->passport_info.mspauth)
-				authstr = g_strdup_printf("Cookie: MSPAuth=%s\r\n",
-					conn->session->passport_info.mspauth);
-
-
 			g_string_append_printf(conn->buf,
 				"POST %s HTTP/1.1\r\n"
 				"SOAPAction: %s\r\n"
 				"Content-Type:text/xml; charset=utf-8\r\n"
-				"%s"
 				"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n"
 				"Accept: */*\r\n"
 				"Host: %s\r\n"
@@ -492,7 +495,7 @@
 				"Connection: Keep-Alive\r\n"
 				"Cache-Control: no-cache\r\n",
 				req->path, req->message->action ? req->message->action : "",
-				authstr ? authstr : "",	conn->host, len);
+				conn->host, len);
 
 			for (iter = req->message->headers; iter; iter = iter->next) {
 				g_string_append(conn->buf, (char *)iter->data);
@@ -509,9 +512,18 @@
 
 			conn->event_handle = purple_input_add(conn->ssl->fd,
 				PURPLE_INPUT_WRITE, msn_soap_write_cb, conn);
-			msn_soap_write_cb(conn, conn->ssl->fd, PURPLE_INPUT_WRITE);
+			if (!msn_soap_write_cb_internal(conn, conn->ssl->fd, PURPLE_INPUT_WRITE, TRUE)) {
+				/* Not connected => reconnect and retry */
+				purple_debug_info("soap", "not connected, reconnecting");
+				
+				conn->connected = FALSE;
+				conn->current_request = NULL;
+				msn_soap_connection_sanitize(conn, FALSE);
+				
+				g_queue_push_head(conn->queue, req);
+				conn->event_handle = purple_timeout_add(0, msn_soap_connection_run, conn);
+			}
 
-			g_free(authstr);
 			g_free(body);
 		}
 	}
@@ -664,21 +676,3 @@
 	g_free(req);
 }
 
-xmlnode *
-msn_soap_xml_get(xmlnode *parent, const char *node)
-{
-	xmlnode *ret = NULL;
-	char **tokens = g_strsplit(node, "/", -1);
-	int i;
-
-	for (i = 0; tokens[i]; i++) {
-		if ((ret = xmlnode_get_child(parent, tokens[i])) != NULL)
-			parent = ret;
-		else
-			break;
-	}
-
-	g_strfreev(tokens);
-	return ret;
-}
-
--- a/libpurple/protocols/msn/soap2.h	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/soap2.h	Sat Jun 07 03:10:15 2008 +0000
@@ -53,6 +53,4 @@
 
 void msn_soap_message_destroy(MsnSoapMessage *message);
 
-xmlnode *msn_soap_xml_get(xmlnode *parent, const char *node);
-
 #endif
--- a/libpurple/protocols/msn/userlist.c	Sat Jun 07 00:00:34 2008 +0000
+++ b/libpurple/protocols/msn/userlist.c	Sat Jun 07 03:10:15 2008 +0000
@@ -24,6 +24,8 @@
 #include "msn.h"
 #include "userlist.h"
 
+#include "contact.h"
+
 const char *lists[] = { "FL", "AL", "BL", "RL" };
 
 typedef struct
@@ -51,7 +53,7 @@
 
 		msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_AL);
 
-		msn_del_contact_from_list(session->contact, NULL, pa->who, MSN_LIST_PL);
+		msn_del_contact_from_list(session, NULL, pa->who, MSN_LIST_PL);
 	}
 
 	g_free(pa->who);
@@ -75,7 +77,7 @@
 		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);
+		msn_del_contact_from_list(session, state, pa->who, MSN_LIST_PL);
 	}
 
 	g_free(pa->who);
@@ -647,7 +649,6 @@
 
 	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);
@@ -656,7 +657,7 @@
 
 	/* delete the contact from address book via soap action */
 	if (user != NULL) {
-		msn_delete_contact(userlist->session->contact, user->uid);
+		msn_delete_contact(userlist->session, user->uid);
 	}
 }
 
@@ -758,7 +759,7 @@
 
 	/* 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);
+	msn_add_contact_to_group(userlist->session, state, who, group_id);
 }
 
 void
@@ -859,7 +860,6 @@
 
 	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(userlist->session);
 	msn_callback_state_set_who(state, who);
@@ -878,7 +878,7 @@
 	/* 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_add_contact_to_group(userlist->session, state, who, new_group_id);
 }
 
 /*load userlist from the Blist file cache*/