changeset 23502:f61f7e8d897e

propagate from branch 'im.pidgin.pidgin' (head 64e9bf80895d2671f0a42fecc17e3ba895b41426) to branch 'im.pidgin.pidgin.khc.msnp15' (head 21f516729b577a6ecb168d8ce480a466ede4c05d)
author Ka-Hing Cheung <khc@hxbc.us>
date Wed, 27 Feb 2008 04:49:37 +0000
parents 00eaff9396ec (diff) 382bc33e8824 (current diff)
children 44159acb7bb7
files libpurple/protocols/msn/notification.c
diffstat 15 files changed, 964 insertions(+), 405 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/msn/contact.c	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/contact.c	Wed Feb 27 04:49:37 2008 +0000
@@ -29,6 +29,7 @@
 #include "xmlnode.h"
 #include "group.h"
 #include "soap2.h"
+#include "nexus.h"
 
 const char *MsnSoapPartnerScenarioText[] =
 {
@@ -210,7 +211,7 @@
 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);
 	} else {
@@ -230,7 +231,9 @@
 	
 	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(contact->session->nexus, MSN_AUTH_CONTACTS),
+		contact->session->user->passport);
 
 	msn_soap_message_send(contact->session,
 		msn_soap_message_new(MSN_ADD_ADDRESSBOOK_SOAP_ACTION,
@@ -269,7 +272,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")) {
@@ -283,7 +286,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)) {
 
@@ -295,7 +298,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")) {
@@ -331,14 +334,14 @@
 	 *
 	 * 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")) {
@@ -354,7 +357,7 @@
 	} 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);
@@ -416,7 +419,9 @@
 		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(contact->session->nexus, MSN_AUTH_CONTACTS),
+		update_str ? update_str : "");
 
 	msn_soap_message_send(contact->session,
 		msn_soap_message_new(MSN_GET_CONTACT_SOAP_ACTION,
@@ -597,7 +602,7 @@
 
 	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"))) {
@@ -606,7 +611,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);
@@ -620,7 +625,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;
@@ -729,7 +734,10 @@
 	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(contact->session->nexus, MSN_AUTH_CONTACTS),
+		update_str ? update_str : "");
 
 	msn_soap_message_send(contact->session,
 		msn_soap_message_new(MSN_GET_ADDRESS_SOAP_ACTION,
@@ -794,7 +802,9 @@
 	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(contact->session->nexus, MSN_AUTH_CONTACTS),
+		contact_xml);
 
 	msn_soap_message_send(contact->session,
 		msn_soap_message_new(MSN_CONTACT_ADD_SOAP_ACTION,
@@ -902,7 +912,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(contact->session->nexus, MSN_AUTH_CONTACTS),
+		groupId, contact_xml);
 
 	msn_soap_message_send(state->session,
 		msn_soap_message_new(MSN_ADD_CONTACT_GROUP_SOAP_ACTION,
@@ -950,7 +962,10 @@
 
 	/* 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);
+	body = g_strdup_printf(MSN_DEL_CONTACT_TEMPLATE,
+		msn_nexus_get_token_str(contact->session->nexus, MSN_AUTH_CONTACTS),
+		contact_id_xml);
+
 	msn_soap_message_send(contact->session,
 		msn_soap_message_new(MSN_CONTACT_DEL_SOAP_ACTION,
 			xmlnode_from_str(body, -1)),
@@ -1022,7 +1037,9 @@
 	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(contact->session->nexus, MSN_AUTH_CONTACTS),
+		contact_id_xml, groupId);
 
 	msn_soap_message_send(contact->session,
 		msn_soap_message_new(MSN_CONTACT_DEL_GROUP_SOAP_ACTION,
@@ -1055,7 +1072,9 @@
 
 	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(contact->session->nexus, MSN_AUTH_CONTACTS),
+		escaped_nickname);
 
 	msn_soap_message_send(contact->session,
 		msn_soap_message_new(MSN_CONTACT_UPDATE_SOAP_ACTION,
@@ -1133,9 +1152,9 @@
 	}
 
 	body = g_strdup_printf( MSN_CONTACT_DELECT_FROM_LIST_TEMPLATE,
-			        MsnSoapPartnerScenarioText[partner_scenario],
-			        MsnMemberRole[list],
-			        member);
+		MsnSoapPartnerScenarioText[partner_scenario],
+		msn_nexus_get_token_str(contact->session->nexus, MSN_AUTH_CONTACTS),
+		MsnMemberRole[list], member);
 
 	msn_soap_message_send(contact->session,
 		msn_soap_message_new(MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION,
@@ -1205,9 +1224,9 @@
 	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(contact->session->nexus, MSN_AUTH_CONTACTS),
+		MsnMemberRole[list], member);
 
 	msn_soap_message_send(contact->session,
 		msn_soap_message_new(MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION,
@@ -1234,13 +1253,19 @@
 msn_get_gleams(MsnContact *contact)
 {
 	MsnSoapReq *soap_request;
+	gchar *body = NULL;
 
 	purple_debug_info("MSNP14","msn get gleams info...\n");
+	
+	body = g_strdup_printf(MSN_GLEAMS_TEMPLATE,
+		msn_nexus_get_token_str(contact->session->nexus, MSN_AUTH_CONTACTS));
+
 	msn_soap_message_send(contact->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
 
@@ -1279,7 +1304,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) {
@@ -1323,6 +1348,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);
@@ -1339,7 +1365,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,
@@ -1347,6 +1376,7 @@
 		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
 		msn_group_read_cb, state);
 
+	g_free(escaped_group_name);
 	g_free(body);
 }
 
@@ -1382,7 +1412,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,
@@ -1400,6 +1432,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);
@@ -1423,8 +1456,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,
@@ -1432,5 +1467,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	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/contact.h	Wed Feb 27 04:49:37 2008 +0000
@@ -31,9 +31,12 @@
 
 #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 +47,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 +76,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 +89,7 @@
 		"</ABApplicationHeader>"\
 		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
 			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+			"<TicketToken>%s</TicketToken>"\
 		"</ABAuthHeader>"\
 	"</soap:Header>"\
 	"<soap:Body>"\
@@ -98,7 +107,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 +117,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 +130,7 @@
 		"</ABApplicationHeader>"\
 		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
 			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+			"<TicketToken>%s</TicketToken>"\
 		"</ABAuthHeader>"\
 	"</soap:Header>"\
 	"<soap:Body>"\
@@ -131,7 +146,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 +159,7 @@
 		"</ABApplicationHeader>"\
 		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
 			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+			"<TicketToken>%s</TicketToken>"\
 		"</ABAuthHeader>"\
 	"</soap:Header>"\
 	"<soap:Body>"\
@@ -157,26 +177,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 +219,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 +271,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 +285,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 +375,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 +405,7 @@
 		"</ABApplicationHeader>"\
 		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
 			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+			"<TicketToken>%s</TicketToken>"\
 		"</ABAuthHeader>"\
 	"</soap:Header>"\
 	"<soap:Body>"\
@@ -301,7 +428,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 +441,7 @@
 		"</ABApplicationHeader>"\
 		"<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\
 			"<ManagedGroupRequest>false</ManagedGroupRequest>"\
+			"<TicketToken>%s</TicketToken>"\
 		"</ABAuthHeader>"\
 	"</soap:Header>"\
 	"<soap:Body>"\
@@ -339,15 +471,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 
 {
--- a/libpurple/protocols/msn/msn.c	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/msn.c	Wed Feb 27 04:49:37 2008 +0000
@@ -935,7 +935,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*/
 
@@ -1002,7 +1005,7 @@
 		}
 
 		msn_message_destroy(msg);
-	}else	{
+	} else {
 		/*send Offline Instant Message,only to MSN Passport User*/
 		MsnSession *session;
 		char *friendname;
@@ -1013,8 +1016,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);
 	}
 
--- a/libpurple/protocols/msn/msn.h	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/msn.h	Wed Feb 27 04:49:37 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	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/msnutils.c	Wed Feb 27 04:49:37 2008 +0000
@@ -513,8 +513,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	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/nexus.c	Wed Feb 27 04:49:37 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,47 +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);
+	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);
 			}
@@ -97,33 +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*/
-			if (session->passport_info.t != NULL){
-				g_free(session->passport_info.t);
-			}
-			session->passport_info.t = g_strdup(msn_twn_t);
+			/* Yay for MS using ISO-8601 */
+			expiry_str = xmlnode_get_data(expires);
 
-			if (session->passport_info.p != NULL)
-				g_free(session->passport_info.p);
-			session->passport_info.p = g_strdup(msn_twn_p);
-
-			cert_str = g_strdup_printf("t=%s&p=%s",msn_twn_t,msn_twn_p);
-			msn_got_login_params(session, cert_str);
+			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 */
@@ -131,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;
 	char *username, *password;
-	char *tail;
-#ifdef NEXUS_LOGIN_TWN
-	char *challenge_str;
-#else
-	char *rst1_str,*rst2_str,*rst3_str;
-#endif
+	GString *domains;
+	char *request;
+	int i;
 
 	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 = 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;
+
 	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(username);
-		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	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/nexus.h	Wed Feb 27 04:49:37 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	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/notification.c	Wed Feb 27 04:49:37 2008 +0000
@@ -204,7 +204,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;
 
@@ -212,7 +212,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
@@ -221,8 +221,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
@@ -248,32 +248,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);
 
@@ -343,7 +325,8 @@
 	 */
 	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));
 }
 
@@ -550,7 +533,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));
@@ -565,7 +548,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);
 
--- a/libpurple/protocols/msn/notification.h	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/notification.h	Wed Feb 27 04:49:37 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	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/oim.c	Wed Feb 27 04:49:37 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,
@@ -112,6 +113,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*/
@@ -146,7 +191,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*/
@@ -158,9 +203,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 *node;
+
+	purple_debug_info("MSNP14:OIM", "%s\n", xmlmsg);
+
+	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;
 
-	purple_debug_info("MSNP14:OIM", "%s", xmlmsg);
+	g_return_if_fail(node != NULL);
 
-	node = xmlnode_from_str(xmlmsg, -1);
 	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	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/oim.h	Wed Feb 27 04:49:37 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	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/session.c	Wed Feb 27 04:49:37 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;
@@ -101,7 +99,7 @@
 	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/soap.c	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/soap.c	Wed Feb 27 04:49:37 2008 +0000
@@ -835,7 +835,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"
@@ -845,7 +844,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	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/soap2.c	Wed Feb 27 04:49:37 2008 +0000
@@ -229,6 +229,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");
@@ -240,6 +241,7 @@
 
 				g_free(reasondata);
 				g_free(faultdata);
+				msn_soap_message_destroy(response);
 				return FALSE;
 			}
 
@@ -252,6 +254,7 @@
 		conn->current_request = NULL;
 		request->cb(request->message, response,
 			request->cb_data);
+		msn_soap_message_destroy(response);
 		msn_soap_request_destroy(request);
 	}
 
@@ -464,22 +467,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"
@@ -487,7 +483,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);
@@ -506,7 +502,6 @@
 				PURPLE_INPUT_WRITE, msn_soap_write_cb, conn);
 			msn_soap_write_cb(conn, conn->ssl->fd, PURPLE_INPUT_WRITE);
 
-			g_free(authstr);
 			g_free(body);
 		}		
 	}
@@ -659,21 +654,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	Wed Feb 27 04:49:20 2008 +0000
+++ b/libpurple/protocols/msn/soap2.h	Wed Feb 27 04:49:37 2008 +0000
@@ -53,6 +53,4 @@
 
 void msn_soap_message_destroy(MsnSoapMessage *message);
 
-xmlnode *msn_soap_xml_get(xmlnode *parent, const char *node);
-
 #endif