Index: protocols/msn/msn_util.c
===================================================================
--- protocols/msn/msn_util.c	(revision 6ddb2236943384d45cacd08e02cb4ef9ed03bba3)
+++ protocols/msn/msn_util.c	(revision d912fe4783cc9f5c2e7204f810df420359d5bee8)
@@ -74,5 +74,5 @@
 }
 
-int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, const char *group )
+int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, const char *group )
 {
 	struct msn_data *md = ic->proto_data;
@@ -131,5 +131,6 @@
 #endif
 	
-	if( !( bu = bee_user_by_handle( ic->bee, ic, who ) ) ||
+	if( !( ( bu = bee_user_by_handle( ic->bee, ic, who ) ) ||
+	       ( bu = bee_user_new( ic->bee, ic, who, 0 ) ) ) ||
 	    !( bd = bu->data ) || bd->flags & list )
 		return 1;
@@ -137,5 +138,8 @@
 	bd->flags |= list;
 	
-	msn_soap_memlist_edit( ic, who, TRUE, list );
+	if( list == MSN_BUDDY_FL )
+		msn_soap_ab_contact_add( ic, bu );
+	else
+		msn_soap_memlist_edit( ic, who, TRUE, list );
 	
 	if( ( adl = adlrml_entry( who, list ) ) )
@@ -179,5 +183,8 @@
 	bd->flags &= ~list;
 	
-	msn_soap_memlist_edit( ic, who, FALSE, list );
+	if( list == MSN_BUDDY_FL )
+		msn_soap_ab_contact_del( ic, bu );
+	else
+		msn_soap_memlist_edit( ic, who, FALSE, list );
 	
 	if( ( adl = adlrml_entry( who, list ) ) )
Index: protocols/msn/soap.c
===================================================================
--- protocols/msn/soap.c	(revision 6ddb2236943384d45cacd08e02cb4ef9ed03bba3)
+++ protocols/msn/soap.c	(revision d912fe4783cc9f5c2e7204f810df420359d5bee8)
@@ -750,2 +750,88 @@
 	                       msn_soap_ab_namechange_free_data );
 }
+
+/* Add a contact. */
+static int msn_soap_ab_contact_add_build_request( struct msn_soap_req_data *soap_req )
+{
+	struct msn_data *md = soap_req->ic->proto_data;
+	bee_user_t *bu = soap_req->data;
+	
+	soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL );
+	soap_req->action = g_strdup( SOAP_AB_CONTACT_ADD_ACTION );
+	soap_req->payload = msn_soap_abservice_build( SOAP_AB_CONTACT_ADD_PAYLOAD,
+		"ContactSave", md->tokens[1], bu->handle, bu->fullname ? bu->fullname : bu->handle );
+	
+	return 1;
+}
+
+static xt_status msn_soap_ab_contact_add_cid( struct xt_node *node, gpointer data )
+{
+	struct msn_soap_req_data *soap_req = data;
+	bee_user_t *bu = soap_req->data;
+	struct msn_buddy_data *bd = bu->data;
+	
+	g_free( bd->cid );
+	bd->cid = g_strdup( node->text );
+	
+	return XT_HANDLED;
+}
+
+static const struct xt_handler_entry msn_soap_ab_contact_add_parser[] = {
+	{ "guid", "ABContactAddResult", msn_soap_ab_contact_add_cid },
+	{ NULL,               NULL,     NULL                        }
+};
+
+static int msn_soap_ab_contact_add_handle_response( struct msn_soap_req_data *soap_req )
+{
+	/* TODO: Ack the change? Not sure what the NAKs look like.. */
+	return MSN_SOAP_OK;
+}
+
+static int msn_soap_ab_contact_add_free_data( struct msn_soap_req_data *soap_req )
+{
+	return 0;
+}
+
+int msn_soap_ab_contact_add( struct im_connection *ic, bee_user_t *bu )
+{
+	return msn_soap_start( ic, bu,
+	                       msn_soap_ab_contact_add_build_request,
+	                       msn_soap_ab_contact_add_parser,
+	                       msn_soap_ab_contact_add_handle_response,
+	                       msn_soap_ab_contact_add_free_data );
+}
+
+/* Remove a contact. */
+static int msn_soap_ab_contact_del_build_request( struct msn_soap_req_data *soap_req )
+{
+	struct msn_data *md = soap_req->ic->proto_data;
+	bee_user_t *bu = soap_req->data;
+	struct msn_buddy_data *bd = bu->data;
+	
+	soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL );
+	soap_req->action = g_strdup( SOAP_AB_CONTACT_DEL_ACTION );
+	soap_req->payload = msn_soap_abservice_build( SOAP_AB_CONTACT_DEL_PAYLOAD,
+		"Timer", md->tokens[1], bd->cid );
+	
+	return 1;
+}
+
+static int msn_soap_ab_contact_del_handle_response( struct msn_soap_req_data *soap_req )
+{
+	/* TODO: Ack the change? Not sure what the NAKs look like.. */
+	return MSN_SOAP_OK;
+}
+
+static int msn_soap_ab_contact_del_free_data( struct msn_soap_req_data *soap_req )
+{
+	return 0;
+}
+
+int msn_soap_ab_contact_del( struct im_connection *ic, bee_user_t *bu )
+{
+	return msn_soap_start( ic, bu,
+	                       msn_soap_ab_contact_del_build_request,
+	                       NULL,
+	                       msn_soap_ab_contact_del_handle_response,
+	                       msn_soap_ab_contact_del_free_data );
+}
Index: protocols/msn/soap.h
===================================================================
--- protocols/msn/soap.h	(revision 6ddb2236943384d45cacd08e02cb4ef9ed03bba3)
+++ protocols/msn/soap.h	(revision d912fe4783cc9f5c2e7204f810df420359d5bee8)
@@ -248,7 +248,42 @@
         "</ABContactUpdate>"
 
+#define SOAP_AB_CONTACT_ADD_ACTION "http://www.msn.com/webservices/AddressBook/ABContactAdd"
+
+#define SOAP_AB_CONTACT_ADD_PAYLOAD \
+        "<ABContactAdd xmlns=\"http://www.msn.com/webservices/AddressBook\">" \
+            "<abId>00000000-0000-0000-0000-000000000000</abId>" \
+            "<contacts>" \
+                "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">" \
+                    "<contactInfo>" \
+                        "<contactType>LivePending</contactType>" \
+                        "<passportName>%s</passportName>" \
+                        "<isMessengerUser>true</isMessengerUser>" \
+                        "<MessengerMemberInfo>" \
+                            "<DisplayName>%s</DisplayName>" \
+                        "</MessengerMemberInfo>" \
+                    "</contactInfo>" \
+                "</Contact>" \
+            "</contacts>" \
+            "<options>" \
+                "<EnableAllowListManagement>true</EnableAllowListManagement>" \
+            "</options>" \
+        "</ABContactAdd>"
+
+#define SOAP_AB_CONTACT_DEL_ACTION "http://www.msn.com/webservices/AddressBook/ABContactDelete"
+
+#define SOAP_AB_CONTACT_DEL_PAYLOAD \
+        "<ABContactDelete xmlns=\"http://www.msn.com/webservices/AddressBook\">" \
+            "<abId>00000000-0000-0000-0000-000000000000</abId>" \
+            "<contacts>" \
+                "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">" \
+                    "<contactId>%s</contactId>" \
+                "</Contact>" \
+            "</contacts>" \
+        "</ABContactDelete>"
+
 int msn_soap_addressbook_request( struct im_connection *ic );
 int msn_soap_addressbook_set_display_name( struct im_connection *ic, const char *new );
-
+int msn_soap_ab_contact_add( struct im_connection *ic, bee_user_t *bu );
+int msn_soap_ab_contact_del( struct im_connection *ic, bee_user_t *bu );
 
 #endif /* __SOAP_H__ */
Index: protocols/msn/tables.c
===================================================================
--- protocols/msn/tables.c	(revision 6ddb2236943384d45cacd08e02cb4ef9ed03bba3)
+++ protocols/msn/tables.c	(revision d912fe4783cc9f5c2e7204f810df420359d5bee8)
@@ -83,4 +83,6 @@
 	{ 230, "Cannot remove that group",                              0 },
 	{ 231, "Invalid group",                                         0 },
+	{ 240, "ADL/RML command with corrupted payload",                STATUS_FATAL },
+	{ 241, "ADL/RML command with invalid modification",             STATUS_FATAL },
 	{ 280, "Switchboard failed",                                    STATUS_SB_FATAL },
 	{ 281, "Transfer to switchboard failed",                        0 },
