changeset 20439:bee467c81570

A bunch of MSNP14 stuff: Don't store the group id on the group blist node. Fix & tidy up payload length detection for commands (errors can have payloads too) Avoid a crash when connecting to a new account with no contact list Tidy up addressbook parsing slightly Fix crashes when buddy list sync issues are detected Fix initial email notifications, Fixes #1293 Plug a few memory leaks Detect OIM authentication failures correctly NOTE: I have disabled dynamic address book retrieval, instead we now receive the whole address book. This is because the blist sync stuff is still very wonky.
author Stu Tomlinson <stu@nosnilmot.com>
date Sun, 27 May 2007 17:00:06 +0000
parents 0d67ac110e2b
children 5ecaa00090d7
files libpurple/protocols/msn/command.c libpurple/protocols/msn/contact.c libpurple/protocols/msn/dialog.c libpurple/protocols/msn/notification.c libpurple/protocols/msn/oim.c libpurple/protocols/msn/session.c libpurple/protocols/msn/state.c libpurple/protocols/msn/switchboard.c libpurple/protocols/msn/userlist.c
diffstat 9 files changed, 284 insertions(+), 183 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/msn/command.c	Sun May 27 11:23:09 2007 +0000
+++ b/libpurple/protocols/msn/command.c	Sun May 27 17:00:06 2007 +0000
@@ -24,10 +24,6 @@
 #include "msn.h"
 #include "command.h"
 
-/*local Function prototype*/
-static int msn_get_payload_position(char *str);
-static int msn_set_payload_len(MsnCommand *cmd);
-
 static gboolean
 is_num(char *str)
 {
@@ -59,51 +55,29 @@
 		(!strcmp(str,"UBM")) ||
 		(!strcmp(str,"FQY")) ||
 		(!strcmp(str,"UUN")) ||
-		(!strcmp(str,"UUX"))){
+		(!strcmp(str,"UUX")) ||
+		(is_num(str))){
 			return TRUE;
 		}
 
 	return FALSE;
 }
 
-/*get the payload positon*/
-static int msn_get_payload_position(char *str)
-{
-	/*because MSG has "MSG hotmail hotmail [payload length]"*/
-	if(!(strcmp(str,"MSG"))|| (!strcmp(str,"UBX")) ){
-		return 2;
-	}
-	/*Yahoo User Message UBM 
-	 * Format UBM email@yahoo.com 32 1 [payload length]*/
-	if(!(strcmp(str,"UBM"))|| (!strcmp(str,"UUM")) ){
-		return 3;
-	}
-
-	return 1;
-}
-
 /*
  * set command Payload length
  */
-static int
+static void
 msn_set_payload_len(MsnCommand *cmd)
 {
-	char * param;
+	char *param;
+	int len = 0;
 
-	if(msn_check_payload_cmd(cmd->command)){
-		param = cmd->params[msn_get_payload_position(cmd->command)];
-#if 0
-		if(!(strcmp(cmd->command,"MSG"))){
-			param = cmd->params[2];
-		}else{
-			param = cmd->params[1];
-		}
-#endif
-		cmd->payload_len = is_num(param) ? atoi(param) : 0;
-	}else{
-		cmd->payload_len = 0;
+	if (msn_check_payload_cmd(cmd->command) && (cmd->param_count > 0)){
+		param = cmd->params[cmd->param_count - 1];
+		len = is_num(param) ? atoi(param) : 0;
 	}
-	return 0;
+
+	cmd->payload_len = len;
 }
 
 MsnCommand *
--- a/libpurple/protocols/msn/contact.c	Sun May 27 11:23:09 2007 +0000
+++ b/libpurple/protocols/msn/contact.c	Sun May 27 17:00:06 2007 +0000
@@ -173,6 +173,10 @@
 	purple_debug_misc("MSNCL","LastChangeNode %s\n",LastChangeStr);
 	
 	memberships =xmlnode_get_child(service,"Memberships");
+	if (memberships == NULL) {
+		xmlnode_free(node);
+		return;
+	}
 	purple_debug_misc("MSNCL","memberships{%p},name:%s\n",memberships,memberships->name);
 	for(membershipnode = xmlnode_get_child(memberships, "Membership"); membershipnode;
 					membershipnode = xmlnode_get_next_twin(membershipnode)){
@@ -244,7 +248,15 @@
 
 	abLastChange = purple_account_get_string(session->account, "ablastChange", NULL);
 	dynamicItemLastChange = purple_account_get_string(session->account, "dynamicItemLastChange", NULL);
+
+#ifdef MSN_PARTIAL_ADDRESSBOOK
+	/* 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, abLastChange, dynamicItemLastChange);
+#else
+	msn_get_address_book(contact, NULL, NULL);
+#endif
 }
 
 static void
@@ -283,45 +295,17 @@
 	g_free(body);
 }
 
-static gboolean
-msn_parse_addressbook(MsnContact * contact)
+static void
+msn_parse_addressbook_groups(MsnContact *contact, xmlnode *node)
 {
-	MsnSession * session;
-	xmlnode * node,*body,*response,*result;
-	xmlnode *groups,*group,*groupname,*groupId,*groupInfo;
-	xmlnode	*contacts,*contactNode,*contactId,*contactInfo,*contactType,*passportName,*displayName,*groupIds,*guid;
-	xmlnode *abNode;
-	char *group_name,*group_id;
-
-	session = contact->session;
-	purple_debug_misc("xml","parse addressbook:{%s}\nsize:%d\n",contact->soapconn->body,contact->soapconn->body_len);
-	node = 	xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len);
+	MsnSession *session = contact->session;
+	xmlnode *group;
 
-	if(node == NULL){
-		purple_debug_misc("xml","parse from str err!\n");
-		return FALSE;
-	}
-	purple_debug_misc("xml","node{%p},name:%s,child:%s,last:%s\n",node,node->name,node->child->name,node->lastchild->name);
-	body = xmlnode_get_child(node,"Body");
-	purple_debug_misc("xml","body{%p},name:%s\n",body,body->name);
-	response = xmlnode_get_child(body,"ABFindAllResponse");
-
-	if (response == NULL) {
-		return FALSE;
-	}
+	for(group = xmlnode_get_child(node, "Group"); group;
+					group = xmlnode_get_next_twin(group)){
+		xmlnode *groupId, *groupInfo, *groupname;
+		char *group_id, *group_name;
 
-	purple_debug_misc("xml","response{%p},name:%s\n",response,response->name);
-	result =xmlnode_get_child(response,"ABFindAllResult");
-	if(result == NULL){
-		purple_debug_misc("MSNAB","receive no address book update\n");
-		return TRUE;
-	}
-	purple_debug_misc("xml","result{%p},name:%s\n",result,result->name);
-
-	/*Process Group List*/
-	groups =xmlnode_get_child(result,"groups");
-	for(group = xmlnode_get_child(groups, "Group"); group;
-					group = xmlnode_get_next_twin(group)){
 		groupId = xmlnode_get_child(group,"groupId");
 		group_id = xmlnode_get_data(groupId);
 		groupInfo = xmlnode_get_child(group,"groupInfo");
@@ -338,45 +322,23 @@
 		purple_debug_misc("MsnAB","group_id:%s name:%s\n",group_id,group_name);
 		if ((purple_find_group(group_name)) == NULL){
 			PurpleGroup *g = purple_group_new(group_name);
-			purple_blist_node_set_string(&(g->node),"groupId",group_id);
 			purple_blist_add_group(g, NULL);
 		}
 		g_free(group_id);
 		g_free(group_name);
 	}
-	/*add a default No group to set up the no group Membership*/
-	group_id = g_strdup(MSN_INDIVIDUALS_GROUP_ID);
-	group_name = g_strdup(MSN_INDIVIDUALS_GROUP_NAME);
-	msn_group_new(session->userlist,group_id , group_name);
-	if (group_id != NULL){
-		purple_debug_misc("MsnAB","group_id:%s name:%s,value:%d\n",group_id,group_name,*group_name=='\0');
-		if ((purple_find_group(group_name)) == NULL){
-			PurpleGroup *g = purple_group_new(group_name);
-			purple_blist_add_group(g, NULL);
-		}
-	}
-	g_free(group_name);
-	g_free(group_id);
+}
 
-	/*add a default No group to set up the no group Membership*/
-	group_id = g_strdup(MSN_NON_IM_GROUP_ID);
-	group_name = g_strdup(MSN_NON_IM_GROUP_NAME);
-	msn_group_new(session->userlist,group_id , group_name);
-	if (group_id != NULL){
-		purple_debug_misc("MsnAB","group_id:%s name:%s,value:%d\n",group_id,group_name,*group_name=='\0');
-		if ((purple_find_group(group_name)) == NULL){
-			PurpleGroup *g = purple_group_new(group_name);
-			purple_blist_add_group(g, NULL);
-		}
-	}
-	g_free(group_name);
-	g_free(group_id);
+static void
+msn_parse_addressbook_contacts(MsnContact *contact, xmlnode *node)
+{
+	MsnSession *session = contact->session;
+	xmlnode *contactNode;
 
-	/*Process contact List*/
-	purple_debug_info("MSNAB","process contact list...\n");
-	contacts =xmlnode_get_child(result,"contacts");
-	for(contactNode = xmlnode_get_child(contacts, "Contact"); contactNode;
+	for(contactNode = xmlnode_get_child(node, "Contact"); contactNode;
 				contactNode = xmlnode_get_next_twin(contactNode)){
+		xmlnode *contactId,*contactInfo,*contactType,*passportName,*displayName,*guid;
+		xmlnode *groupIds;
 		MsnUser *user;
 		char *passport,*Name,*uid,*type;
 
@@ -444,7 +406,7 @@
 		if(displayName == NULL){
 			Name = g_strdup(passport);
 		}else{
-			Name =xmlnode_get_data(displayName);	
+			Name =xmlnode_get_data(displayName);
 		}
 
 		purple_debug_misc("MsnAB","passport:{%s} uid:{%s} display:{%s}\n",
@@ -453,7 +415,6 @@
 		user = msn_userlist_find_add_user(session->userlist, passport,Name);
 		msn_user_set_uid(user,uid);
 		msn_user_set_type(user,msn_get_user_type(type));
-		user->list_op |= MSN_LIST_FL_OP;
 		g_free(Name);
 		g_free(passport);
 		g_free(uid);
@@ -464,6 +425,7 @@
 		if(groupIds){
 			for(guid = xmlnode_get_child(groupIds, "guid");guid;
 							guid = xmlnode_get_next_twin(guid)){
+				char *group_id;
 				group_id = xmlnode_get_data(guid);
 				msn_user_add_group_id(user,group_id);
 				purple_debug_misc("MsnAB","guid:%s\n",group_id);
@@ -471,10 +433,76 @@
 			}
 		}else{
 			/*not in any group,Then set default group*/
-			group_id = g_strdup(MSN_INDIVIDUALS_GROUP_ID);
-			msn_user_add_group_id(user,group_id);
-			g_free(group_id);
+			msn_user_add_group_id(user, MSN_INDIVIDUALS_GROUP_ID);
 		}
+
+		msn_got_lst_user(session, user, MSN_LIST_FL_OP, NULL);
+	}
+}
+
+static gboolean
+msn_parse_addressbook(MsnContact * contact)
+{
+	MsnSession * session;
+	xmlnode * node,*body,*response,*result;
+	xmlnode *groups;
+	xmlnode	*contacts;
+	xmlnode *abNode;
+
+	session = contact->session;
+	purple_debug_misc("xml","parse addressbook:{%s}\nsize:%d\n",contact->soapconn->body,contact->soapconn->body_len);
+	node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len);
+
+	if(node == NULL){
+		purple_debug_misc("xml","parse from str err!\n");
+		return FALSE;
+	}
+	purple_debug_misc("xml","node{%p},name:%s,child:%s,last:%s\n",node,node->name,node->child->name,node->lastchild->name);
+	body = xmlnode_get_child(node,"Body");
+	purple_debug_misc("xml","body{%p},name:%s\n",body,body->name);
+	response = xmlnode_get_child(body,"ABFindAllResponse");
+
+	if (response == NULL) {
+		return FALSE;
+	}
+
+	purple_debug_misc("xml","response{%p},name:%s\n",response,response->name);
+	result =xmlnode_get_child(response,"ABFindAllResult");
+	if(result == NULL){
+		purple_debug_misc("MSNAB","receive no address book update\n");
+		return TRUE;
+	}
+	purple_debug_misc("xml","result{%p},name:%s\n",result,result->name);
+
+	/*Process Group List*/
+	groups = xmlnode_get_child(result,"groups");
+	if (groups != NULL) {
+		msn_parse_addressbook_groups(contact, groups);
+	}
+
+	/*add a default No group to set up the no group Membership*/
+	msn_group_new(session->userlist, MSN_INDIVIDUALS_GROUP_ID,
+				  MSN_INDIVIDUALS_GROUP_NAME);
+	purple_debug_misc("MsnAB","group_id:%s name:%s\n",
+					  MSN_INDIVIDUALS_GROUP_ID, MSN_INDIVIDUALS_GROUP_NAME);
+	if ((purple_find_group(MSN_INDIVIDUALS_GROUP_NAME)) == NULL){
+		PurpleGroup *g = purple_group_new(MSN_INDIVIDUALS_GROUP_NAME);
+		purple_blist_add_group(g, NULL);
+	}
+
+	/*add a default No group to set up the no group Membership*/
+	msn_group_new(session->userlist, MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME);
+	purple_debug_misc("MsnAB","group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME);
+	if ((purple_find_group(MSN_NON_IM_GROUP_NAME)) == NULL){
+		PurpleGroup *g = purple_group_new(MSN_NON_IM_GROUP_NAME);
+		purple_blist_add_group(g, NULL);
+	}
+
+	/*Process contact List*/
+	purple_debug_info("MSNAB","process contact list...\n");
+	contacts =xmlnode_get_child(result,"contacts");
+	if (contacts != NULL) {
+		msn_parse_addressbook_contacts(contact, contacts);
 	}
 
 	abNode =xmlnode_get_child(result,"ab");
--- a/libpurple/protocols/msn/dialog.c	Sun May 27 11:23:09 2007 +0000
+++ b/libpurple/protocols/msn/dialog.c	Sun May 27 17:00:06 2007 +0000
@@ -34,9 +34,36 @@
 
 } 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. */
+/* Actually with our MSNP14 code that isn't true yet, he won't be added back :( */
+static void
+msn_complete_sync_issue(MsnAddRemData *data)
+{
+	PurpleBuddy *buddy;
+	PurpleGroup *group = NULL;
+
+	if (data->group != NULL)
+		group = purple_find_group(data->group);
+
+	if (group != NULL)
+		buddy = purple_find_buddy_in_group(purple_connection_get_account(data->gc), data->who, group);
+	else
+		buddy = purple_find_buddy(purple_connection_get_account(data->gc), data->who);
+
+	if (buddy != NULL)
+		purple_blist_remove_buddy(buddy);
+}
+
+
 static void
 msn_add_cb(MsnAddRemData *data)
 {
+#if 0
+	/* this *should* be necessary !! */
+	msn_complete_sync_issue(data);
+#endif
+
 	if (g_list_find(purple_connections_get_all(), data->gc) != NULL)
 	{
 		MsnSession *session = data->gc->proto_data;
@@ -53,6 +80,8 @@
 static void
 msn_rem_cb(MsnAddRemData *data)
 {
+	msn_complete_sync_issue(data);
+
 	if (g_list_find(purple_connections_get_all(), data->gc) != NULL)
 	{
 		MsnSession *session = data->gc->proto_data;
@@ -74,8 +103,6 @@
 	PurpleAccount *account;
 	MsnAddRemData *data;
 	char *msg, *reason;
-	PurpleBuddy *buddy;
-	PurpleGroup *group = NULL;
 
 	account = session->account;
 	gc = purple_account_get_connection(account);
@@ -111,17 +138,6 @@
 						_("Yes"), G_CALLBACK(msn_add_cb),
 						_("No"), G_CALLBACK(msn_rem_cb));
 
-	if (group_name != NULL)
-		group = purple_find_group(group_name);
-
-	if (group != NULL)
-		buddy = purple_find_buddy_in_group(account, passport, group);
-	else
-		buddy = purple_find_buddy(account, passport);
-
-	if (buddy != NULL)
-		purple_blist_remove_buddy(buddy);
-
 	g_free(reason);
 	g_free(msg);
 }
--- a/libpurple/protocols/msn/notification.c	Sun May 27 11:23:09 2007 +0000
+++ b/libpurple/protocols/msn/notification.c	Sun May 27 17:00:06 2007 +0000
@@ -599,7 +599,8 @@
 	domain = tokens[1];
 
 	/*find a domain Node*/
-	for(d_node = xmlnode_get_child(mlNode,"d"); d_node; d_node = xmlnode_get_next_twin(d_node)){
+	for(d_node = xmlnode_get_child(mlNode,"d"); d_node; d_node = xmlnode_get_next_twin(d_node))
+	{
 		const char * attr = NULL;
 		purple_debug_info("MaYuan","d_node:%s\n",d_node->name);
 		attr = xmlnode_get_attrib(d_node,"n");
@@ -610,7 +611,8 @@
 			break;
 		}
 	}
-	if(d_node == NULL){
+	if(d_node == NULL)
+	{
 		/*domain not found, create a new domain Node*/
 		purple_debug_info("MaYuan","get No d_node\n");
 		d_node = xmlnode_new("d");
@@ -623,7 +625,7 @@
 	xmlnode_set_attrib(c_node,"n",email);
 
 	list_op_str = g_strdup_printf("%d",list_op);
-	purple_debug_info("MaYuan","list_op:%d\n",list_op_str);
+	purple_debug_info("MaYuan","list_op:%d\n",list_op);
 	xmlnode_set_attrib(c_node,"l",list_op_str);
 	g_free(list_op_str);
 #if 0
@@ -643,7 +645,7 @@
 #endif
 	xmlnode_insert_child(d_node, c_node);
 
-	g_free(tokens);
+	g_strfreev(tokens);
 }
 
 static void
@@ -743,6 +745,24 @@
 }
 
 static void
+adl_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
+{
+	MsnSession *session;
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	char *reason = NULL;
+
+	session = cmdproc->session;
+	account = session->account;
+	gc = purple_account_get_connection(account);
+
+	purple_debug_error("msn","ADL error\n");
+	reason = g_strdup_printf(_("Unknown error (%d)"), error);
+	purple_notify_error(gc, NULL, _("Unable to add user"), reason);
+	g_free(reason);
+}
+
+static void
 fqy_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
 			 size_t len)
 {
@@ -1582,12 +1602,17 @@
 		session->passport_info.sl = atol(value);
 
 	/*starting retrieve the contact list*/
+#ifdef MSN_PARTIAL_ADDRESSBOOK
 	msn_userlist_load(session);
-	
+#endif
 	session->contact = msn_contact_new(session);
 	clLastChange = purple_account_get_string(session->account, "CLLastChange", NULL);
 	msn_get_contact_list(session->contact, clLastChange);
-//	msn_contact_connect(session->contact);
+#if 0
+	/* always get the full list? */
+	msn_get_contact_list(session->contact, NULL);
+	msn_contact_connect(session->contact);
+#endif
 }
 
 static void
@@ -1648,58 +1673,72 @@
 initial_mdata_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
 {
 	MsnSession *session;
-	char **elems, **cur, **tokens;
-
-//	purple_debug_info("MaYuan","mdata...{%s} \n",msg->body);
+	PurpleConnection *gc;
+	GHashTable *table;
+	const char *mdata, *unread;
 
-//	/*time debug*/
-	{
-	const char *timestr;
-	time_t t;
-	struct tm *tm;
-	char datestr[]="2006-07-15T07:21:26+0700";
-	GDate *date;
-	time(&t);
-	tm = gmtime(&t);
-	timestr = purple_utf8_strftime("%a, %d %b %Y %T %Z", tm);
-//	strftime(datestr,strlen(datestr),"%a",tm);
-	date = g_date_new();
-	g_date_set_parse(date,datestr);
-	purple_debug_info("MaYuan","date is NULL?date valid%d\n",g_date_valid(date));
-	g_date_free(date);
-	purple_debug_info("MaYuan","utf8 time:{%s}\n",timestr);
-	}
+	session = cmdproc->session;
+	gc = session->account->gc;
+
+	if (strcmp(msg->remote_user, "Hotmail"))
+		/* This isn't an official message. */
+		return;
 
 	/*new a oim session*/
-	session = cmdproc->session;
 	session->oim = msn_oim_new(session);
 //	msn_oim_connect(session->oim);
 
-	/*parse offline message data*/
-	elems = g_strsplit(msg->body, "\r\n", 0);
-	for (cur = elems; *cur != NULL; cur++){
-		const char *key, *value;
+	table = msn_message_get_hashtable_from_body(msg);
 
-//		purple_debug_info("MaYuan","cur:{%s}\n",*cur);
-		tokens = g_strsplit(*cur, ": ", 2);
+	mdata = g_hash_table_lookup(table, "Mail-Data");
+
+	if (mdata != NULL)
+		msn_parse_oim_msg(session->oim, mdata);
 
-		key = tokens[0];
-		value = tokens[1];
+	if (g_hash_table_lookup(table, "Inbox-URL") == NULL)
+	{
+		g_hash_table_destroy(table);
+		return;
+	}
 
-		/*if not MIME content ,then return*/
-		if ((key != NULL) && (!strcmp(key, "Mail-Data")) ){
-//			purple_debug_info("MaYuan","data:{%s}\n",value);
-			msn_parse_oim_msg(session->oim,value);
-			g_strfreev(tokens);
-			break;
-		}
+	if (session->passport_info.file == NULL)
+	{
+		MsnTransaction *trans;
+		trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX");
+		msn_transaction_queue_cmd(trans, msg->cmd);
 
-		g_strfreev(tokens);
+		msn_cmdproc_send_trans(cmdproc, trans);
+
+		g_hash_table_destroy(table);
+		return;
 	}
 
-	g_strfreev(elems);
-/* test code for add group*/
-//	msn_add_group(session,"hello");
+	if (!purple_account_get_check_mail(session->account))
+	{
+		g_hash_table_destroy(table);
+		return;
+	}
+
+	unread = g_hash_table_lookup(table, "Inbox-Unread");
+
+	if (unread != NULL)
+	{
+		int count = atoi(unread);
+
+		if (count > 0)
+		{
+			const char *passport;
+			const char *url;
+
+			passport = msn_user_get_passport(session->user);
+			url = session->passport_info.file;
+
+			purple_notify_emails(gc, atoi(unread), FALSE, NULL, NULL,
+							   &passport, &url, NULL, NULL);
+		}
+	}
+
+	g_hash_table_destroy(table);
 }
 
 /*offline Message Notification*/
@@ -1923,6 +1962,7 @@
 	msn_table_add_cmd(cbs_table, "fallback", "XFR", xfr_cmd);
 
 	msn_table_add_error(cbs_table, "ADD", add_error);
+	msn_table_add_error(cbs_table, "ADL", adl_error);
 	msn_table_add_error(cbs_table, "REG", reg_error);
 	msn_table_add_error(cbs_table, "RMG", rmg_error);
 	/* msn_table_add_error(cbs_table, "REA", rea_error); */
--- a/libpurple/protocols/msn/oim.c	Sun May 27 11:23:09 2007 +0000
+++ b/libpurple/protocols/msn/oim.c	Sun May 27 17:00:06 2007 +0000
@@ -195,7 +195,7 @@
 	faultCodeStr = xmlnode_get_data(faultCodeNode);
 	purple_debug_info("MaYuan","fault code:{%s}\n",faultCodeStr);
 
-	if(strcmp(faultCodeStr,"q0:AuthenticationFailed")){
+	if(!strcmp(faultCodeStr,"q0:AuthenticationFailed")){
 		/*other Fault Reason?*/
 		goto oim_send_process_fail;
 	}
@@ -209,9 +209,12 @@
 	 */
 	detailNode = xmlnode_get_child(faultNode, "detail");
 	if(detailNode == NULL){
-			goto oim_send_process_fail;
+		goto oim_send_process_fail;
 	}
 	challengeNode = xmlnode_get_child(detailNode,"LockKeyChallenge");
+	if (challengeNode == NULL) {
+		goto oim_send_process_fail;
+	}
 
 	g_free(oim->challenge);
 	oim->challenge = xmlnode_get_data(challengeNode);
@@ -520,10 +523,38 @@
 void
 msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg)
 {
-	xmlnode *mdNode,*mNode,*ENode,*INode,*rtNode,*nNode;
-	char *passport,*msgid,*nickname, *rTime = NULL;
+	xmlnode *node, *mdNode,*mNode,*ENode,*INode,*rtNode,*nNode;
+	char *passport,*msgid,*nickname, *unread, *rTime = NULL;
+
+	node = xmlnode_from_str(xmlmsg, strlen(xmlmsg));
+
+	ENode = xmlnode_get_child(node, "E");
+	INode = xmlnode_get_child(ENode, "IU");
+	unread = xmlnode_get_data(INode);
+
+	if (unread != NULL)
+	{
+		int count = atoi(unread);
 
-	mdNode = xmlnode_from_str(xmlmsg, strlen(xmlmsg));
+		if (count > 0)
+		{
+			MsnSession *session = oim->session;
+			const char *passport;
+			const char *url;
+
+			passport = msn_user_get_passport(session->user);
+			url = session->passport_info.file;
+
+			purple_notify_emails(session->account->gc, atoi(unread), FALSE, NULL, NULL,
+					&passport, &url, NULL, NULL);
+		}
+	}
+
+	mdNode = xmlnode_get_child(node, "MD");
+	if (mdNode == NULL) {
+		xmlnode_free(node);
+		return;
+	}
 	for(mNode = xmlnode_get_child(mdNode, "M"); mNode;
 					mNode = xmlnode_get_next_twin(mNode)){
 		/*email Node*/
@@ -537,17 +568,21 @@
 		nickname = xmlnode_get_data(nNode);
 		/*receive time*/
 		rtNode = xmlnode_get_child(mNode,"RT");
-		if(rtNode != NULL)
+		if(rtNode != NULL) {
 			rTime = xmlnode_get_data(rtNode);
-/*		purple_debug_info("MaYuan","E:{%s},I:{%s},rTime:{%s}\n",passport,msgid,rTime);*/
+			rtNode = NULL;
+		}
+/*		purple_debug_info("MaYuan","E:{%s},I:{%s},rTime:{%s}\n",passport,msgid,rTime); */
 
 		oim->oim_list = g_list_append(oim->oim_list,msgid);
 		msn_oim_post_single_get_msg(oim,msgid);
 		g_free(passport);
-//		g_free(msgid);
+		g_free(msgid);
 		g_free(rTime);
+		rTime = NULL;
 		g_free(nickname);
 	}
+	xmlnode_free(node);
 }
 
 /*Post to get the Offline Instant Message*/
--- a/libpurple/protocols/msn/session.c	Sun May 27 11:23:09 2007 +0000
+++ b/libpurple/protocols/msn/session.c	Sun May 27 17:00:06 2007 +0000
@@ -273,9 +273,10 @@
 	 */
 	for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {
 		PurpleGroup *group = (PurpleGroup *)gnode;
-		const char *group_name = group->name;
+		const char *group_name;
 		if(!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
+		group_name = group->name;
 		if(!g_strcasecmp(group_name, MSN_INDIVIDUALS_GROUP_NAME)
 						||	!g_strcasecmp(group_name,MSN_NON_IM_GROUP_NAME)){
 			continue;
@@ -322,7 +323,7 @@
 					{
 						/* 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);
+						msn_show_sync_issue(session, purple_buddy_get_name(b), group_name);
 					}
 				}
 			}
--- a/libpurple/protocols/msn/state.c	Sun May 27 11:23:09 2007 +0000
+++ b/libpurple/protocols/msn/state.c	Sun May 27 17:00:06 2007 +0000
@@ -89,12 +89,13 @@
 	char *buffer=NULL, *inptr, *outptr, *tmpptr;
 	int length, strings, tmp;
 
-	purple_debug_info("msn", "Parsing currentmedia string: \"%s\"\n", cmedia);
-	if( (cmedia == NULL) || (!strcmp(cmedia, ""))) {
+	if((cmedia == NULL) || (*cmedia == '\0')) {
 		purple_debug_info("msn", "No currentmedia string\n");
 		return NULL;
 	}
 
+	purple_debug_info("msn", "Parsing currentmedia string: \"%s\"\n", cmedia);
+
 	cmedia_array=g_strsplit(cmedia, "\\0", 0);
 
 	strings=1;	/* Skip first empty string */
@@ -231,7 +232,7 @@
 	presence = purple_account_get_presence(account);
 	status = purple_presence_get_active_status(presence);
 	statusline = purple_status_get_attr_string(status, "message");
-	session ->psm = msn_build_psm(statusline, NULL, NULL);
+	session->psm = msn_build_psm(statusline, NULL, NULL);
 	payload = session->psm;
 
 	purple_debug_info("MaYuan","UUX{%s}\n",payload);
--- a/libpurple/protocols/msn/switchboard.c	Sun May 27 11:23:09 2007 +0000
+++ b/libpurple/protocols/msn/switchboard.c	Sun May 27 17:00:06 2007 +0000
@@ -29,8 +29,6 @@
 
 #include "error.h"
 
-#define MSN_DEBUG_SB
-
 static MsnTable *cbs_table;
 
 static void msg_error_helper(MsnCmdProc *cmdproc, MsnMessage *msg,
--- a/libpurple/protocols/msn/userlist.c	Sun May 27 11:23:09 2007 +0000
+++ b/libpurple/protocols/msn/userlist.c	Sun May 27 17:00:06 2007 +0000
@@ -689,7 +689,11 @@
 		}
 	}
 
-	user = msn_userlist_find_user(userlist, who);
+	/* XXX: using _add_user here may not be correct (should add them in the
+	   ACK to the ADL command, and we might also want to make sure the user's groups
+	   are correct. but for now we need to make sure they exist early enough that
+	   the ILN command doesn't screw us up */
+	user = msn_userlist_find_add_user(userlist, who, who);
 
 	/* First we're going to check if it's already there. */
 	if (user_is_there(user, list_id, group_id))
@@ -701,6 +705,10 @@
 
 	store_name = (user != NULL) ? get_store_name(user) : who;
 
+	/* XXX: see XXX above, this should really be done when we get the response from
+	   the server */
+	msn_user_set_op(user, list_id);
+
 	/* Then request the add to the server. */
 	list = lists[list_id];