changeset 21109:e64e6fbd1351

merge_into_workspace of c0e79d15a4fe4c5b0129fcae5060754b25f72a56 and 1bd638d193e3a865ce99ed451afc25d957d7c9a2
author Ka-Hing Cheung <khc@hxbc.us>
date Tue, 30 Oct 2007 06:29:13 +0000
parents 29d8c86c14cd (current diff) 90fd0826c6ce (diff)
children dead11aac1bc
files libpurple/protocols/msn/contact.c libpurple/protocols/msn/contact.h libpurple/protocols/msn/nexus.c libpurple/protocols/msn/oim.c libpurple/protocols/msn/userlist.c po/sr@Latn.po
diffstat 6 files changed, 542 insertions(+), 976 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/msn/contact.c	Thu Oct 04 06:13:01 2007 +0000
+++ b/libpurple/protocols/msn/contact.c	Tue Oct 30 06:29:13 2007 +0000
@@ -28,6 +28,7 @@
 #include "contact.h"
 #include "xmlnode.h"
 #include "group.h"
+#include "soap2.h"
 
 const char *MsnSoapPartnerScenarioText[] =
 {
@@ -47,6 +48,11 @@
 	"Pending"
 };
 
+typedef struct {
+	MsnContact *contact;
+	MsnSoapPartnerScenario which;
+} GetContactListCbData;
+
 /* new a contact */
 MsnContact *
 msn_contact_new(MsnSession *session)
@@ -55,7 +61,6 @@
 
 	contact = g_new0(MsnContact, 1);
 	contact->session = session;
-	contact->soapconn = msn_soap_new(session,contact,1);
 
 	return contact;
 }
@@ -64,15 +69,18 @@
 void
 msn_contact_destroy(MsnContact *contact)
 {
-	msn_soap_destroy(contact->soapconn);
 	g_free(contact);
 }
 
 MsnCallbackState *
-msn_callback_state_new(void)
+msn_callback_state_new(MsnSession *session)
 {
-	return g_new0(MsnCallbackState, 1);
-}
+	MsnCallbackState *state = g_new0(MsnCallbackState, 1);
+
+	state->session = session;
+
+	return state;
+}	
 
 void
 msn_callback_state_free(MsnCallbackState *state)
@@ -176,36 +184,6 @@
 	state->action |= action;
 }
 
-/*contact SOAP server login error*/
-static void
-msn_contact_login_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error)
-{
-	MsnSession *session;
-
-	session = soapconn->session;
-	g_return_if_fail(session != NULL);
-
-	msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to contact server"));
-}
-
-/*msn contact SOAP server connect process*/
-static gboolean
-msn_contact_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc)
-{
-	MsnSession * session;
-	MsnContact *contact;
-
-	contact = soapconn->parent;
-	g_return_val_if_fail(contact != NULL, TRUE);
-
-	session = contact->session;
-	g_return_val_if_fail(session != NULL, FALSE);
-
-	/*login ok!We can retrieve the contact list*/
-//	msn_get_contact_list(contact, MSN_PS_INITIAL, NULL);
-	return TRUE;
-}
-
 /*get MSN member role utility*/
 static MsnListId
 msn_get_memberrole(char *role)
@@ -244,37 +222,20 @@
 }
 
 /* Create the AddressBook in the server, if we don't have one */
-static gboolean
-msn_create_address_cb(MsnSoapConn *soapconn)
+static void
+msn_create_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data)
 {
-	MsnContact *contact;
-
-	if (soapconn->body == NULL)
-		return TRUE;
-
-	contact = soapconn->parent;
-	g_return_val_if_fail(contact != NULL, TRUE);
-
-	purple_debug_info("MSN AddressBook", "Address Book successfully created!\n");
-	msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL);
-
-//	msn_soap_free_read_buf(soapconn);
-	return TRUE;
-}
-
-static void
-msn_create_address_written_cb(MsnSoapConn *soapconn)
-{
-	purple_debug_info("MSN AddressBook","AddressBookAdd written\n");
-	soapconn->read_cb = msn_create_address_cb;
-
-	return;
+	if (resp && msn_soap_xml_get(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 {
+		purple_debug_info("msnab", "Address Book creation failed!\n");
+	}
 }
 
 static void
 msn_create_address_book(MsnContact * contact)
 {
-	MsnSoapReq *soap_request;
 	gchar *body;
 
 	g_return_if_fail(contact != NULL);
@@ -282,323 +243,184 @@
 	g_return_if_fail(contact->session->user != NULL);
 	g_return_if_fail(contact->session->user->passport != NULL);
 	
-	purple_debug_info("MSN AddressBook","Creating an Address Book.\n");
+	purple_debug_info("msnab","Creating an Address Book.\n");
 
 	body = g_strdup_printf(MSN_ADD_ADDRESSBOOK_TEMPLATE, contact->session->user->passport);
 
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					MSN_ADDRESS_BOOK_POST_URL,MSN_ADD_ADDRESSBOOK_SOAP_ACTION,
-					body,
-					NULL,
-					msn_create_address_cb,
-					msn_create_address_written_cb,
-					msn_contact_connect_init);
-	msn_soap_post(contact->soapconn, soap_request);
+	msn_soap_message_send(contact->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);
 
 	g_free(body);
-	
-	return;
+}
+
+static void
+msn_parse_each_member(MsnSession *session, xmlnode *member, const char *node,
+	MsnListId list)
+{
+	char *passport = xmlnode_get_data(xmlnode_get_child(member, node));
+	char *type = xmlnode_get_data(xmlnode_get_child(member, "type"));
+	char *member_id = xmlnode_get_data(xmlnode_get_child(member, "MembershipId"));
+	MsnUser *user = msn_userlist_find_add_user(session->userlist, passport, NULL);
+
+	purple_debug_info("msncl","%s name: %s, Type: %s\n", node, passport, type);
+
+	if (member_id) {
+		user->membership_id[list] = atoi(member_id);
+	}
+
+	msn_got_lst_user(session, user, 1 << list, NULL);         
+
+	g_free(passport);
+	g_free(type);
+	g_free(member_id);
+}
+
+static void
+msn_parse_each_service(MsnSession *session, xmlnode *service)
+{
+	xmlnode *type;
+
+	if ((type = msn_soap_xml_get(service, "Info/Handle/Type"))) {
+		char *type_str = xmlnode_get_data(type);
+
+		if (g_str_equal(type_str, "Profile")) {
+			/* Process Windows Live 'Messenger Roaming Identity' */
+		} else if (g_str_equal(type_str, "Messenger")) {
+			xmlnode *lastchange = xmlnode_get_child(service, "LastChange");
+			char *lastchange_str = xmlnode_get_data(lastchange);
+			xmlnode *membership;
+
+			purple_debug_info("msncl","last change: %s\n", lastchange_str);	
+			purple_account_set_string(session->account,	"CLLastChange",
+				lastchange_str);
+
+			for (membership = msn_soap_xml_get(service,
+					"Memberships/Membership");
+				 membership; membership = xmlnode_get_next_twin(membership)) {
+
+				xmlnode *role = xmlnode_get_child(membership, "MemberRole");
+				char *role_str = xmlnode_get_data(role);
+				MsnListId list = msn_get_memberrole(role_str);
+				xmlnode *member;
+
+				purple_debug_info("msncl", "MemberRole role: %s, list: %d\n",
+					role, list);
+
+				for (member = msn_soap_xml_get(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")) {
+						msn_parse_each_member(session, member, "PassportName",
+							list);
+					} else if (g_str_equal(member_type, "PhoneMember")) {
+
+					} else if (g_str_equal(member_type, "EmailMember")) {
+						msn_parse_each_member(session, member, "Email",	list);
+					}
+				}
+
+				g_free(role_str);
+			}
+
+			g_free(lastchange_str);
+		}
+
+		g_free(type_str);
+	}
 }
 
 /*parse contact list*/
 static void
-msn_parse_contact_list(MsnContact * contact)
+msn_parse_contact_list(MsnContact *contact, xmlnode *node)
 {
-	MsnSession * session;
-	MsnListOp list_op = 0;
-	MsnListId list;
-	char * passport, *typedata;
-	xmlnode *fault, *faultstringnode, *faultdetail, *errorcode;
-	xmlnode *node, *body, *response, *result, *services;
-	xmlnode *service, *memberships, *info, *handle, *handletype;
-	xmlnode *membershipnode, *members, *member, *passportNode;
-
-	session = contact->session;
-	node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len);
-
-	if (node == NULL) {
-		purple_debug_error("MSNCL","Unable to parse SOAP data!\n");
-		return;
-	}
-
-	purple_debug_misc("MSNCL","Parsing contact list with size %d\n", contact->soapconn->body_len);
+	xmlnode *fault, *faultnode;
 
-	purple_debug_misc("MSNCL","Root node @ %p: Name: '%s', child: '%s', lastchild: '%s'\n", node,
-		node->name ? node->name : "(null)",
-		(node->child && node->child->name) ? node->child->name : "(null)",
-		(node->lastchild && node->lastchild->name) ? node->lastchild->name : "(null)");
-
-	body = xmlnode_get_child(node, "Body");
-
-	if (body == NULL) {
-		purple_debug_warning("MSNCL", "Failed to parse contact list Body node\n");
-		xmlnode_free(node);
-		return;
-	}
-	purple_debug_info("MSNCL","Body @ %p:  Name: '%s'\n",body,body->name);
-
-	/* Did we receive a <Fault> ? */
-	if ( (fault = xmlnode_get_child(body, "Fault")) != NULL) {
-	        purple_debug_info("MSNCL","Fault received from SOAP server!\n");
-
-		if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) {
-			gchar * faultstring = xmlnode_get_data(faultstringnode);
-			purple_debug_info("MSNCL", "Faultstring: %s\n", faultstring ? faultstring : "(null)");
+	/* we may get a response if our cache data is too old:
+	 *
+	 * <faultstring>Need to do full sync. Can't sync deltas Client
+	 * has too old a copy for us to do a delta sync</faultstring>
+	 *
+	 * this is not handled yet
+	 */
+	if ((fault = msn_soap_xml_get(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 ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) {
-			purple_debug_info("MSNCL","detail @ %p, name: %s\n",faultdetail, faultdetail->name);
-
-			if ( (errorcode = xmlnode_get_child(faultdetail, "errorcode")) != NULL ) {
-				purple_debug_info("MSNCL","errorcode @ %p, name: %s\n", errorcode, errorcode->name);
-
-				if (errorcode->child != NULL) {
-					gchar *errorcodestring = xmlnode_get_data(errorcode);
-					purple_debug_info("MSNCL", "Error Code: %s\n", errorcodestring ? errorcodestring : "(null)");
-
-					if (errorcodestring && !strncmp(errorcodestring, "ABDoesNotExist", 14) ) {
-						xmlnode_free(node);
-						g_free(errorcodestring);
-						msn_create_address_book(contact);
-						return;
-					}
-					g_free(errorcodestring);
-				}
-			}
-		}
-		xmlnode_free(node);
-		msn_get_contact_list(contact, MSN_PS_INITIAL, NULL);
-		return;
-	}
-
-	response = xmlnode_get_child(body,"FindMembershipResponse");
+		if ((faultnode = msn_soap_xml_get(fault, "detail/errorcode"))) {
+			char *errorcode = xmlnode_get_data(faultnode);
 
-	if (response == NULL) {
-		/* we may get a response if our cache data is too old:
-		 *
-		 * <faultstring>Need to do full sync. Can't sync deltas Client
-		 * has too old a copy for us to do a delta sync</faultstring>
-		 */
-		xmlnode_free(node);
-		msn_get_contact_list(contact, MSN_PS_INITIAL, NULL);
-		return;
-	}
-	purple_debug_info("MSNCL","FindMembershipResponse @ %p: Name: '%s'\n",response,response->name);
-
-	result = xmlnode_get_child(response,"FindMembershipResult");
-	if (result == NULL) {
-		purple_debug_warning("MSNCL","Received No Update!\n");
-		xmlnode_free(node);
-		return;
-	}
-	purple_debug_info("MSNCL","Result @ %p: Name: '%s'\n", result, result->name);
+			if (g_str_equal(errorcode, "ABDoesNotExist")) {
+				msn_create_address_book(contact);
+				g_free(errorcode);
+				return;
+			}
 
-	if ( (services = xmlnode_get_child(result,"Services")) == NULL) {
-		purple_debug_misc("MSNCL","No <Services> received.\n");
-		xmlnode_free(node);
-		return;
-	}
-
-	purple_debug_info("MSNCL","Services @ %p\n",services);
-	
-	for (service = xmlnode_get_child(services, "Service"); service;
-	                                service = xmlnode_get_next_twin(service)) {
-		purple_debug_info("MSNCL","Service @ %p\n",service);
-
-		if ( (info = xmlnode_get_child(service,"Info")) == NULL ) {
-			purple_debug_error("MSNCL","Error getting 'Info' child node\n");
-			continue;
-		}
-		if ( (handle = xmlnode_get_child(info,"Handle")) == NULL ) {
-			purple_debug_error("MSNCL","Error getting 'Handle' child node\n");
-			continue;
-		}
-		if ( (handletype = xmlnode_get_child(handle,"Type")) == NULL ) {
-			purple_debug_error("MSNCL","Error getting 'Type' child node\n");
-			continue;
+			g_free(errorcode);
 		}
 
-		if ( (typedata = xmlnode_get_data(handletype)) == NULL) {
-			purple_debug_error("MSNCL","Error retrieving data from 'Type' child node\n");
-			continue;
-		}
-
-		purple_debug_info("MSNCL","processing '%s' Service\n", typedata);
-
-		if ( !g_strcasecmp(typedata, "Profile") ) {
-			/* Process Windows Live 'Messenger Roaming Identity' */
-			g_free(typedata);
-			continue;
-		}
-
-		if ( !g_strcasecmp(typedata, "Messenger") ) {
-			char *LastChangeStr = NULL;
-			xmlnode *LastChangeNode;
-
-			/*Last Change Node*/
-			if ((LastChangeNode = xmlnode_get_child(service, "LastChange")))
-				LastChangeStr = xmlnode_get_data(LastChangeNode);
-			purple_debug_info("MSNCL","LastChangeNode: '%s'\n",LastChangeStr ? LastChangeStr : "(null)");
-			purple_account_set_string(session->account, "CLLastChange", LastChangeStr);
-			g_free(LastChangeStr);
+		msn_get_contact_list(contact, MSN_PS_INITIAL, NULL);
+	} else {
+		xmlnode *service;
 
-			memberships = xmlnode_get_child(service,"Memberships");
-			if (memberships == NULL) {
-				purple_debug_warning("MSNCL","Memberships = NULL, cleaning up and returning.\n");
-				g_free(typedata);
-				xmlnode_free(node);
-				return;
-			}
-			purple_debug_info("MSNCL","Memberships @ %p: Name: '%s'\n",memberships,memberships->name);
-			for (membershipnode = xmlnode_get_child(memberships, "Membership"); membershipnode;
-							membershipnode = xmlnode_get_next_twin(membershipnode)){
-				xmlnode *roleNode;
-				char *role = NULL;
-				list = 0;
+		for (service = msn_soap_xml_get(node, "Body/FindMembershipResponse/"
+				"FindMembershipResult/Services/Service");
+			 service; service = xmlnode_get_next_twin(service)) {
+			msn_parse_each_service(contact->session, service);
+		}
+	}
+}
 
-				if ((roleNode = xmlnode_get_child(membershipnode,"MemberRole"))) {
-					role = xmlnode_get_data(roleNode);
-					list = msn_get_memberrole(role);
-				}
-				list_op = 1 << list;
-
-				purple_debug_info("MSNCL","MemberRole role: %s, list_op: %d\n", role ? role : "(null)", list_op);
+static void
+msn_get_contact_list_cb(MsnSoapMessage *req, MsnSoapMessage *resp,
+	gpointer data)
+{
+	GetContactListCbData *cb_data = data;
+	MsnContact *contact = cb_data->contact;
+	MsnSession *session = contact->session;
 
-				g_free(role);
-
-				members = xmlnode_get_child(membershipnode, "Members");
-				for (member = xmlnode_get_child(members, "Member"); member;
-						member = xmlnode_get_next_twin(member)){
-					MsnUser *user = NULL;
-					xmlnode *typeNode, *membershipIdNode = NULL;
-					gchar *type, *membershipId = NULL;
-					const char *member_type = xmlnode_get_attrib(member, "type");
+	g_return_if_fail(session != NULL);
 
-					if (!member_type) {
-						purple_debug_error("msn", "No Member Type specified for Member.\n");
-						continue;
-					}
+	if (resp != NULL) {
+		const char *abLastChange;
+		const char *dynamicItemLastChange;
 
-					if(!g_strcasecmp(member_type, "PassportMember") ) {
-						passport = type = NULL;
-						if ((passportNode = xmlnode_get_child(member, "PassportName")))
-							passport = xmlnode_get_data(passportNode);
-						if ((typeNode = xmlnode_get_child(member, "Type")))
-							type = xmlnode_get_data(typeNode);
-						purple_debug_info("MSNCL","Passport name: '%s', Type: %s\n", passport ? passport : "(null)", type ? type : "(null)");
-						/* Why do we even bother parsing it just to free it??? */
-						g_free(type);
-
-						user = msn_userlist_find_add_user(session->userlist,passport,NULL);
-						g_free(passport);
-
-						membershipIdNode = xmlnode_get_child(member,"MembershipId");
-						if (membershipIdNode != NULL) {
-							membershipId = xmlnode_get_data(membershipIdNode);
-							if (membershipId != NULL) {
-								user->membership_id[list] = atoi(membershipId);
-								g_free(membershipId);
-							}
-						}
+		purple_debug_misc("msncl","Got the contact list!\n");
 
-						msn_got_lst_user(session, user, list_op, NULL);
-					}
-					else if (!g_strcasecmp(member_type, "PhoneMember")) {
-						purple_debug_info("msn", "Recieved Phone Member; ignoring.\n");
-					}
-					else if (!g_strcasecmp(member_type, "EmailMember")) {
-						xmlnode *emailNode;
-						passport = NULL;
-
-						if ((emailNode = xmlnode_get_child(member, "Email")))
-							passport = xmlnode_get_data(emailNode);
-						purple_debug_info("MSNCL","Email Member: Name: '%s', list_op: %d\n", passport ? passport : "(null)", list_op);
-
-						user = msn_userlist_find_add_user(session->userlist, passport, NULL);
-						g_free(passport);
+		msn_parse_contact_list(cb_data->contact, resp->xml);
+		abLastChange = purple_account_get_string(session->account,
+			"ablastChange", NULL);
+		dynamicItemLastChange = purple_account_get_string(session->account,
+			"dynamicItemLastChange", NULL);
 
-						membershipIdNode = xmlnode_get_child(member,"MembershipId");
-						if (membershipIdNode != NULL) {
-							membershipId = xmlnode_get_data(membershipIdNode);
-							if (membershipId != NULL) {
-								user->membership_id[list] = atoi(membershipId);
-								g_free(membershipId);
-							}
-						}
-
-						msn_got_lst_user(session, user, list_op, NULL);
-					} else {
-						purple_debug_info("msn", "Unknown Member type: %s\n", member_type);
-					}
-				}
-			}
-			g_free(typedata);	/* Free 'Type' node data after processing 'Messenger' Service */
+		if (cb_data->which == MSN_PS_INITIAL) {
+#ifdef MSN_PARTIAL_LISTS
+			/* XXX: this should be enabled when we can correctly do partial
+			   syncs with the server. Currently we need to retrieve the whole
+			   list to detect sync issues */
+			msn_get_address_book(contact, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange);
+#else
+			msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL);
+#endif
 		}
 	}
 
-	xmlnode_free(node);	/* Free the whole XML tree */
+	g_free(cb_data);
 }
 
-static gboolean
-msn_get_contact_list_cb(MsnSoapConn *soapconn)
+/*SOAP  get contact list*/
+void
+msn_get_contact_list(MsnContact * contact,
+	const MsnSoapPartnerScenario partner_scenario, const char *update_time)
 {
-	MsnContact *contact;
-	MsnSession *session;
-	const char *abLastChange;
-	const char *dynamicItemLastChange;
-	gchar *partner_scenario;
-
-	if (soapconn->body == NULL)
-		return TRUE;
-
-	purple_debug_misc("MSNCL","Got the contact list!\n");
-
-	contact = soapconn->parent;
-	g_return_val_if_fail(contact != NULL, TRUE);
-	session = soapconn->session;
-	g_return_val_if_fail(session != NULL, FALSE);
-	g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
-
-	partner_scenario = soapconn->data_cb;
-
-	msn_parse_contact_list(contact);
-	/*free the read buffer*/
-	msn_soap_free_read_buf(soapconn);
-
-	abLastChange = purple_account_get_string(session->account, "ablastChange", NULL);
-	dynamicItemLastChange = purple_account_get_string(session->account, "dynamicItemLastChange", NULL);
-
-	if (!strcmp(partner_scenario, MsnSoapPartnerScenarioText[MSN_PS_INITIAL])) {
-
-#ifdef MSN_PARTIAL_LISTS
-		/* XXX: this should be enabled when we can correctly do partial
-	 	  syncs with the server. Currently we need to retrieve the whole
-	 	  list to detect sync issues */
-		msn_get_address_book(contact, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange);
-#else
-		msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL);
-#endif
-	} else {
-		msn_soap_free_read_buf(soapconn);
-	}
-
-	return TRUE;
-}
-
-static void
-msn_get_contact_written_cb(MsnSoapConn *soapconn)
-{
-	purple_debug_misc("MSNCL","Sent SOAP request for the contact list.\n");
-	soapconn->read_cb = msn_get_contact_list_cb;
-}
-
-/* SOAP  get contact list*/
-void
-msn_get_contact_list(MsnContact * contact, const MsnSoapPartnerScenario partner_scenario, const char *update_time)
-{
-	MsnSoapReq *soap_request;
-	gchar *body;
+	gchar *body = NULL;
 	gchar *update_str = NULL;
+	GetContactListCbData cb_data = { contact, partner_scenario };
 	const gchar *partner_scenario_str = MsnSoapPartnerScenarioText[partner_scenario];
 
 	purple_debug_misc("MSNCL","Getting Contact List.\n");
@@ -609,17 +431,14 @@
 	}
 
 	body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, update_str ? update_str : "");
-	g_free(update_str);
 
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					MSN_GET_CONTACT_POST_URL,
-					MSN_GET_CONTACT_SOAP_ACTION,
-					body,
-					(gpointer) partner_scenario_str,
-					msn_get_contact_list_cb,
-					msn_get_contact_written_cb,
-					msn_contact_connect_init);
-	msn_soap_post(contact->soapconn,soap_request);
+	msn_soap_message_send(contact->session,
+		msn_soap_message_new(MSN_GET_CONTACT_SOAP_ACTION,
+			xmlnode_from_str(body, -1)),
+		MSN_CONTACT_SERVER, MSN_GET_CONTACT_POST_URL,
+		msn_get_contact_list_cb, g_memdup(&cb_data, sizeof(cb_data)));
+
+	g_free(update_str);
 	g_free(body);
 }
 
@@ -629,7 +448,7 @@
 	MsnSession *session = contact->session;
 	xmlnode *group;
 
-	purple_debug_info("MsnAb","msn_parse_addressbook_groups()\n");
+	purple_debug_info("MSNAB","msn_parse_addressbook_groups()\n");
 
 	for(group = xmlnode_get_child(node, "Group"); group;
 					group = xmlnode_get_next_twin(group)){
@@ -781,81 +600,48 @@
 }
 
 static gboolean
-msn_parse_addressbook(MsnContact * contact)
+msn_parse_addressbook(MsnContact * contact, xmlnode *node)
 {
-	MsnSession *session;
-	xmlnode * node,*body,*response,*result;
+	MsnSession * session;
+	xmlnode *result;
 	xmlnode *groups;
 	xmlnode *contacts;
 	xmlnode *abNode;
-	xmlnode *fault, *faultstringnode, *faultdetail, *errorcode;
+	xmlnode *fault;
 
 	session = contact->session;
 
-	node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len);
-	if ( node == NULL ) {
-		purple_debug_error("MSN AddressBook","Error parsing Address Book with size %d\n", contact->soapconn->body_len);
+	if ((fault = msn_soap_xml_get(node, "Body/Fault"))) {
+		xmlnode *faultnode;
+
+		if ((faultnode = xmlnode_get_child(fault, "faultstring"))) {
+			gchar *faultstring = xmlnode_get_data(faultnode);
+			purple_debug_info("MSNAB","Faultstring: %s\n", faultstring);
+			g_free(faultstring);
+		}
+
+		if ((faultnode = msn_soap_xml_get(fault, "detail/errorcode"))) {
+			gchar *errorcode = xmlnode_get_data(faultnode);
+
+			purple_debug_info("MSNAB", "Error Code: %s\n", errorcode);
+						
+			if (g_str_equal(errorcode, "ABDoesNotExist")) {
+				g_free(errorcode);
+				return TRUE;
+			}
+		}
+
 		return FALSE;
 	}
 
-	purple_debug_misc("MSN AddressBook", "Parsing Address Book with size %d\n", contact->soapconn->body_len);
-
-	purple_debug_misc("MSN AddressBook","node{%p},name:%s,child:%s,last:%s\n", node,
-		node->name ? node->name : "(null)",
-		(node->child && node->child->name) ? node->child->name : "(null)",
-		(node->lastchild && node->lastchild->name) ? node->lastchild->name : "(null)");
-
-	body = xmlnode_get_child(node,"Body");
-	purple_debug_misc("MSN AddressBook","body{%p},name:%s\n",body,body->name);
-
-	/* TODO: This appears to be used in a number of places and should be de-duplicated */
-	if ( (fault = xmlnode_get_child(body, "Fault")) != NULL) {
-		purple_debug_info("MSN AddressBook","Fault received from SOAP server!\n");
-		
-		if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) {
-			gchar *faultstring = xmlnode_get_data(faultstringnode);
-			purple_debug_info("MSN AddressBook","Faultstring: %s\n", faultstring ? faultstring : "(null)");
-			g_free(faultstring);
-		}
-		if ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) {
-			purple_debug_info("MSN AddressBook","detail @ %p, name: %s\n",faultdetail, faultdetail->name);
-
-			if ( (errorcode = xmlnode_get_child(faultdetail, "errorcode")) != NULL ) {
-				gchar *errorcodestring;
-				purple_debug_info("MSN AddressBook","errorcode @ %p, name: %s\n",errorcode, errorcode->name);
-
-				errorcodestring = xmlnode_get_data(errorcode);
-				purple_debug_info("MSN AddressBook", "Error Code: %s\n", errorcodestring ? errorcodestring : "(null)");
-						
-				if (errorcodestring && !strncmp(errorcodestring, "ABDoesNotExist", 14) ) {
-					g_free(errorcodestring);
-					xmlnode_free(node);
-					return TRUE;
-				}
-				g_free(errorcodestring);
-			}
-		}
-		xmlnode_free(node);
-		return FALSE;
+	result = msn_soap_xml_get(node, "Body/ABFindAllResponse/ABFindAllResult");
+	if(result == NULL){
+		purple_debug_misc("MSNAB","receive no address book update\n");
+		return TRUE;
 	}
 
-
-	response = xmlnode_get_child(body,"ABFindAllResponse");
-
-	if (response == NULL) {
-		xmlnode_free(node);
-		return FALSE;
-	}
-
-	purple_debug_misc("MSN SOAP","response{%p},name:%s\n",response,response->name);
-	result = xmlnode_get_child(response,"ABFindAllResult");
-	if(result == NULL){
-		purple_debug_misc("MSNAB","receive no address book update\n");
-		xmlnode_free(node);
-		return TRUE;
-	}
-	purple_debug_info("MSN SOAP","result{%p},name:%s\n",result,result->name);
-
+	/* I don't see this "groups" tag documented on msnpiki, need to find out
+	   if they are really there, and update msnpiki */
 	/*Process Group List*/
 	groups = xmlnode_get_child(result,"groups");
 	if (groups != NULL) {
@@ -865,7 +651,7 @@
 	/*add a default No group to set up the no group Membership*/
 	msn_group_new(session->userlist, MSN_INDIVIDUALS_GROUP_ID,
 				  MSN_INDIVIDUALS_GROUP_NAME);
-	purple_debug_misc("MsnAB","group_id:%s name:%s\n",
+	purple_debug_misc("MSNAB","group_id:%s name:%s\n",
 					  MSN_INDIVIDUALS_GROUP_ID, MSN_INDIVIDUALS_GROUP_NAME);
 	if ((purple_find_group(MSN_INDIVIDUALS_GROUP_NAME)) == NULL){
 		PurpleGroup *g = purple_group_new(MSN_INDIVIDUALS_GROUP_NAME);
@@ -874,7 +660,7 @@
 
 	/*add a default No group to set up the no group Membership*/
 	msn_group_new(session->userlist, MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME);
-	purple_debug_misc("MsnAB","group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME);
+	purple_debug_misc("MSNAB","group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME);
 	if ((purple_find_group(MSN_NON_IM_GROUP_NAME)) == NULL){
 		PurpleGroup *g = purple_group_new(MSN_NON_IM_GROUP_NAME);
 		purple_blist_add_group(g, NULL);
@@ -894,7 +680,7 @@
 
 		if ((node2 = xmlnode_get_child(abNode, "lastChange")))
 			tmp = xmlnode_get_data(node2);
-		purple_debug_info("MsnAB"," lastchanged Time:{%s}\n", tmp ? tmp : "(null)");
+		purple_debug_info("MSNAB"," lastchanged Time:{%s}\n", tmp ? tmp : "(null)");
 		purple_account_set_string(session->account, "ablastChange", tmp);
 
 		g_free(tmp); tmp = NULL;
@@ -905,68 +691,51 @@
 		g_free(tmp);
 	}
 
-	xmlnode_free(node);
-	msn_soap_free_read_buf(contact->soapconn);
 	return TRUE;
 }
 
-static gboolean
-msn_get_address_cb(MsnSoapConn *soapconn)
+static void
+msn_get_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data)
 {
-	MsnContact *contact;
+	MsnContact *contact = data;
 	MsnSession *session;
 
-	if (soapconn->body == NULL)
-		return TRUE;
+	if (resp == NULL)
+		return;
 
-	contact = soapconn->parent;
-	g_return_val_if_fail(contact != NULL, TRUE);
-	session = soapconn->session;
-	g_return_val_if_fail(session != NULL, FALSE);
+	g_return_if_fail(contact != NULL);
+	session = contact->session;
+	g_return_if_fail(session != NULL);
 
-	purple_debug_misc("MSN AddressBook", "Got the Address Book!\n");
+	purple_debug_misc("MSNAB", "Got the Address Book!\n");
 
-	if ( msn_parse_addressbook(contact) ) {
-		//msn_soap_free_read_buf(soapconn);
-
+	if (msn_parse_addressbook(contact, resp->xml)) {
 		if (!session->logged_in) {
 			msn_send_privacy(session->account->gc);
 			msn_notification_dump_contact(session);
 		}
-
-		/*free the read buffer*/
-		msn_soap_free_read_buf(soapconn);
-		return TRUE;
 	} else {
-		/* This is making us loop infinitely when we fail to parse the address book,
-		  disable for now (we should re-enable when we send timestamps)
+		/* This is making us loop infinitely when we fail to parse the
+		  address book, disable for now (we should re-enable when we
+		  send timestamps)
 		*/
 		/*
 		msn_get_address_book(contact, NULL, NULL);
 		*/
 		msn_session_disconnect(session);
 		purple_connection_error(session->account->gc, _("Unable to retrieve MSN Address Book"));
-		return FALSE;
 	}
 }
 
-/**/
-static void
-msn_address_written_cb(MsnSoapConn *soapconn)
-{
-	purple_debug_misc("MSN AddressBook","Sent SOAP request for the Address Book.\n");
-	soapconn->read_cb = msn_get_address_cb;
-}
-
 /*get the address book*/
 void
-msn_get_address_book(MsnContact *contact, const MsnSoapPartnerScenario partner_scenario, const char *LastChanged, const char *dynamicItemLastChange)
+msn_get_address_book(MsnContact *contact,
+	MsnSoapPartnerScenario partner_scenario, const char *LastChanged,
+	const char *dynamicItemLastChange)
 {
-	MsnSoapReq *soap_request;
-	char *body;
-	char *update_str = NULL;
+	char *body, *update_str = NULL;
 
-	purple_debug_misc("MSN AddressBook","Getting Address Book\n");
+	purple_debug_misc("MSNAB","Getting Address Book\n");
 
 	/*build SOAP and POST it*/
 	if (dynamicItemLastChange != NULL)
@@ -974,79 +743,58 @@
 	else if (LastChanged != NULL)
 		update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, LastChanged);
 
-
 	body = g_strdup_printf(MSN_GET_ADDRESS_TEMPLATE, MsnSoapPartnerScenarioText[partner_scenario], update_str ? update_str : "");
-	g_free(update_str);
 
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					MSN_ADDRESS_BOOK_POST_URL,MSN_GET_ADDRESS_SOAP_ACTION,
-					body,
-					NULL,
-					msn_get_address_cb,
-					msn_address_written_cb,
-					msn_contact_connect_init);
-	msn_soap_post(contact->soapconn,soap_request);
+	msn_soap_message_send(contact->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);
+
+	g_free(update_str);
 	g_free(body);
 }
 
-static gboolean
-msn_add_contact_read_cb(MsnSoapConn *soapconn)
+static void
+msn_add_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp,
+	gpointer data)
 {
-	MsnCallbackState *state = NULL;
-	MsnUserList *userlist;
-	MsnUser *user;
-	
-	g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
-	g_return_val_if_fail(soapconn->session != NULL, FALSE);
-	g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE);
+	MsnCallbackState *state = data;
+	MsnSession *session = state->session;
 
-	state = (MsnCallbackState *) soapconn->data_cb;
+	g_return_if_fail(session != NULL);
 
-	if (soapconn->body == NULL) {
-		msn_callback_state_free(state);
-		return TRUE;
-	}
+	if (resp != NULL) {
+		MsnUserList *userlist = session->userlist;
+		MsnUser *user;
 	
-	userlist = soapconn->session->userlist;
-	
-	purple_debug_info("MSNCL","Contact added successfully\n");
+		purple_debug_info("MSNCL","Contact added successfully\n");
 
-	// the code this block is replacing didn't send ADL for yahoo contacts,
-	// but i haven't confirmed this is WLM's behaviour wrt yahoo contacts
-
-	if ( !msn_user_is_yahoo(soapconn->session->account, state->who) ) {
-		
-		msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL);
-		msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL);
-	}
-	msn_notification_send_fqy(soapconn->session, state->who);
+		// the code this block is replacing didn't send ADL for yahoo contacts,
+		// but i haven't confirmed this is WLM's behaviour wrt yahoo contacts
+		if ( !msn_user_is_yahoo(session->account, state->who) ) {
+			msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL);
+			msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL);
+		}
 
-	user = msn_userlist_find_add_user(userlist, state->who, state->who);
-	msn_user_add_group_id(user, state->guid);
-
-	msn_soap_free_read_buf(soapconn);
-	msn_callback_state_free(state);
+		msn_notification_send_fqy(session, state->who);
 
-	return TRUE;
-}
+		user = msn_userlist_find_add_user(userlist, state->who, state->who);
+		msn_user_add_group_id(user, state->guid);
+	}
 
-static void
-msn_add_contact_written_cb(MsnSoapConn *soapconn)
-{
-	purple_debug_info("MSNCL","Add contact request written\n");
-	soapconn->read_cb = msn_add_contact_read_cb;
+	msn_callback_state_free(state);
 }
 
 /* add a Contact in MSN_INDIVIDUALS_GROUP */
 void
 msn_add_contact(MsnContact *contact, MsnCallbackState *state, const char *passport)
 {
-	MsnSoapReq *soap_request;
 	gchar *body = NULL;
 	gchar *contact_xml = NULL;
 
-	g_return_if_fail(passport != NULL);
-/*	gchar *escaped_displayname;
+#if 0
+	gchar *escaped_displayname;
 
 
 	 if (displayname != NULL) {
@@ -1055,87 +803,71 @@
 		escaped_displayname = passport;
 	 }
 	contact_xml = g_strdup_printf(MSN_XML_ADD_CONTACT, escaped_displayname, passport);
-*/
+#endif
+
 	purple_debug_info("MSNCL","Adding contact %s to contact list\n", passport);
 
-//	if ( !strcmp(state->guid, MSN_INDIVIDUALS_GROUP_ID) ) {
-		contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport);
-//	}
+	contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport);
 	body = g_strdup_printf(MSN_ADD_CONTACT_TEMPLATE, contact_xml);
 
+	msn_soap_message_send(contact->session,
+		msn_soap_message_new(MSN_CONTACT_ADD_SOAP_ACTION,
+			xmlnode_from_str(body, -1)),
+		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
+		msn_add_contact_read_cb, state);
+
 	g_free(contact_xml);
-
-	/*build SOAP and POST it*/
-
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					MSN_ADDRESS_BOOK_POST_URL,
-					MSN_CONTACT_ADD_SOAP_ACTION,
-					body,
-					state,
-					msn_add_contact_read_cb,
-					msn_add_contact_written_cb,
-					msn_contact_connect_init);
-	msn_soap_post(contact->soapconn,soap_request);
-
 	g_free(body);
 }
 
-static gboolean
-msn_add_contact_to_group_read_cb(MsnSoapConn *soapconn)
+static void
+msn_add_contact_to_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp,
+	gpointer data)
 {
-	MsnCallbackState *state; 
+	MsnCallbackState *state = data;
 	MsnUserList *userlist;
 
-	g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
-	g_return_val_if_fail(soapconn->session != NULL, FALSE);
-	g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE);
+	g_return_if_fail(data != NULL);
+
+	userlist = state->session->userlist;
 
-	userlist = soapconn->session->userlist;
+	if (resp != NULL) {
+		if (msn_userlist_add_buddy_to_group(userlist, state->who,
+				state->new_group_name)) {
+			purple_debug_info("MSNCL", "Contact %s added to group %s successfully!\n", state->who, state->new_group_name);
+		} else {
+			purple_debug_info("MSNCL","Contact %s added to group %s successfully on server, but failed in the local list\n", state->who, state->new_group_name);
+		}
 
-	state = (MsnCallbackState *) soapconn->data_cb;
+		if (state->action & MSN_ADD_BUDDY) {
+			MsnUser *user = msn_userlist_find_user(userlist, state->who);
 
-	if (soapconn->body == NULL) {
-		msn_callback_state_free(state);
-		return TRUE;
-	}
-	
-	if (msn_userlist_add_buddy_to_group(userlist, state->who, state->new_group_name) == TRUE) {
-		purple_debug_info("MSNCL", "Contact %s added to group %s successfully!\n", state->who, state->new_group_name);
-	} else {
-		purple_debug_info("MSNCL","Contact %s added to group %s successfully on server, but failed in the local list\n", state->who, state->new_group_name);
+        	if ( !msn_user_is_yahoo(state->session->account, state->who) ) {
+
+				msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL);
+				msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL);
+	        }
+	        msn_notification_send_fqy(state->session, state->who);
+
+			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_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);
+		}
 	}
 
-	if (state->action & MSN_ADD_BUDDY) {
-
-        	if ( !msn_user_is_yahoo(soapconn->session->account, state->who) ) {
-
-		                msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL);
-		                msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL);
-	        }
-	        msn_notification_send_fqy(soapconn->session, state->who);
-	}
-
-	if (state->action & MSN_MOVE_BUDDY) {
-		msn_del_contact_from_group(soapconn->session->contact, state->who, state->old_group_name);
-	} else {
-		msn_callback_state_free(state);
-		msn_soap_free_read_buf(soapconn);
-	}
-	return TRUE;
-}
-
-static void
-msn_add_contact_to_group_written_cb(MsnSoapConn *soapconn)
-{
-	purple_debug_info("MSNCL","Add contact to group request sent!\n");
-	soapconn->read_cb = msn_add_contact_to_group_read_cb;
+	msn_callback_state_free(state);
 }
 
 void
 msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state, 
 			 const char *passport, const char *groupId)
 {
-	MsnSoapReq *soap_request;
 	MsnUserList *userlist;
 	MsnUser *user;
 	gchar *body = NULL, *contact_xml;
@@ -1168,13 +900,14 @@
 		return;
 	}
 
-
 	purple_debug_info("MSNCL", "Adding user %s to group %s\n", passport, 
 			  msn_userlist_find_group_name(userlist, groupId));
 
 	user = msn_userlist_find_user(userlist, passport);
 	if (user == NULL) {
-		purple_debug_warning("MSN CL", "Unable to retrieve user %s from the userlist!\n", passport);
+		purple_debug_warning("MSNCL", "Unable to retrieve user %s from the userlist!\n", passport);
+		msn_callback_state_free(state);                                     
+		return; /* guess this never happened! */
 	}
 
 	if (user->uid != NULL) {
@@ -1184,60 +917,35 @@
 	}
 
 	body = g_strdup_printf(MSN_ADD_CONTACT_GROUP_TEMPLATE, groupId, contact_xml);
-	g_free(contact_xml);
-
-	/*build SOAP and POST it*/
 
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					MSN_ADDRESS_BOOK_POST_URL,
-					MSN_ADD_CONTACT_GROUP_SOAP_ACTION,
-					body,
-					state,
-					msn_add_contact_to_group_read_cb,
-					msn_add_contact_to_group_written_cb,
-					msn_contact_connect_init);
-	msn_soap_post(contact->soapconn,soap_request);
+	msn_soap_message_send(state->session,
+		msn_soap_message_new(MSN_ADD_CONTACT_GROUP_SOAP_ACTION,
+			xmlnode_from_str(body, -1)),
+		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
+		msn_add_contact_to_group_read_cb, state);
 
+	g_free(contact_xml);
 	g_free(body);
 }
 
-
-
-static gboolean
-msn_delete_contact_read_cb(MsnSoapConn *soapconn)
+static void
+msn_delete_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp,
+	gpointer data)
 {
-	MsnUser *user;
-	MsnCallbackState *state = (MsnCallbackState *) soapconn->data_cb;
-	MsnUserList *userlist; 
-
-	g_return_val_if_fail(soapconn->session != NULL, FALSE);
-	g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE);
+	MsnCallbackState *state = data;
 
-	userlist = soapconn->session->userlist;
+	if (resp != NULL) {
+		MsnUserList *userlist = state->session->userlist;
+		MsnUser *user = msn_userlist_find_user_with_id(userlist, state->uid);
 
-        if (soapconn->body == NULL) {
-                msn_callback_state_free(state);
-                return TRUE;
-        }
+		purple_debug_info("MSNCL","Delete contact successful\n");
 
-	purple_debug_info("MSNCL","Delete contact successful\n");
-
-	user = msn_userlist_find_user_with_id(userlist, state->uid);
-	if (user != NULL) {
-		msn_userlist_remove_user(userlist, user);
+		if (user != NULL) {
+			msn_userlist_remove_user(userlist, user);
+		}
 	}
 
 	msn_callback_state_free(state);
-	msn_soap_free_read_buf(soapconn);
-
-	return TRUE;
-}
-
-static void
-msn_delete_contact_written_cb(MsnSoapConn *soapconn)
-{
-	purple_debug_info("MSNCL","Delete contact request written\n");
-	soapconn->read_cb = msn_delete_contact_read_cb;
 }
 
 /*delete a Contact*/
@@ -1246,72 +954,52 @@
 {	
 	gchar *body = NULL;
 	gchar *contact_id_xml = NULL ;
-	MsnSoapReq *soap_request;
 	MsnCallbackState *state;
 
 	g_return_if_fail(contactId != NULL);
 	contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, contactId);
 
-	state = msn_callback_state_new();
+	state = msn_callback_state_new(contact->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);
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					MSN_ADDRESS_BOOK_POST_URL,
-					MSN_CONTACT_DEL_SOAP_ACTION,
-					body,
-					state,
-					msn_delete_contact_read_cb,
-					msn_delete_contact_written_cb,
-					msn_contact_connect_init);
+	msn_soap_message_send(contact->session,
+		msn_soap_message_new(MSN_CONTACT_DEL_SOAP_ACTION,
+			xmlnode_from_str(body, -1)),
+		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
+		msn_delete_contact_read_cb, state);
 
 	g_free(contact_id_xml);
-
-	/* POST the SOAP request */
-	msn_soap_post(contact->soapconn, soap_request);
-
 	g_free(body);
 }
 
-static gboolean
-msn_del_contact_from_group_read_cb(MsnSoapConn *soapconn)
+static void
+msn_del_contact_from_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp,
+	gpointer data)
 {
-	MsnCallbackState *state = (MsnCallbackState *) soapconn->data_cb;
+	MsnCallbackState *state = data;
 
-	if (soapconn->body == NULL) {
-		msn_callback_state_free(state);
-		return TRUE;
-	}
-	
-	if (msn_userlist_rem_buddy_from_group(soapconn->session->userlist, state->who, state->old_group_name)) {
-		purple_debug_info("MSN CL", "Contact %s deleted successfully from group %s\n", state->who, state->old_group_name);
-	} else {
-		purple_debug_info("MSN CL", "Contact %s deleted successfully from group %s in the server, but failed in the local list\n", state->who, state->old_group_name);
+	if (resp != NULL) {
+		if (msn_userlist_rem_buddy_from_group(state->session->userlist,
+				state->who, state->old_group_name)) {
+			purple_debug_info("MSNCL", "Contact %s deleted successfully from group %s\n", state->who, state->old_group_name);
+		} else {
+			purple_debug_info("MSNCL", "Contact %s deleted successfully from group %s in the server, but failed in the local list\n", state->who, state->old_group_name);
+		}
 	}
 	
 	msn_callback_state_free(state);
-	msn_soap_free_read_buf(soapconn);
-
-	return TRUE;
-}
-
-static void
-msn_del_contact_from_group_written_cb(MsnSoapConn *soapconn)
-{
-	purple_debug_info("MSN CL","Del contact from group request sent!\n");
-	soapconn->read_cb = msn_del_contact_from_group_read_cb;
 }
 
 void
 msn_del_contact_from_group(MsnContact *contact, const char *passport, const char *group_name)
 {
-	MsnSoapReq *soap_request;
 	MsnUserList * userlist;
 	MsnUser *user;
 	MsnCallbackState *state;
-	gchar *body = NULL, *contact_id_xml;
+	gchar *body, *contact_id_xml;
 	const gchar *groupId;
 	
 	g_return_if_fail(passport != NULL);
@@ -1324,16 +1012,16 @@
 	
 	groupId = msn_userlist_find_group_id(userlist, group_name);
 	if (groupId != NULL) {
-		purple_debug_info("MSN CL", "Deleting user %s from group %s\n", passport, group_name);
+		purple_debug_info("MSNCL", "Deleting user %s from group %s\n", passport, group_name);
 	} else {
-		purple_debug_warning("MSN CL", "Unable to retrieve group id from group %s !\n", group_name);
+		purple_debug_warning("MSNCL", "Unable to retrieve group id from group %s !\n", group_name);
 		return;
 	}
 	
 	user = msn_userlist_find_user(userlist, passport);
 	
 	if (user == NULL) {
-		purple_debug_warning("MSN CL", "Unable to retrieve user from passport %s!\n", passport);
+		purple_debug_warning("MSNCL", "Unable to retrieve user from passport %s!\n", passport);
 		return;
 	}
 
@@ -1342,58 +1030,40 @@
 		return;
 	}
 
-	state = msn_callback_state_new();
+	state = msn_callback_state_new(contact->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);
+
+	msn_soap_message_send(contact->session,
+		msn_soap_message_new(MSN_CONTACT_DEL_GROUP_SOAP_ACTION,
+			xmlnode_from_str(body, -1)),
+		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
+		msn_del_contact_from_group_read_cb, state);
+	
 	g_free(contact_id_xml);
-
-	/*build SOAP and POST it*/
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					    MSN_ADDRESS_BOOK_POST_URL,
-					    MSN_CONTACT_DEL_GROUP_SOAP_ACTION,
-					    body,
-					    state,
-					    msn_del_contact_from_group_read_cb,
-					    msn_del_contact_from_group_written_cb,
-					    msn_contact_connect_init);
-	msn_soap_post(contact->soapconn,soap_request);
-
 	g_free(body);
 }
 
 
-static gboolean
-msn_update_contact_read_cb(MsnSoapConn *soapconn)
+static void
+msn_update_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp,
+	gpointer data)
 {
-	if (soapconn->body == NULL)
-		return TRUE;
-
-	purple_debug_info("MSN CL","Contact updated successfully\n");
-
-	return TRUE;
-}
-
-static void
-msn_update_contact_written_cb(MsnSoapConn *soapconn)
-{
-	purple_debug_info("MSN CL","Update contact information request sent\n");
-	soapconn->read_cb = msn_update_contact_read_cb;
+	if (resp)
+		purple_debug_info("MSN CL","Contact updated successfully\n");
+	else
+		purple_debug_info("MSN CL","Contact updated successfully\n");
 }
 
 /* Update a contact's nickname */
-
 void
 msn_update_contact(MsnContact *contact, const char* nickname)
 {
-	MsnSoapReq *soap_request;
-	gchar *body, *escaped_nickname;
-
-	/* I'm not sure this is right, but if it isn't, the rest of this function will need to be fixed */
-	g_return_if_fail(nickname != NULL);
+	gchar *body = NULL, *escaped_nickname;
 
 	purple_debug_info("MSN CL","Update contact information with new friendly name: %s\n", nickname);
 
@@ -1401,83 +1071,49 @@
 
 	body = g_strdup_printf(MSN_CONTACT_UPDATE_TEMPLATE, escaped_nickname);
 
+	msn_soap_message_send(contact->session,
+		msn_soap_message_new(MSN_CONTACT_UPDATE_SOAP_ACTION,
+			xmlnode_from_str(body, -1)),
+		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
+		msn_update_contact_read_cb, NULL);
+
 	g_free(escaped_nickname);
-	/*build SOAP and POST it*/
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					MSN_ADDRESS_BOOK_POST_URL,
-					MSN_CONTACT_UPDATE_SOAP_ACTION,
-					body,
-					NULL,
-					msn_update_contact_read_cb,
-					msn_update_contact_written_cb,
-					msn_contact_connect_init);
-	msn_soap_post(contact->soapconn, soap_request);
-
 	g_free(body);
 }
 
-
-static gboolean
-msn_del_contact_from_list_read_cb(MsnSoapConn *soapconn)
+static void
+msn_del_contact_from_list_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp,
+	gpointer data)
 {
-	MsnCallbackState *state = NULL;
+	MsnCallbackState *state = data;
+	MsnSession *session = state->session;
 
-	g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
-	g_return_val_if_fail(soapconn->session != NULL, FALSE);
-	g_return_val_if_fail(soapconn->session->contact != NULL, FALSE);
-	g_return_val_if_fail(soapconn->session->userlist != NULL, FALSE);
-
-	state = (MsnCallbackState *) soapconn->data_cb;
-
-	if (soapconn->body == NULL) {
-		msn_callback_state_free(state);
-		return TRUE;
-	}
-	
-	purple_debug_info("MSN CL", "Contact %s deleted successfully from %s list on server!\n", state->who, MsnMemberRole[state->list_id]);
+	if (resp != NULL) {
+		purple_debug_info("MSN CL", "Contact %s deleted successfully from %s list on server!\n", state->who, MsnMemberRole[state->list_id]);
 
-	if (state->list_id == MSN_LIST_PL) {
-		MsnUser *user = msn_userlist_find_user(soapconn->session->userlist, state->who);
-		
-		if (user != NULL)
-			msn_user_unset_op(user, MSN_LIST_PL_OP);
+		if (state->list_id == MSN_LIST_PL) {
+			MsnUser *user = msn_userlist_find_user(session->userlist, state->who);
 
-		msn_add_contact_to_list(soapconn->session->contact, state, state->who, MSN_LIST_RL);
-		return TRUE;
-	}
+			if (user != NULL)
+				msn_user_unset_op(user, MSN_LIST_PL_OP);
 
-	if (state->list_id == MSN_LIST_AL) {
-		purple_privacy_permit_remove(soapconn->session->account, state->who, TRUE);
-		msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_BL);
-		msn_callback_state_free(state);
-		return TRUE;
-	}
-
-	if (state->list_id == MSN_LIST_BL) {
-		purple_privacy_deny_remove(soapconn->session->account, state->who, TRUE);
-		msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_AL);
-		msn_callback_state_free(state);
-		return TRUE;
+			msn_add_contact_to_list(session->contact, state, state->who, MSN_LIST_RL);
+		} 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);
+		} 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_callback_state_free(state);
-	msn_soap_free_read_buf(soapconn);
-
-	return TRUE;
-}
-
-static void
-msn_del_contact_from_list_written_cb(MsnSoapConn *soapconn)
-{
-	purple_debug_info("MSN CL","Delete contact from list SOAP request sent!\n");
-	soapconn->read_cb = msn_del_contact_from_list_read_cb;
 }
 
 void
 msn_del_contact_from_list(MsnContact *contact, MsnCallbackState *state,
 			  const gchar *passport, const MsnListId list)
 {
-	MsnSoapReq *soap_request;
 	gchar *body = NULL, *member = NULL;
 	MsnSoapPartnerScenario partner_scenario;
 	MsnUser *user;
@@ -1489,7 +1125,7 @@
 	purple_debug_info("MSN CL", "Deleting contact %s from %s list\n", passport, MsnMemberRole[list]);
 
 	if (state == NULL) {
-		state = msn_callback_state_new();
+		state = msn_callback_state_new(contact->session);
 	}
 	msn_callback_state_set_list_id(state, list);
 	msn_callback_state_set_who(state, passport);
@@ -1513,79 +1149,55 @@
 			        MsnSoapPartnerScenarioText[partner_scenario],
 			        MsnMemberRole[list],
 			        member);
-	g_free(member);
 
-	soap_request = msn_soap_request_new( MSN_CONTACT_SERVER,
-					     MSN_SHARE_POST_URL,
-					     MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION,
-					     body,
-					     state,
-					     msn_del_contact_from_list_read_cb,
-					     msn_del_contact_from_list_written_cb,
-					     msn_contact_connect_init);
+	msn_soap_message_send(contact->session,
+		msn_soap_message_new(MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION,
+			xmlnode_from_str(body, -1)),
+		MSN_CONTACT_SERVER, MSN_SHARE_POST_URL,
+		msn_del_contact_from_list_read_cb, state);
 
-	msn_soap_post(contact->soapconn,soap_request);
-	
+	g_free(member);
 	g_free(body);
 }
 
-static gboolean
-msn_add_contact_to_list_read_cb(MsnSoapConn *soapconn)
+static void
+msn_add_contact_to_list_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp,
+	gpointer data)
 {
-	MsnCallbackState *state = NULL;
+	MsnCallbackState *state = data;
 
-	g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
-	g_return_val_if_fail(soapconn->session != NULL, FALSE);
-	g_return_val_if_fail(soapconn->session->userlist != NULL, FALSE);
-
-	state = (MsnCallbackState *) soapconn->data_cb;
+	g_return_if_fail(state != NULL);
+	g_return_if_fail(state->session != NULL);
+	g_return_if_fail(state->session->contact != NULL);
 	
-	if (soapconn->body == NULL) {
-		msn_callback_state_free(state);
-		return TRUE;
-	}
-	
-	purple_debug_info("MSN CL", "Contact %s added successfully to %s list on server!\n", state->who, MsnMemberRole[state->list_id]);
+	if (resp != NULL) {
+		purple_debug_info("MSN CL", "Contact %s added successfully to %s list on server!\n", state->who, MsnMemberRole[state->list_id]);
 
-	if (state->list_id == MSN_LIST_RL) {
-		MsnUser *user = msn_userlist_find_user(soapconn->session->userlist, state->who);
+		if (state->list_id == MSN_LIST_RL) {
+			MsnUser *user = msn_userlist_find_user(state->session->userlist, state->who);
 		
-		if (user != NULL) {
-			msn_user_set_op(user, MSN_LIST_RL_OP);
-		}
+			if (user != NULL) {
+				msn_user_set_op(user, MSN_LIST_RL_OP);
+			}
+
+			if (state->action & MSN_DENIED_BUDDY) {
 
-		if (state->action & MSN_DENIED_BUDDY) {
-			g_return_val_if_fail(soapconn->session->contact != NULL, FALSE);
-
-			msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_BL);
-			return TRUE;
+				msn_add_contact_to_list(state->session->contact, 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) {
+				purple_privacy_deny_add(state->session->account, state->who, TRUE);
+			}
 		}
 	}
 
-	if (state->list_id == MSN_LIST_AL) {
-		purple_privacy_permit_add(soapconn->session->account, state->who, TRUE);
-	} else if (state->list_id == MSN_LIST_BL) {
-		purple_privacy_deny_add(soapconn->session->account, state->who, TRUE);
-	}
-
 	msn_callback_state_free(state);
-	msn_soap_free_read_buf(soapconn);
-	return TRUE;
-}
-
-
-static void
-msn_add_contact_to_list_written_cb(MsnSoapConn *soapconn)
-{
-	purple_debug_info("MSN CL","Add contact to list SOAP request sent!\n");
-	soapconn->read_cb = msn_add_contact_to_list_read_cb;
 }
 
 void
 msn_add_contact_to_list(MsnContact *contact, MsnCallbackState *state,
 			const gchar *passport, const MsnListId list)
 {
-	MsnSoapReq *soap_request;
 	gchar *body = NULL, *member = NULL;
 	MsnSoapPartnerScenario partner_scenario;
 
@@ -1596,7 +1208,7 @@
 	purple_debug_info("MSN CL", "Adding contact %s to %s list\n", passport, MsnMemberRole[list]);
 
 	if (state == NULL) {
-		state = msn_callback_state_new();
+		state = msn_callback_state_new(contact->session);
 	}
 	msn_callback_state_set_list_id(state, list);
 	msn_callback_state_set_who(state, passport);
@@ -1610,37 +1222,24 @@
 			       MsnMemberRole[list], 
 			       member);
 
-	g_free(member);
+	msn_soap_message_send(contact->session,
+		msn_soap_message_new(MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION,
+			xmlnode_from_str(body, -1)),
+		MSN_CONTACT_SERVER, MSN_SHARE_POST_URL,
+		msn_add_contact_to_list_read_cb, state);
 
-	soap_request = msn_soap_request_new( MSN_CONTACT_SERVER,
-					     MSN_SHARE_POST_URL,
-					     MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION,
-					     body,
-					     state,
-					     msn_add_contact_to_list_read_cb,
-					     msn_add_contact_to_list_written_cb,
-					     msn_contact_connect_init);
-
-	msn_soap_post(contact->soapconn, soap_request);
-
+	g_free(member);
 	g_free(body);
 }
 
-
 #if 0
-static gboolean
-msn_gleams_read_cb(MsnSoapConn * soapconn)
+static void
+msn_gleams_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data)
 {
-	purple_debug_info("MSN CL","Gleams read done\n");
-	return TRUE;
-}
-
-static void
-msn_gleams_written_cb(MsnSoapConn * soapconn)
-{
-	purple_debug_info("MSNP14","finish Group written\n");
-	soapconn->read_cb = msn_gleams_read_cb;
-//	msn_soap_read_cb(data,source,cond);
+	if (resp != NULL)
+		purple_debug_info("MSNP14","Gleams read done\n");
+	else
+		purple_debug_info("MSNP14","Gleams read failed\n");
 }
 
 /*get the gleams info*/
@@ -1650,16 +1249,11 @@
 	MsnSoapReq *soap_request;
 
 	purple_debug_info("MSNP14","msn get gleams info...\n");
-	/*build SOAP and POST it*/
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					MSN_ADDRESS_BOOK_POST_URL,
-					MSN_GET_GLEAMS_SOAP_ACTION,
-					MSN_GLEAMS_TEMPLATE,
-					NULL,
-					msn_gleams_read_cb,
-					msn_gleams_written_cb,
-					msn_contact_connect_init);
-	msn_soap_post(contact->soapconn,soap_request);
+	msn_soap_message_send(contact->session,
+		msn_soap_message_new(MSN_GET_GLEAMS_SOAP_ACTION,
+			xmlnode_from_str(MSN_GLEAMS_TEMPLATE, -1)),
+		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
+		msn_gleams_read_cb, NULL);
 }
 #endif
 
@@ -1668,100 +1262,88 @@
  * Group Operations
  ***************************************************************/
 
-static gboolean
-msn_group_read_cb(MsnSoapConn *soapconn)
+static void
+msn_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data)
 {
-	MsnUserList *userlist;
-	MsnCallbackState *state = NULL;
+	MsnCallbackState *state = data;
 	
-	purple_debug_info("MSN CL", "Group request successful.\n");
+	purple_debug_info("MSNCL", "Group request successful.\n");
 	
-	g_return_val_if_fail(soapconn->session != NULL, FALSE);
-	g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE);
-	g_return_val_if_fail(soapconn->session->contact != NULL, FALSE);
+	g_return_if_fail(state->session != NULL);
+	g_return_if_fail(state->session->userlist != NULL);
+	g_return_if_fail(state->session->contact != NULL);
 
-	state = (MsnCallbackState *) soapconn->data_cb;
-	
-	if (soapconn->body == NULL) {
+	if (resp == NULL) {
 		msn_callback_state_free(state);
-		return TRUE;
+		return;
 	}
-	
+
 	if (state) {
-		userlist = soapconn->session->userlist;
+		MsnSession *session = state->session;
+		MsnUserList *userlist = session->userlist;
 		
 		if (state->action & MSN_RENAME_GROUP) {
-			msn_userlist_rename_group_id(soapconn->session->userlist,
+			msn_userlist_rename_group_id(session->userlist,
 						     state->guid,
 						     state->new_group_name);
 		}
 		
 		if (state->action & MSN_ADD_GROUP) {
-			gchar *guid, *endguid;
-			
-			guid = g_strstr_len(soapconn->read_buf, soapconn->read_len, "<guid>");
-			guid += 6;
-			endguid = g_strstr_len(soapconn->read_buf, soapconn->read_len, "</guid>");
-			*endguid = '\0';
-			/* create and add the new group to the userlist */
-			purple_debug_info("MSN CL", "Adding group %s with guid = %s to the userlist\n", state->new_group_name, guid);
-			msn_group_new(soapconn->session->userlist, guid, state->new_group_name);
+			/* 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,
+				"Body/ABGroupAddResponse/ABGroupAddResult/guid");
+
+			if (guid_node) {
+				char *guid = xmlnode_get_data(guid_node);
+
+				/* create and add the new group to the userlist */
+				purple_debug_info("MSNCL", "Adding group %s with guid = %s to the userlist\n", state->new_group_name, guid);
+				msn_group_new(session->userlist, guid, state->new_group_name);
 
-			if (state->action & MSN_ADD_BUDDY) {
-				msn_userlist_add_buddy(soapconn->session->userlist,
-						       state->who,
-						       state->new_group_name);
-				msn_callback_state_free(state);
-				return TRUE;
-			}
-			
-			if (state->action & MSN_MOVE_BUDDY) {
-				msn_add_contact_to_group(soapconn->session->contact, state, state->who, guid); 
-				return TRUE;
+				if (state->action & MSN_ADD_BUDDY) {
+					msn_userlist_add_buddy(session->userlist,
+						state->who,
+						state->new_group_name);
+					msn_callback_state_free(state);
+				} else if (state->action & MSN_MOVE_BUDDY) {
+					msn_add_contact_to_group(session->contact, state, state->who, guid); 
+				}
+
+				g_free(guid);
+			} else {
+				purple_debug_info("MSNCL", "Adding group %s failed\n",
+					state->new_group_name);
 			}
 		}
 		
 		if (state->action & MSN_DEL_GROUP) {
 			GList *l;
 			
-			msn_userlist_remove_group_id(soapconn->session->userlist, state->guid);
+			msn_userlist_remove_group_id(session->userlist, state->guid);
 			for (l = userlist->users; l != NULL; l = l->next) {
 				msn_user_remove_group_id( (MsnUser *)l->data, state->guid);
 			}
-			
 		}
 			
 		msn_callback_state_free(state);
 	}
-	
-	msn_soap_free_read_buf(soapconn);
-	return TRUE;
-}
-
-static void
-msn_group_written_cb(MsnSoapConn *soapconn)
-{
-	purple_debug_info("MSN CL","Sent group request.\n");
-	soapconn->read_cb = msn_group_read_cb;
 }
 
 /* add group */
 void
 msn_add_group(MsnSession *session, MsnCallbackState *state, const char* group_name)
 {
-	MsnSoapReq *soap_request;
-	MsnContact *contact;
 	char *body = NULL;
-	gchar *escaped_group_name;
 
 	g_return_if_fail(session != NULL);
 	g_return_if_fail(group_name != NULL);
 	
-	contact = session->contact;
-	purple_debug_info("MSN CL","Adding group %s to contact list.\n", group_name);
+	purple_debug_info("MSNCL","Adding group %s to contact list.\n", group_name);
 
 	if (state == NULL) {
-		state = msn_callback_state_new();
+		state = msn_callback_state_new(session);
 	}
 
 	msn_callback_state_set_action(state, MSN_ADD_GROUP);
@@ -1770,21 +1352,14 @@
 	/* escape group name's html special chars so it can safely be sent
 	* in a XML SOAP request
 	*/
-	escaped_group_name = g_markup_escape_text(group_name, -1);
-	body = g_strdup_printf(MSN_GROUP_ADD_TEMPLATE, escaped_group_name);
-	g_free(escaped_group_name);
+	body = g_markup_printf_escaped(MSN_GROUP_ADD_TEMPLATE, group_name);
 
-	/*build SOAP and POST it*/
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					MSN_ADDRESS_BOOK_POST_URL,
-					MSN_GROUP_ADD_SOAP_ACTION,
-					body,
-					state,
-					msn_group_read_cb,
-					msn_group_written_cb,
-					msn_contact_connect_init);
-	msn_soap_post(contact->soapconn,soap_request);
-	
+	msn_soap_message_send(session,
+		msn_soap_message_new(MSN_GROUP_ADD_SOAP_ACTION,
+			xmlnode_from_str(body, -1)),
+		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
+		msn_group_read_cb, state);
+
 	g_free(body);
 }
 
@@ -1792,8 +1367,6 @@
 void
 msn_del_group(MsnSession *session, const gchar *group_name)
 {
-	MsnSoapReq *soap_request;
-	MsnContact *contact;
 	MsnCallbackState *state;
 	char *body = NULL;
 	const gchar *guid;
@@ -1801,8 +1374,7 @@
 	g_return_if_fail(session != NULL);
 	
 	g_return_if_fail(group_name != NULL);
-	contact = session->contact;
-	purple_debug_info("MSN CL","Deleting group %s from contact list\n", group_name);
+	purple_debug_info("MSNCL","Deleting group %s from contact list\n", group_name);
 	
 	guid = msn_userlist_find_group_id(session->userlist, group_name);
 	
@@ -1810,7 +1382,7 @@
 	*  we need to delete nothing
 	*/
 	if (guid == NULL) {
-		purple_debug_info("MSN CL", "Group %s guid not found, returning.\n", group_name);
+		purple_debug_info("MSNCL", "Group %s guid not found, returning.\n", group_name);
 		return;
 	}
 
@@ -1819,21 +1391,17 @@
 		return;
 	}
 
-	state = msn_callback_state_new();
+	state = msn_callback_state_new(session);
 	msn_callback_state_set_action(state, MSN_DEL_GROUP);
 	msn_callback_state_set_guid(state, guid);
 	
 	body = g_strdup_printf(MSN_GROUP_DEL_TEMPLATE, guid);
-	/*build SOAP and POST it*/
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					    MSN_ADDRESS_BOOK_POST_URL,
-					    MSN_GROUP_DEL_SOAP_ACTION,
-					    body,
-					    state,
-					    msn_group_read_cb,
-					    msn_group_written_cb,
-					    msn_contact_connect_init);
-	msn_soap_post(contact->soapconn, soap_request);
+
+	msn_soap_message_send(session,
+		msn_soap_message_new(MSN_GROUP_DEL_SOAP_ACTION,
+			xmlnode_from_str(body, -1)),
+		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
+		msn_group_read_cb, state);
 
 	g_free(body);
 }
@@ -1842,24 +1410,22 @@
 void
 msn_contact_rename_group(MsnSession *session, const char *old_group_name, const char *new_group_name)
 {
-	MsnSoapReq *soap_request;
-	MsnContact *contact;
-	gchar * escaped_group_name, *body = NULL;
+	gchar *body = NULL;
 	const gchar * guid;
-	MsnCallbackState *state = msn_callback_state_new();
+	MsnCallbackState *state;
 	
 	g_return_if_fail(session != NULL);
 	g_return_if_fail(session->userlist != NULL);
 	g_return_if_fail(old_group_name != NULL);
 	g_return_if_fail(new_group_name != NULL);
 	
-	contact = session->contact;
 	purple_debug_info("MSN CL", "Renaming group %s to %s.\n", old_group_name, new_group_name);
 	
 	guid = msn_userlist_find_group_id(session->userlist, old_group_name);
 	if (guid == NULL)
 		return;
 
+	state = msn_callback_state_new(session);
 	msn_callback_state_set_guid(state, guid);
 	msn_callback_state_set_new_group_name(state, new_group_name);
 
@@ -1870,31 +1436,14 @@
 
 	msn_callback_state_set_action(state, MSN_RENAME_GROUP);
 	
-	/* escape group name's html special chars so it can safely be sent
-	 * in a XML SOAP request
-	*/
-	escaped_group_name = g_markup_escape_text(new_group_name, -1);
-	
-	body = g_strdup_printf(MSN_GROUP_RENAME_TEMPLATE, guid, escaped_group_name);
+	body = g_markup_printf_escaped(MSN_GROUP_RENAME_TEMPLATE,
+		guid, new_group_name);
 	
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					    MSN_ADDRESS_BOOK_POST_URL,
-					    MSN_GROUP_RENAME_SOAP_ACTION,
-					    body,
-					    state,
-					    msn_group_read_cb,
-					    msn_group_written_cb,
-					    msn_contact_connect_init);
-	msn_soap_post(contact->soapconn, soap_request);
-	
-	g_free(escaped_group_name);
+	msn_soap_message_send(session,
+		msn_soap_message_new(MSN_GROUP_RENAME_SOAP_ACTION,
+			xmlnode_from_str(body, -1)),
+		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,
+		msn_group_read_cb, state);
+
 	g_free(body);
 }
-
-void
-msn_contact_connect_init(MsnSoapConn *soapconn)
-{
-	msn_soap_init(soapconn, MSN_CONTACT_SERVER, TRUE,
-		      msn_contact_login_connect_cb,
-		      msn_contact_login_error_cb);
-}
--- a/libpurple/protocols/msn/contact.h	Thu Oct 04 06:13:01 2007 +0000
+++ b/libpurple/protocols/msn/contact.h	Tue Oct 30 06:29:13 2007 +0000
@@ -380,6 +380,7 @@
 	gchar * guid;
 	MsnListId list_id;
 	MsnCallbackAction action;
+	MsnSession *session;
 };
 
 typedef enum 
@@ -397,7 +398,7 @@
 MsnContact * msn_contact_new(MsnSession *session);
 void msn_contact_destroy(MsnContact *contact);
 
-MsnCallbackState * msn_callback_state_new(void);
+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);
 void msn_callback_state_set_uid(MsnCallbackState *state, const gchar *uid);
--- a/libpurple/protocols/msn/nexus.c	Thu Oct 04 06:13:01 2007 +0000
+++ b/libpurple/protocols/msn/nexus.c	Tue Oct 30 06:29:13 2007 +0000
@@ -174,7 +174,7 @@
 		g_free(password);
 		msn_nexus_destroy(nexus);
 		session->nexus = NULL;
-		return FALSE;
+		return;
 	}
 
 	/*
@@ -216,7 +216,5 @@
 	soap = msn_soap_message_new(NULL, xmlnode_from_str(tail, -1));
 	msn_soap_message_send(nexus->session, soap, MSN_TWN_SERVER, TWN_POST_URL,
 		nexus_got_response_cb, nexus);
-
-	return TRUE;
 }
 
--- a/libpurple/protocols/msn/oim.c	Thu Oct 04 06:13:01 2007 +0000
+++ b/libpurple/protocols/msn/oim.c	Tue Oct 30 06:29:13 2007 +0000
@@ -138,7 +138,6 @@
 	gpointer data)
 {
 	MsnOim *oim = data;
-	xmlnode	*faultNode, *challengeNode;
 	MsnOimSendReq *msg = g_queue_pop_head(oim->send_queue);
 
 	g_return_if_fail(msg != NULL);
@@ -146,34 +145,54 @@
 	if (response == NULL) {
 		purple_debug_info("MSNP14", "cannot send OIM: %s\n", msg->oim_msg);
 	} else {
-		faultNode = msn_soap_xml_get(response->xml, "Body/Fault");
+		xmlnode	*faultNode = msn_soap_xml_get(response->xml, "Body/Fault");
 
 		if (faultNode == NULL) {
 			/*Send OK! return*/
 			purple_debug_info("MSNP14", "sent OIM: %s\n", msg->oim_msg);
 		} else {
-			/*get the challenge,and repost it*/
-			challengeNode = msn_soap_xml_get(faultNode,
-				"detail/LockKeyChallenge");
+			xmlnode *faultcode = xmlnode_get_child(faultNode, "faultcode");
+
+			if (faultcode) {
+				char *faultcode_str = xmlnode_get_data(faultcode);
 
-			if (challengeNode == NULL) {
-				purple_debug_info("MSNP14", "can't find lock key for OIM: %s\n", msg);
-			} else {
-				char buf[33];
+				if (g_str_equal(faultcode_str, "q0:AuthenticationFailed")) {
+					xmlnode *challengeNode = msn_soap_xml_get(faultNode,
+						"detail/LockKeyChallenge");
+
+					if (challengeNode == NULL) {
+						if (oim->challenge) {
+							g_free(oim->challenge);
+							oim->challenge = NULL;
 
-				char *challenge = xmlnode_get_data(challengeNode);
-				msn_handle_chl(challenge, buf);
+							purple_debug_info("msnoim","resending OIM: %s\n",
+								msg->oim_msg);
+							g_queue_push_head(oim->send_queue, msg);
+							msn_oim_send_msg(oim);
+							return;
+						} else {
+							purple_debug_info("msnoim",
+								"can't find lock key for OIM: %s\n",
+								msg->oim_msg);
+						}
+					} else {
+						char buf[33];
 
-				g_free(oim->challenge);
-				oim->challenge = g_strndup(buf, sizeof(buf));
-				g_free(challenge);
-				purple_debug_info("MSNP14","lockkey:{%s}\n",oim->challenge);
+						char *challenge = xmlnode_get_data(challengeNode);
+						msn_handle_chl(challenge, buf);
+
+						g_free(oim->challenge);
+						oim->challenge = g_strndup(buf, sizeof(buf));
+						g_free(challenge);
+						purple_debug_info("MSNP14","lockkey:{%s}\n",oim->challenge);
 
-				/*repost the send*/
-				purple_debug_info("MSNP14","resending OIM: %s\n", msg->oim_msg);
-				g_queue_push_head(oim->send_queue, msg);
-				msn_oim_send_msg(oim);
-				return;
+						/*repost the send*/
+						purple_debug_info("MSNP14","resending OIM: %s\n", msg->oim_msg);
+						g_queue_push_head(oim->send_queue, msg);
+						msn_oim_send_msg(oim);
+						return;
+					}
+				}
 			}
 		}
 	}
--- a/libpurple/protocols/msn/soap2.c	Thu Oct 04 06:13:01 2007 +0000
+++ b/libpurple/protocols/msn/soap2.c	Tue Oct 30 06:29:13 2007 +0000
@@ -329,7 +329,6 @@
 				value = sep + 2;
 				*sep = '\0';
 				msn_soap_message_add_header(conn->message, key, value);
-				purple_debug_info("soap", "header %s: %s\n", key, value);
 
 				if ((conn->response_code == 301 || conn->response_code == 300)
 					&& strcmp(key, "Location") == 0) {
--- a/libpurple/protocols/msn/userlist.c	Thu Oct 04 06:13:01 2007 +0000
+++ b/libpurple/protocols/msn/userlist.c	Tue Oct 30 06:29:13 2007 +0000
@@ -70,7 +70,7 @@
 	{
 		MsnSession *session = pa->gc->proto_data;
 		MsnUserList *userlist = session->userlist;
-		MsnCallbackState *state = msn_callback_state_new();
+		MsnCallbackState *state = msn_callback_state_new(session);
 
 		msn_callback_state_set_action(state, MSN_DENIED_BUDDY);
 
@@ -683,7 +683,7 @@
 	
 	purple_debug_info("MSN Userlist", "Add user: %s to group: %s\n", who, new_group_name);
 
-	state = msn_callback_state_new();
+	state = msn_callback_state_new(userlist->session);
 	msn_callback_state_set_who(state, who);
 	msn_callback_state_set_new_group_name(state, new_group_name);
 
@@ -844,7 +844,7 @@
 	g_return_if_fail(userlist->session != NULL);
 	g_return_if_fail(userlist->session->contact != NULL);
 
-	state = msn_callback_state_new();
+	state = msn_callback_state_new(userlist->session);
 	msn_callback_state_set_who(state, who);
 	msn_callback_state_set_action(state, MSN_MOVE_BUDDY);
 	msn_callback_state_set_old_group_name(state, old_group_name);