diff libpurple/protocols/msn/contact.c @ 20486:ff4ae9dde291

Make block/unblock work right, as well as being add by a buddy. Finally fixes #723
author Carlos Silva <typ0@pidgin.im>
date Mon, 03 Sep 2007 05:47:52 +0000
parents 98613886411a
children 321d25932f5e
line wrap: on
line diff
--- a/libpurple/protocols/msn/contact.c	Fri Aug 31 18:15:23 2007 +0000
+++ b/libpurple/protocols/msn/contact.c	Mon Sep 03 05:47:52 2007 +0000
@@ -25,19 +25,27 @@
  */
 
 #include "msn.h"
-#include "soap.h"
 #include "contact.h"
 #include "xmlnode.h"
 #include "group.h"
 
-
 const char *MsnSoapPartnerScenarioText[] =
 {
         "Initial",
         "ContactSave",
-	"MessengerPendingList"
+	"MessengerPendingList",
+	"ContactMsgrAPI",
+	"BlockUnblock"
 };
 
+const char *MsnMemberRole[] =
+{
+	"Forward",
+	"Allow",
+	"Block",
+	"Reverse",
+	"Pending"
+};
 
 /* new a contact */
 MsnContact *
@@ -180,18 +188,18 @@
 }
 
 /*get MSN member role utility*/
-static int
+static MsnListId
 msn_get_memberrole(char * role)
 {
 	
 	if (!strcmp(role,"Allow")) {
-		return MSN_LIST_AL_OP;
+		return MSN_LIST_AL;
 	} else if (!strcmp(role,"Block")) {
-		return MSN_LIST_BL_OP;
+		return MSN_LIST_BL;
 	} else if (!strcmp(role,"Reverse")) {
-		return MSN_LIST_RL_OP;
+		return MSN_LIST_RL;
 	} else if (!strcmp(role,"Pending")) {
-		return MSN_LIST_PL_OP;
+		return MSN_LIST_PL;
 	}
 	return 0;
 }
@@ -274,7 +282,8 @@
 msn_parse_contact_list(MsnContact * contact)
 {
 	MsnSession * session;
-	int list_op = 0;
+	MsnListOp list_op = 0;
+	MsnListId list;
 	char * passport, *typedata;
 	xmlnode *fault, *faultstringnode, *faultdetail, *errorcode;
 	xmlnode *node, *body, *response, *result, *services;
@@ -421,7 +430,9 @@
 
 				roleNode = xmlnode_get_child(membershipnode,"MemberRole");
 				role = xmlnode_get_data(roleNode);
-				list_op = msn_get_memberrole(role);
+				list = msn_get_memberrole(role);
+				list_op = 1 << list;
+
 				purple_debug_info("MSNCL","MemberRole role: %s, list_op: %d\n",role,list_op);
 				
 				g_free(role);
@@ -429,9 +440,9 @@
 				members = xmlnode_get_child(membershipnode,"Members");
 				for (member = xmlnode_get_child(members, "Member"); member;
 						member = xmlnode_get_next_twin(member)){
-					MsnUser *user;
-					xmlnode * typeNode;
-					char * type;
+					MsnUser *user = NULL;
+					xmlnode *typeNode, *membershipIdNode=NULL;
+					gchar *type, *membershipId = NULL;
 
 					purple_debug_info("MSNCL","Member type: %s\n", xmlnode_get_attrib(member,"type"));
 					
@@ -444,7 +455,18 @@
 						g_free(type);
 
 						user = msn_userlist_find_add_user(session->userlist,passport,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);
+
 						g_free(passport);
 					}
 					
@@ -458,6 +480,16 @@
 						passport = xmlnode_get_data(emailNode);
 						purple_debug_info("MSNCL","Email Member: Name: '%s', list_op: %d\n", passport, list_op);
 						user = msn_userlist_find_add_user(session->userlist, passport, 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);
 						g_free(passport);
 					}
@@ -473,11 +505,12 @@
 static void
 msn_get_contact_list_cb(gpointer data, gint source, PurpleInputCondition cond)
 {
-	MsnSoapConn *soapconn = data;	
+	MsnSoapConn *soapconn = data;
 	MsnContact *contact;
 	MsnSession *session;
 	const char *abLastChange;
 	const char *dynamicItemLastChange;
+	gchar *partner_scenario;
 
 	purple_debug_misc("MSNCL","Got the contact list!\n");
 
@@ -485,6 +518,9 @@
 	g_return_if_fail(contact != NULL);
 	session = soapconn->session;
 	g_return_if_fail(session != NULL);
+	g_return_if_fail(soapconn->data_cb != NULL);
+
+	partner_scenario = soapconn->data_cb;
 
 	msn_parse_contact_list(contact);
 	/*free the read buffer*/
@@ -493,15 +529,19 @@
 	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);
+		/* 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);
+		msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL);
 #endif
-	msn_soap_free_read_buf(soapconn);
+	} else {
+		msn_soap_free_read_buf(soapconn);
+	}
 }
 
 static void
@@ -519,23 +559,27 @@
 msn_get_contact_list(MsnContact * contact, const MsnSoapPartnerScenario partner_scenario, const char *update_time)
 {
 	MsnSoapReq *soap_request;
-	char *body = NULL;
-	char * update_str;
+	gchar *body = NULL;
+	gchar * update_str;
+	const gchar *partner_scenario_str = MsnSoapPartnerScenarioText[partner_scenario];
 
 	purple_debug_misc("MSNCL","Getting Contact List.\n");
+
 	if ( update_time != NULL ) {
 		purple_debug_info("MSNCL","Last update time: %s\n",update_time);
 		update_str = g_strdup_printf(MSN_GET_CONTACT_UPDATE_XML,update_time);
 	} else {
 		update_str = g_strdup("");
 	}
-	body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, MsnSoapPartnerScenarioText[partner_scenario], update_str);
+
+	body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, update_str);
 	g_free(update_str);
 
 	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					MSN_GET_CONTACT_POST_URL,MSN_GET_CONTACT_SOAP_ACTION,
+					MSN_GET_CONTACT_POST_URL,
+					MSN_GET_CONTACT_SOAP_ACTION,
 					body,
-					NULL,
+					(gpointer) partner_scenario_str,
 					msn_get_contact_list_cb,
 					msn_get_contact_written_cb);
 	msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init);
@@ -933,12 +977,17 @@
 		msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL);
 	}
 	msn_notification_send_fqy(soapconn->session, state->who);
-	
+
 	user = msn_userlist_find_add_user(userlist, state->who, state->who);
 	msn_user_add_group_id(user, state->guid);
 
+	if (msn_userlist_user_is_in_list(user, MSN_LIST_PL)) {
+		msn_del_contact_from_list(soapconn->session->contact, NULL, state->who, MSN_LIST_PL);
+	} else {
+		msn_soap_free_read_buf(soapconn);
+	}
+	
 	msn_callback_state_free(state);
-	msn_soap_free_read_buf(soapconn);
 }
 
 static void
@@ -1015,12 +1064,20 @@
 	}
 
 	if (state->action & MSN_ADD_BUDDY) {
+		MsnUser *user = msn_userlist_find_user(userlist, state->who);
+
         	if ( !msn_user_is_yahoo(soapconn->session->account, state->who) ) {
 
 		                msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL);
 		                msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL);
 	        }
 	        msn_notification_send_fqy(soapconn->session, state->who);
+
+		if (msn_userlist_user_is_in_list(user, MSN_LIST_PL)) {
+			msn_del_contact_from_list(soapconn->session->contact, NULL, state->who, MSN_LIST_PL);
+			msn_callback_state_free(state);
+			return;
+		}
 	}
 
 	if (state->action & MSN_MOVE_BUDDY) {
@@ -1295,79 +1352,192 @@
 	g_free(body);
 }
 
+
 static void
-msn_block_read_cb(gpointer data, gint source, PurpleInputCondition cond)
+msn_del_contact_from_list_read_cb(gpointer data, gint source, PurpleInputCondition cond)
 {
-	purple_debug_info("MSNP14","block read done\n");
+	MsnSoapConn * soapconn = data;
+	MsnCallbackState *state = NULL;
+
+	g_return_if_fail(soapconn->data_cb != NULL);
+	g_return_if_fail(soapconn->session != NULL);
+	g_return_if_fail(soapconn->session->contact != NULL);
+
+	state = (MsnCallbackState *) soapconn->data_cb;
+
+	purple_debug_info("MSN CL", "Contact %s deleted successfully from %s list on server!\n", state->who, MsnMemberRole[state->list_id]);
+
+	if (state->list_id == MSN_LIST_PL) {
+		msn_add_contact_to_list(soapconn->session->contact, state, state->who, MSN_LIST_RL);
+		return;
+	}
+
+	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;
+	}
+
+	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;
+	}
+
+	msn_callback_state_free(state);
+	msn_soap_free_read_buf(soapconn);
 }
 
 static void
-msn_block_written_cb(gpointer data, gint source, PurpleInputCondition cond)
+msn_del_contact_from_list_written_cb(gpointer data, gint source, PurpleInputCondition cond)
 {
-	MsnSoapConn * soapconn = data;	
+	MsnSoapConn * soapconn = data;
 
-	purple_debug_info("MSNP14","finish block written\n");
-	soapconn->read_cb = msn_block_read_cb;
+	purple_debug_info("MSN CL","Delete contact from list SOAP request sent!\n");
+	soapconn->read_cb = msn_del_contact_from_list_read_cb;
 }
 
-/*block a Contact*/
 void
-msn_block_contact(MsnContact *contact, const char* membership_id)
+msn_del_contact_from_list(MsnContact *contact, MsnCallbackState *state,
+			  const gchar *passport, const MsnListId list)
 {
 	MsnSoapReq *soap_request;
-	char *body = NULL;
+	gchar *body = NULL, *member = NULL;
+	MsnSoapPartnerScenario partner_scenario;
+	MsnUser *user;
+
+	g_return_if_fail(contact != NULL);
+	g_return_if_fail(passport != NULL);
+	g_return_if_fail(list < 5);
+
+	purple_debug_info("MSN CL", "Deleting contact %s from %s list\n", passport, MsnMemberRole[list]);
+
+	if (state == NULL) {
+		state = msn_callback_state_new();
+	}
+	msn_callback_state_set_list_id(state, list);
+	msn_callback_state_set_who(state, passport);
+
+	if (list == MSN_LIST_PL) {
+		g_return_if_fail(contact->session != NULL);
+		g_return_if_fail(contact->session->userlist != NULL);
+
+		user = msn_userlist_find_user(contact->session->userlist, passport);
+
+		partner_scenario = MSN_PS_CONTACT_API;
+		member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML, user->membership_id[MSN_LIST_PL]);
+	} else {
+		/* list == MSN_LIST_AL || list == MSN_LIST_BL */
+		partner_scenario = MSN_PS_BLOCK_UNBLOCK;
+		
+		member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, passport);
+	}
+
+	body = g_strdup_printf( MSN_CONTACT_DELECT_FROM_LIST_TEMPLATE,
+			        MsnSoapPartnerScenarioText[partner_scenario],
+			        MsnMemberRole[list],
+			        member);
+	g_free(member);
+
+	soap_request = msn_soap_request_new( MSN_CONTACT_SERVER,
+					     MSN_SHARE_POST_URL,
+					     MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION,
+					     body,
+					     state,
+					     msn_del_contact_from_list_read_cb,
+					     msn_del_contact_from_list_written_cb);
+
+	msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init);
+	
+	g_free(body);
+}
+
+static void
+msn_add_contact_to_list_read_cb(gpointer data, gint source, PurpleInputCondition cond)
+{
+	MsnSoapConn * soapconn = data;
+	MsnCallbackState *state = NULL;
+
+	g_return_if_fail(soapconn->data_cb != NULL);
+
+	state = (MsnCallbackState *) soapconn->data_cb;
+	
+	purple_debug_info("MSN CL", "Contact %s added successfully to %s list on server!\n", state->who, MsnMemberRole[state->list_id]);
 
-	purple_debug_info("MSNP14","msn block a contact...\n");
-	body = g_strdup_printf(MSN_CONTACT_DELECT_FROM_ALLOW_TEMPLATE, membership_id);
-	/*build SOAP and POST it*/
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					MSN_SHARE_POST_URL,
-					MSN_CONTACT_BLOCK_SOAP_ACTION,
-					body,
-					NULL,
-					msn_block_read_cb,
-					msn_block_written_cb);
-	msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init);
+	if (state->list_id == MSN_LIST_RL && (state->action & MSN_DENIED_BUDDY) ) {
+		g_return_if_fail(soapconn->session != NULL);
+		g_return_if_fail(soapconn->session->contact != NULL);
+
+		msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_BL);
+		return;
+	}
+
+	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);
+}
+
+
+static void
+msn_add_contact_to_list_written_cb(gpointer data, gint source, PurpleInputCondition cond)
+{
+	MsnSoapConn * soapconn = data;
+
+	purple_debug_info("MSN CL","Add contact to list SOAP request sent!\n");
+	soapconn->read_cb = msn_add_contact_to_list_read_cb;
+}
+
+void
+msn_add_contact_to_list(MsnContact *contact, MsnCallbackState *state,
+			const gchar *passport, const MsnListId list)
+{
+	MsnSoapReq *soap_request;
+	gchar *body = NULL, *member = NULL;
+	MsnSoapPartnerScenario partner_scenario;
+
+	g_return_if_fail(contact != NULL);
+	g_return_if_fail(passport != NULL);
+	g_return_if_fail(list < 5);
+
+	purple_debug_info("MSN CL", "Adding contact %s to %s list\n", passport, MsnMemberRole[list]);
+
+	if (state == NULL) {
+		state = msn_callback_state_new();
+	}
+	msn_callback_state_set_list_id(state, list);
+	msn_callback_state_set_who(state, passport);
+
+	partner_scenario = (list == MSN_LIST_RL) ? MSN_PS_CONTACT_API : MSN_PS_BLOCK_UNBLOCK;
+
+	member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, passport);
+
+	body = g_strdup_printf(MSN_CONTACT_ADD_TO_LIST_TEMPLATE, 
+			       MsnSoapPartnerScenarioText[partner_scenario],
+			       MsnMemberRole[list], 
+			       member);
+
+	g_free(member);
+
+	soap_request = msn_soap_request_new( MSN_CONTACT_SERVER,
+					     MSN_SHARE_POST_URL,
+					     MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION,
+					     body,
+					     state,
+					     msn_add_contact_to_list_read_cb,
+					     msn_add_contact_to_list_written_cb);
+
+	msn_soap_post(contact->soapconn, soap_request, msn_contact_connect_init);
 
 	g_free(body);
 }
 
-static void
-msn_unblock_read_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
-	purple_debug_info("MSNP14","unblock read done\n");
-}
-
-static void
-msn_unblock_written_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
-	MsnSoapConn * soapconn = data;	
-
-	purple_debug_info("MSNP14","finish unblock written\n");
-	soapconn->read_cb = msn_unblock_read_cb;
-}
-
-/*unblock a contact*/
-void
-msn_unblock_contact(MsnContact *contact,const char* passport)
-{
-	MsnSoapReq *soap_request;
-	char *body = NULL;
-
-	purple_debug_info("MSNP14","msn unblock a contact...\n");
-
-	body = g_strdup_printf(MSN_UNBLOCK_CONTACT_TEMPLATE,passport);
-	/*build SOAP and POST it*/
-	soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
-					MSN_SHARE_POST_URL,MSN_CONTACT_UNBLOCK_SOAP_ACTION,
-					body,
-					NULL,
-					msn_unblock_read_cb,
-					msn_unblock_written_cb);
-	msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init);
-
-	g_free(body);
-}
 
 #if 0
 static void
@@ -1552,7 +1722,7 @@
 	}
 
 	if ( !strcmp(guid, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(guid, MSN_NON_IM_GROUP_ID) ) {
-		// add back PurpleGroup since it isn't really removed in the server?
+		// XXX add back PurpleGroup since it isn't really removed in the server?
 		return;
 	}