Index: protocols/msn/msn.c
===================================================================
--- protocols/msn/msn.c	(revision e0e15468835d5ae5bce54a28bd7a5b7aea66a1e2)
+++ protocols/msn/msn.c	(revision 80175a1558f297d5505ed4e91a261781ec9c65a2)
@@ -83,4 +83,5 @@
 	struct msn_data *md = ic->proto_data;
 	GSList *l;
+	int i;
 	
 	if( md )
@@ -107,7 +108,6 @@
 		msn_msgq_purge( ic, &md->msgq );
 		
-		g_free( md->tokens[0] );
-		g_free( md->tokens[1] );
-		g_free( md->tokens[2] );
+		for( i = 0; i < sizeof( md->tokens ) / sizeof( md->tokens[0] ); i ++ )
+			g_free( md->tokens[i] );
 		g_free( md->lock_key );
 		
@@ -337,4 +337,5 @@
 	account_t *acc = set->data;
 	struct im_connection *ic = acc->ic;
+	struct msn_data *md = ic->proto_data;
 	
 	if( strlen( value ) > 129 )
@@ -343,4 +344,8 @@
 		return NULL;
 	}
+	
+	if( md->flags & MSN_GOT_PROFILE_DN )
+		imcb_log( ic, "Warning: Persistent name changes for this account have to be done "
+		              "in the profile. BitlBee doesn't currently support this." );
 	
 	msn_soap_addressbook_set_display_name( ic, value );
Index: protocols/msn/msn.h
===================================================================
--- protocols/msn/msn.h	(revision e0e15468835d5ae5bce54a28bd7a5b7aea66a1e2)
+++ protocols/msn/msn.h	(revision 80175a1558f297d5505ed4e91a261781ec9c65a2)
@@ -50,10 +50,7 @@
 
 #define MSNP11_PROD_KEY "ILTXC!4IXB5FB*PX"
-//PK}_A_0N_K%O?A9S"
 #define MSNP11_PROD_ID  "PROD0119GSJUC$18"
-//PROD0114ES4Z%Q5W"
 #define MSNP_VER        "MSNP15"
 #define MSNP_BUILD      "8.5.1288"
-//"8.1.0178"
 
 #define MSN_SB_NEW         -24062002
@@ -76,4 +73,11 @@
 #define PROFILE_URL "http://members.msn.com/"
 
+typedef enum
+{
+	MSN_GOT_PROFILE = 1,
+	MSN_GOT_PROFILE_DN = 2,
+	MSN_DONE_ADL = 4,
+} msn_flags_t;
+
 struct msn_data
 {
@@ -82,7 +86,8 @@
 	int fd;
 	struct msn_handler_data *handler;
+	msn_flags_t flags;
 	
 	int trId;
-	char *tokens[3];
+	char *tokens[4];
 	char *lock_key;
 	
@@ -206,4 +211,5 @@
 void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error );
 void msn_auth_got_contact_list( struct im_connection *ic );
+int msn_ns_finish_login( struct im_connection *ic );
 
 /* msn_util.c */
Index: protocols/msn/ns.c
===================================================================
--- protocols/msn/ns.c	(revision e0e15468835d5ae5bce54a28bd7a5b7aea66a1e2)
+++ protocols/msn/ns.c	(revision 80175a1558f297d5505ed4e91a261781ec9c65a2)
@@ -259,7 +259,5 @@
 	{
 		msn_ns_send_adl_start( ic );
-		
-		if( md->adl_todo < 0 && !( ic->flags & OPT_LOGGED_IN ) )
-			return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) );
+		return msn_ns_finish_login( ic );
 	}
 	else if( strcmp( cmd[0], "ADL" ) == 0 )
@@ -268,12 +266,5 @@
 		{
 			msn_ns_send_adl( ic );
-			
-			if( md->adl_todo < 0 && !( ic->flags & OPT_LOGGED_IN ) )
-			{
-				msn_ns_send_adl( ic );
-				
-				if( md->adl_todo < 0 && !( ic->flags & OPT_LOGGED_IN ) )
-					return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) );
-			}
+			return msn_ns_finish_login( ic );
 		}
 		else if( num_parts >= 3 )
@@ -818,2 +809,18 @@
 	msn_ns_send_adl( ic );
 }
+
+int msn_ns_finish_login( struct im_connection *ic )
+{
+	struct msn_data *md = ic->proto_data;
+	
+	if( ic->flags & OPT_LOGGED_IN )
+		return 1;
+	
+	if( md->adl_todo < 0 )
+		md->flags |= MSN_DONE_ADL;
+	
+	if( ( md->flags & MSN_DONE_ADL ) && ( md->flags & MSN_GOT_PROFILE ) )
+		return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) );
+	else
+		return 1;
+}
Index: protocols/msn/soap.c
===================================================================
--- protocols/msn/soap.c	(revision e0e15468835d5ae5bce54a28bd7a5b7aea66a1e2)
+++ protocols/msn/soap.c	(revision 80175a1558f297d5505ed4e91a261781ec9c65a2)
@@ -209,5 +209,5 @@
 	
 	*id -= '1';
-	if( *id >= 0 && *id <= 2 )
+	if( *id >= 0 && *id < sizeof( md->tokens ) / sizeof( md->tokens[0] ) )
 	{
 		g_free( md->tokens[(int)*id] );
@@ -687,5 +687,4 @@
 	struct msn_soap_req_data *soap_req = data;
 	struct im_connection *ic = soap_req->ic;
-	struct msn_data *md = soap_req->ic->proto_data;
 	struct msn_group *group;
 	
@@ -705,11 +704,12 @@
 	if( type && g_strcasecmp( type, "me" ) == 0 )
 	{
-#if 0
-		g_free( md->myid );
-		md->myid = g_strdup( id );
-#endif		
 		set_t *set = set_find( &ic->acc->set, "display_name" );
 		g_free( set->value );
 		set->value = g_strdup( display_name );
+		
+		/* Try to fetch the profile; if the user has one, that's where
+		   we can find the persistent display_name. */
+		if( ( p = xt_find_node( node->children, "CID" ) ) && p->text )
+			msn_soap_profile_get( ic, p->text );
 		
 		return XT_HANDLED;
@@ -882,2 +882,66 @@
 	                       msn_soap_ab_contact_del_free_data );
 }
+
+
+
+/* Storage stuff: Fetch profile. */
+static int msn_soap_profile_get_build_request( struct msn_soap_req_data *soap_req )
+{
+	struct msn_data *md = soap_req->ic->proto_data;
+	
+	soap_req->url = g_strdup( SOAP_STORAGE_URL );
+	soap_req->action = g_strdup( SOAP_PROFILE_GET_ACTION );
+	soap_req->payload = g_markup_printf_escaped( SOAP_PROFILE_GET_PAYLOAD,
+		md->tokens[3], (char*) soap_req->data );
+	
+	return 1;
+}
+
+static xt_status msn_soap_profile_get_result( struct xt_node *node, gpointer data )
+{
+	struct msn_soap_req_data *soap_req = data;
+	struct im_connection *ic = soap_req->ic;
+	struct msn_data *md = soap_req->ic->proto_data;
+	struct xt_node *dn;
+	
+	if( ( dn = xt_find_node( node->children, "DisplayName" ) ) && dn->text )
+	{
+		set_t *set = set_find( &ic->acc->set, "display_name" );
+		g_free( set->value );
+		set->value = g_strdup( dn->text );
+		
+		md->flags |= MSN_GOT_PROFILE_DN;
+	}
+	
+	return XT_HANDLED;
+}
+
+static const struct xt_handler_entry msn_soap_profile_get_parser[] = {
+	{ "ExpressionProfile", "GetProfileResult", msn_soap_profile_get_result },
+	{ NULL,               NULL,     NULL                        }
+};
+
+static int msn_soap_profile_get_handle_response( struct msn_soap_req_data *soap_req )
+{
+	struct msn_data *md = soap_req->ic->proto_data;
+	
+	md->flags |= MSN_GOT_PROFILE;
+	msn_ns_finish_login( soap_req->ic );
+	
+	return MSN_SOAP_OK;
+}
+
+static int msn_soap_profile_get_free_data( struct msn_soap_req_data *soap_req )
+{
+	g_free( soap_req->data );
+	return 0;
+}
+
+int msn_soap_profile_get( struct im_connection *ic, const char *cid )
+{
+	return msn_soap_start( ic, g_strdup( cid ),
+	                       msn_soap_profile_get_build_request,
+	                       msn_soap_profile_get_parser,
+	                       msn_soap_profile_get_handle_response,
+	                       msn_soap_profile_get_free_data );
+}
Index: protocols/msn/soap.h
===================================================================
--- protocols/msn/soap.h	(revision e0e15468835d5ae5bce54a28bd7a5b7aea66a1e2)
+++ protocols/msn/soap.h	(revision 80175a1558f297d5505ed4e91a261781ec9c65a2)
@@ -126,4 +126,13 @@
                "<wsse:PolicyReference xmlns=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" URI=\"MBI_SSL\"></wsse:PolicyReference>" \
            "</wst:RequestSecurityToken>" \
+           "<wst:RequestSecurityToken Id=\"RST3\">" \
+               "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \
+               "<wsp:AppliesTo>" \
+                   "<wsa:EndpointReference>" \
+                       "<wsa:Address>storage.msn.com</wsa:Address>" \
+                   "</wsa:EndpointReference>" \
+               "</wsp:AppliesTo>" \
+               "<wsse:PolicyReference xmlns=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" URI=\"MBI_SSL\"></wsse:PolicyReference>" \
+           "</wst:RequestSecurityToken>" \
        "</ps:RequestMultipleSecurityTokens>" \
    "</Body>" \
@@ -287,3 +296,51 @@
 int msn_soap_ab_contact_del( struct im_connection *ic, bee_user_t *bu );
 
+
+#define SOAP_STORAGE_URL "https://storage.msn.com/storageservice/SchematizedStore.asmx"
+#define SOAP_PROFILE_GET_ACTION "http://www.msn.com/webservices/storage/w10/GetProfile"
+
+#define SOAP_PROFILE_GET_PAYLOAD \
+"<?xml version=\"1.0\" encoding=\"utf-8\"?>" \
+"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \
+  "<soap:Header xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \
+    "<StorageApplicationHeader xmlns=\"http://www.msn.com/webservices/storage/w10\">" \
+      "<ApplicationID>Messenger Client 9.0</ApplicationID>" \
+      "<Scenario>Initial</Scenario>" \
+    "</StorageApplicationHeader>" \
+    "<StorageUserHeader xmlns=\"http://www.msn.com/webservices/storage/w10\">" \
+      "<Puid>0</Puid>" \
+      "<TicketToken>%s</TicketToken>" \
+    "</StorageUserHeader>" \
+  "</soap:Header>" \
+  "<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \
+    "<GetProfile xmlns=\"http://www.msn.com/webservices/storage/w10\">" \
+      "<profileHandle>" \
+        "<Alias>" \
+          "<Name>%s</Name>" \
+          "<NameSpace>MyCidStuff</NameSpace>" \
+        "</Alias>" \
+        "<RelationshipName>MyProfile</RelationshipName>" \
+      "</profileHandle>" \
+      "<profileAttributes>" \
+        "<ResourceID>true</ResourceID>" \
+        "<DateModified>true</DateModified>" \
+        "<ExpressionProfileAttributes>" \
+          "<ResourceID>true</ResourceID>" \
+          "<DateModified>true</DateModified>" \
+          "<DisplayName>true</DisplayName>" \
+          "<DisplayNameLastModified>true</DisplayNameLastModified>" \
+          "<PersonalStatus>true</PersonalStatus>" \
+          "<PersonalStatusLastModified>true</PersonalStatusLastModified>" \
+          "<StaticUserTilePublicURL>true</StaticUserTilePublicURL>" \
+          "<Photo>true</Photo>" \
+          "<Flags>true</Flags>" \
+        "</ExpressionProfileAttributes>" \
+      "</profileAttributes>" \
+    "</GetProfile>" \
+  "</soap:Body>" \
+"</soap:Envelope>"
+
+int msn_soap_profile_get( struct im_connection *ic, const char *cid );
+
+
 #endif /* __SOAP_H__ */
