changeset 20390:d634f88e25d8

msn.tgz from SF Patch #1621854 from Ka-Hing Cheung "This tarball brings soc-2006-msnp13 up to head. In addition to that it also fixes a crash with sending offline messages. I wasn't able to generate a diff against that branch, svn seems to insist on diff'ing against HEAD after I run the merge command. After running `svn merge -r 16309:HEAD https://gaim.svn.sourceforge.net/svnroot/gaim/trunk` on the soc-2006-msnp13 you can replace the msn directory with the attached tarball. The fix for offline messaging is on msn.c:901: if (!session->oim) session->oim = msn_oim_new(session)" committer: Richard Laager <rlaager@wiktel.com>
author Ka-Hing Cheung <khc@hxbc.us>
date Sun, 15 Apr 2007 02:18:17 +0000
parents e354528c4163
children 0b0ecee55091 9755b2f7bb0f
files libgaim/protocols/msn/command.c libgaim/protocols/msn/contact.c libgaim/protocols/msn/contact.h libgaim/protocols/msn/dialog.c libgaim/protocols/msn/directconn.c libgaim/protocols/msn/directconn.h libgaim/protocols/msn/msn.c libgaim/protocols/msn/nexus.c libgaim/protocols/msn/oim.c libgaim/protocols/msn/servconn.c libgaim/protocols/msn/session.c libgaim/protocols/msn/slp.c libgaim/protocols/msn/slplink.c libgaim/protocols/msn/switchboard.c libgaim/protocols/msn/switchboard.h libgaim/protocols/msn/userlist.c
diffstat 16 files changed, 527 insertions(+), 416 deletions(-) [+]
line wrap: on
line diff
--- a/libgaim/protocols/msn/command.c	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/command.c	Sun Apr 15 02:18:17 2007 +0000
@@ -112,8 +112,6 @@
 	MsnCommand *cmd;
 	char *tmp;
 	char *param_start;
-	char *param;
-	int c;
 
 	g_return_val_if_fail(string != NULL, NULL);
 
@@ -127,6 +125,12 @@
 	{
 		*param_start++ = '\0';
 		cmd->params = g_strsplit(param_start, " ", 0);
+	}
+
+	if (cmd->params != NULL)
+	{
+		char *param;
+		int c;
 
 		for (c = 0; cmd->params[c]; c++);
 		cmd->param_count = c;
@@ -134,10 +138,10 @@
 		param = cmd->params[0];
 
 		cmd->trId = is_num(param) ? atoi(param) : 0;
-	}
-	else
+	}else{
 		cmd->trId = 0;
 	}
+
 	/*add payload Length checking*/
 	msn_set_payload_len(cmd);
 	gaim_debug_info("MaYuan","get payload len:%d\n",cmd->payload_len);
--- a/libgaim/protocols/msn/contact.c	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/contact.c	Sun Apr 15 02:18:17 2007 +0000
@@ -215,11 +215,11 @@
 static void
 msn_get_contact_list_cb(gpointer data, gint source, GaimInputCondition cond)
 {
-	MsnSoapConn * soapconn = data;	
+	MsnSoapConn *soapconn = data;	
 	MsnContact *contact;
 	MsnSession *session;
-	const char * abLastChange;
-	const char * dynamicItemLastChange;
+	const char *abLastChange;
+	const char *dynamicItemLastChange;
 
 	contact = soapconn->parent;
 	g_return_if_fail(contact != NULL);
@@ -235,7 +235,7 @@
 
 	abLastChange = gaim_blist_node_get_string(msn_session_get_bnode(contact->session),"ablastChange");
 	dynamicItemLastChange = gaim_blist_node_get_string(msn_session_get_bnode(contact->session),"dynamicItemLastChange");
-	msn_get_address_book(contact,abLastChange,dynamicItemLastChange);
+	msn_get_address_book(contact, abLastChange, dynamicItemLastChange);
 }
 
 static void
@@ -517,7 +517,7 @@
 
 /*get the address book*/
 void
-msn_get_address_book(MsnContact *contact,char * LastChanged, char * dynamicItemLastChange)
+msn_get_address_book(MsnContact *contact, const char *LastChanged, const char *dynamicItemLastChange)
 {
 	MsnSoapReq *soap_request;
 	char *body = NULL;
@@ -532,7 +532,7 @@
 	}
 	if(dynamicItemLastChange != NULL){
 		update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML,
-								ab_update_str,dynamicItemLastChange);
+									 dynamicItemLastChange);
 	}else{
 		update_str = g_strdup(ab_update_str);
 	}
@@ -655,6 +655,7 @@
 }
 
 /*update a contact's Nickname*/
+#if 0
 void
 msn_update_contact(MsnContact *contact,const char* nickname)
 {
@@ -674,6 +675,7 @@
 
 	g_free(body);
 }
+#endif
 
 static void
 msn_block_read_cb(gpointer data, gint source, GaimInputCondition cond)
@@ -762,6 +764,7 @@
 //	msn_soap_read_cb(data,source,cond);
 }
 
+#if 0
 /*get the gleams info*/
 void
 msn_get_gleams(MsnContact *contact)
@@ -777,6 +780,7 @@
 					msn_gleams_written_cb);
 	msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init);
 }
+#endif
 
 /***************************************************************
  * Group Operation
--- a/libgaim/protocols/msn/contact.h	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/contact.h	Sun Apr 15 02:18:17 2007 +0000
@@ -214,7 +214,7 @@
 
 void msn_contact_connect(MsnContact *contact);
 void msn_get_contact_list(MsnContact * contact,char * update);
-void msn_get_address_book(MsnContact *contact,char * update, char * gupdate);
+void msn_get_address_book(MsnContact *contact, const char * update, const char * gupdate);
 
 /*contact SOAP Operation*/
 void msn_add_contact(MsnContact *contact,const char *passport,const char *groupId);
--- a/libgaim/protocols/msn/dialog.c	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/dialog.c	Sun Apr 15 02:18:17 2007 +0000
@@ -34,40 +34,20 @@
 
 } MsnAddRemData;
 
-/* Remove the buddy referenced by the MsnAddRemData before the serverside list is changed.
- * If the buddy will be added, he'll be added back; if he will be removed, he won't be. */
-static void
-msn_complete_sync_issue(MsnAddRemData *data)
-{
-	GaimBuddy *buddy;
-	GaimGroup *group = NULL;
-
-	if (data->group != NULL)
-		group = gaim_find_group(data->group);
-	
-	if (group != NULL)
-		buddy = gaim_find_buddy_in_group(gaim_connection_get_account(data->gc), data->who, group);
-	else
-		buddy = gaim_find_buddy(gaim_connection_get_account(data->gc), data->who);
-	
-	if (buddy != NULL)
-		gaim_blist_remove_buddy(buddy);
-}
-
 static void
 msn_add_cb(MsnAddRemData *data)
 {
-	MsnSession *session;
-	MsnUserList *userlist;
-
-	msn_complete_sync_issue(data);
+	if (g_list_find(gaim_connections_get_all(), data->gc) != NULL)
+	{
+		MsnSession *session = data->gc->proto_data;
+		MsnUserList *userlist = session->userlist;
 
-	session = data->gc->proto_data;
-	userlist = session->userlist;
+		msn_userlist_add_buddy(userlist, data->who, MSN_LIST_FL, data->group);
+	}
 
-	msn_userlist_add_buddy(userlist, data->who, MSN_LIST_FL, data->group);
+	if (data->group != NULL)
+		g_free(data->group);
 
-	g_free(data->group);
 	g_free(data->who);
 	g_free(data);
 }
@@ -75,17 +55,17 @@
 static void
 msn_rem_cb(MsnAddRemData *data)
 {
-	MsnSession *session;
-	MsnUserList *userlist;
-
-	msn_complete_sync_issue(data);
+	if (g_list_find(gaim_connections_get_all(), data->gc) != NULL)
+	{
+		MsnSession *session = data->gc->proto_data;
+		MsnUserList *userlist = session->userlist;
 
-	session = data->gc->proto_data;
-	userlist = session->userlist;
+		msn_userlist_rem_buddy(userlist, data->who, MSN_LIST_FL, data->group);
+	}
 
-	msn_userlist_rem_buddy(userlist, data->who, MSN_LIST_FL, data->group);
+	if (data->group != NULL)
+		g_free(data->group);
 
-	g_free(data->group);
 	g_free(data->who);
 	g_free(data);
 }
@@ -113,16 +93,13 @@
 						  gaim_account_get_username(account),
 						  gaim_account_get_protocol_name(account));
 
-	if (group_name != NULL)
-	{
+	if (group_name != NULL){
 		reason = g_strdup_printf(_("%s on the local list is "
 								   "inside the group \"%s\" but not on "
 								   "the server list. "
 								   "Do you want this buddy to be added?"),
 								 passport, group_name);
-	}
-	else
-	{
+	}else{
 		reason = g_strdup_printf(_("%s is on the local list but "
 								   "not on the server list. "
 								   "Do you want this buddy to be added?"),
@@ -137,10 +114,11 @@
 	if (group_name != NULL)
 		group = gaim_find_group(group_name);
 
-	if (group != NULL)
+	if (group != NULL){
 		buddy = gaim_find_buddy_in_group(account, passport, group);
-	else
+	}else{
 		buddy = gaim_find_buddy(account, passport);
+	}
 
 	if (buddy != NULL)
 		gaim_blist_remove_buddy(buddy);
--- a/libgaim/protocols/msn/directconn.c	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/directconn.c	Sun Apr 15 02:18:17 2007 +0000
@@ -76,7 +76,6 @@
  * Connection Functions
  **************************************************************************/
 
-#if 0
 static int
 create_listener(int port)
 {
@@ -160,7 +159,6 @@
 
 	return fd;
 }
-#endif
 
 static size_t
 msn_directconn_write(MsnDirectConn *directconn,
@@ -288,6 +286,11 @@
 		/* ERROR */
 		gaim_debug_error("msn", "error reading\n");
 
+		if (directconn->inpa)
+			gaim_input_remove(directconn->inpa);
+
+		close(directconn->fd);
+
 		msn_directconn_destroy(directconn);
 
 		return;
@@ -302,6 +305,11 @@
 		/* ERROR */
 		gaim_debug_error("msn", "error reading\n");
 
+		if (directconn->inpa)
+			gaim_input_remove(directconn->inpa);
+
+		close(directconn->fd);
+
 		msn_directconn_destroy(directconn);
 
 		return;
@@ -348,17 +356,22 @@
 		/* ERROR */
 		gaim_debug_error("msn", "error reading\n");
 
+		if (directconn->inpa)
+			gaim_input_remove(directconn->inpa);
+
+		close(directconn->fd);
+
 		msn_directconn_destroy(directconn);
 	}
 }
 
 static void
-connect_cb(gpointer data, gint source, const gchar *error_message)
+connect_cb(gpointer data, gint source, GaimInputCondition cond)
 {
 	MsnDirectConn* directconn;
 	int fd;
 
-	gaim_debug_misc("msn", "directconn: connect_cb: %d\n", source);
+	gaim_debug_misc("msn", "directconn: connect_cb: %d, %d.\n", source, cond);
 
 	directconn = data;
 	directconn->connect_data = NULL;
@@ -409,6 +422,7 @@
 msn_directconn_connect(MsnDirectConn *directconn, const char *host, int port)
 {
 	MsnSession *session;
+	int r;
 
 	g_return_val_if_fail(directconn != NULL, FALSE);
 	g_return_val_if_fail(host       != NULL, TRUE);
@@ -434,7 +448,6 @@
 		return FALSE;
 }
 
-#if 0
 void
 msn_directconn_listen(MsnDirectConn *directconn)
 {
@@ -454,7 +467,6 @@
 	directconn->port = port;
 	directconn->c = 0;
 }
-#endif
 
 MsnDirectConn*
 msn_directconn_new(MsnSlpLink *slplink)
@@ -476,6 +488,7 @@
 void
 msn_directconn_destroy(MsnDirectConn *directconn)
 {
+
 	if (directconn->connect_data != NULL)
 		gaim_proxy_connect_cancel(directconn->connect_data);
 
--- a/libgaim/protocols/msn/directconn.h	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/directconn.h	Sun Apr 15 02:18:17 2007 +0000
@@ -52,9 +52,7 @@
 MsnDirectConn *msn_directconn_new(MsnSlpLink *slplink);
 gboolean msn_directconn_connect(MsnDirectConn *directconn,
 								const char *host, int port);
-#if 0
 void msn_directconn_listen(MsnDirectConn *directconn);
-#endif
 void msn_directconn_send_msg(MsnDirectConn *directconn, MsnMessage *msg);
 void msn_directconn_parse_nonce(MsnDirectConn *directconn, const char *nonce);
 void msn_directconn_destroy(MsnDirectConn *directconn);
--- a/libgaim/protocols/msn/msn.c	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/msn.c	Sun Apr 15 02:18:17 2007 +0000
@@ -67,10 +67,8 @@
 	MsnGetInfoData *info_data;
 	char *stripped;
 	char *url_buffer;
-	GString *s;
+	GaimNotifyUserInfo *user_info;
 	char *photo_url_text;
-	char *tooltip_text;
-	const char *title;
 
 } MsnGetInfoStepTwoData;
 
@@ -562,7 +560,7 @@
 }
 
 static void
-msn_tooltip_text(GaimBuddy *buddy, GString *str, gboolean full)
+msn_tooltip_text(GaimBuddy *buddy, GaimNotifyUserInfo *user_info, gboolean full)
 {
 	MsnUser *user;
 	GaimPresence *presence = gaim_buddy_get_presence(buddy);
@@ -570,33 +568,34 @@
 
 	user = buddy->proto_data;
 
+	
 	if (gaim_presence_is_online(presence))
 	{
 		char *psm;
 		psm = msn_status_text(buddy);
-		if (psm)
-			g_string_append_printf(str, _("\n<b>%s:</b> %s"), _("Psm"),psm);
-		g_free(psm);
 
-		g_string_append_printf(str, _("\n<b>%s:</b> %s"), _("Status"),
-							   gaim_presence_is_idle(presence) ?
-							   _("Idle") : gaim_status_get_name(status));
+		gaim_notify_user_info_add_pair(user_info, _("Status"),
+									   (gaim_presence_is_idle(presence) ? _("Idle") : gaim_status_get_name(status)));
+		if (psm) {
+			gaim_notify_user_info_add_pair(user_info, _("PSM"), psm);
+			g_free(psm);
+		}
 	}
-
+	
 	if (full && user)
 	{
-		g_string_append_printf(str, _("\n<b>%s:</b> %s"), _("Has you"),
-							   (user->list_op & (1 << MSN_LIST_RL)) ?
-							   _("Yes") : _("No"));
+		gaim_notify_user_info_add_pair(user_info, _("Has you"),
+									   ((user->list_op & (1 << MSN_LIST_RL)) ? _("Yes") : _("No")));
+	}
 
 	/* XXX: This is being shown in non-full tooltips because the
 	 * XXX: blocked icon overlay isn't always accurate for MSN.
 	 * XXX: This can die as soon as gaim_privacy_check() knows that
 	 * XXX: this prpl always honors both the allow and deny lists. */
 	if (user)
-		g_string_append_printf(str, _("\n<b>%s:</b> %s"), _("Blocked"),
-							   (user->list_op & (1 << MSN_LIST_BL)) ?
-							   _("Yes") : _("No"));
+	{
+		gaim_notify_user_info_add_pair(user_info, _("Blocked"),
+									   ((user->list_op & (1 << MSN_LIST_BL)) ? _("Yes") : _("No")));
 	}
 }
 
@@ -605,7 +604,6 @@
 {
 	GaimStatusType *status;
 	GList *types = NULL;
-
 #if 0
 	status = gaim_status_type_new_full(GAIM_STATUS_AVAILABLE,
 			NULL, NULL, FALSE, TRUE, FALSE);
@@ -633,13 +631,11 @@
 			"message", _("Message"), gaim_value_new(GAIM_TYPE_STRING),
 			NULL);
 	types = g_list_append(types, status);
-
 	status = gaim_status_type_new_with_attrs(
 			GAIM_STATUS_AWAY, "phone", _("On the Phone"), TRUE, TRUE, FALSE,
 			"message", _("Message"), gaim_value_new(GAIM_TYPE_STRING),
 			NULL);
 	types = g_list_append(types, status);
-
 	status = gaim_status_type_new_with_attrs(
 			GAIM_STATUS_AWAY, "lunch", _("Out to Lunch"), TRUE, TRUE, FALSE,
 			"message", _("Message"), gaim_value_new(GAIM_TYPE_STRING),
@@ -901,6 +897,10 @@
 		
 		gaim_debug_info("MaYuan","prepare to send offline Message\n");		
 		session = gc->proto_data;
+		/* XXX/khc: hack */
+		if (!session->oim)
+			session->oim = msn_oim_new(session);
+
 		oim = session->oim;
 		friendname = msn_encode_mime(account->username);
 		msn_oim_prep_send_msg_info(oim,
@@ -908,33 +908,6 @@
 			message);
 		msn_oim_send_msg(oim);
 	}
-	else
-	{
-		char *body_str, *body_enc, *pre, *post;
-		const char *format;
-		/*
-		 * In MSN, you can't send messages to yourself, so
-		 * we'll fake like we received it ;)
-		 */
-		body_str = msn_message_to_string(msg);
-		body_enc = g_markup_escape_text(body_str, -1);
-		g_free(body_str);
-
-		format = msn_message_get_attr(msg, "X-MMS-IM-Format");
-		msn_parse_format(format, &pre, &post);
-		body_str = g_strdup_printf("%s%s%s", pre ? pre :  "",
-								   body_enc ? body_enc : "", post ? post : "");
-		g_free(body_enc);
-		g_free(pre);
-		g_free(post);
-
-		serv_got_typing_stopped(gc, who);
-		serv_got_im(gc, who, body_str, flags, time(NULL));
-		g_free(body_str);
-	}
-
-	msn_message_destroy(msg);
-
 	return 1;
 }
 
@@ -994,8 +967,7 @@
 
 	gc = gaim_account_get_connection(account);
 
-	if (gc != NULL)
-	{
+	if (gc != NULL){
 		session = gc->proto_data;
 		msn_change_status(session);
 	}
@@ -1072,6 +1044,7 @@
 	userlist = session->userlist;
 	who = msn_normalize(gc->account, buddy->name);
 
+	gaim_debug_info("MaYuan","add user:{%s} to group:{%s}\n",who,group->name);
 	if (!session->logged_in)
 	{
 #if 0
@@ -1448,45 +1421,41 @@
 	}
 }
 
-static char *
-msn_tooltip_info_text(MsnGetInfoData *info_data)
+/**
+ * Extract info text from info_data and add it to user_info
+ */
+static gboolean
+msn_tooltip_extract_info_text(GaimNotifyUserInfo *user_info, MsnGetInfoData *info_data)
 {
-	GString *s;
 	GaimBuddy *b;
 
-	s = g_string_sized_new(80); /* wild guess */
-
 	b = gaim_find_buddy(gaim_connection_get_account(info_data->gc),
 						info_data->name);
 
 	if (b){
-		GString *str = g_string_new("");
 		char *tmp;
 
 		if (b->alias && b->alias[0]){
 			char *aliastext = g_markup_escape_text(b->alias, -1);
-			g_string_append_printf(s, _("<b>Alias:</b> %s<br>"), aliastext);
+			gaim_notify_user_info_add_pair(user_info, _("Alias"), aliastext);
 			g_free(aliastext);
 		}
 
 		if (b->server_alias){
 			char *nicktext = g_markup_escape_text(b->server_alias, -1);
-			g_string_append_printf(s, _("<b>%s:</b> "), _("Nickname"));
-			g_string_append_printf(s, "<font sml=\"msn\">%s</font><br>",
-					nicktext);
+			tmp = g_strdup_printf("<font sml=\"msn\">%s</font><br>", nicktext);
+			gaim_notify_user_info_add_pair(user_info, _("Nickname"), tmp);
+			g_free(tmp);
 			g_free(nicktext);
 		}
 
-		msn_tooltip_text(b, str, TRUE);
-		tmp = gaim_strreplace((*str->str == '\n' ? str->str + 1 : str->str),
-							  "\n", "<br>");
-		g_string_free(str, TRUE);
-		g_string_append_printf(s, "%s<br>", tmp);
-//		gaim_debug_info("MaYuan","tooltip info string:{%s}\n",s);
-		g_free(tmp);
+		/* Add the tooltip information */
+		msn_tooltip_text(b, user_info, TRUE);
+
+		return TRUE;
 	}
 
-	return g_string_free(s, FALSE);
+	return FALSE;
 }
 
 #if PHOTO_SUPPORT
@@ -1499,14 +1468,14 @@
 	if ((p = strstr(url_text, PHOTO_URL)) != NULL){
 		p += strlen(PHOTO_URL);
 	}
-
 	if (p && (strncmp(p, "http://",strlen("http://")) == 0) && ((q = strchr(p, '"')) != NULL))
 			return g_strndup(p, q - p);
 
 	return NULL;
 }
 
-static void msn_got_photo(void *data, const char *url_text, size_t len);
+static void msn_got_photo(GaimUtilFetchUrlData *url_data, gpointer data,
+		const gchar *url_text, size_t len, const gchar *error_message);
 
 #endif
 
@@ -1522,26 +1491,25 @@
 #endif
 
 #define MSN_GOT_INFO_GET_FIELD(a, b) \
-	found = gaim_markup_extract_info_field(stripped, stripped_len, s, \
-			"\n" a ":\t", 0, "\n", 0, "Undisclosed", b, 0, NULL, NULL); \
+	found = gaim_markup_extract_info_field(stripped, stripped_len, user_info, \
+			"\n" a ":", 0, "\n", 0, "Undisclosed", b, 0, NULL, NULL); \
 	if (found) \
 		sect_info = TRUE;
 
 static void
-msn_got_info(void *data, const char *url_text, size_t len)
+msn_got_info(GaimUtilFetchUrlData *url_data, gpointer data,
+		const gchar *url_text, size_t len, const gchar *error_message)
 {
 	MsnGetInfoData *info_data = (MsnGetInfoData *)data;
-	char *stripped, *p, *q;
-	char buf[1024];
-	char *tooltip_text;
+	GaimNotifyUserInfo *user_info;
+	char *stripped, *p, *q, *tmp;
 	char *user_url = NULL;
 	gboolean found;
+	gboolean has_tooltip_text = FALSE;
 	gboolean has_info = FALSE;
 	gboolean sect_info = FALSE;
-	const char* title = NULL;
+	gboolean has_contact_info = FALSE;
 	char *url_buffer;
-	char *personal = NULL;
-	char *business = NULL;
 	GString *s, *s2;
 	int stripped_len;
 #if PHOTO_SUPPORT
@@ -1560,17 +1528,20 @@
 		return;
 	}
 
-	tooltip_text = msn_tooltip_info_text(info_data);
-	title = _("MSN Profile");
+	user_info = gaim_notify_user_info_new();
+	has_tooltip_text = msn_tooltip_extract_info_text(user_info, info_data);
 
-	if (url_text == NULL || strcmp(url_text, "") == 0)
+	if (error_message != NULL || url_text == NULL || strcmp(url_text, "") == 0)
 	{
-		g_snprintf(buf, 1024, "<html><body>%s<b>%s</b></body></html>",
-				tooltip_text, _("Error retrieving profile"));
+		tmp = g_strdup_printf("<b>%s</b>", _("Error retrieving profile"));
+		gaim_notify_user_info_add_pair(user_info, NULL, tmp);
+		g_free(tmp);
 
-		gaim_notify_userinfo(info_data->gc, info_data->name, buf, NULL, NULL);
+		gaim_notify_userinfo(info_data->gc, info_data->name, user_info, NULL, NULL);
+		gaim_notify_user_info_destroy(user_info);
 
-		g_free(tooltip_text);
+		g_free(info_data->name);
+		g_free(info_data);
 		return;
 	}
 
@@ -1628,10 +1599,16 @@
 	/* No we're not. */
 	s = g_string_sized_new(strlen(url_buffer));
 	s2 = g_string_sized_new(strlen(url_buffer));
-
+	
+	/* General section header */
+	if (has_tooltip_text)
+		gaim_notify_user_info_add_section_break(user_info);
+	
+	gaim_notify_user_info_add_section_header(user_info, _("General"));
+	
 	/* Extract their Name and put it in */
-	MSN_GOT_INFO_GET_FIELD("Name", _("Name"))
-
+	MSN_GOT_INFO_GET_FIELD("Name", _("Name"));
+	
 	/* General */
 	MSN_GOT_INFO_GET_FIELD("Nickname", _("Nickname"));
 	MSN_GOT_INFO_GET_FIELD("Age", _("Age"));
@@ -1640,7 +1617,7 @@
 	MSN_GOT_INFO_GET_FIELD("Location", _("Location"));
 
 	/* Extract their Interests and put it in */
-	found = gaim_markup_extract_info_field(stripped, stripped_len, s,
+	found = gaim_markup_extract_info_field(stripped, stripped_len, user_info,
 			"\nInterests\t", 0, " (/default.aspx?page=searchresults", 0,
 			"Undisclosed", _("Hobbies and Interests") /* _("Interests") */,
 			0, NULL, NULL);
@@ -1649,20 +1626,24 @@
 		sect_info = TRUE;
 
 	MSN_GOT_INFO_GET_FIELD("More about me", _("A Little About Me"));
-
+	
 	if (sect_info)
 	{
-		/* trim off the trailing "<br>\n" */
-		g_string_truncate(s, strlen(s->str) - 5);
-		g_string_append_printf(s2, _("%s<b>General</b><br>%s"),
-							   (*tooltip_text) ? "<hr>" : "", s->str);
-		s = g_string_truncate(s, 0);
 		has_info = TRUE;
 		sect_info = FALSE;
 	}
-
-
+    else 
+    {
+		/* Remove the section header */
+		gaim_notify_user_info_remove_last_item(user_info);
+		if (has_tooltip_text)
+			gaim_notify_user_info_remove_last_item(user_info);
+	}
+											   
 	/* Social */
+	gaim_notify_user_info_add_section_break(user_info);
+	gaim_notify_user_info_add_section_header(user_info, _("Social"));
+										   
 	MSN_GOT_INFO_GET_FIELD("Marital status", _("Marital Status"));
 	MSN_GOT_INFO_GET_FIELD("Interested in", _("Interests"));
 	MSN_GOT_INFO_GET_FIELD("Pets", _("Pets"));
@@ -1675,14 +1656,22 @@
 
 	if (sect_info)
 	{
-		g_string_append_printf(s2, _("%s<b>Social</b><br>%s"), has_info ? "<br><hr>" : "", s->str);
-		s = g_string_truncate(s, 0);
 		has_info = TRUE;
 		sect_info = FALSE;
 	}
+    else 
+    {
+		/* Remove the section header */
+		gaim_notify_user_info_remove_last_item(user_info);
+		gaim_notify_user_info_remove_last_item(user_info);
+	}
 
 	/* Contact Info */
 	/* Personal */
+	gaim_notify_user_info_add_section_break(user_info);
+	gaim_notify_user_info_add_section_header(user_info, _("Contact Info"));
+	gaim_notify_user_info_add_section_header(user_info, _("Personal"));
+
 	MSN_GOT_INFO_GET_FIELD("Name", _("Name"));
 	MSN_GOT_INFO_GET_FIELD("Significant other", _("Significant Other"));
 	MSN_GOT_INFO_GET_FIELD("Home phone", _("Home Phone"));
@@ -1698,12 +1687,18 @@
 
 	if (sect_info)
 	{
-		personal = g_strdup_printf(_("<br><b>Personal</b><br>%s"), s->str);
-		s = g_string_truncate(s, 0);
+		has_info = TRUE;
 		sect_info = FALSE;
+		has_contact_info = TRUE;
+	}
+    else 
+    {
+		/* Remove the section header */
+		gaim_notify_user_info_remove_last_item(user_info);
 	}
 
 	/* Business */
+	gaim_notify_user_info_add_section_header(user_info, _("Work"));
 	MSN_GOT_INFO_GET_FIELD("Name", _("Name"));
 	MSN_GOT_INFO_GET_FIELD("Job title", _("Job Title"));
 	MSN_GOT_INFO_GET_FIELD("Company", _("Company"));
@@ -1722,27 +1717,22 @@
 
 	if (sect_info)
 	{
-		business = g_strdup_printf(_("<br><b>Business</b><br>%s"), s->str);
-		s = g_string_truncate(s, 0);
+		has_info = TRUE;
 		sect_info = FALSE;
+		has_contact_info = TRUE;
+	}
+    else 
+    {
+		/* Remove the section header */
+		gaim_notify_user_info_remove_last_item(user_info);
 	}
 
-	if ((personal != NULL) || (business != NULL))
+	if (!has_contact_info)
 	{
-		/* trim off the trailing "<br>\n" */
-		g_string_truncate(s, strlen(s->str) - 5);
-
-		has_info = TRUE;
-		g_string_append_printf(s2, _("<hr><b>Contact Info</b>%s%s"),
-							   personal ? personal : "",
-							   business ? business : "");
+		/* Remove the Contact Info section header */
+		gaim_notify_user_info_remove_last_item(user_info);
 	}
 
-	g_free(personal);
-	g_free(business);
-	g_string_free(s, TRUE);
-	s = s2;
-
 #if 0 /* these probably don't show up any more */
 	/*
 	 * The fields, 'A Little About Me', 'Favorite Things', 'Hobbies
@@ -1867,12 +1857,9 @@
 	/* If we were able to fetch a homepage url earlier, stick it in there */
 	if (user_url != NULL)
 	{
-		g_snprintf(buf, sizeof(buf),
-				   "<b>%s:</b><br><a href=\"%s\">%s</a><br>\n",
-				   _("Homepage"), user_url, user_url);
-
-		g_string_append(s, buf);
-
+		tmp = g_strdup_printf("<a href=\"%s\">%s</a>", user_url, user_url);
+		gaim_notify_user_info_add_pair(user_info, _("Homepage"), tmp);
+		g_free(tmp);
 		g_free(user_url);
 
 		has_info = TRUE;
@@ -1891,25 +1878,22 @@
 		char *p = strstr(url_buffer, "form id=\"SpacesSearch\" name=\"SpacesSearch\"");
 		GaimBuddy *b = gaim_find_buddy
 				(gaim_connection_get_account(info_data->gc), info_data->name);
-		g_string_append_printf(s, "<br><b>%s</b><br>%s<br><br>",
-				_("Error retrieving profile"),
-				((p && b)?
-					_("The user has not created a public profile."):
-				 p? _("MSN reported not being able to find the user's profile. "
-					  "This either means that the user does not exist, "
-					  "or that the user exists "
-					  "but has not created a public profile."):
-					_("Gaim could not find "	/* This should never happen */
-					  "any information in the user's profile. "
-					  "The user most likely does not exist.")));
+		gaim_notify_user_info_add_pair(user_info, _("Error retrieving profile"),
+									   ((p && b) ? _("The user has not created a public profile.") :
+										(p ? _("MSN reported not being able to find the user's profile. "
+											   "This either means that the user does not exist, "
+											   "or that the user exists "
+											   "but has not created a public profile.") :
+										 _("Gaim could not find "	/* This should never happen */
+										   "any information in the user's profile. "
+										   "The user most likely does not exist."))));
 	}
+
 	/* put a link to the actual profile URL */
-	g_string_append_printf(s, _("<hr><b>%s:</b> "), _("Profile URL"));
-	g_string_append_printf(s, "<br><a href=\"%s%s\">%s%s</a><br>",
-			PROFILE_URL, info_data->name, PROFILE_URL, info_data->name);
-
-	/* Finish it off, and show it to them */
-	g_string_append(s, "</body></html>\n");
+	tmp = g_strdup_printf("<a href=\"%s%s\">%s%s</a>",
+					PROFILE_URL, info_data->name, PROFILE_URL, info_data->name);
+	gaim_notify_user_info_add_pair(user_info, _("Profile URL"), tmp);
+	g_free(tmp);									   
 
 #if PHOTO_SUPPORT
 	/* Find the URL to the photo; must be before the marshalling [Bug 994207] */
@@ -1921,47 +1905,45 @@
 	info2_data->info_data = info_data;
 	info2_data->stripped = stripped;
 	info2_data->url_buffer = url_buffer;
-	info2_data->s = s;
+	info2_data->user_info = user_info;
 	info2_data->photo_url_text = photo_url_text;
-	info2_data->tooltip_text = tooltip_text;
-	info2_data->title = title;
 
 	/* Try to put the photo in there too, if there's one */
 	if (photo_url_text)
 	{
-		gaim_url_fetch(photo_url_text, FALSE, NULL, FALSE, msn_got_photo,
+		gaim_util_fetch_url(photo_url_text, FALSE, NULL, FALSE, msn_got_photo,
 					   info2_data);
 	}
 	else
 	{
 		/* Emulate a callback */
-		msn_got_photo(info2_data, NULL, 0);
+		/* TODO: Huh? */
+		msn_got_photo(NULL, info2_data, NULL, 0, NULL);
 	}
 }
 
 static void
-msn_got_photo(void *data, const char *url_text, size_t len)
+msn_got_photo(GaimUtilFetchUrlData *url_data, gpointer user_data,
+		const gchar *url_text, size_t len, const gchar *error_message)
 {
-	MsnGetInfoStepTwoData *info2_data = (MsnGetInfoStepTwoData *)data;
+	MsnGetInfoStepTwoData *info2_data = (MsnGetInfoStepTwoData *)user_data;
 	int id = -1;
 
 	/* Unmarshall the saved state */
 	MsnGetInfoData *info_data = info2_data->info_data;
 	char *stripped = info2_data->stripped;
 	char *url_buffer = info2_data->url_buffer;
-	GString *s = info2_data->s;
+	GaimNotifyUserInfo *user_info = info2_data->user_info;
 	char *photo_url_text = info2_data->photo_url_text;
-	char *tooltip_text = info2_data->tooltip_text;
 
 	/* Make sure the connection is still valid if we got here by fetching a photo url */
-	if (url_text &&
-		g_list_find(gaim_connections_get_all(), info_data->gc) == NULL)
+	if (url_text && (error_message != NULL ||
+					 g_list_find(gaim_connections_get_all(), info_data->gc) == NULL))
 	{
 		gaim_debug_warning("msn", "invalid connection. ignoring buddy photo info.\n");
 		g_free(stripped);
 		g_free(url_buffer);
-		g_string_free(s, TRUE);
-		g_free(tooltip_text);
+		g_free(user_info);
 		g_free(info_data->name);
 		g_free(info_data);
 		g_free(photo_url_text);
@@ -1971,7 +1953,7 @@
 	}
 
 	/* Try to put the photo in there too, if there's one and is readable */
-	if (data && url_text && len != 0)
+	if (user_data && url_text && len != 0)
 	{
 		if (strstr(url_text, "400 Bad Request")
 			|| strstr(url_text, "403 Forbidden")
@@ -1987,20 +1969,17 @@
 			gaim_debug_info("msn", "%s is %d bytes\n", photo_url_text, len);
 			id = gaim_imgstore_add(url_text, len, NULL);
 			g_snprintf(buf, sizeof(buf), "<img id=\"%d\"><br>", id);
-			g_string_prepend(s, buf);
+			gaim_notify_user_info_prepend_pair(user_info, NULL, buf);
 		}
 	}
 
 	/* We continue here from msn_got_info, as if nothing has happened */
 #endif
-
-	g_string_prepend(s, tooltip_text);
-	gaim_notify_userinfo(info_data->gc, info_data->name, s->str, NULL, NULL);
+	gaim_notify_userinfo(info_data->gc, info_data->name, user_info, NULL, NULL);
 
 	g_free(stripped);
 	g_free(url_buffer);
-	g_string_free(s, TRUE);
-	g_free(tooltip_text);
+	gaim_notify_user_info_destroy(user_info);
 	g_free(info_data->name);
 	g_free(info_data);
 #if PHOTO_SUPPORT
@@ -2023,7 +2002,7 @@
 
 	url = g_strdup_printf("%s%s", PROFILE_URL, name);
 
-	gaim_url_fetch(url, FALSE,
+	gaim_util_fetch_url(url, FALSE,
 				   "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
 				   TRUE, msn_got_info, data);
 
@@ -2053,7 +2032,7 @@
 	OPT_PROTO_MAIL_CHECK,
 	NULL,					/* user_splits */
 	NULL,					/* protocol_options */
-	{"png", 0, 0, 96, 96, GAIM_ICON_SCALE_SEND},	/* icon_spec */
+	{"png", 0, 0, 96, 96, 0, GAIM_ICON_SCALE_SEND},	/* icon_spec */
 	msn_list_icon,			/* list_icon */
 	msn_list_emblems,		/* list_emblems */
 	msn_status_text,		/* status_text */
@@ -2110,6 +2089,8 @@
 	msn_new_xfer,			/* new_xfer */
 	NULL,					/* offline_message */
 	NULL,					/* whiteboard_prpl_ops */
+	NULL,					/* send_raw */
+	NULL,					/* roomlist_room_serialize */
 };
 
 static GaimPluginInfo info =
@@ -2127,10 +2108,10 @@
 	"MSN",                                            /**< name           */
 	VERSION,                                          /**< version        */
 	                                                  /**  summary        */
-	N_("MSN Protocol Plugin"),
+	N_("Windows Live Messenger Protocol Plugin"),
 	                                                  /**  description    */
-	N_("MSN Protocol Plugin"),
-	"Christian Hammond <chipx86@gnupdate.org>",       /**< author         */
+	N_("Windows Live Messenger Protocol Plugin"),
+	"MaYuan <mayuan2006@gmail.com>",				/**< author         */
 	GAIM_WEBSITE,                                     /**< homepage       */
 
 	msn_load,                                         /**< load           */
--- a/libgaim/protocols/msn/nexus.c	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/nexus.c	Sun Apr 15 02:18:17 2007 +0000
@@ -25,6 +25,7 @@
 #include "soap.h"
 #include "nexus.h"
 #include "notification.h"
+
 #undef NEXUS_LOGIN_TWN
 
 /*Local Function Prototype*/
@@ -60,6 +61,66 @@
 	g_free(nexus);
 }
 
+#if 0 /* khc */
+/**************************************************************************
+ * Util
+ **************************************************************************/
+
+static gssize
+msn_ssl_read(MsnNexus *nexus)
+{
+	gssize len;
+	char temp_buf[4096];
+
+	if ((len = gaim_ssl_read(nexus->gsc, temp_buf,
+			sizeof(temp_buf))) > 0)
+	{
+		nexus->read_buf = g_realloc(nexus->read_buf,
+			nexus->read_len + len + 1);
+		strncpy(nexus->read_buf + nexus->read_len, temp_buf, len);
+		nexus->read_len += len;
+		nexus->read_buf[nexus->read_len] = '\0';
+	}
+
+	return len;
+}
+
+static void
+nexus_write_cb(gpointer data, gint source, GaimInputCondition cond)
+{
+	MsnNexus *nexus = data;
+	int len, total_len;
+
+	total_len = strlen(nexus->write_buf);
+
+	len = gaim_ssl_write(nexus->gsc,
+		nexus->write_buf + nexus->written_len,
+		total_len - nexus->written_len);
+
+	if (len < 0 && errno == EAGAIN)
+		return;
+	else if (len <= 0) {
+		gaim_input_remove(nexus->input_handler);
+		nexus->input_handler = 0;
+		/* TODO: notify of the error */
+		return;
+	}
+	nexus->written_len += len;
+
+	if (nexus->written_len < total_len)
+		return;
+
+	gaim_input_remove(nexus->input_handler);
+	nexus->input_handler = 0;
+
+	g_free(nexus->write_buf);
+	nexus->write_buf = NULL;
+	nexus->written_len = 0;
+
+	nexus->written_cb(nexus, source, 0);
+}
+
+#endif
 /**************************************************************************
  * Login
  **************************************************************************/
@@ -72,6 +133,8 @@
 	session = soapconn->session;
 	g_return_if_fail(session != NULL);
 
+	soapconn->gsc = NULL;
+
 	msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication:Unable to connect"));
 	/* the above line will result in nexus being destroyed, so we don't want
 	 * to destroy it here, or we'd crash */
@@ -93,7 +156,6 @@
 
 	nexus = soapconn->parent;
 	g_return_if_fail(nexus != NULL);
-
 	session = nexus->session;
 	g_return_if_fail(session != NULL);
 
@@ -276,12 +338,6 @@
 	request_str = g_strdup_printf("%s%s", head,tail);
 	gaim_debug_misc("msn", "TWN Sending: {%s}\n", request_str);
 
-	buffer = g_strdup_printf("%s,pwd=XXXXXXXX,%s\r\n", head, tail);
-	request_str = g_strdup_printf("%s,pwd=%s,%s\r\n", head, password, tail);
-
-	gaim_debug_misc("msn", "Sending: {%s}\n", buffer);
-
-	g_free(buffer);
 	g_free(head);
 	g_free(tail);
 	g_free(username);
@@ -291,15 +347,121 @@
 	msn_soap_write(soapconn,request_str,nexus_login_written_cb);
 
 	return;
+}
+
+#if 0 /* khc */
+static void
+nexus_connect_written_cb(gpointer data, gint source, GaimInputCondition cond)
+{
+	MsnNexus *nexus = data;
+	int len;
+	char *da_login;
+	char *base, *c;
+
+	if (nexus->input_handler == 0)
+		//TODO: Use gaim_ssl_input_add()?
+		nexus->input_handler = gaim_input_add(nexus->gsc->fd,
+			GAIM_INPUT_READ, nexus_connect_written_cb, nexus);
+
+	/* Get the PassportURLs line. */
+	len = msn_ssl_read(nexus);
+
+	if (len < 0 && errno == EAGAIN)
+		return;
+	else if (len < 0) {
+		gaim_input_remove(nexus->input_handler);
+		nexus->input_handler = 0;
+		g_free(nexus->read_buf);
+		nexus->read_buf = NULL;
+		nexus->read_len = 0;
+		/* TODO: error handling */
+		return;
+	}
+
+	if (g_strstr_len(nexus->read_buf, nexus->read_len,
+			"\r\n\r\n") == NULL)
+		return;
+
+	gaim_input_remove(nexus->input_handler);
+	nexus->input_handler = 0;
+
+	base = strstr(nexus->read_buf, "PassportURLs");
+
+	if (base == NULL)
+	{
+		g_free(nexus->read_buf);
+		nexus->read_buf = NULL;
+		nexus->read_len = 0;
+		return;
+	}
+
+	if ((da_login = strstr(base, "DALogin=")) != NULL)
+	{
+		/* skip over "DALogin=" */
+		da_login += 8;
+
+		if ((c = strchr(da_login, ',')) != NULL)
+			*c = '\0';
+
+		if ((c = strchr(da_login, '/')) != NULL)
+		{
+			nexus->login_path = g_strdup(c);
+			*c = '\0';
+		}
+
+		nexus->login_host = g_strdup(da_login);
+	}
+
+	g_free(nexus->read_buf);
+	nexus->read_buf = NULL;
+	nexus->read_len = 0;
+
+	gaim_ssl_close(nexus->gsc);
+
+	/* Now begin the connection to the login server. */
+	nexus->gsc = gaim_ssl_connect(nexus->session->account,
+			nexus->login_host, GAIM_SSL_DEFAULT_PORT,
+			login_connect_cb, login_error_cb, nexus);
+}
 
 
-}
-
+#endif
 
 /**************************************************************************
  * Connect
  **************************************************************************/
 
+#if 0 /* khc */
+static void
+nexus_connect_cb(gpointer data, GaimSslConnection *gsc,
+				 GaimInputCondition cond)
+{
+	MsnNexus *nexus;
+	MsnSession *session;
+
+	nexus = data;
+	g_return_if_fail(nexus != NULL);
+
+	session = nexus->session;
+	g_return_if_fail(session != NULL);
+
+	msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH);
+
+	nexus->write_buf = g_strdup("GET /rdr/pprdr.asp\r\n\r\n");
+	nexus->written_len = 0;
+
+	nexus->read_len = 0;
+
+	nexus->written_cb = nexus_connect_written_cb;
+
+	nexus->input_handler = gaim_input_add(gsc->fd, GAIM_INPUT_WRITE,
+		nexus_write_cb, nexus);
+
+	nexus_write_cb(nexus, gsc->fd, GAIM_INPUT_WRITE);
+}
+
+#endif
+
 void
 msn_nexus_connect(MsnNexus *nexus)
 {
@@ -308,3 +470,4 @@
 	msn_soap_init(nexus->soapconn,MSN_TWN_SERVER,1,nexus_login_connect_cb,nexus_login_error_cb);
 	msn_soap_connect(nexus->soapconn);
 }
+
--- a/libgaim/protocols/msn/oim.c	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/oim.c	Sun Apr 15 02:18:17 2007 +0000
@@ -251,6 +251,8 @@
 {
 	MsnOimSendReq *request;
 
+	g_return_if_fail(oim != NULL);
+
 	request = msn_oim_new_send_req(membername,friendname,tomember,oim->send_seq,msg);
 	g_queue_push_tail(oim->send_queue,request);
 }
--- a/libgaim/protocols/msn/servconn.c	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/servconn.c	Sun Apr 15 02:18:17 2007 +0000
@@ -166,9 +166,9 @@
  **************************************************************************/
 
 static void
-connect_cb(gpointer data, gint source, const gchar *error_message)
+connect_cb(gpointer data, gint source, GaimInputCondition cond)
 {
-	MsnServConn *servconn;
+	MsnServConn *servconn = data;
 
 	servconn = data;
 	servconn->connect_data = NULL;
@@ -203,6 +203,7 @@
 msn_servconn_connect(MsnServConn *servconn, const char *host, int port)
 {
 	MsnSession *session;
+	int r;
 
 	g_return_val_if_fail(servconn != NULL, FALSE);
 	g_return_val_if_fail(host     != NULL, FALSE);
@@ -240,9 +241,9 @@
 	{
 		servconn->processing = TRUE;
 		return TRUE;
+	}else{
+		return FALSE;
 	}
-	else
-		return FALSE;
 }
 
 void
@@ -435,14 +436,12 @@
 
 		servconn->rx_len -= cur_len;
 
-		if (servconn->payload_len)
-		{
+		if (servconn->payload_len){
 			msn_cmdproc_process_payload(servconn->cmdproc, cur, cur_len);
 			servconn->payload_len = 0;
-		}
-		else
-		{
+		}else{
 			msn_cmdproc_process_cmd_text(servconn->cmdproc, cur);
+			servconn->payload_len = servconn->cmdproc->last_cmd->payload_len;
 		}
 	} while (servconn->connected && !servconn->wasted && servconn->rx_len > 0);
 
--- a/libgaim/protocols/msn/session.c	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/session.c	Sun Apr 15 02:18:17 2007 +0000
@@ -42,7 +42,6 @@
 
 	session->user = msn_user_new(session->userlist,
 								 gaim_account_get_username(account), NULL);
-
 	session->bnode = NULL;
 	
 	/*if you want to chat with Yahoo Messenger*/
@@ -271,13 +270,7 @@
 
 	g_return_if_fail(gc != NULL);
 
-	/* The core used to use msn_add_buddy to add all buddies before
-	 * being logged in. This no longer happens, so we manually iterate
-	 * over the whole buddy list to identify sync issues. */
-
-	for (gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) {
-		GaimGroup *group = (GaimGroup *)gnode;
-		const char *group_name = group->name;
+	for (gnode = gaim_get_blist()->root; gnode; gnode = gnode->next){
 		if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
 			continue;
 		for(cnode = gnode->child; cnode; cnode = cnode->next) {
@@ -364,11 +357,9 @@
 								break;
 							}
 						}
-
 					}
 
-					if (!found)
-					{
+					if (!found){
 						/* The user was not on the server list or not in that group
 						 * on the server list */
 						msn_show_sync_issue(session, b->name, group_name);
@@ -503,3 +494,4 @@
 	/* Sync users */
 	msn_session_sync_users(session);
 }
+
--- a/libgaim/protocols/msn/slp.c	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/slp.c	Sun Apr 15 02:18:17 2007 +0000
@@ -341,33 +341,31 @@
 
 		xfer = gaim_xfer_new(account, GAIM_XFER_RECEIVE,
 							 slpcall->slplink->remote_user);
-		if (xfer)
-		{
-			bin = (char *)gaim_base64_decode(context, &bin_len);
-			file_size = GUINT32_FROM_LE(*((gsize *)bin + 2));
+
+		bin = (char *)gaim_base64_decode(context, &bin_len);
+		file_size = GUINT32_FROM_LE(*((gsize *)bin + 2));
 
-			uni_name = (gunichar2 *)(bin + 20);
-			while(*uni_name != 0 && ((char *)uni_name - (bin + 20)) < MAX_FILE_NAME_LEN) {
-				*uni_name = GUINT16_FROM_LE(*uni_name);
-				uni_name++;
-			}
+		uni_name = (gunichar2 *)(bin + 20);
+		while(*uni_name != 0 && ((char *)uni_name - (bin + 20)) < MAX_FILE_NAME_LEN) {
+			*uni_name = GUINT16_FROM_LE(*uni_name);
+			uni_name++;
+		}
 
-			file_name = g_utf16_to_utf8((const gunichar2 *)(bin + 20), -1,
-										NULL, NULL, NULL);
+		file_name = g_utf16_to_utf8((const gunichar2 *)(bin + 20), -1,
+									NULL, NULL, NULL);
 
-			g_free(bin);
+		g_free(bin);
 
-			gaim_xfer_set_filename(xfer, file_name);
-			gaim_xfer_set_size(xfer, file_size);
-			gaim_xfer_set_init_fnc(xfer, msn_xfer_init);
-			gaim_xfer_set_request_denied_fnc(xfer, msn_xfer_cancel);
-			gaim_xfer_set_cancel_recv_fnc(xfer, msn_xfer_cancel);
+		gaim_xfer_set_filename(xfer, file_name);
+		gaim_xfer_set_size(xfer, file_size);
+		gaim_xfer_set_init_fnc(xfer, msn_xfer_init);
+		gaim_xfer_set_request_denied_fnc(xfer, msn_xfer_cancel);
+		gaim_xfer_set_cancel_recv_fnc(xfer, msn_xfer_cancel);
 
-			slpcall->xfer = xfer;
-			xfer->data = slpcall;
+		slpcall->xfer = xfer;
+		xfer->data = slpcall;
 
-			gaim_xfer_request(xfer);
-		}
+		gaim_xfer_request(xfer);
 	}
 }
 
@@ -753,7 +751,7 @@
 		 * reporting bugs. Hopefully this doesn't cause more crashes. Stu.
 		 */
 		if (slplink->swboard != NULL)
-			slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink);
+			slplink->swboard->slplink = slplink;
 		else
 			gaim_debug_error("msn", "msn_p2p_msg, swboard is NULL, ouch!\n");
 	}
@@ -773,15 +771,14 @@
 	gc = slpcall->slplink->session->account->gc;
 	who = slpcall->slplink->remote_user;
 
-	if ((conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_ANY, who, gc->account))) {
+	conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_ANY, who, gc->account);
 
-		/* FIXME: it would be better if we wrote the data as we received it
-		          instead of all at once, calling write multiple times and
-		          close once at the very end
-		*/
-		gaim_conv_custom_smiley_write(conv, slpcall->data_info, data, size);
-		gaim_conv_custom_smiley_close(conv, slpcall->data_info);
-	}
+	/* FIXME: it would be better if we wrote the data as we received it
+	          instead of all at once, calling write multiple times and
+	          close once at the very end
+	*/
+	gaim_conv_custom_smiley_write(conv, slpcall->data_info, data, size);
+	gaim_conv_custom_smiley_close(conv, slpcall->data_info );
 #ifdef MSN_DEBUG_UD
 	gaim_debug_info("msn", "Got smiley: %s\n", slpcall->data_info);
 #endif
--- a/libgaim/protocols/msn/slplink.c	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/slplink.c	Sun Apr 15 02:18:17 2007 +0000
@@ -102,7 +102,7 @@
 	g_return_if_fail(slplink != NULL);
 
 	if (slplink->swboard != NULL)
-		slplink->swboard->slplinks = g_list_remove(slplink->swboard->slplinks, slplink);
+		slplink->swboard->slplink = NULL;
 
 	session = slplink->session;
 
@@ -259,7 +259,7 @@
 				return;
 
 			/* If swboard is destroyed we will be too */
-			slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink);
+			slplink->swboard->slplink = slplink;
 		}
 
 		msn_switchboard_send_msg(slplink->swboard, msg, TRUE);
--- a/libgaim/protocols/msn/switchboard.c	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/switchboard.c	Sun Apr 15 02:18:17 2007 +0000
@@ -84,8 +84,8 @@
 	swboard->destroying = TRUE;
 
 	/* If it linked us is because its looking for trouble */
-	while (swboard->slplinks != NULL)
-		msn_slplink_destroy(swboard->slplinks->data);
+	if (swboard->slplink != NULL)
+		msn_slplink_destroy(swboard->slplink);
 
 	/* Destroy the message queue */
 	while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL)
@@ -646,10 +646,6 @@
 	swboard = cmdproc->data;
 	user = cmd->params[0];
 
-	/* cmdproc->data is set to NULL when the switchboard is destroyed;
-	 * we may get a bye shortly thereafter. */
-	g_return_if_fail(swboard != NULL);
-
 	if (!(swboard->flag & MSN_SB_FLAG_IM) && (swboard->conv != NULL))
 		gaim_debug_error("msn_switchboard", "bye_cmd: helper bug\n");
 
--- a/libgaim/protocols/msn/switchboard.h	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/switchboard.h	Sun Apr 15 02:18:17 2007 +0000
@@ -102,7 +102,7 @@
 
 	MsnSBErrorType error; /**< The error that occurred in this switchboard
 							(if applicable). */
-	GList *slplinks; /**< The list of slplinks that are using this switchboard. */
+	MsnSlpLink *slplink; /**< The slplink that is using this switchboard. */
 };
 
 /**
--- a/libgaim/protocols/msn/userlist.c	Sun Apr 15 02:10:37 2007 +0000
+++ b/libgaim/protocols/msn/userlist.c	Sun Apr 15 02:18:17 2007 +0000
@@ -40,23 +40,10 @@
 static void
 msn_accept_add_cb(MsnPermitAdd *pa)
 {
-	if (g_list_find(gaim_connections_get_all(), pa->gc) != NULL)
-	{
-		MsnSession *session = pa->gc->proto_data;
-		MsnUserList *userlist = session->userlist;
-		GaimBuddy *buddy;
-
-		msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_AL, NULL);
+	MsnSession *session = pa->gc->proto_data;
+	MsnUserList *userlist = session->userlist;
 
-		buddy = gaim_find_buddy(pa->gc->account, pa->who);
-
-		if (buddy != NULL)
-			gaim_account_notify_added(pa->gc->account, pa->who,
-				NULL, pa->friendly, NULL);
-		else
-			gaim_account_request_add(pa->gc->account, pa->who,
-				NULL, pa->friendly, NULL);
-	}
+	msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_AL, NULL);
 
 	g_free(pa->who);
 	g_free(pa->friendly);
@@ -83,35 +70,16 @@
 got_new_entry(GaimConnection *gc, const char *passport, const char *friendly)
 {
 	MsnPermitAdd *pa;
-	char *msg;
 
 	pa = g_new0(MsnPermitAdd, 1);
 	pa->who = g_strdup(passport);
 	pa->friendly = g_strdup(friendly);
 	pa->gc = gc;
+	
+	gaim_account_request_authorization(gaim_connection_get_account(gc), passport, NULL, friendly, NULL,
+					   gaim_find_buddy(gaim_connection_get_account(gc), passport) != NULL,
+					   G_CALLBACK(msn_accept_add_cb), G_CALLBACK(msn_cancel_add_cb), pa);
 
-	if (friendly != NULL)
-	{
-		msg = g_strdup_printf(
-				   _("The user %s (%s) wants to add %s to his or her "
-					 "buddy list."),
-				   passport, friendly,
-				   gaim_account_get_username(gc->account));
-	}
-	else
-	{
-		msg = g_strdup_printf(
-				   _("The user %s wants to add %s to his or "
-					 "her buddy list."),
-				   passport, gaim_account_get_username(gc->account));
-	}
-
-	gaim_request_action(gc, NULL, msg, NULL,
-						GAIM_DEFAULT_ACTION_NONE, pa, 2,
-						_("Authorize"), G_CALLBACK(msn_accept_add_cb),
-						_("Deny"), G_CALLBACK(msn_cancel_add_cb));
-
-	g_free(msg);
 }
 
 /**************************************************************************
@@ -188,7 +156,6 @@
 {
 	MsnSession *session;
 	MsnCmdProc *cmdproc;
-	MsnTransaction *trans;
 	MsnMoveBuddy *data;
 
 	session = userlist->session;
@@ -206,9 +173,6 @@
 	/*add new group via SOAP action*/
 	msn_add_group(session, new_group_name);
 
-	msn_transaction_set_data(trans, data);
-
-	msn_cmdproc_send_trans(cmdproc, trans);
 }
 
 /**************************************************************************
@@ -255,22 +219,14 @@
 		if (group_id != NULL)
 		{
 			msn_user_add_group_id(user, group_id);
-		}
-		else
-		{
+		}else{
 			/* session->sync->fl_users_count++; */
 		}
-	}
-	else if (list_id == MSN_LIST_AL)
-	{
+	}else if (list_id == MSN_LIST_AL){
 		gaim_privacy_permit_add(account, passport, TRUE);
-	}
-	else if (list_id == MSN_LIST_BL)
-	{
+	}else if (list_id == MSN_LIST_BL){
 		gaim_privacy_deny_add(account, passport, TRUE);
-	}
-	else if (list_id == MSN_LIST_RL)
-	{
+	}else if (list_id == MSN_LIST_RL){
 		GaimConnection *gc;
 		GaimConversation *convo;
 
@@ -294,8 +250,7 @@
  			g_free(msg);
  		}
  
-		if (!(user->list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP)))
-		{
+		if (!(user->list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP))){
 			/*
 			 * TODO: The friendly name was NULL for me when I
 			 *       looked at this.  Maybe we should use the store
@@ -320,29 +275,19 @@
 
 	passport = msn_user_get_passport(user);
 
-	if (list_id == MSN_LIST_FL)
-	{
+	if (list_id == MSN_LIST_FL){
 		/* TODO: When is the user totally removed? */
-		if (group_id != NULL)
-		{
+		if (group_id != NULL){
 			msn_user_remove_group_id(user, group_id);
 			return;
-		}
-		else
-		{
+		}else{
 			/* session->sync->fl_users_count--; */
 		}
-	}
-	else if (list_id == MSN_LIST_AL)
-	{
+	}else if (list_id == MSN_LIST_AL){
 		gaim_privacy_permit_remove(account, passport, TRUE);
-	}
-	else if (list_id == MSN_LIST_BL)
-	{
+	}else if (list_id == MSN_LIST_BL){
 		gaim_privacy_deny_remove(account, passport, TRUE);
-	}
-	else if (list_id == MSN_LIST_RL)
-	{
+	}else if (list_id == MSN_LIST_RL){
 		GaimConversation *convo;
 
 		gaim_debug_info("msn",
@@ -367,11 +312,9 @@
 	user->list_op &= ~(1 << list_id);
 	/* gaim_user_remove_list_id (user, list_id); */
 
-	if (user->list_op == 0)
-	{
+	if (user->list_op == 0){
 		gaim_debug_info("msn", "Buddy '%s' shall be deleted?.\n",
 						passport);
-
 	}
 }
 
@@ -390,8 +333,7 @@
 	passport = msn_user_get_passport(user);
 	store = msn_user_get_store_name(user);
 
-	if (list_op & MSN_LIST_FL_OP)
-	{
+	if (list_op & MSN_LIST_FL_OP){
 		GSList *c;
 		for (c = group_ids; c != NULL; c = g_slist_next(c))	{
 			char *group_id;
@@ -404,22 +346,19 @@
 		serv_got_alias(gc, passport, store);
 	}
 
-	if (list_op & MSN_LIST_AL_OP)
-	{
+	if (list_op & MSN_LIST_AL_OP){
 		/* These are users who are allowed to see our status. */
 		gaim_privacy_deny_remove(account, passport, TRUE);
 		gaim_privacy_permit_add(account, passport, TRUE);
 	}
 
-	if (list_op & MSN_LIST_BL_OP)
-	{
+	if (list_op & MSN_LIST_BL_OP){
 		/* These are users who are not allowed to see our status. */
 		gaim_privacy_permit_remove(account, passport, TRUE);
 		gaim_privacy_deny_add(account, passport, TRUE);
 	}
 
-	if (list_op & MSN_LIST_RL_OP)
-	{
+	if (list_op & MSN_LIST_RL_OP){
 		/* These are users who have us on their buddy list. */
 		/*
 		 * TODO: What is store name set to when this happens?
@@ -428,8 +367,7 @@
 		 *       should use the friendly name, instead? --KingAnt
 		 */
 
-		if (!(list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP)))
-		{
+		if (!(list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP))){
 //			got_new_entry(gc, passport, store);
 		}
 	}
@@ -465,19 +403,15 @@
 	GList *l;
 
 	/*destroy userlist*/
-	for (l = userlist->users; l != NULL; l = l->next)
-	{
+	for (l = userlist->users; l != NULL; l = l->next){
 		msn_user_destroy(l->data);
 	}
-
 	g_list_free(userlist->users);
 
 	/*destroy group list*/
-	for (l = userlist->groups; l != NULL; l = l->next)
-	{
+	for (l = userlist->groups; l != NULL; l = l->next){
 		msn_group_destroy(l->data);
 	}
-
 	g_list_free(userlist->groups);
 
 	g_queue_free(userlist->buddy_icon_requests);
@@ -488,6 +422,20 @@
 	g_free(userlist);
 }
 
+MsnUser *
+msn_userlist_find_add_user(MsnUserList *userlist,const char *passport,const char *userName)
+{
+	MsnUser *user;
+
+	user = msn_userlist_find_user(userlist, passport);
+	if (user == NULL){
+		user = msn_user_new(userlist, passport, userName);
+		msn_userlist_add_user(userlist, user);
+	}
+	msn_user_set_store_name(user, userName);
+	return user;
+}
+
 void
 msn_userlist_add_user(MsnUserList *userlist, MsnUser *user)
 {
@@ -507,14 +455,15 @@
 
 	g_return_val_if_fail(passport != NULL, NULL);
 
-	for (l = userlist->users; l != NULL; l = l->next)
-	{
+	for (l = userlist->users; l != NULL; l = l->next){
 		MsnUser *user = (MsnUser *)l->data;
-
+//		gaim_debug_info("MsnUserList","user passport:%s,passport:%s\n",user->passport,passport);
 		g_return_val_if_fail(user->passport != NULL, NULL);
 
-		if (!strcmp(passport, user->passport))
+		if (!g_strcasecmp(passport, user->passport)){
+//			gaim_debug_info("MsnUserList","return:%p\n",user);
 			return user;
+		}
 	}
 
 	return NULL;
@@ -540,11 +489,10 @@
 	g_return_val_if_fail(userlist != NULL, NULL);
 	g_return_val_if_fail(id       != NULL, NULL);
 
-	for (l = userlist->groups; l != NULL; l = l->next)
-	{
+	for (l = userlist->groups; l != NULL; l = l->next){
 		MsnGroup *group = l->data;
 
-		if (!g_strcasecmp(group->id, id))
+		if (!g_strcasecmp(group->id,id))
 			return group;
 	}
 
@@ -559,8 +507,7 @@
 	g_return_val_if_fail(userlist != NULL, NULL);
 	g_return_val_if_fail(name     != NULL, NULL);
 
-	for (l = userlist->groups; l != NULL; l = l->next)
-	{
+	for (l = userlist->groups; l != NULL; l = l->next){
 		MsnGroup *group = l->data;
 
 		if ((group->name != NULL) && !g_strcasecmp(name, group->name))
@@ -577,11 +524,9 @@
 
 	group = msn_userlist_find_group_with_name(userlist, group_name);
 
-	if (group != NULL)
+	if (group != NULL){
 		return msn_group_get_id(group);
-	}
-	else
-	{
+	}else{
 		return NULL;
 	}
 }
@@ -593,10 +538,11 @@
 
 	group = msn_userlist_find_group_with_id(userlist, group_id);
 
-	if (group != NULL)
+	if (group != NULL){
 		return msn_group_get_name(group);
-	else
+	}else{
 		return NULL;
+	}
 }
 
 void
@@ -634,7 +580,6 @@
 	const char *list;
 
 	user = msn_userlist_find_user(userlist, who);
-	group_id = -1;
 
 	g_return_if_fail(user != NULL);
 
@@ -654,8 +599,7 @@
 	}
 
 	/* First we're going to check if not there. */
-	if (!(user_is_there(user, list_id, group_id)))
-	{
+	if (!(user_is_there(user, list_id, group_id))){
 		list = lists[list_id];
 		gaim_debug_error("msn", "User '%s' is not there: %s\n",
 						 who, list);
@@ -682,13 +626,11 @@
 	gaim_debug_info("MaYuan", "userlist add buddy,name:{%s},group:{%s}\n",who ,group_name);
 	group_id = NULL;
 
-	if (!gaim_email_is_valid(who))
-	{
+	if (!gaim_email_is_valid(who)){
 		/* only notify the user about problems adding to the friends list
 		 * maybe we should do something else for other lists, but it probably
 		 * won't cause too many problems if we just ignore it */
-		if (list_id == MSN_LIST_FL)
-		{
+		if (list_id == MSN_LIST_FL)	{
 			char *str = g_strdup_printf(_("Unable to add \"%s\"."), who);
 			gaim_notify_error(NULL, NULL, str,
 							  _("The screen name specified is invalid."));
@@ -698,12 +640,10 @@
 		return;
 	}
 
-	if (group_name != NULL)
-	{
+	if (group_name != NULL){
 		group_id = msn_userlist_find_group_id(userlist, group_name);
 
-		if (group_id < 0)
-		{
+		if (group_id == NULL){
 			/* Whoa, we must add that group first. */
 			msn_request_add_group(userlist, who, NULL, group_name);
 			return;
@@ -713,8 +653,7 @@
 	user = msn_userlist_find_user(userlist, who);
 
 	/* First we're going to check if it's already there. */
-	if (user_is_there(user, list_id, group_id))
-	{
+	if (user_is_there(user, list_id, group_id)){
 		list = lists[list_id];
 		gaim_debug_error("msn", "User '%s' is already there: %s\n", who, list);
 		return;
@@ -727,8 +666,10 @@
 
 	gaim_debug_info("MaYuan", "add user:{%s} to group id {%s}\n",store_name ,group_id);
 	msn_add_contact(userlist->session->contact,who,group_id);
+#if 1
 	msn_notification_add_buddy(userlist->session->notification, list, who,
 							   store_name, group_id);
+#endif
 }
 
 void
@@ -739,8 +680,7 @@
 
 	new_group_id = msn_userlist_find_group_id(userlist, new_group_name);
 
-	if (new_group_id == NULL)
-	{
+	if (new_group_id == NULL){
 		msn_request_add_group(userlist, who, old_group_name, new_group_name);
 		return;
 	}
@@ -748,3 +688,47 @@
 	msn_userlist_add_buddy(userlist, who, MSN_LIST_FL, new_group_name);
 	msn_userlist_rem_buddy(userlist, who, MSN_LIST_FL, old_group_name);
 }
+
+/*load userlist from the Blist file cache*/
+void
+msn_userlist_load(MsnSession *session)
+{
+	GaimBlistNode *gnode, *cnode, *bnode;
+	GaimConnection *gc = gaim_account_get_connection(session->account);
+	GSList *l;
+	MsnUser * user;
+
+	g_return_if_fail(gc != NULL);
+
+	for (gnode = gaim_get_blist()->root; gnode; gnode = gnode->next){
+		if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
+			continue;
+		for(cnode = gnode->child; cnode; cnode = cnode->next) {
+			if(!GAIM_BLIST_NODE_IS_CONTACT(cnode))
+				continue;
+			for(bnode = cnode->child; bnode; bnode = bnode->next) {
+				GaimBuddy *b;
+				if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
+					continue;
+				b = (GaimBuddy *)bnode;
+				if(b->account == gc->account){
+					user = msn_userlist_find_add_user(session->userlist,
+						b->name,NULL);
+					msn_user_set_op(user,MSN_LIST_FL_OP);
+				}
+			}
+		}
+	}
+	for (l = session->account->permit; l != NULL; l = l->next) {
+		user = msn_userlist_find_add_user(session->userlist,
+						(char *)l->data,NULL);
+		msn_user_set_op(user,MSN_LIST_AL_OP);
+	}
+	for (l = session->account->deny; l != NULL; l = l->next) {
+		user = msn_userlist_find_add_user(session->userlist,
+						(char *)l->data,NULL);
+		msn_user_set_op(user,MSN_LIST_BL_OP);
+	}
+	
+}
+