Index: protocols/msn/msn.h
===================================================================
--- protocols/msn/msn.h	(revision ff27648aee17e649cdd1e47f503271e4fccbff43)
+++ protocols/msn/msn.h	(revision 5a7af1ba940521a65b3611e5f96ffa9306497e45)
@@ -94,5 +94,10 @@
 	const struct msn_away_state *away_state;
 	GSList *groups;
+	
+	/* Mostly used for sending the ADL command; since MSNP13 the client
+	   is responsible for downloading the contact list and then sending
+	   it to the MSNP server. */
 	GTree *domaintree;
+	int adl_todo;
 };
 
@@ -164,4 +169,5 @@
 	MSN_BUDDY_RL = 8,
 	MSN_BUDDY_PL = 16,
+	MSN_BUDDY_ADL_SYNCED = 256,
 } msn_buddy_flags_t;
 
Index: protocols/msn/ns.c
===================================================================
--- protocols/msn/ns.c	(revision ff27648aee17e649cdd1e47f503271e4fccbff43)
+++ protocols/msn/ns.c	(revision 5a7af1ba940521a65b3611e5f96ffa9306497e45)
@@ -35,4 +35,5 @@
 static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts );
 
+static void msn_ns_send_adl_start( struct im_connection *ic );
 static void msn_ns_send_adl( struct im_connection *ic );
 
@@ -257,5 +258,5 @@
 	else if( strcmp( cmd[0], "BLP" ) == 0 )
 	{
-		msn_ns_send_adl( ic );
+		msn_ns_send_adl_start( ic );
 	}
 	else if( strcmp( cmd[0], "ADL" ) == 0 )
@@ -263,22 +264,24 @@
 		if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 )
 		{
-			char buf[1024];
-			char *fn_raw;
-			char *fn;
-			
-			if( ic->flags & OPT_LOGGED_IN )
-				return 1;
-			
-			if( ( fn_raw = set_getstr( &ic->acc->set, "display_name" ) ) == NULL )
-				fn_raw = ic->acc->user;
-			fn = g_malloc( strlen( fn_raw ) * 3 + 1 );
-			strcpy( fn, fn_raw );
-			http_encode( fn );
-			
-			g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n",
-			            ++md->trId, fn );
-			g_free( fn );
-			
-			msn_write( ic, buf, strlen( buf ) );
+			msn_ns_send_adl( ic );
+			
+			if( md->adl_todo < 0 && !( ic->flags & OPT_LOGGED_IN ) )
+			{
+				char buf[1024];
+				char *fn_raw;
+				char *fn;
+				
+				if( ( fn_raw = set_getstr( &ic->acc->set, "display_name" ) ) == NULL )
+					fn_raw = ic->acc->user;
+				fn = g_malloc( strlen( fn_raw ) * 3 + 1 );
+				strcpy( fn, fn_raw );
+				http_encode( fn );
+				
+				g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n",
+				            ++md->trId, fn );
+				g_free( fn );
+				
+				msn_write( ic, buf, strlen( buf ) );
+			}
 		}
 		else if( num_parts >= 3 )
@@ -733,9 +736,10 @@
 	struct bee_user *bu = value;
 	struct msn_buddy_data *bd = bu->data;
+	struct msn_data *md = bu->ic->proto_data;
 	char handle[strlen(bu->handle)];
 	char *domain;
 	char l[4];
 	
-	if( ( bd->flags & 7 ) == 0 )
+	if( ( bd->flags & 7 ) == 0 || ( bd->flags & MSN_BUDDY_ADL_SYNCED ) )
 		return FALSE;
 	
@@ -761,5 +765,7 @@
 	xt_insert_child( d, c );
 	
-	return FALSE;
+	/* Do this in batches of 100. */
+	bd->flags |= MSN_BUDDY_ADL_SYNCED;
+	return (--md->adl_todo % 140) == 0;
 }
 
@@ -767,6 +773,30 @@
 {
 	struct xt_node *adl;
+	struct msn_data *md = ic->proto_data;
+	char *adls, buf[64];
+	
+	adl = xt_new_node( "ml", NULL, NULL );
+	xt_add_attr( adl, "l", "1" );
+	g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl );
+	if( adl->children == NULL )
+	{
+		/* This tells the caller that we're done now. */
+		md->adl_todo = -1;
+		xt_free_node( adl );
+		return;
+	}
+	adls = xt_to_string( adl );
+	
+	g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n", ++md->trId, strlen( adls ) );
+	if( msn_write( ic, buf, strlen( buf ) ) )
+		msn_write( ic, adls, strlen( adls ) );
+	
+	g_free( adls );
+}
+
+static void msn_ns_send_adl_start( struct im_connection *ic )
+{
 	struct msn_data *md;
-	char *adls, buf[64];
+	GSList *l;
 	
 	/* Dead connection? */
@@ -775,15 +805,17 @@
 	
 	md = ic->proto_data;
-	
-	adl = xt_new_node( "ml", NULL, NULL );
-	xt_add_attr( adl, "l", "1" );
-	g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl );
-	adls = xt_to_string( adl );
-	
-	g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n", ++md->trId, strlen( adls ) );
-	if( msn_write( ic, buf, strlen( buf ) ) )
-		msn_write( ic, adls, strlen( adls ) );
-	
-	g_free( adls );
-	xt_free_node( adl );
+	md->adl_todo = 0;
+	for( l = ic->bee->users; l; l = l->next )
+	{
+		bee_user_t *bu = l->data;
+		struct msn_buddy_data *bd = bu->data;
+		
+		if( bu->ic != ic || ( bd->flags & 7 ) == 0 )
+			continue;
+		
+		bd->flags &= ~MSN_BUDDY_ADL_SYNCED;
+		md->adl_todo++;
+	}
+	
+	msn_ns_send_adl( ic );
 }
