diff libpurple/protocols/msn/notification.c @ 20394:4a099e4d0d09

propagate from branch 'im.pidgin.pidgin' (head 98b6b547b29ea1192b73cc4e1de1e674edef4328) to branch 'im.pidgin.rlaager.merging.msnp13-and-pidgin' (head 4d82c29e56bd33cd6f94302e343dfeb5d68ab3eb)
author Richard Laager <rlaager@wiktel.com>
date Sun, 15 Apr 2007 03:43:17 +0000
parents fa8aeab4ca5a
children 6f986caeab59
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/msn/notification.c	Sun Apr 15 03:43:17 2007 +0000
@@ -0,0 +1,1922 @@
+/**
+ * @file notification.c Notification server functions
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "msn.h"
+#include "notification.h"
+#include "state.h"
+#include "error.h"
+#include "msnutils.h"
+#include "page.h"
+
+#include "userlist.h"
+#include "sync.h"
+#include "slplink.h"
+
+static MsnTable *cbs_table;
+
+/****************************************************************************
+ * 	Local Function Prototype
+ ****************************************************************************/
+
+static void msn_notification_fqy_yahoo(MsnSession *session, const char *passport);
+static void msn_notification_post_adl(MsnCmdProc *cmdproc, char *payload, int payload_len);
+static void msn_add_contact_xml(xmlnode *mlNode, const char *passport, int list_op, int type);
+
+/**************************************************************************
+ * Main
+ **************************************************************************/
+
+static void
+destroy_cb(MsnServConn *servconn)
+{
+	MsnNotification *notification;
+
+	notification = servconn->cmdproc->data;
+	g_return_if_fail(notification != NULL);
+
+	msn_notification_destroy(notification);
+}
+
+MsnNotification *
+msn_notification_new(MsnSession *session)
+{
+	MsnNotification *notification;
+	MsnServConn *servconn;
+
+	g_return_val_if_fail(session != NULL, NULL);
+
+	notification = g_new0(MsnNotification, 1);
+
+	notification->session = session;
+	notification->servconn = servconn = msn_servconn_new(session, MSN_SERVCONN_NS);
+	msn_servconn_set_destroy_cb(servconn, destroy_cb);
+
+	notification->cmdproc = servconn->cmdproc;
+	notification->cmdproc->data = notification;
+	notification->cmdproc->cbs_table = cbs_table;
+
+	return notification;
+}
+
+void
+msn_notification_destroy(MsnNotification *notification)
+{
+	notification->cmdproc->data = NULL;
+
+	msn_servconn_set_destroy_cb(notification->servconn, NULL);
+
+	msn_servconn_destroy(notification->servconn);
+
+	g_free(notification);
+}
+
+/**************************************************************************
+ * Connect
+ **************************************************************************/
+
+static void
+connect_cb(MsnServConn *servconn)
+{
+	MsnCmdProc *cmdproc;
+	MsnSession *session;
+	PurpleAccount *account;
+	char **a, **c, *vers;
+	int i;
+
+	g_return_if_fail(servconn != NULL);
+
+	cmdproc = servconn->cmdproc;
+	session = servconn->session;
+	account = session->account;
+
+	/* Allocate an array for CVR0, NULL, and all the versions */
+//	a = c = g_new0(char *, session->protocol_ver - WLM_MIN_PROTOCOL + 3);
+	a = c = g_new0(char *, WLM_MAX_PROTOCOL - WLM_MIN_PROTOCOL + 3);
+
+//	for (i = session->protocol_ver; i >= WLM_MIN_PROTOCOL; i--)
+	for (i = WLM_MAX_PROTOCOL; i >= WLM_MIN_PROTOCOL; i--)
+		*c++ = g_strdup_printf("MSNP%d", i);
+
+	*c++ = g_strdup("CVR0");
+
+	vers = g_strjoinv(" ", a);
+
+	if (session->login_step == MSN_LOGIN_STEP_START){
+		msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE);
+	}else{
+		msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE2);
+	}
+
+	msn_cmdproc_send(cmdproc, "VER", "%s", vers);
+
+	g_strfreev(a);
+	g_free(vers);
+}
+
+gboolean
+msn_notification_connect(MsnNotification *notification, const char *host, int port)
+{
+	MsnServConn *servconn;
+
+	g_return_val_if_fail(notification != NULL, FALSE);
+
+	servconn = notification->servconn;
+
+	msn_servconn_set_connect_cb(servconn, connect_cb);
+	notification->in_use = msn_servconn_connect(servconn, host, port);
+
+	return notification->in_use;
+}
+
+void
+msn_notification_disconnect(MsnNotification *notification)
+{
+	g_return_if_fail(notification != NULL);
+	g_return_if_fail(notification->in_use);
+
+	msn_servconn_disconnect(notification->servconn);
+
+	notification->in_use = FALSE;
+}
+
+/**************************************************************************
+ * Util
+ **************************************************************************/
+
+static void
+group_error_helper(MsnSession *session, const char *msg, const char *group_id, int error)
+{
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	char *reason = NULL;
+	char *title = NULL;
+
+	account = session->account;
+	gc = purple_account_get_connection(account);
+
+	if (error == 224){
+		if (group_id == 0){
+			return;
+		}else{
+			const char *group_name;
+			group_name = msn_userlist_find_group_name(session->userlist,group_id);
+			reason = g_strdup_printf(_("%s is not a valid group."),
+									 group_name);
+		}
+	}else{
+		reason = g_strdup(_("Unknown error."));
+	}
+
+	title = g_strdup_printf(_("%s on %s (%s)"), msg,
+						  purple_account_get_username(account),
+						  purple_account_get_protocol_name(account));
+	purple_notify_error(gc, NULL, title, reason);
+	g_free(title);
+	g_free(reason);
+}
+
+/**************************************************************************
+ * Login
+ **************************************************************************/
+
+void
+msn_got_login_params(MsnSession *session, const char *login_params)
+{
+	MsnCmdProc *cmdproc;
+
+	cmdproc = session->notification->cmdproc;
+
+	msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_END);
+
+	msn_cmdproc_send(cmdproc, "USR", "TWN S %s", login_params);
+}
+
+static void
+cvr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	PurpleAccount *account;
+
+	account = cmdproc->session->account;
+	msn_cmdproc_send(cmdproc, "USR", "TWN I %s",
+					 purple_account_get_username(account));
+}
+
+static void
+usr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSession *session;
+	PurpleAccount *account;
+	PurpleConnection *gc;
+
+	session = cmdproc->session;
+	account = session->account;
+	gc = purple_account_get_connection(account);
+
+	if (!g_ascii_strcasecmp(cmd->params[1], "OK")){
+		/* authenticate OK */
+		/* friendly name part no longer true in msnp11 */
+#if 0
+		const char *friendly = purple_url_decode(cmd->params[3]);
+
+		purple_connection_set_display_name(gc, friendly);
+#endif
+		msn_session_set_login_step(session, MSN_LOGIN_STEP_SYN);
+
+//		msn_cmdproc_send(cmdproc, "SYN", "%s", "0");
+		//TODO we should use SOAP contact to fetch contact list
+	} else if (!g_ascii_strcasecmp(cmd->params[1], "TWN")){
+		/* Passport authentication */
+		char **elems, **cur, **tokens;
+
+		session->nexus = msn_nexus_new(session);
+
+		/* Parse the challenge data. */
+		session->nexus->challenge_data_str = g_strdup(cmd->params[3]);
+		elems = g_strsplit(cmd->params[3], ",", 0);
+
+		for (cur = elems; *cur != NULL; cur++){
+			tokens = g_strsplit(*cur, "=", 2);
+			if(tokens[0]&&tokens[1]){
+				purple_debug_info("MaYuan","challenge %p,key:%s,value:%s\n",
+									session->nexus->challenge_data,tokens[0],tokens[1]);
+				g_hash_table_insert(session->nexus->challenge_data, tokens[0], tokens[1]);
+			}
+			/* Don't free each of the tokens, only the array. */
+			g_free(tokens);
+		}
+
+		g_strfreev(elems);
+
+		msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_START);
+
+		msn_nexus_connect(session->nexus);
+	}
+}
+
+static void
+usr_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
+{
+	MsnErrorType msnerr = 0;
+
+	switch (error)
+	{
+		case 500:
+		case 601:
+		case 910:
+		case 921:
+			msnerr = MSN_ERROR_SERV_UNAVAILABLE;
+			break;
+		case 911:
+			msnerr = MSN_ERROR_AUTH;
+			break;
+		default:
+			return;
+			break;
+	}
+
+	msn_session_set_error(cmdproc->session, msnerr, NULL);
+}
+
+static void
+ver_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSession *session;
+	PurpleAccount *account;
+	gboolean protocol_supported = FALSE;
+	char proto_str[8];
+	size_t i;
+
+	session = cmdproc->session;
+	account = session->account;
+
+	g_snprintf(proto_str, sizeof(proto_str), "MSNP%d", session->protocol_ver);
+
+	for (i = 1; i < cmd->param_count; i++)
+	{
+		if (!strcmp(cmd->params[i], proto_str))
+		{
+			protocol_supported = TRUE;
+			break;
+		}
+	}
+
+	if (!protocol_supported)
+	{
+		msn_session_set_error(session, MSN_ERROR_UNSUPPORTED_PROTOCOL,
+							  NULL);
+		return;
+	}
+
+	/*
+	 * Windows Live Messenger 8.0 
+	 * Notice :CVR String discriminate!
+	 * reference of http://www.microsoft.com/globaldev/reference/oslocversion.mspx
+	 * to see the Local ID
+	 */
+	msn_cmdproc_send(cmdproc, "CVR",
+//					 "0x0409 winnt 5.1 i386 MSG80BETA 8.0.0689 msmsgs %s",
+					"0x0804 winnt 5.1 i386 MSNMSGR 8.0.0792 msmsgs %s",
+					 purple_account_get_username(account));
+}
+
+/**************************************************************************
+ * Log out
+ **************************************************************************/
+
+static void
+out_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	if (!g_ascii_strcasecmp(cmd->params[0], "OTH"))
+		msn_session_set_error(cmdproc->session, MSN_ERROR_SIGN_OTHER,
+							  NULL);
+	else if (!g_ascii_strcasecmp(cmd->params[0], "SSD"))
+		msn_session_set_error(cmdproc->session, MSN_ERROR_SERV_DOWN, NULL);
+}
+
+void
+msn_notification_close(MsnNotification *notification)
+{
+	g_return_if_fail(notification != NULL);
+
+	if (!notification->in_use)
+		return;
+
+	msn_cmdproc_send_quick(notification->cmdproc, "OUT", NULL, NULL);
+
+	msn_notification_disconnect(notification);
+}
+
+/**************************************************************************
+ * Messages
+ **************************************************************************/
+
+static void
+msg_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+			 size_t len)
+{
+	MsnMessage *msg;
+
+	msg = msn_message_new_from_cmd(cmdproc->session, cmd);
+
+	msn_message_parse_payload(msg, payload, len,MSG_LINE_DEM,MSG_BODY_DEM);
+#ifdef MSN_DEBUG_NS
+	msn_message_show_readable(msg, "Notification", TRUE);
+#endif
+
+	msn_cmdproc_process_msg(cmdproc, msg);
+
+	msn_message_destroy(msg);
+}
+
+static void
+msg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_info("MaYuan","Processing MSG... \n");
+	if(cmd->payload_len == 0){
+		return;
+	}
+	/* NOTE: cmd is not always cmdproc->last_cmd, sometimes cmd is a queued
+	 * command and we are processing it */
+	if (cmd->payload == NULL)
+	{
+		cmdproc->last_cmd->payload_cb  = msg_cmd_post;
+		cmdproc->servconn->payload_len = atoi(cmd->params[2]);
+	}
+	else
+	{
+		g_return_if_fail(cmd->payload_cb != NULL);
+
+		purple_debug_info("MaYuan","MSG payload:{%s}\n",cmd->payload);
+		cmd->payload_cb(cmdproc, cmd, cmd->payload, cmd->payload_len);
+	}
+}
+
+/*send Message to Yahoo Messenger*/
+void
+uum_send_msg(MsnSession *session,MsnMessage *msg)
+{
+	MsnCmdProc *cmdproc;
+	MsnTransaction *trans;
+	char *payload;
+	gsize payload_len;
+	int type;
+	
+	cmdproc = session->notification->cmdproc;
+	g_return_if_fail(msg     != NULL);
+	payload = msn_message_gen_payload(msg, &payload_len);
+	purple_debug_info("MaYuan","send UUM,payload{%s},strlen:%d,len:%d\n",
+		payload,strlen(payload),payload_len);
+	type = msg->type;
+	trans = msn_transaction_new(cmdproc, "UUM","%s 32 %d %d",msg->remote_user,type,payload_len);
+	msn_transaction_set_payload(trans, payload, strlen(payload));
+	msn_cmdproc_send_trans(cmdproc, trans);
+}
+
+static void
+ubm_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+			 size_t len)
+{
+	MsnMessage *msg;
+	PurpleConnection *gc;
+	const char *passport;
+	const char *content_type;
+
+	purple_debug_info("MaYuan","Process UBM payload:%s\n",payload);
+	msg = msn_message_new_from_cmd(cmdproc->session, cmd);
+
+	msn_message_parse_payload(msg, payload, len,MSG_LINE_DEM,MSG_BODY_DEM);
+#ifdef MSN_DEBUG_NS
+	msn_message_show_readable(msg, "Notification", TRUE);
+#endif
+
+	gc = cmdproc->session->account->gc;
+	passport = msg->remote_user;
+
+	content_type = msn_message_get_content_type(msg);
+	purple_debug_info("MaYuan","type:%d\n",content_type);
+	if(!strcmp(content_type,"text/plain")){
+		const char *value;
+		const char *body;
+		char *body_str;
+		char *body_enc;
+		char *body_final = NULL;
+		size_t body_len;
+
+		body = msn_message_get_bin_data(msg, &body_len);
+		body_str = g_strndup(body, body_len);
+		body_enc = g_markup_escape_text(body_str, -1);
+		g_free(body_str);
+
+		if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL)	{
+			char *pre, *post;
+
+			msn_parse_format(value, &pre, &post);
+			body_final = g_strdup_printf("%s%s%s", pre ? pre : "",
+							body_enc ? body_enc : "", post ? post : "");
+			g_free(pre);
+			g_free(post);
+			g_free(body_enc);
+		}
+		serv_got_im(gc, passport, body_final, 0, time(NULL));
+	}
+	if(!strcmp(content_type,"text/x-msmsgscontrol")){
+		if(msn_message_get_attr(msg, "TypingUser") != NULL){
+			serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT,
+						PURPLE_TYPING);
+		}
+	}
+	if(!strcmp(content_type,"text/x-msnmsgr-datacast")){
+		char *username, *str;
+		PurpleAccount *account;
+		PurpleBuddy *buddy;
+		const char *user;
+
+		account = cmdproc->session->account;
+		user = msg->remote_user;
+
+		if ((buddy = purple_find_buddy(account, user)) != NULL){
+			username = g_markup_escape_text(purple_buddy_get_alias(buddy), -1);
+		}else{
+			username = g_markup_escape_text(user, -1);
+		}
+
+		str = g_strdup_printf(_("%s just sent you a Nudge!"), username);
+		g_free(username);
+		msn_session_report_user(cmdproc->session,user,str,PURPLE_MESSAGE_SYSTEM);
+		g_free(str);
+	}
+	msn_message_destroy(msg);
+}
+
+/*Yahoo msg process*/
+static void
+ubm_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_info("MaYuan","Processing UBM... \n");
+	if(cmd->payload_len == 0){
+		return;
+	}
+	/* NOTE: cmd is not always cmdproc->last_cmd, sometimes cmd is a queued
+	 * command and we are processing it */
+	if (cmd->payload == NULL){
+		cmdproc->last_cmd->payload_cb  = ubm_cmd_post;
+		cmdproc->servconn->payload_len = atoi(cmd->params[2]);
+	}else{
+		g_return_if_fail(cmd->payload_cb != NULL);
+
+		purple_debug_info("MaYuan","UBM payload:{%s}\n",cmd->payload);
+		ubm_cmd_post(cmdproc, cmd, cmd->payload, cmd->payload_len);
+	}
+}
+
+/**************************************************************************
+ * Challenges
+ *  we use MD5 to caculate the Chanllenges 
+ **************************************************************************/
+static void
+chl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnTransaction *trans;
+	char buf[33];
+
+#if 0
+	cipher = purple_ciphers_find_cipher("md5");
+	context = purple_cipher_context_new(cipher, NULL);
+	purple_cipher_context_append(context, (const guchar *)cmd->params[1],
+							   strlen(cmd->params[1]));
+	challenge_resp = MSNP13_WLM_PRODUCT_KEY;
+
+	purple_cipher_context_append(context, (const guchar *)challenge_resp,
+							   strlen(challenge_resp));
+	purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
+	purple_cipher_context_destroy(context);
+
+	for (i = 0; i < 16; i++){
+		g_snprintf(buf + (i*2), 3, "%02x", digest[i]);
+	}
+#else
+	msn_handle_chl(cmd->params[1], buf);
+#endif
+//	purple_debug_info("MaYuan","<<challenge:{%s}:{%s}\n",cmd->params[1],buf);
+	trans = msn_transaction_new(cmdproc, "QRY", "%s 32", MSNP13_WLM_PRODUCT_ID);
+
+	msn_transaction_set_payload(trans, buf, 32);
+
+	msn_cmdproc_send_trans(cmdproc, trans);
+}
+
+/**************************************************************************
+ * Buddy Lists
+ **************************************************************************/
+/* add contact to xmlnode */
+static void 
+msn_add_contact_xml(xmlnode *mlNode,const char *passport,int list_op,int type)
+{
+	xmlnode *d_node,*c_node;
+	char **tokens;
+	char *email,*domain;
+	char *list_op_str,*type_str;
+
+	purple_debug_info("MaYuan","passport:%s\n",passport);
+	tokens = g_strsplit(passport, "@", 2);
+	email = tokens[0];
+	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)){
+		const char * attr = NULL;
+		purple_debug_info("MaYuan","d_node:%s\n",d_node->name);
+		attr = xmlnode_get_attrib(d_node,"n");
+		if(attr == NULL){
+			continue;
+		}
+		if(!strcmp(attr,domain)){
+			break;
+		}
+	}
+	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");
+		xmlnode_set_attrib(d_node,"n",domain);
+		xmlnode_insert_child(mlNode,d_node);
+	}
+
+	/*create contact node*/
+	c_node = xmlnode_new("c");
+	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);
+	xmlnode_set_attrib(c_node,"l",list_op_str);
+	g_free(list_op_str);
+#if 0
+	type_str = g_strdup_printf("%d",type);
+	xmlnode_set_attrib(c_node,"t",type_str);
+#else
+	if(g_strrstr(domain,"yahoo") != NULL){
+		type_str = g_strdup_printf("32");
+	}else{
+		/*passport*/
+		type_str = g_strdup_printf("1");
+	}
+	/*mobile*/
+	//type_str = g_strdup_printf("4");
+	xmlnode_set_attrib(c_node,"t",type_str);
+	g_free(type_str);
+#endif
+	xmlnode_insert_child(d_node, c_node);
+
+	g_free(tokens);
+}
+
+static void
+msn_notification_post_adl(MsnCmdProc *cmdproc, char *payload, int payload_len)
+{
+	MsnTransaction *trans;
+
+	purple_debug_info("MaYuan","Send ADL{%s}\n",payload);
+	trans = msn_transaction_new(cmdproc, "ADL","%d",strlen(payload));
+	msn_transaction_set_payload(trans, payload, strlen(payload));
+	msn_cmdproc_send_trans(cmdproc, trans);
+}
+
+/*dump contact info to NS*/
+void
+msn_notification_dump_contact(MsnSession *session)
+{
+	MsnUserList *userlist;
+	MsnUser *user;
+	GList *l;
+	xmlnode *adl_node;
+	char *payload;
+	int payload_len;
+	const char *display_name;
+
+	userlist = session->userlist;
+	adl_node = xmlnode_new("ml");
+	adl_node->child = NULL;
+	xmlnode_set_attrib(adl_node, "l", "1");
+
+	/*get the userlist*/
+	for (l = userlist->users; l != NULL; l = l->next){
+		user = l->data;
+		msn_add_contact_xml(adl_node,user->passport,user->list_op&MSN_LIST_OP_MASK,user->type);
+	}
+
+	payload = xmlnode_to_str(adl_node,&payload_len);
+	xmlnode_free(adl_node);
+
+	msn_notification_post_adl(session->notification->cmdproc,payload,payload_len);
+
+	display_name = purple_connection_get_display_name(session->account->gc);
+	if (display_name && strcmp(display_name,
+							   purple_account_get_username(session->account))) {
+		msn_act_id(session->account->gc, display_name);
+	}
+
+}
+
+/*Post FQY to NS,Inform add a Yahoo User*/
+static void
+msn_notification_fqy_yahoo(MsnSession *session, const char *passport)
+{
+	MsnTransaction *trans;
+	MsnCmdProc *cmdproc;
+	char* email,*domain,*payload;
+	char **tokens;
+
+	cmdproc = session->notification->cmdproc;
+
+	tokens = g_strsplit(passport, "@", 2);
+	email = tokens[0];
+	domain = tokens[1];
+
+	payload = g_strdup_printf("<ml><d n=\"%s\"><c n=\"%s\"/></d></ml>",domain,email);
+	trans = msn_transaction_new(cmdproc, "FQY","%d",strlen(payload));
+	msn_transaction_set_payload(trans, payload, strlen(payload));
+	msn_cmdproc_send_trans(cmdproc, trans);
+
+	g_free(payload);
+	g_free(tokens);
+}
+
+static void
+blp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_info("MaYuan","Process BLP\n");
+}
+
+static void
+adl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_info("MaYuan","Process ADL\n");
+}
+
+static void
+fqy_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+			 size_t len)
+{
+	purple_debug_info("MaYuan","FQY payload{%s}\n",payload);
+	msn_notification_post_adl(cmdproc,payload,len);
+}
+
+static void
+fqy_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_info("MaYuan","Process FQY\n");
+	cmdproc->last_cmd->payload_cb  = fqy_cmd_post;
+}
+
+static void
+rml_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+#if 0
+	MsnTransaction *trans;
+	char * payload;
+#endif
+
+	purple_debug_info("MaYuan","Process ADL\n");
+#if 0
+	trans = msn_transaction_new(cmdproc, "RML","");
+
+	msn_transaction_set_payload(trans, payload, strlen(payload));
+
+	msn_cmdproc_send_trans(cmdproc, trans);
+#endif
+}
+
+static void
+add_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
+{
+	MsnSession *session;
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	const char *list, *passport;
+	char *reason = NULL;
+	char *msg = NULL;
+	char **params;
+
+	session = cmdproc->session;
+	account = session->account;
+	gc = purple_account_get_connection(account);
+	params = g_strsplit(trans->params, " ", 0);
+
+	list     = params[0];
+	passport = params[1];
+
+	if (!strcmp(list, "FL"))
+		msg = g_strdup_printf(_("Unable to add user on %s (%s)"),
+							  purple_account_get_username(account),
+							  purple_account_get_protocol_name(account));
+	else if (!strcmp(list, "BL"))
+		msg = g_strdup_printf(_("Unable to block user on %s (%s)"),
+							  purple_account_get_username(account),
+							  purple_account_get_protocol_name(account));
+	else if (!strcmp(list, "AL"))
+		msg = g_strdup_printf(_("Unable to permit user on %s (%s)"),
+							  purple_account_get_username(account),
+							  purple_account_get_protocol_name(account));
+
+	if (!strcmp(list, "FL"))
+	{
+		if (error == 210)
+		{
+			reason = g_strdup_printf(_("%s could not be added because "
+									   "your buddy list is full."), passport);
+		}
+	}
+
+	if (reason == NULL)
+	{
+		if (error == 208)
+		{
+			reason = g_strdup_printf(_("%s is not a valid passport account."),
+									 passport);
+		}
+		else if (error == 500)
+		{
+			reason = g_strdup(_("Service Temporarily Unavailable."));
+		}
+		else
+		{
+			reason = g_strdup(_("Unknown error."));
+		}
+	}
+
+	if (msg != NULL)
+	{
+		purple_notify_error(gc, NULL, msg, reason);
+		g_free(msg);
+	}
+
+	if (!strcmp(list, "FL"))
+	{
+		PurpleBuddy *buddy;
+
+		buddy = purple_find_buddy(account, passport);
+
+		if (buddy != NULL)
+			purple_blist_remove_buddy(buddy);
+	}
+
+	g_free(reason);
+
+	g_strfreev(params);
+}
+
+static void
+adg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSession *session;
+	gint group_id;
+	const char *group_name;
+
+	session = cmdproc->session;
+
+	group_id = atoi(cmd->params[3]);
+
+	group_name = purple_url_decode(cmd->params[2]);
+
+	msn_group_new(session->userlist, cmd->params[3], group_name);
+
+	/* There is a user that must me moved to this group */
+	if (cmd->trans->data)
+	{
+		/* msn_userlist_move_buddy(); */
+		MsnUserList *userlist = cmdproc->session->userlist;
+		MsnMoveBuddy *data = cmd->trans->data;
+
+		if (data->old_group_name != NULL)
+		{
+			msn_userlist_rem_buddy(userlist, data->who, MSN_LIST_FL, data->old_group_name);
+			g_free(data->old_group_name);
+		}
+
+		msn_userlist_add_buddy(userlist, data->who, MSN_LIST_FL, group_name);
+		g_free(data->who);
+
+	}
+}
+
+static void
+fln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSlpLink *slplink;
+	MsnUser *user;
+
+	user = msn_userlist_find_user(cmdproc->session->userlist, cmd->params[0]);
+
+	user->status = "offline";
+	msn_user_update(user);
+
+	slplink = msn_session_find_slplink(cmdproc->session, cmd->params[0]);
+
+	if (slplink != NULL)
+		msn_slplink_destroy(slplink);
+
+}
+
+static void
+iln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSession *session;
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	MsnUser *user;
+	MsnObject *msnobj;
+	int wlmclient;
+	const char *state, *passport, *friendly;
+
+	session = cmdproc->session;
+	account = session->account;
+	gc = purple_account_get_connection(account);
+
+	state    = cmd->params[1];
+	passport = cmd->params[2];
+	/*if a contact is actually on the WLM part or the yahoo part*/
+	wlmclient = atoi(cmd->params[3]);
+	friendly = purple_url_decode(cmd->params[4]);
+
+	user = msn_userlist_find_user(session->userlist, passport);
+
+	serv_got_alias(gc, passport, friendly);
+
+	msn_user_set_friendly_name(user, friendly);
+
+	if (session->protocol_ver >= 9 && cmd->param_count == 8)
+	{
+		msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[5]));
+		msn_user_set_object(user, msnobj);
+	}
+
+	msn_user_set_state(user, state);
+	msn_user_update(user);
+}
+
+static void
+ipg_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len)
+{
+#if 0
+	purple_debug_misc("msn", "Incoming Page: {%s}\n", payload);
+#endif
+}
+
+static void
+ipg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	cmdproc->servconn->payload_len = atoi(cmd->params[0]);
+	cmdproc->last_cmd->payload_cb = ipg_cmd_post;
+}
+
+static void
+nln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSession *session;
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	MsnUser *user;
+	MsnObject *msnobj;
+	int clientid;
+	int wlmclient;
+	const char *state, *passport, *friendly, *old_friendly;
+
+	session = cmdproc->session;
+	account = session->account;
+	gc = purple_account_get_connection(account);
+
+	state    = cmd->params[0];
+	passport = cmd->params[1];
+	wlmclient = atoi(cmd->params[2]);
+	friendly = purple_url_decode(cmd->params[3]);
+
+	user = msn_userlist_find_user(session->userlist, passport);
+
+	old_friendly = msn_user_get_friendly_name(user);
+	if (!old_friendly || (old_friendly && strcmp(old_friendly, friendly)))
+	{
+		serv_got_alias(gc, passport, friendly);
+		msn_user_set_friendly_name(user, friendly);
+	}
+
+	if (session->protocol_ver >= 9)
+	{
+		if (cmd->param_count == 7)
+		{
+			msnobj =
+				msn_object_new_from_string(purple_url_decode(cmd->params[4]));
+			msn_user_set_object(user, msnobj);
+		}
+		else
+		{
+			msn_user_set_object(user, NULL);
+		}
+	}
+
+	clientid = atoi(cmd->params[4]);
+	user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE);
+
+	msn_user_set_state(user, state);
+	msn_user_update(user);
+}
+
+#if 0
+static void
+chg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	char *state = cmd->params[1];
+	int state_id = 0;
+
+	if (!strcmp(state, "NLN"))
+		state_id = MSN_ONLINE;
+	else if (!strcmp(state, "BSY"))
+		state_id = MSN_BUSY;
+	else if (!strcmp(state, "IDL"))
+		state_id = MSN_IDLE;
+	else if (!strcmp(state, "BRB"))
+		state_id = MSN_BRB;
+	else if (!strcmp(state, "AWY"))
+		state_id = MSN_AWAY;
+	else if (!strcmp(state, "PHN"))
+		state_id = MSN_PHONE;
+	else if (!strcmp(state, "LUN"))
+		state_id = MSN_LUNCH;
+	else if (!strcmp(state, "HDN"))
+		state_id = MSN_HIDDEN;
+
+	cmdproc->session->state = state_id;
+}
+#endif
+
+
+static void
+not_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len)
+{
+#if 0
+	MSN_SET_PARAMS("NOT %d\r\n%s", cmdproc->servconn->payload, payload);
+	purple_debug_misc("msn", "Notification: {%s}\n", payload);
+#endif
+}
+
+static void
+not_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	cmdproc->servconn->payload_len = atoi(cmd->params[0]);
+	cmdproc->last_cmd->payload_cb = not_cmd_post;
+}
+
+static void
+rea_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	/* TODO: This might be for us too */
+
+	MsnSession *session;
+	PurpleConnection *gc;
+	const char *friendly;
+
+	session = cmdproc->session;
+	gc = session->account->gc;
+	friendly = purple_url_decode(cmd->params[3]);
+
+	purple_connection_set_display_name(gc, friendly);
+}
+
+static void
+prp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSession *session = cmdproc->session;
+	const char *type, *value;
+
+	g_return_if_fail(cmd->param_count >= 3);
+
+	type  = cmd->params[2];
+
+	if (cmd->param_count == 4)
+	{
+		value = cmd->params[3];
+		if (!strcmp(type, "PHH"))
+			msn_user_set_home_phone(session->user, purple_url_decode(value));
+		else if (!strcmp(type, "PHW"))
+			msn_user_set_work_phone(session->user, purple_url_decode(value));
+		else if (!strcmp(type, "PHM"))
+			msn_user_set_mobile_phone(session->user, purple_url_decode(value));
+	}
+	else
+	{
+		if (!strcmp(type, "PHH"))
+			msn_user_set_home_phone(session->user, NULL);
+		else if (!strcmp(type, "PHW"))
+			msn_user_set_work_phone(session->user, NULL);
+		else if (!strcmp(type, "PHM"))
+			msn_user_set_mobile_phone(session->user, NULL);
+		else if (!strcmp(type, "MFM")) {
+			type = cmd->params[1];
+			purple_connection_set_display_name(
+				purple_account_get_connection(session->account),
+				purple_url_decode(cmd->params[2]));
+		}
+	}
+}
+
+static void
+reg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSession *session;
+	const char *group_id, *group_name;
+
+	session = cmdproc->session;
+	group_id = cmd->params[2];
+	group_name = purple_url_decode(cmd->params[3]);
+
+	msn_userlist_rename_group_id(session->userlist, group_id, group_name);
+}
+
+static void
+reg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
+{
+	const char * group_id;
+	char **params;
+
+	params = g_strsplit(trans->params, " ", 0);
+
+	group_id = params[0];
+
+	group_error_helper(cmdproc->session, _("Unable to rename group"), group_id, error);
+
+	g_strfreev(params);
+}
+
+static void
+rem_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSession *session;
+	MsnUser *user;
+	const char *group_id, *list, *passport;
+	MsnListId list_id;
+
+	session = cmdproc->session;
+	list = cmd->params[1];
+	passport = cmd->params[3];
+	user = msn_userlist_find_user(session->userlist, passport);
+
+	g_return_if_fail(user != NULL);
+
+	list_id = msn_get_list_id(list);
+
+	if (cmd->param_count == 5)
+		group_id = cmd->params[4];
+	else
+		group_id = NULL;
+
+	msn_got_rem_user(session, user, list_id, group_id);
+	msn_user_update(user);
+}
+
+static void
+rmg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSession *session;
+	const char *group_id;
+
+	session = cmdproc->session;
+	group_id = cmd->params[2];
+
+	msn_userlist_remove_group_id(session->userlist, group_id);
+}
+
+static void
+rmg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
+{
+	const char *group_id;
+	char **params;
+
+	params = g_strsplit(trans->params, " ", 0);
+
+	group_id = atoi(params[0]);
+
+	group_error_helper(cmdproc->session, _("Unable to delete group"), group_id, error);
+
+	g_strfreev(params);
+}
+
+static void
+syn_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSession *session;
+	int total_users;
+
+	session = cmdproc->session;
+
+	if (cmd->param_count == 2)
+	{
+		/*
+		 * This can happen if we sent a SYN with an up-to-date
+		 * buddy list revision, but we send 0 to get a full list.
+		 * So, error out.
+		 */
+
+		msn_session_set_error(cmdproc->session, MSN_ERROR_BAD_BLIST, NULL);
+		return;
+	}
+
+	total_users  = atoi(cmd->params[2]);
+
+	if (total_users == 0)
+	{
+		msn_session_finish_login(session);
+	}
+	else
+	{
+		/* syn_table */
+		MsnSync *sync;
+
+		sync = msn_sync_new(session);
+		sync->total_users = total_users;
+		sync->old_cbs_table = cmdproc->cbs_table;
+
+		session->sync = sync;
+		cmdproc->cbs_table = sync->cbs_table;
+	}
+}
+
+/**************************************************************************
+ * Misc commands
+ **************************************************************************/
+
+static void
+url_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSession *session;
+	PurpleAccount *account;
+	const char *rru;
+	const char *url;
+	PurpleCipher *cipher;
+	PurpleCipherContext *context;
+	guchar digest[16];
+	FILE *fd;
+	char *buf;
+	char buf2[3];
+	char sendbuf[64];
+	int i;
+
+	session = cmdproc->session;
+	account = session->account;
+
+	rru = cmd->params[1];
+	url = cmd->params[2];
+
+	buf = g_strdup_printf("%s%lu%s",
+			   session->passport_info.mspauth,
+			   time(NULL) - session->passport_info.sl,
+			   purple_connection_get_password(account->gc));
+
+	cipher = purple_ciphers_find_cipher("md5");
+	context = purple_cipher_context_new(cipher, NULL);
+
+	purple_cipher_context_append(context, (const guchar *)buf, strlen(buf));
+	purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
+	purple_cipher_context_destroy(context);
+
+	g_free(buf);
+
+	memset(sendbuf, 0, sizeof(sendbuf));
+
+	for (i = 0; i < 16; i++)
+	{
+		g_snprintf(buf2, sizeof(buf2), "%02x", digest[i]);
+		strcat(sendbuf, buf2);
+	}
+
+	if (session->passport_info.file != NULL)
+	{
+		g_unlink(session->passport_info.file);
+		g_free(session->passport_info.file);
+	}
+
+	if ((fd = purple_mkstemp(&session->passport_info.file, FALSE)) == NULL)
+	{
+		purple_debug_error("msn",
+						 "Error opening temp passport file: %s\n",
+						 strerror(errno));
+	}
+	else
+	{
+		fputs("<html>\n"
+			  "<head>\n"
+			  "<noscript>\n"
+			  "<meta http-equiv=\"Refresh\" content=\"0; "
+			  "url=http://www.hotmail.com\">\n"
+			  "</noscript>\n"
+			  "</head>\n\n",
+			  fd);
+
+		fprintf(fd, "<body onload=\"document.pform.submit(); \">\n");
+		fprintf(fd, "<form name=\"pform\" action=\"%s\" method=\"POST\">\n\n",
+				url);
+		fprintf(fd, "<input type=\"hidden\" name=\"mode\" value=\"ttl\">\n");
+		fprintf(fd, "<input type=\"hidden\" name=\"login\" value=\"%s\">\n",
+				purple_account_get_username(account));
+		fprintf(fd, "<input type=\"hidden\" name=\"username\" value=\"%s\">\n",
+				purple_account_get_username(account));
+		if (session->passport_info.sid != NULL)
+			fprintf(fd, "<input type=\"hidden\" name=\"sid\" value=\"%s\">\n",
+					session->passport_info.sid);
+		if (session->passport_info.kv != NULL)
+			fprintf(fd, "<input type=\"hidden\" name=\"kv\" value=\"%s\">\n",
+					session->passport_info.kv);
+		fprintf(fd, "<input type=\"hidden\" name=\"id\" value=\"2\">\n");
+		fprintf(fd, "<input type=\"hidden\" name=\"sl\" value=\"%ld\">\n",
+				time(NULL) - session->passport_info.sl);
+		fprintf(fd, "<input type=\"hidden\" name=\"rru\" value=\"%s\">\n",
+				rru);
+		if (session->passport_info.mspauth != NULL)
+			fprintf(fd, "<input type=\"hidden\" name=\"auth\" value=\"%s\">\n",
+					session->passport_info.mspauth);
+		fprintf(fd, "<input type=\"hidden\" name=\"creds\" value=\"%s\">\n",
+				sendbuf); /* TODO Digest me (huh? -- ChipX86) */
+		fprintf(fd, "<input type=\"hidden\" name=\"svc\" value=\"mail\">\n");
+		fprintf(fd, "<input type=\"hidden\" name=\"js\" value=\"yes\">\n");
+		fprintf(fd, "</form></body>\n");
+		fprintf(fd, "</html>\n");
+
+		if (fclose(fd))
+		{
+			purple_debug_error("msn",
+							 "Error closing temp passport file: %s\n",
+							 strerror(errno));
+
+			g_unlink(session->passport_info.file);
+			g_free(session->passport_info.file);
+			session->passport_info.file = NULL;
+		}
+#ifdef _WIN32
+		else
+		{
+			/*
+			 * Renaming file with .html extension, so that the
+			 * win32 open_url will work.
+			 */
+			char *tmp;
+
+			if ((tmp =
+				g_strdup_printf("%s.html",
+					session->passport_info.file)) != NULL)
+			{
+				if (g_rename(session->passport_info.file,
+							tmp) == 0)
+				{
+					g_free(session->passport_info.file);
+					session->passport_info.file = tmp;
+				}
+				else
+					g_free(tmp);
+			}
+		}
+#endif
+	}
+}
+/**************************************************************************
+ * Switchboards
+ **************************************************************************/
+
+static void
+rng_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSession *session;
+	MsnSwitchBoard *swboard;
+	const char *session_id;
+	char *host;
+	int port;
+
+	session = cmdproc->session;
+	session_id = cmd->params[0];
+
+	msn_parse_socket(cmd->params[1], &host, &port);
+
+	if (session->http_method)
+		port = 80;
+
+	swboard = msn_switchboard_new(session);
+
+	msn_switchboard_set_invited(swboard, TRUE);
+	msn_switchboard_set_session_id(swboard, cmd->params[0]);
+	msn_switchboard_set_auth_key(swboard, cmd->params[3]);
+	swboard->im_user = g_strdup(cmd->params[4]);
+	/* msn_switchboard_add_user(swboard, cmd->params[4]); */
+
+	if (!msn_switchboard_connect(swboard, host, port))
+		msn_switchboard_destroy(swboard);
+
+	g_free(host);
+}
+
+static void
+xfr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	char *host;
+	int port;
+
+	if (strcmp(cmd->params[1], "SB") && strcmp(cmd->params[1], "NS"))
+	{
+		/* Maybe we can have a generic bad command error. */
+		purple_debug_error("msn", "Bad XFR command (%s)\n", cmd->params[1]);
+		return;
+	}
+
+	msn_parse_socket(cmd->params[2], &host, &port);
+
+	if (!strcmp(cmd->params[1], "SB"))
+	{
+		purple_debug_error("msn", "This shouldn't be handled here.\n");
+	}
+	else if (!strcmp(cmd->params[1], "NS"))
+	{
+		MsnSession *session;
+
+		session = cmdproc->session;
+
+		msn_session_set_login_step(session, MSN_LOGIN_STEP_TRANSFER);
+
+		msn_notification_connect(session->notification, host, port);
+	}
+
+	g_free(host);
+}
+
+static void
+gcf_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+			 size_t len)
+{
+	/*get the payload content*/
+	purple_debug_info("MaYuan","GCF{%s}\n",cmd->payload);
+}
+
+static void
+gcf_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_info("MaYuan","Processing GCF... \n");
+	cmdproc->last_cmd->payload_cb  = gcf_cmd_post;
+	return;
+}
+
+static void
+sbs_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_info("MaYuan","Processing SBS... \n");
+	if(cmd->payload_len == 0){
+		return;
+	}
+	/*get the payload content*/
+}
+
+/*
+ * Get the UBX's PSM info
+ * Post it to the User status
+ * Thanks for Chris <ukdrizzle@yahoo.co.uk>'s code
+ */
+static void
+ubx_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+			 size_t len)
+{
+	MsnSession *session;
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	MsnUser *user;
+	const char *passport;
+	char *psm_str;
+
+	/*get the payload content*/
+//	purple_debug_info("MaYuan","UBX {%s} payload{%s}\n",cmd->params[0], cmd->payload);
+
+	session = cmdproc->session;
+	account = session->account;
+	gc = purple_account_get_connection(account);
+
+	passport = cmd->params[0];
+	user = msn_userlist_find_user(session->userlist, passport);
+	
+	psm_str = msn_get_psm(cmd->payload,len);
+	msn_user_set_statusline(user, psm_str);
+	msn_user_update(user);
+
+	g_free(psm_str);
+}
+
+static void
+ubx_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_info("MaYuan","UBX... \n");
+	if(cmd->payload_len == 0){
+		return;
+	}
+	cmdproc->last_cmd->payload_cb  = ubx_cmd_post;
+}
+
+static void
+uux_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	purple_debug_info("MaYuan","UUX... \n");
+}
+
+/**************************************************************************
+ * Message Types
+ **************************************************************************/
+
+static void
+profile_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
+{
+	MsnSession *session;
+	const char *value;
+	const char *clLastChange;
+
+	purple_debug_info("MaYuan","profile_msg... \n");
+	session = cmdproc->session;
+
+	if (strcmp(msg->remote_user, "Hotmail"))
+		/* This isn't an official message. */
+		return;
+
+	if ((value = msn_message_get_attr(msg, "kv")) != NULL)
+	{
+		if (session->passport_info.kv != NULL)
+			g_free(session->passport_info.kv);
+
+		session->passport_info.kv = g_strdup(value);
+	}
+
+	if ((value = msn_message_get_attr(msg, "sid")) != NULL)
+	{
+		if (session->passport_info.sid != NULL)
+			g_free(session->passport_info.sid);
+
+		session->passport_info.sid = g_strdup(value);
+	}
+
+	if ((value = msn_message_get_attr(msg, "MSPAuth")) != NULL)
+	{
+		if (session->passport_info.mspauth != NULL)
+			g_free(session->passport_info.mspauth);
+
+		purple_debug_info("MaYuan","MSPAuth:%s\n",value);
+		session->passport_info.mspauth = g_strdup(value);
+	}
+
+	if ((value = msn_message_get_attr(msg, "ClientIP")) != NULL)
+	{
+		if (session->passport_info.client_ip != NULL)
+			g_free(session->passport_info.client_ip);
+
+		session->passport_info.client_ip = g_strdup(value);
+	}
+
+	if ((value = msn_message_get_attr(msg, "ClientPort")) != NULL)
+{	
+	session->passport_info.client_port = ntohs(atoi(value));
+}
+
+	if ((value = msn_message_get_attr(msg, "LoginTime")) != NULL)
+		session->passport_info.sl = atol(value);
+
+	/*starting retrieve the contact list*/
+	msn_userlist_load(session);
+	
+	msn_session_set_bnode(session);
+	session->contact = msn_contact_new(session);
+	clLastChange = purple_blist_node_get_string(msn_session_get_bnode(session),"CLLastChange");
+	msn_get_contact_list(session->contact, clLastChange);
+//	msn_contact_connect(session->contact);
+}
+
+static void
+initial_email_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
+{
+	MsnSession *session;
+	PurpleConnection *gc;
+	GHashTable *table;
+	const char *unread;
+
+	session = cmdproc->session;
+	gc = session->account->gc;
+
+	if (strcmp(msg->remote_user, "Hotmail"))
+		/* This isn't an official message. */
+		return;
+
+	if (session->passport_info.file == NULL)
+	{
+		MsnTransaction *trans;
+		trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX");
+		msn_transaction_queue_cmd(trans, msg->cmd);
+
+		msn_cmdproc_send_trans(cmdproc, trans);
+
+		return;
+	}
+
+	if (!purple_account_get_check_mail(session->account))
+		return;
+
+	table = msn_message_get_hashtable_from_body(msg);
+
+	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 process*/
+static void
+initial_mdata_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
+{
+	MsnSession *session;
+	char **elems, **cur, **tokens;
+
+//	purple_debug_info("MaYuan","mdata...{%s} \n",msg->body);
+
+//	/*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);
+	}
+
+	/*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;
+
+//		purple_debug_info("MaYuan","cur:{%s}\n",*cur);
+		tokens = g_strsplit(*cur, ": ", 2);
+
+		key = tokens[0];
+		value = tokens[1];
+
+		/*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;
+		}
+
+		g_strfreev(tokens);
+	}
+
+	g_strfreev(elems);
+/* test code for add group*/
+//	msn_add_group(session,"hello");
+}
+
+/*offline Message Notification*/
+static void
+delete_oim_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
+{
+}
+
+static void
+email_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
+{
+	MsnSession *session;
+	PurpleConnection *gc;
+	GHashTable *table;
+	char *from, *subject, *tmp;
+
+	session = cmdproc->session;
+	gc = session->account->gc;
+
+	if (strcmp(msg->remote_user, "Hotmail"))
+		/* This isn't an official message. */
+		return;
+
+	if (session->passport_info.file == NULL)
+	{
+		MsnTransaction *trans;
+		trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX");
+		msn_transaction_queue_cmd(trans, msg->cmd);
+
+		msn_cmdproc_send_trans(cmdproc, trans);
+
+		return;
+	}
+
+	if (!purple_account_get_check_mail(session->account))
+		return;
+
+	table = msn_message_get_hashtable_from_body(msg);
+
+	from = subject = NULL;
+
+	tmp = g_hash_table_lookup(table, "From");
+	if (tmp != NULL)
+		from = purple_mime_decode_field(tmp);
+
+	tmp = g_hash_table_lookup(table, "Subject");
+	if (tmp != NULL)
+		subject = purple_mime_decode_field(tmp);
+
+	purple_notify_email(gc,
+					  (subject != NULL ? subject : ""),
+					  (from != NULL ?  from : ""),
+					  msn_user_get_passport(session->user),
+					  session->passport_info.file, NULL, NULL);
+
+	if (from != NULL)
+		g_free(from);
+
+	if (subject != NULL)
+		g_free(subject);
+
+	g_hash_table_destroy(table);
+}
+
+static void
+system_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
+{
+	GHashTable *table;
+	const char *type_s;
+
+	if (strcmp(msg->remote_user, "Hotmail"))
+		/* This isn't an official message. */
+		return;
+
+	table = msn_message_get_hashtable_from_body(msg);
+
+	if ((type_s = g_hash_table_lookup(table, "Type")) != NULL)
+	{
+		int type = atoi(type_s);
+		char buf[MSN_BUF_LEN];
+		int minutes;
+
+		switch (type)
+		{
+			case 1:
+				minutes = atoi(g_hash_table_lookup(table, "Arg1"));
+				g_snprintf(buf, sizeof(buf), ngettext(
+							"The MSN server will shut down for maintenance "
+							"in %d minute. You will automatically be "
+							"signed out at that time.  Please finish any "
+							"conversations in progress.\n\nAfter the "
+							"maintenance has been completed, you will be "
+							"able to successfully sign in.",
+							"The MSN server will shut down for maintenance "
+							"in %d minutes. You will automatically be "
+							"signed out at that time.  Please finish any "
+							"conversations in progress.\n\nAfter the "
+							"maintenance has been completed, you will be "
+							"able to successfully sign in.", minutes),
+						minutes);
+			default:
+				break;
+		}
+
+		if (*buf != '\0')
+			purple_notify_info(cmdproc->session->account->gc, NULL, buf, NULL);
+	}
+
+	g_hash_table_destroy(table);
+}
+
+void
+msn_notification_add_buddy(MsnNotification *notification, const char *list,
+						   const char *who, const char *store_name,
+						   const char *group_id)
+{
+	MsnCmdProc *cmdproc;
+	xmlnode *adl_node;
+	char *payload;
+	int payload_len;
+
+	cmdproc = notification->servconn->cmdproc;
+
+	adl_node = xmlnode_new("ml");
+	adl_node->child = NULL;
+
+	msn_add_contact_xml(adl_node,who,1,1);
+
+	payload = xmlnode_to_str(adl_node,&payload_len);
+	xmlnode_free(adl_node);
+	if (msn_user_is_yahoo(notification->session->account,who))
+	{
+		msn_notification_fqy_yahoo(notification->session, who);
+	}
+	else
+	{
+		msn_notification_post_adl(notification->servconn->cmdproc,
+							payload,payload_len);
+	}
+}
+
+void
+msn_notification_rem_buddy(MsnNotification *notification, const char *list,
+						   const char *who, const char *group_id)
+{
+	MsnCmdProc *cmdproc;
+	MsnTransaction *trans;
+	xmlnode *rml_node;
+	char *payload;
+	int payload_len;
+
+	cmdproc = notification->servconn->cmdproc;
+
+	rml_node = xmlnode_new("ml");
+	rml_node->child = NULL;
+
+	msn_add_contact_xml(rml_node,who,1,1);
+
+	payload = xmlnode_to_str(rml_node,&payload_len);
+	xmlnode_free(rml_node);
+
+	purple_debug_info("MaYuan","RML{%s}\n",payload);
+	trans = msn_transaction_new(cmdproc, "RML","%d",strlen(payload));
+	msn_transaction_set_payload(trans, payload, strlen(payload));
+	msn_cmdproc_send_trans(cmdproc, trans);
+}
+
+/**************************************************************************
+ * Init
+ **************************************************************************/
+void
+msn_notification_init(void)
+{
+	/* TODO: check prp, blp */
+
+	cbs_table = msn_table_new();
+
+	/* Synchronous */
+	msn_table_add_cmd(cbs_table, "CHG", "CHG", NULL);
+	msn_table_add_cmd(cbs_table, "CHG", "ILN", iln_cmd);
+	msn_table_add_cmd(cbs_table, "ADL", "ILN", iln_cmd);
+	msn_table_add_cmd(cbs_table, "REM", "REM", rem_cmd);
+	msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd);
+	msn_table_add_cmd(cbs_table, "USR", "XFR", xfr_cmd);
+	msn_table_add_cmd(cbs_table, "USR", "GCF", gcf_cmd);
+	msn_table_add_cmd(cbs_table, "SYN", "SYN", syn_cmd);
+	msn_table_add_cmd(cbs_table, "CVR", "CVR", cvr_cmd);
+	msn_table_add_cmd(cbs_table, "VER", "VER", ver_cmd);
+	msn_table_add_cmd(cbs_table, "REA", "REA", rea_cmd);
+	msn_table_add_cmd(cbs_table, "PRP", "PRP", prp_cmd);
+	msn_table_add_cmd(cbs_table, "BLP", "BLP", blp_cmd);
+//	msn_table_add_cmd(cbs_table, "BLP", "BLP", NULL);
+	msn_table_add_cmd(cbs_table, "REG", "REG", reg_cmd);
+	msn_table_add_cmd(cbs_table, "ADG", "ADG", adg_cmd);
+	msn_table_add_cmd(cbs_table, "RMG", "RMG", rmg_cmd);
+	msn_table_add_cmd(cbs_table, "XFR", "XFR", xfr_cmd);
+
+	/* Asynchronous */
+	msn_table_add_cmd(cbs_table, NULL, "IPG", ipg_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "UBM", ubm_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "GCF", gcf_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "SBS", sbs_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "NOT", not_cmd);
+
+	msn_table_add_cmd(cbs_table, NULL, "CHL", chl_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "RML", rml_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "ADL", adl_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "FQY", fqy_cmd);
+
+	msn_table_add_cmd(cbs_table, NULL, "QRY", NULL);
+	msn_table_add_cmd(cbs_table, NULL, "QNG", NULL);
+	msn_table_add_cmd(cbs_table, NULL, "FLN", fln_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "NLN", nln_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "ILN", iln_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "RNG", rng_cmd);
+
+	msn_table_add_cmd(cbs_table, NULL, "UBX", ubx_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "UUX", uux_cmd);
+
+	msn_table_add_cmd(cbs_table, NULL, "URL", url_cmd);
+
+	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, "REG", reg_error);
+	msn_table_add_error(cbs_table, "RMG", rmg_error);
+	/* msn_table_add_error(cbs_table, "REA", rea_error); */
+	msn_table_add_error(cbs_table, "USR", usr_error);
+
+	msn_table_add_msg_type(cbs_table,
+						   "text/x-msmsgsprofile",
+						   profile_msg);
+	/*initial OIM notification*/
+	msn_table_add_msg_type(cbs_table,
+							"text/x-msmsgsinitialmdatanotification",
+							initial_mdata_msg);	
+	/*OIM notification when user online*/
+	msn_table_add_msg_type(cbs_table,
+							"text/x-msmsgsoimnotification",
+							initial_mdata_msg);	
+	msn_table_add_msg_type(cbs_table,
+						   "text/x-msmsgsinitialemailnotification",
+						   initial_email_msg);
+	msn_table_add_msg_type(cbs_table,
+						   "text/x-msmsgsemailnotification",
+						   email_msg);
+	/*delete an offline Message notification*/
+	msn_table_add_msg_type(cbs_table,
+							"text/x-msmsgsactivemailnotification",
+						   delete_oim_msg);
+	msn_table_add_msg_type(cbs_table,
+						   "application/x-msmsgssystemmessage",
+						   system_msg);
+}
+
+void
+msn_notification_end(void)
+{
+	msn_table_destroy(cbs_table);
+}
+