? .gdb_history
? src/.gdb_history
Index: src/gtkdebug.c
===================================================================
RCS file: /cvsroot/gaim/gaim/src/gtkdebug.c,v
retrieving revision 1.55
diff -u -p -r1.55 gtkdebug.c
--- src/gtkdebug.c	28 Jun 2005 20:20:18 -0000	1.55
+++ src/gtkdebug.c	30 Jun 2005 23:12:28 -0000
@@ -669,12 +669,15 @@ gaim_gtk_debug_unregister_category(const
 {
 	GtkTreeModel *model = NULL;
 
+	if (debug_win != NULL) {
+
 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(debug_win->treeview));
 
-	gtk_tree_model_foreach(model,
-	                       (GtkTreeModelForeachFunc)find_and_remove_category,
-	                       (char *)category);
+		gtk_tree_model_foreach(model,
+				 (GtkTreeModelForeachFunc)find_and_remove_category,
+				 (char *)category);
 
+	}
 	g_hash_table_remove(debug_categories, category);
 }
 
Index: src/protocols/msn/group.c
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/group.c,v
retrieving revision 1.5
diff -u -p -r1.5 group.c
--- src/protocols/msn/group.c	6 Jun 2004 03:42:54 -0000	1.5
+++ src/protocols/msn/group.c	30 Jun 2005 23:12:28 -0000
@@ -25,18 +25,18 @@
 #include "group.h"
 
 MsnGroup *
-msn_group_new(MsnUserList *userlist, int id, const char *name)
+msn_group_new(MsnUserList *userlist, const char *id, const char *name)
 {
 	MsnGroup *group;
 
-	g_return_val_if_fail(id >= 0,      NULL);
+	g_return_val_if_fail(id != NULL,   NULL);
 	g_return_val_if_fail(name != NULL, NULL);
 
 	group = g_new0(MsnGroup, 1);
 
 	msn_userlist_add_group(userlist, group);
 
-	group->id      = id;
+	group->id      = g_strdup(id);
 	group->name    = g_strdup(name);
 
 	return group;
@@ -48,16 +48,20 @@ msn_group_destroy(MsnGroup *group)
 	g_return_if_fail(group != NULL);
 
 	g_free(group->name);
+	g_free(group->id);
 	g_free(group);
 }
 
 void
-msn_group_set_id(MsnGroup *group, int id)
+msn_group_set_id(MsnGroup *group, const char *id)
 {
 	g_return_if_fail(group != NULL);
-	g_return_if_fail(id >= 0);
+	g_return_if_fail(id != NULL);
 
-	group->id = id;
+	if (group->id)
+		g_free(group->id);
+
+	group->id = g_strdup(id);
 }
 
 void
@@ -72,10 +76,10 @@ msn_group_set_name(MsnGroup *group, cons
 	group->name = g_strdup(name);
 }
 
-int
+const char *
 msn_group_get_id(const MsnGroup *group)
 {
-	g_return_val_if_fail(group != NULL, -1);
+	g_return_val_if_fail(group != NULL, NULL);
 
 	return group->id;
 }
Index: src/protocols/msn/group.h
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/group.h,v
retrieving revision 1.5
diff -u -p -r1.5 group.h
--- src/protocols/msn/group.h	6 Jun 2004 03:42:54 -0000	1.5
+++ src/protocols/msn/group.h	30 Jun 2005 23:12:28 -0000
@@ -40,7 +40,7 @@ struct _MsnGroup
 {
 	MsnSession *session;    /**< The MSN session.           */
 
-	int id;                 /**< The group ID.              */
+	char *id;               /**< The group ID.              */
 	char *name;             /**< The name of the group.     */
 };
 
@@ -58,7 +58,7 @@ struct _MsnGroup
  *
  * @return A new group structure.
  */
-MsnGroup *msn_group_new(MsnUserList *userlist, int id, const char *name);
+MsnGroup *msn_group_new(MsnUserList *userlist, const char *id, const char *name);
 
 /**
  * Destroys a group structure.
@@ -73,7 +73,7 @@ void msn_group_destroy(MsnGroup *group);
  * @param group The group.
  * @param id    The ID.
  */
-void msn_group_set_id(MsnGroup *group, int id);
+void msn_group_set_id(MsnGroup *group, const char *id);
 
 /**
  * Sets the name for a group.
@@ -90,7 +90,7 @@ void msn_group_set_name(MsnGroup *group,
  *
  * @return The ID.
  */
-int msn_group_get_id(const MsnGroup *group);
+const char *msn_group_get_id(const MsnGroup *group);
 
 /**
  * Returns the name for a group.
Index: src/protocols/msn/msg.c
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/msg.c,v
retrieving revision 1.46
diff -u -p -r1.46 msg.c
--- src/protocols/msn/msg.c	10 Jun 2005 04:42:40 -0000	1.46
+++ src/protocols/msn/msg.c	30 Jun 2005 23:12:29 -0000
@@ -532,6 +532,16 @@ msn_message_get_bin_data(const MsnMessag
 	return msg->body;
 }
 
+int
+msn_message_add_bin_data(MsnMessage *msg, const void *data, size_t len)
+{
+	int newsize = msg->body_len + len;
+	msg->body = g_realloc(msg->body, newsize);
+	memcpy(msg->body + msg->body_len, data, len);
+	msg->body_len = newsize;
+}
+
+
 void
 msn_message_set_content_type(MsnMessage *msg, const char *type)
 {
Index: src/protocols/msn/msg.h
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/msg.h,v
retrieving revision 1.18
diff -u -p -r1.18 msg.h
--- src/protocols/msn/msg.h	30 Dec 2004 15:55:19 -0000	1.18
+++ src/protocols/msn/msg.h	30 Jun 2005 23:12:29 -0000
@@ -50,7 +50,9 @@ typedef enum
 	MSN_MSG_TEXT,
 	MSN_MSG_TYPING,
 	MSN_MSG_CAPS,
-	MSN_MSG_SLP
+	MSN_MSG_SLP,
+	MSN_MSG_NUDGE,
+	MSN_MSG_WINK
 
 } MsnMsgType;
 
@@ -251,6 +253,15 @@ const char *msn_message_get_body(const M
 void msn_message_set_bin_data(MsnMessage *msg, const void *data, size_t len);
 
 /**
+ * Append some data to the binary content of the message.
+ *
+ * @param msg  The message.
+ * @param data The binary data to add.
+ * @param len  The length of the data.
+ */
+int msn_message_add_bin_data(MsnMessage *msg, const void *data, size_t len);
+
+/**
  * Returns the binary content of the message.
  *
  * @param msg The message.
Index: src/protocols/msn/msn.c
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/msn.c,v
retrieving revision 1.363
diff -u -p -r1.363 msn.c
--- src/protocols/msn/msn.c	28 Jun 2005 06:13:03 -0000	1.363
+++ src/protocols/msn/msn.c	30 Jun 2005 23:12:32 -0000
@@ -92,6 +92,26 @@ msn_normalize(const GaimAccount *account
 }
 
 static void
+msn_set_prp(GaimConnection *gc, const char *type, const char *entry)
+{
+	MsnCmdProc *cmdproc;
+	MsnSession *session;
+
+	session = gc->proto_data;
+	cmdproc = session->notification->cmdproc;
+
+	if (entry == NULL || *entry == '\0')
+	{
+		msn_cmdproc_send(cmdproc, "PRP", "%s", type);
+	}
+	else
+	{
+		msn_cmdproc_send(cmdproc, "PRP", "%s %s", type,
+						 gaim_url_encode(entry));
+	}
+}
+
+static void
 msn_act_id(GaimConnection *gc, const char *entry)
 {
 	MsnCmdProc *cmdproc;
@@ -118,26 +138,7 @@ msn_act_id(GaimConnection *gc, const cha
 	msn_cmdproc_send(cmdproc, "REA", "%s %s",
 					 gaim_account_get_username(account),
 					 alias);
-}
-
-static void
-msn_set_prp(GaimConnection *gc, const char *type, const char *entry)
-{
-	MsnCmdProc *cmdproc;
-	MsnSession *session;
-
-	session = gc->proto_data;
-	cmdproc = session->notification->cmdproc;
-
-	if (entry == NULL || *entry == '\0')
-	{
-		msn_cmdproc_send(cmdproc, "PRP", "%s", type);
-	}
-	else
-	{
-		msn_cmdproc_send(cmdproc, "PRP", "%s %s", type,
-						 gaim_url_encode(entry));
-	}
+	msn_set_prp(gc, "MFN", alias);
 }
 
 static void
@@ -880,13 +881,18 @@ fake_userlist_add_buddy(MsnUserList *use
 	MsnUser *user;
 	static int group_id_c = 1;
 	int group_id;
+	char tempgid[40];
 
 	group_id = -1;
 
+	gaim_debug_info("msn", "VERIFY THIS FUNCTION fake_userlist_add_buddy()\n");
+	gaim_debug_info("msn", "VERIFY THIS FUNCTION fake_userlist_add_buddy()\n");
+
 	if (group_name != NULL)
 	{
 		MsnGroup *group;
-		group = msn_group_new(userlist, group_id_c, group_name);
+		snprintf(tempgid, sizeof(tempgid), "%8.8x-0000-0000-0000-000000000000", group_id_c);
+		group = msn_group_new(userlist, tempgid, group_name);
 		group_id = group_id_c++;
 	}
 
@@ -1213,13 +1219,14 @@ msn_group_buddy(GaimConnection *gc, cons
 	msn_userlist_move_buddy(userlist, who, old_group_name, new_group_name);
 }
 
+/* TODO: test this function */
 static void
 msn_rename_group(GaimConnection *gc, const char *old_name,
 				 GaimGroup *group, GList *moved_buddies)
 {
 	MsnSession *session;
 	MsnCmdProc *cmdproc;
-	int old_gid;
+	const char *old_gid;
 	const char *enc_new_group_name;
 
 	session = gc->proto_data;
@@ -1228,14 +1235,14 @@ msn_rename_group(GaimConnection *gc, con
 
 	old_gid = msn_userlist_find_group_id(session->userlist, old_name);
 
-	if (old_gid >= 0)
+	if (old_gid)
 	{
-		msn_cmdproc_send(cmdproc, "REG", "%d %s 0", old_gid,
+		msn_cmdproc_send(cmdproc, "REG", "%d %s", old_gid,
 						 enc_new_group_name);
 	}
 	else
 	{
-		msn_cmdproc_send(cmdproc, "ADG", "%s 0", enc_new_group_name);
+		msn_cmdproc_send(cmdproc, "ADG", "%s", enc_new_group_name);
 	}
 }
 
@@ -1290,14 +1297,15 @@ msn_remove_group(GaimConnection *gc, Gai
 {
 	MsnSession *session;
 	MsnCmdProc *cmdproc;
-	int group_id;
+	const char *group_id;
 
 	session = gc->proto_data;
 	cmdproc = session->notification->cmdproc;
 
-	if ((group_id = msn_userlist_find_group_id(session->userlist, group->name)) >= 0)
+	group_id = msn_userlist_find_group_id(session->userlist, group->name);
+	if (group_id != NULL)
 	{
-		msn_cmdproc_send(cmdproc, "RMG", "%d", group_id);
+		msn_cmdproc_send(cmdproc, "RMG", "%s", group_id);
 	}
 }
 
Index: src/protocols/msn/msn.h
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/msn.h,v
retrieving revision 1.28
diff -u -p -r1.28 msn.h
--- src/protocols/msn/msn.h	11 Mar 2005 13:05:30 -0000	1.28
+++ src/protocols/msn/msn.h	30 Jun 2005 23:12:32 -0000
@@ -88,15 +88,18 @@ typedef enum
 
 typedef enum
 {
-	MSN_CLIENT_CAP_WIN_MOBILE = 0x001,
-	MSN_CLIENT_CAP_UNKNOWN_1  = 0x002,
-	MSN_CLIENT_CAP_VIEW_INK   = 0x004,
-	MSN_CLIENT_CAP_SEND_INK   = 0x008,
-	MSN_CLIENT_CAP_VIDEO_CHAT = 0x010,
-	MSN_CLIENT_CAP_BASE       = 0x020,
-	MSN_CLIENT_CAP_MSNMOBILE  = 0x040,
-	MSN_CLIENT_CAP_MSNDIRECT  = 0x080,
-	MSN_CLIENT_CAP_WEBMSGR    = 0x100
+	MSN_CLIENT_CAP_WIN_MOBILE = 0x00001,
+	MSN_CLIENT_CAP_UNKNOWN_1  = 0x00002,
+	MSN_CLIENT_CAP_INK_GIF    = 0x00004,
+	MSN_CLIENT_CAP_INK_ISF    = 0x00008,
+	MSN_CLIENT_CAP_VIDEO_CHAT = 0x00010,
+	MSN_CLIENT_CAP_BASE       = 0x00020,
+	MSN_CLIENT_CAP_MSNMOBILE  = 0x00040,
+	MSN_CLIENT_CAP_MSNDIRECT  = 0x00080,
+	MSN_CLIENT_CAP_WEBMSGR    = 0x00100,
+	MSN_CLIENT_CAP_DIRECTIM   = 0x04000,
+	MSN_CLIENT_CAP_WINKS      = 0x08000,
+	MSN_CLIENT_CAP_SEARCH     = 0x10000
 
 } MsnClientCaps;
 
@@ -110,10 +113,18 @@ typedef enum
 
 } MsnClientVerId;
 
-#define MSN_CLIENT_ID_VERSION      MSN_CLIENT_VER_6_0
+#define MSN_CLIENT_ID_VERSION      MSN_CLIENT_VER_7_0
 #define MSN_CLIENT_ID_RESERVED_1   0x00
 #define MSN_CLIENT_ID_RESERVED_2   0x00
-#define MSN_CLIENT_ID_CAPABILITIES MSN_CLIENT_CAP_BASE
+/* 
+ * This is the official capabilities supported by the last 
+ * MSN messenger 7.0.0813. Even if we don't support directIM
+ * and winks, this suppress some nasty message in our window
+ */
+#define MSN_CLIENT_ID_CAPABILITIES (MSN_CLIENT_CAP_BASE | \
+                                    MSN_CLIENT_CAP_INK_GIF | \
+    	                            MSN_CLIENT_CAP_DIRECTIM | \
+                                    MSN_CLIENT_CAP_WINKS)
 
 #define MSN_CLIENT_ID \
 	((MSN_CLIENT_ID_VERSION    << 24) | \
Index: src/protocols/msn/notification.c
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/notification.c,v
retrieving revision 1.147
diff -u -p -r1.147 notification.c
--- src/protocols/msn/notification.c	16 Apr 2005 18:44:40 -0000	1.147
+++ src/protocols/msn/notification.c	30 Jun 2005 23:12:35 -0000
@@ -32,6 +32,23 @@
 #include "sync.h"
 #include "slplink.h"
 
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+#define bswap_32(x) \
+       ((((x) & 0xff000000) >> 24) |\
+	(((x) & 0x00ff0000) >>  8) |\
+        (((x) & 0x0000ff00) <<  8) |\
+	(((x) & 0x000000ff) << 24))
+#endif
+
+#ifdef WORDS_BIGENDIAN
+#define cpu_to_le32(x) bswap_32(x)
+#else
+#define cpu_to_le32(x) (x)
+#endif
+
+
 static MsnTable *cbs_table;
 
 /**************************************************************************
@@ -153,7 +170,7 @@ msn_notification_disconnect(MsnNotificat
  **************************************************************************/
 
 static void
-group_error_helper(MsnSession *session, const char *msg, int group_id, int error)
+group_error_helper(MsnSession *session, const char *msg, const char *group_id, int error)
 {
 	GaimAccount *account;
 	GaimConnection *gc;
@@ -165,7 +182,7 @@ group_error_helper(MsnSession *session, 
 
 	if (error == 224)
 	{
-		if (group_id == 0)
+		if (group_id == NULL)
 		{
 			return;
 		}
@@ -239,7 +256,6 @@ usr_cmd(MsnCmdProc *cmdproc, MsnCommand 
 
 		msn_session_set_login_step(session, MSN_LOGIN_STEP_SYN);
 
-		msn_cmdproc_send(cmdproc, "SYN", "%s", "0");
 	}
 	else if (!g_ascii_strcasecmp(cmd->params[1], "TWN"))
 	{
@@ -323,7 +339,7 @@ ver_cmd(MsnCmdProc *cmdproc, MsnCommand 
 	}
 
 	msn_cmdproc_send(cmdproc, "CVR",
-					 "0x0409 winnt 5.1 i386 MSNMSGR 6.0.0602 MSMSGS %s",
+					 "0x0409 winnt 5.1 i386 MSNMSGR 7.0.0813 MSMSGS %s",
 					 gaim_account_get_username(account));
 }
 
@@ -363,12 +379,32 @@ msg_cmd_post(MsnCmdProc *cmdproc, MsnCom
 			 size_t len)
 {
 	MsnMessage *msg;
+	const char *content_type;
 
 	msg = msn_message_new_from_cmd(cmdproc->session, cmd);
 
 	msn_message_parse_payload(msg, payload, len);
 	/* msn_message_show_readable(msg, "Notification", TRUE); */
 
+	/* Special case for multiple messages */
+	content_type = msn_message_get_content_type(msg);
+	if (content_type)
+	 {
+	   if (strcmp(content_type, "text/x-msnmsgr-datacast") == 0) {
+	      const char *nchunks;
+
+	      nchunks = msn_message_get_attr(msg, "Chunks");
+	      if (nchunks)
+	       {
+		 /* Oh no, it's a multipart message */
+		 /* So don't process it, and don't free it, but change the msg callback */
+		 
+
+
+
+	       }
+	   }
+	 }
 	msn_cmdproc_process_msg(cmdproc, msg);
 
 	msn_message_destroy(msg);
@@ -397,36 +433,124 @@ msg_cmd(MsnCmdProc *cmdproc, MsnCommand 
  * Challenges
  **************************************************************************/
 
+/* 
+ * These constants are use by the last MSN messenger 7.0.0813 for protocol
+ * version 11
+ */
+#define MSN_PRODUCT_ID "PROD0101{0RM?UBW"
+#define MSN_PRODUCT_KEY "CFHUR$52U_{VIX5T"
+#define MSN_MAGIC_NUM 0x0E79A9C1UL
+
 static void
 chl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnTransaction *trans;
-	char buf[33];
-	const char *challenge_resp;
+	char challenge_response[33];
+	const char *challenge;
 	GaimCipher *cipher;
 	GaimCipherContext *context;
 	guint8 digest[16];
-	int i;
+	unsigned int md5hashs[4];
+	unsigned int *mdbyint;
+	unsigned char *chlbychar;
+	unsigned char *chlstring;
+	unsigned int i, chlstringlen;
+	unsigned long long crchigh, crclow;	/* use 64 bits math */
+	static const char hexchars[]="0123456789abcdef";
 
-	cipher = gaim_ciphers_find_cipher("md5");
-	context = gaim_cipher_context_new(cipher, NULL);
 
-	gaim_cipher_context_append(context, cmd->params[1],
-							   strlen(cmd->params[1]));
+	challenge = cmd->params[1];
 
-	challenge_resp = "VT6PX?UQTM4WM%YR";
+	cipher = gaim_ciphers_find_cipher("md5");
+	context = gaim_cipher_context_new(cipher, NULL);
 
-	gaim_cipher_context_append(context, challenge_resp,
-							   strlen(challenge_resp));
+	gaim_cipher_context_append(context, challenge, strlen(challenge));
+	gaim_cipher_context_append(context, MSN_PRODUCT_KEY, strlen(MSN_PRODUCT_KEY));
 	gaim_cipher_context_digest(context, sizeof(digest), digest, NULL);
 	gaim_cipher_context_destroy(context);
 
-	for (i = 0; i < 16; i++)
-		g_snprintf(buf + (i*2), 3, "%02x", digest[i]);
+	for (i = 0; i <  4; i++) {
+	   /* Read in little endian format */
+	   unsigned int a;
+	   a = (digest[i*4+0]) 
+	     | (digest[i*4+1]<<8)
+	     | (digest[i*4+2]<<16)
+	     | (digest[i*4+3]<<24);
+	   md5hashs[i] = a & 0x7fffffff;
+	}
+
+	/* Concatenate and pad "challenge+MSN_PRODUCT_ID+00000" */
+	chlstringlen = strlen(challenge) + strlen(MSN_PRODUCT_ID);
+	chlstring = malloc(chlstringlen + 9);
+	if (chlstring == NULL)
+	  return;
+	memcpy(chlstring, challenge, strlen(challenge));
+	memcpy(chlstring+strlen(challenge), MSN_PRODUCT_ID, strlen(MSN_PRODUCT_ID));
+	while ( (chlstringlen % 8) )
+	 {
+	   chlstring[chlstringlen]='0';
+	   chlstringlen++;
+	 }
+
+	/* Make the key */
+	chlbychar = chlstring;
+	crchigh = crclow = 0;
+
+	for (i=0; i <(chlstringlen/4)-1; i+=2)
+	 {
+	   unsigned long long temp;
+	   /* read a 32 bits little endian */
+	   temp  = *chlbychar++;
+	   temp |= (*chlbychar++)<<8;
+	   temp |= (*chlbychar++)<<16;
+	   temp |= (*chlbychar++)<<24;
+	   temp *= MSN_MAGIC_NUM;
+	   temp %= 0x7FFFFFFF;
+	   temp += crchigh;
+	   temp *= md5hashs[0];
+	   temp += md5hashs[1];
+	   temp %= 0x7FFFFFFF;
+
+	   crchigh = *chlbychar++;
+	   crchigh |= (*chlbychar++)<<8;
+	   crchigh |= (*chlbychar++)<<16;
+	   crchigh |= (*chlbychar++)<<24;
+	   crchigh += temp;
+	   crchigh %= 0x7FFFFFFF;
+	   crchigh *= md5hashs[2];
+	   crchigh += md5hashs[3];
+	   crchigh %= 0x7FFFFFFF;
+
+	   crclow += crchigh;
+	   crclow += temp;
+
+	 }      
+	free(chlstring);
+
+	/* finalize the key */
+	crchigh = (crchigh + md5hashs[1]) % 0x7FFFFFFF;
+	crclow  = (crclow  + md5hashs[3]) % 0x7FFFFFFF;
+
+	/* convert the key in little endian mode */
+	crchigh = cpu_to_le32(crchigh);
+	crclow  = cpu_to_le32(crclow);
+
+	/* XOR two 64bits numbers with the key */
+	mdbyint = (unsigned int *)digest;
+
+	mdbyint[0] ^= crchigh;
+	mdbyint[1] ^= crclow;
+	mdbyint[2] ^= crchigh;
+	mdbyint[3] ^= crclow;
+
+	for (i=0; i<16; i++) {
+	   challenge_response[(i*2)+0] = hexchars[(digest[i]>>4)];
+	   challenge_response[(i*2)+1] = hexchars[digest[i]&0xF];
+	}
 
-	trans = msn_transaction_new(cmdproc, "QRY", "%s 32", "PROD0038W!61ZTF9");
+	trans = msn_transaction_new(cmdproc, "QRY", MSN_PRODUCT_ID" 32");
 
-	msn_transaction_set_payload(trans, buf, 32);
+	msn_transaction_set_payload(trans, challenge_response, 32);
 
 	msn_cmdproc_send_trans(cmdproc, trans);
 }
@@ -435,8 +559,13 @@ chl_cmd(MsnCmdProc *cmdproc, MsnCommand 
  * Buddy Lists
  **************************************************************************/
 
+/*
+ * Ack to op "Add a new contact to the list"
+ *
+ * msn: S: NS 000: ADC 0 RL N=pingus911@hotmail.com F=pingus
+ */
 static void
-add_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+adc_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSession *session;
 	MsnUser *user;
@@ -444,11 +573,13 @@ add_cmd(MsnCmdProc *cmdproc, MsnCommand 
 	const char *passport;
 	const char *friendly;
 	MsnListId list_id;
-	int group_id;
+	const char *group_id;
+	const char *contact_id;
 
 	list     = cmd->params[1];
-	passport = cmd->params[3];
-	friendly = gaim_url_decode(cmd->params[4]);
+	passport = cmd->params[2]+2;
+	friendly = gaim_url_decode(cmd->params[3]+2);
+	contact_id = cmd->params[4]+2;
 
 	session = cmdproc->session;
 
@@ -460,16 +591,21 @@ add_cmd(MsnCmdProc *cmdproc, MsnCommand 
 		msn_userlist_add_user(session->userlist, user);
 	}
 	else
+	{
 		msn_user_set_friendly_name(user, friendly);
+		msn_user_set_guid(user, contact_id);
+	}
 
 	list_id = msn_get_list_id(list);
 
-	if (cmd->param_count >= 6)
-		group_id = atoi(cmd->params[5]);
-	else
-		group_id = -1;
+	/*
+	 * FIXME (luc) Need to move the contact in the group selected. I hope
+	 * they are only one group in the list .
+	 */ 
+	group_id = NULL;
 
 	msn_got_add_user(session, user, list_id, group_id);
+	msn_user_set_state(user, "AWY");
 	msn_user_update(user);
 }
 
@@ -491,6 +627,8 @@ add_error(MsnCmdProc *cmdproc, MsnTransa
 
 	list     = params[0];
 	passport = params[1];
+	if (passport[0]=='N' && passport[1]=='=')
+		passport+=2;
 
 	if (!strcmp(list, "FL"))
 		msg = g_strdup_printf(_("Unable to add user on %s (%s)"),
@@ -548,19 +686,25 @@ add_error(MsnCmdProc *cmdproc, MsnTransa
 	g_strfreev(params);
 }
 
+/*
+ *
+ * Add a new group
+ *
+ * msn: S: NS 000: ADG 14 XXXXgroupnameXXX d5fcb271-4e4f-4011-9d66-0af4135885d8
+ */
 static void
 adg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnGroup *group;
 	MsnSession *session;
-	gint group_id;
+	const char *group_id;
 	const char *group_name;
 
 	session = cmdproc->session;
 
-	group_id = atoi(cmd->params[3]);
+	group_id = cmd->params[2];
 
-	group_name = gaim_url_decode(cmd->params[2]);
+	group_name = gaim_url_decode(cmd->params[1]);
 
 	group = msn_group_new(session->userlist, group_id, group_name);
 
@@ -650,6 +794,14 @@ ipg_cmd(MsnCmdProc *cmdproc, MsnCommand 
 	cmdproc->last_cmd->payload_cb = ipg_cmd_post;
 }
 
+/*
+ * msn: S: NS 000: NLN NLN xxxxxx@hotmail.com oezjfozjefeziojf 1073856548
+ * ...%3Cmsnobj%20Creator%3D%22xxxxxx%40hotmail.com%22%20Size%3D%2214850%22
+ * ...%20Type%3D%223%22%20Location%3D%22TFR10.dat%22%20Friendly%3D%22AAA%3D
+ * ...%22%20SHA1D%3D%22LU9e09HVMsArY6nIgkUK7RfyqQo%3D%22%20SHA1C%3D%22tRih5
+ * ...%2BAV2kpfn9iQ5DwbpL0%2F1NI%3D%22%2F%3E:w
+ *
+ */
 static void
 nln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
@@ -678,8 +830,8 @@ nln_cmd(MsnCmdProc *cmdproc, MsnCommand 
 	{
 		if (cmd->param_count == 5)
 		{
-			msnobj =
-				msn_object_new_from_string(gaim_url_decode(cmd->params[4]));
+		  	const char *objstr = gaim_url_decode(cmd->params[4]);
+			msnobj = msn_object_new_from_string(objstr);
 			msn_user_set_object(user, msnobj);
 		}
 		else
@@ -786,11 +938,11 @@ static void
 reg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSession *session;
-	int group_id;
+	const char *group_id;
 	const char *group_name;
 
 	session = cmdproc->session;
-	group_id = atoi(cmd->params[2]);
+	group_id = cmd->params[2];
 	group_name = gaim_url_decode(cmd->params[3]);
 
 	msn_userlist_rename_group_id(session->userlist, group_id, group_name);
@@ -799,12 +951,12 @@ reg_cmd(MsnCmdProc *cmdproc, MsnCommand 
 static void
 reg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
 {
-	int group_id;
+	const char *group_id;
 	char **params;
 
 	params = g_strsplit(trans->params, " ", 0);
 
-	group_id = atoi(params[0]);
+	group_id = params[0];
 
 	group_error_helper(cmdproc->session, _("Unable to rename group"), group_id, error);
 
@@ -819,7 +971,7 @@ rem_cmd(MsnCmdProc *cmdproc, MsnCommand 
 	const char *list;
 	const char *passport;
 	MsnListId list_id;
-	int group_id;
+	const char *group_id;
 
 	session = cmdproc->session;
 	list = cmd->params[1];
@@ -831,9 +983,9 @@ rem_cmd(MsnCmdProc *cmdproc, MsnCommand 
 	list_id = msn_get_list_id(list);
 
 	if (cmd->param_count == 5)
-		group_id = atoi(cmd->params[4]);
+		group_id = cmd->params[4];
 	else
-		group_id = -1;
+		group_id = NULL;
 
 	msn_got_rem_user(session, user, list_id, group_id);
 	msn_user_update(user);
@@ -843,10 +995,10 @@ static void
 rmg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSession *session;
-	int group_id;
+	const char *group_id;
 
 	session = cmdproc->session;
-	group_id = atoi(cmd->params[2]);
+	group_id = cmd->params[1];
 
 	msn_userlist_remove_group_id(session->userlist, group_id);
 }
@@ -854,12 +1006,12 @@ rmg_cmd(MsnCmdProc *cmdproc, MsnCommand 
 static void
 rmg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
 {
-	int group_id;
+	const char *group_id;
 	char **params;
 
 	params = g_strsplit(trans->params, " ", 0);
 
-	group_id = atoi(params[0]);
+	group_id = params[0];
 
 	group_error_helper(cmdproc->session, _("Unable to delete group"), group_id, error);
 
@@ -870,7 +1022,8 @@ static void
 syn_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSession *session;
-	int total_users;
+	int total_users, total_groups;
+	MsnSync *sync;
 
 	session = cmdproc->session;
 
@@ -886,24 +1039,18 @@ syn_cmd(MsnCmdProc *cmdproc, MsnCommand 
 		return;
 	}
 
-	total_users  = atoi(cmd->params[2]);
+	total_users  = atoi(cmd->params[3]);
+	total_groups  = atoi(cmd->params[4]);
 
-	if (total_users == 0)
-	{
-		msn_session_finish_login(session);
-	}
-	else
-	{
-		/* syn_table */
-		MsnSync *sync;
+	/* syn_table */
 
-		sync = msn_sync_new(session);
-		sync->total_users = total_users;
-		sync->old_cbs_table = cmdproc->cbs_table;
+	sync = msn_sync_new(session);
+	sync->total_users = total_users;
+	sync->total_groups = total_groups;
+	sync->old_cbs_table = cmdproc->cbs_table;
 
-		session->sync = sync;
-		cmdproc->cbs_table = sync->cbs_table;
-	}
+	session->sync = sync;
+	cmdproc->cbs_table = sync->cbs_table;
 }
 
 /**************************************************************************
@@ -1158,6 +1305,11 @@ profile_msg(MsnCmdProc *cmdproc, MsnMess
 
 	if ((value = msn_message_get_attr(msg, "LoginTime")) != NULL)
 		session->passport_info.sl = atol(value);
+
+
+	msn_session_set_login_step(session, MSN_LOGIN_STEP_SYN);
+	msn_cmdproc_send(cmdproc, "SYN", "0 0");
+
 }
 
 static void
@@ -1319,35 +1471,30 @@ system_msg(MsnCmdProc *cmdproc, MsnMessa
 void
 msn_notification_add_buddy(MsnNotification *notification, const char *list,
 						   const char *who, const char *store_name,
-						   int group_id)
+						   const char *group_id)
 {
 	MsnCmdProc *cmdproc;
 	cmdproc = notification->servconn->cmdproc;
 
-	if (group_id < 0 && !strcmp(list, "FL"))
-		group_id = 0;
+	if (group_id == NULL && !strcmp(list, "FL"))
+	 {
+		/* TODO Choose the first group ? */
+		group_id = NULL;
+	 }
 
-	if (group_id >= 0)
-	{
-		msn_cmdproc_send(cmdproc, "ADD", "%s %s %s %d",
-						 list, who, store_name, group_id);
-	}
-	else
-	{
-		msn_cmdproc_send(cmdproc, "ADD", "%s %s %s", list, who, store_name);
-	}
+	msn_cmdproc_send(cmdproc, "ADC", "%s N=%s F=%s", list, who, store_name);
 }
 
 void
 msn_notification_rem_buddy(MsnNotification *notification, const char *list,
-						   const char *who, int group_id)
+						   const char *who, const char *group_id)
 {
 	MsnCmdProc *cmdproc;
 	cmdproc = notification->servconn->cmdproc;
 
-	if (group_id >= 0)
+	if (group_id)
 	{
-		msn_cmdproc_send(cmdproc, "REM", "%s %s %d", list, who, group_id);
+		msn_cmdproc_send(cmdproc, "REM", "%s %s %s", list, who, group_id);
 	}
 	else
 	{
@@ -1355,6 +1502,43 @@ msn_notification_rem_buddy(MsnNotificati
 	}
 }
 
+static void
+ubx_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+			 size_t len)
+{
+	MsnMessage *msg;
+
+	msg = msn_message_new_from_cmd(cmdproc->session, cmd);
+
+	/* What do to do with this type of message ? */
+	//msn_message_parse_payload(msg, payload, len);
+	//msn_cmdproc_process_msg(cmdproc, msg);
+	gaim_debug_misc("msn", "ubx_cmd [%s]\n", payload);
+
+	msn_message_destroy(msg);
+}
+
+static void
+ubx_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	/* 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  = ubx_cmd_post;
+		cmdproc->servconn->payload_len = atoi(cmd->params[1]);
+	}
+	else
+	{
+		g_return_if_fail(cmd->payload_cb != NULL);
+		gaim_debug_misc("msn", "ARGHHHHHHHHH ubx_cmd why to do in this place\n");
+
+	}
+}
+
+
+
 /**************************************************************************
  * Init
  **************************************************************************/
@@ -1369,8 +1553,8 @@ msn_notification_init(void)
 	/* Synchronous */
 	msn_table_add_cmd(cbs_table, "CHG", "CHG", chg_cmd);
 	msn_table_add_cmd(cbs_table, "CHG", "ILN", iln_cmd);
-	msn_table_add_cmd(cbs_table, "ADD", "ADD", add_cmd);
-	msn_table_add_cmd(cbs_table, "ADD", "ILN", iln_cmd);
+	msn_table_add_cmd(cbs_table, "ADC", "ADC", adc_cmd);
+	msn_table_add_cmd(cbs_table, "ADC", "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);
@@ -1393,8 +1577,9 @@ msn_notification_init(void)
 
 	msn_table_add_cmd(cbs_table, NULL, "CHL", chl_cmd);
 	msn_table_add_cmd(cbs_table, NULL, "REM", rem_cmd);
-	msn_table_add_cmd(cbs_table, NULL, "ADD", add_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "ADC", adc_cmd);
 
+	msn_table_add_cmd(cbs_table, NULL, "SBS", NULL);
 	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);
@@ -1402,12 +1587,14 @@ msn_notification_init(void)
 	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, "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, "ADC", 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); */
Index: src/protocols/msn/notification.h
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/notification.h,v
retrieving revision 1.9
diff -u -p -r1.9 notification.h
--- src/protocols/msn/notification.h	7 Jan 2005 02:48:33 -0000	1.9
+++ src/protocols/msn/notification.h	30 Jun 2005 23:12:35 -0000
@@ -46,10 +46,10 @@ void msn_notification_init(void);
 
 void msn_notification_add_buddy(MsnNotification *notification,
 								const char *list, const char *who,
-								const char *store_name, int group_id);
+								const char *store_name, const char *group_id);
 void msn_notification_rem_buddy(MsnNotification *notification,
 								const char *list, const char *who,
-								int group_id);
+								const char *group_id);
 MsnNotification *msn_notification_new(MsnSession *session);
 void msn_notification_destroy(MsnNotification *notification);
 gboolean msn_notification_connect(MsnNotification *notification,
Index: src/protocols/msn/session.c
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/session.c,v
retrieving revision 1.45
diff -u -p -r1.45 session.c
--- src/protocols/msn/session.c	9 May 2005 12:43:52 -0000	1.45
+++ src/protocols/msn/session.c	30 Jun 2005 23:12:36 -0000
@@ -44,7 +44,7 @@ msn_session_new(GaimAccount *account)
 	session->user = msn_user_new(session->userlist,
 								 gaim_account_get_username(account), NULL);
 
-	session->protocol_ver = 9;
+	session->protocol_ver = 11;
 	session->conv_seq = 1;
 
 	return session;
@@ -262,20 +262,20 @@ msn_session_sync_users(MsnSession *sessi
 				for (l = local_user->group_ids; l != NULL; l = l->next)
 				{
 					const char *group_name;
-					int gid;
+					const char *gid;
 					gboolean found = FALSE;
 					GList *l2;
 
 					group_name =
 						msn_userlist_find_group_name(local_user->userlist,
-													 GPOINTER_TO_INT(l->data));
+													 l->data);
 
 					gid = msn_userlist_find_group_id(remote_user->userlist,
 													 group_name);
 
 					for (l2 = remote_user->group_ids; l2 != NULL; l2 = l2->next)
 					{
-						if (GPOINTER_TO_INT(l2->data) == gid)
+						if (strcmp(l2->data, gid) == 0)
 						{
 							found = TRUE;
 							break;
Index: src/protocols/msn/switchboard.c
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/switchboard.c,v
retrieving revision 1.101
diff -u -p -r1.101 switchboard.c
--- src/protocols/msn/switchboard.c	10 Apr 2005 16:49:05 -0000	1.101
+++ src/protocols/msn/switchboard.c	30 Jun 2005 23:12:39 -0000
@@ -741,23 +741,125 @@ joi_cmd(MsnCmdProc *cmdproc, MsnCommand 
 		msn_switchboard_close(swboard);
 }
 
+static int
+msg_compare_message_id(gconstpointer a, gconstpointer b)
+{
+	const MsnMessage *msga = a;
+	const char *msgida, *msgidb = b;
+
+	msgida = msn_message_get_attr(msga, "Message-ID");
+
+	return strcmp(msgida, msgidb);
+}
+
 static void
 msg_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len)
 {
-	MsnMessage *msg;
+	MsnMessage *msg, *msgroot;
+	MsnSwitchBoard *swboard;
+	const char *message_id;
+	const char *content_type;
+	const char *chuncks_value;
+	const char *chunck_value;
+	int nchunks, chunk;
+	const void *body;
+        size_t bodylen;
 
 	msg = msn_message_new_from_cmd(cmdproc->session, cmd);
 
 	msn_message_parse_payload(msg, payload, len);
-	/* msn_message_show_readable(msg, "SB RECV", FALSE); */
+	msn_message_show_readable(msg, "SB RECV", FALSE);
 
 	if (msg->remote_user != NULL)
 		g_free (msg->remote_user);
 
 	msg->remote_user = g_strdup(cmd->params[0]);
-	msn_cmdproc_process_msg(cmdproc, msg);
+	swboard = cmdproc->data;
 
-	msn_message_destroy(msg);
+	/*
+	 * When sending multipart message, the other part of the message
+	 * doesn't contains a content-type, but a message ID. So search in the
+	 * list of previous messages receved if we found this messageID.
+	 */
+	content_type = msn_message_get_content_type(msg);
+	if (content_type == NULL)
+	{
+	  message_id = msn_message_get_attr(msg, "Message-ID");
+	  chunck_value = msn_message_get_attr(msg, "Chunk");
+	  if (message_id && chunck_value)
+	   {
+	     /* I'ts another part of a previous message */
+	     GSList *elem = g_slist_find_custom(swboard->multipart_list,
+		 				message_id, 
+		 				msg_compare_message_id);
+
+	     if (elem == NULL)
+	      {
+		gaim_debug_error("msn", "This message seems to be %s"
+		   " part a previous message. But i found no reference for a"
+		   " previous message using this Message-ID: %s\n", 
+		   chunck_value, message_id);
+		 msn_message_destroy(msg);
+		 return;
+	      }
+	     msgroot = elem->data;
+	     nchunks = atoi(msn_message_get_attr(msgroot, "Chunks"));
+	     nchunks--;
+	     chunk = atoi(chunck_value);
+
+	     gaim_debug_info("msn", "This message is a multipart message %d/%d\n",
+		 	     chunk, nchunks);
+
+	     /* append the body, to our previous body */
+	     body = msn_message_get_bin_data(msg, &bodylen);
+	     msn_message_add_bin_data(msgroot, body, bodylen);
+
+	     /* Check if this is the last part of the message */
+
+	     if (nchunks == chunk)
+	      {
+		/* Ok this is the last part of the message, so process it */
+		msn_cmdproc_process_msg(cmdproc, msgroot);
+
+		swboard->multipart_list = g_slist_remove(swboard->multipart_list, msgroot);
+
+	      }
+	     msn_message_destroy(msg);
+	     return;
+	   }
+	}
+
+	/* Is it a multipart message ? */
+	chuncks_value = msn_message_get_attr(msg, "Chunks");
+	if (   strcmp(content_type, "text/x-msnmsgr-datacast") == 0
+	    && chuncks_value != NULL)
+	 {
+	   /* Ok, we have the first part of a multipart message */
+	   /* Try to verify if this message is not already in the list */
+	   message_id = msn_message_get_attr(msg, "Message-ID");
+	   if (message_id)
+	    {
+	      GSList *elem = g_slist_find_custom(swboard->multipart_list,
+		 				 message_id, 
+						 msg_compare_message_id);
+
+	      if (elem)
+	       {
+		 gaim_debug_error("msn", "Try to add a new MSG with the same Message-ID\n");
+		 msn_message_destroy(msg);
+		 return;
+	       }
+	    }
+	   gaim_debug_info("msn", "This message is a multipart message."
+	       "This message to complete needs %s parts\n", chuncks_value);
+	   swboard->multipart_list= g_slist_append(swboard->multipart_list, msg);
+	 }
+	else
+        {
+	  /* Process this message */
+	  msn_cmdproc_process_msg(cmdproc, msg);
+	  msn_message_destroy(msg);
+	}
 }
 
 static void
@@ -962,6 +1064,84 @@ clientcaps_msg(MsnCmdProc *cmdproc, MsnM
 #endif
 }
 
+static void
+msn_datacast_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
+{
+    MsnSession *session;
+    MsnSwitchBoard *swboard;
+    MsnUser *user;
+    MsnObject *msnobj;
+    GHashTable *table;
+    const char *typeid, *data;
+    char *passport = msg->remote_user;
+
+    session = cmdproc->session;
+    swboard = cmdproc->data;
+
+    msn_message_show_readable(msg, passport, TRUE);
+
+    table = msn_message_get_hashtable_from_body(msg);
+
+    typeid = g_hash_table_lookup(table, "ID");
+    if (typeid == NULL)
+      goto free_hashtable;
+
+    if (strcmp(typeid, "1") == 0) {
+
+       gaim_debug_info("msn", "%s has sent to you a nudge\n", passport);
+
+    } else if (strcmp(typeid, "2") == 0) {
+
+       gaim_debug_info("msn", "%s has sent to you a wink but you need to have flash support\n", passport);
+
+       data = g_hash_table_lookup(table, "Data");
+       if (data == NULL)
+	 goto free_hashtable;
+
+       msnobj = msn_object_new_from_string(data);
+
+       gaim_debug_info("msn", "details:\n%s\n" , msn_object_to_string(msnobj));
+
+       msn_object_destroy(msnobj);
+
+    }
+
+free_hashtable:
+  g_hash_table_destroy(table);
+
+}
+
+static void
+send_wink(MsnSwitchBoard *swboard)
+{
+	MsnMessage *msg;
+
+	msg = msn_message_new(MSN_MSG_WINK);
+	msn_message_set_content_type(msg, "text/x-msnmsgr-datacast");
+	msn_message_set_flag(msg, 'U');
+	//msn_message_set_bin_data(msg, MSN_CLIENTINFO, strlen(MSN_CLIENTINFO));
+
+	//msn_switchboard_send_msg(swboard, msg, TRUE);
+
+	msn_message_destroy(msg);
+}
+
+static void
+send_nudge(MsnSwitchBoard *swboard)
+{
+	MsnMessage *msg;
+
+	msg = msn_message_new(MSN_MSG_NUDGE);
+	msn_message_set_content_type(msg, "text/x-msnmsgr-datacast");
+	msn_message_set_flag(msg, 'U');
+	//msn_message_set_bin_data(msg, MSN_CLIENTINFO, strlen(MSN_CLIENTINFO));
+
+	//msn_switchboard_send_msg(swboard, msg, TRUE);
+
+	msn_message_destroy(msg);
+}
+
+
 /**************************************************************************
  * Connect stuff
  **************************************************************************/
@@ -1240,6 +1420,8 @@ msn_switchboard_init(void)
 						   msn_p2p_msg);
 	msn_table_add_msg_type(cbs_table, "text/x-mms-emoticon",
 						   msn_emoticon_msg);
+	msn_table_add_msg_type(cbs_table, "text/x-msnmsgr-datacast",
+						   msn_datacast_msg);
 #if 0
 	msn_table_add_msg_type(cbs_table, "text/x-msmmsginvite",
 						   msn_invite_msg);
Index: src/protocols/msn/switchboard.h
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/switchboard.h,v
retrieving revision 1.24
diff -u -p -r1.24 switchboard.h
--- src/protocols/msn/switchboard.h	2 Apr 2005 16:38:33 -0000	1.24
+++ src/protocols/msn/switchboard.h	30 Jun 2005 23:12:40 -0000
@@ -96,6 +96,7 @@ struct _MsnSwitchBoard
 
 	int chat_id;
 
+	GSList *multipart_list; /**< List of multi-part messages not completed. */
 	GQueue *msg_queue; /**< Queue of messages to send. */
 	GList *ack_list; /**< List of messages waiting for an ack. */
 
Index: src/protocols/msn/sync.c
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/sync.c,v
retrieving revision 1.6
diff -u -p -r1.6 sync.c
--- src/protocols/msn/sync.c	30 Dec 2004 15:55:19 -0000	1.6
+++ src/protocols/msn/sync.c	30 Jun 2005 23:12:40 -0000
@@ -54,11 +54,30 @@ blp_cmd(MsnCmdProc *cmdproc, MsnCommand 
 		 */
 		gc->account->perm_deny = GAIM_PRIVACY_ALLOW_USERS;
 	}
+
+	//msn_cmdproc_send(cmdproc, "GCF", "Shields.xml", "0");
+
+}
+
+static void msn_check_sync_done(MsnCmdProc *cmdproc)
+{
+  MsnSession *session = cmdproc->session;
+
+  if (   session->sync->num_users == session->sync->total_users
+      && session->sync->num_groups == session->sync->total_groups)
+   {
+     cmdproc->cbs_table = session->sync->old_cbs_table;
+     msn_session_finish_login(session);
+
+     msn_sync_destroy(session->sync);
+     session->sync = NULL;
+   }
 }
 
 static void
 prp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
+	GaimConnection *gc = cmdproc->session->account->gc;
 	MsnSession *session = cmdproc->session;
 	const char *type, *value;
 
@@ -73,6 +92,25 @@ prp_cmd(MsnCmdProc *cmdproc, MsnCommand 
 			msn_user_set_work_phone(session->user, gaim_url_decode(value));
 		else if (!strcmp(type, "PHM"))
 			msn_user_set_mobile_phone(session->user, gaim_url_decode(value));
+		else if (!strcmp(type, "MFN"))
+			gaim_connection_set_display_name(gc, gaim_url_decode(value));
+		else if (!strcmp(type, "MBE"))
+			msn_user_set_mobile_enable(session->user, strcmp(value, "Y")==0);
+		else if (!strcmp(type, "WWE"))
+		{
+		  /*
+		   * What to do with WWE ? according to the documentation is
+		   * like MBE. For now, do nothing
+		   */
+
+		  /* 
+		   * Sometimes, we don't have a list of users, so switch to the
+		   * notification table. Becase WWE is the last command sent by
+		   * the server.
+		   */
+		  msn_check_sync_done(cmdproc);
+
+		}
 	}
 	else
 	{
@@ -92,15 +130,15 @@ lsg_cmd(MsnCmdProc *cmdproc, MsnCommand 
 	MsnGroup *group;
 	GaimGroup *g;
 	const char *name;
-	int group_id;
+	const char *group_id;
 
-	group_id = atoi(cmd->params[0]);
-	name = gaim_url_decode(cmd->params[1]);
+	name = gaim_url_decode(cmd->params[0]);
+	group_id = cmd->params[1];
 
 	group = msn_group_new(session->userlist, group_id, name);
 
 	/* HACK */
-	if (group_id == 0)
+	if (group_id == NULL)
 		/* Group of ungroupped buddies */
 		return;
 
@@ -109,20 +147,48 @@ lsg_cmd(MsnCmdProc *cmdproc, MsnCommand 
 		g = gaim_group_new(name);
 		gaim_blist_add_group(g, NULL);
 	}
+
+	session->sync->num_groups++;
+
+	msn_check_sync_done(cmdproc);
 }
 
+static void msn_free_group_id(void *group_id, gpointer unused)
+{
+  free(group_id);
+}
+
+/*
+ *
+ * msn: S: NS 000: LST N=xxxxxxxxxxx@hotmail.com F=zzz C=<GUID> 11 <GUID>,<GUID>
+ * msn: S: NS 000: LST N=xxxxxxxxx@hotmail.com F=zzzzzz 16
+ *
+ */
 static void
 lst_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSession *session = cmdproc->session;
-	char *passport = NULL;
+	const char *passport = NULL;
 	const char *friend = NULL;
+	const char *cuid = NULL;
 	int list_op;
 	MsnUser *user;
-
-	passport = cmd->params[0];
-	friend   = gaim_url_decode(cmd->params[1]);
-	list_op  = atoi(cmd->params[2]);
+	int i = 0;
+	
+	
+	while (1)
+	 {
+	   if (strncmp(cmd->params[i], "N=", 2)==0)
+	     passport = cmd->params[i]+2;	/* skip the N= */
+	   else if (strncmp(cmd->params[i], "F=", 2)==0)
+	     friend   = gaim_url_decode(cmd->params[1]+2);	/* skip the F= */
+	   else if (strncmp(cmd->params[i], "C=", 2)==0)
+	     cuid     = cmd->params[i]+2;	/* skip the C= */
+	   else
+	     break;
+	   i++;
+	 }
+	list_op  = atoi(cmd->params[i]);
 
 	user = msn_user_new(session->userlist, passport, friend);
 
@@ -132,14 +198,14 @@ lst_cmd(MsnCmdProc *cmdproc, MsnCommand 
 
 	/* TODO: This can be improved */
 
-	if (list_op & MSN_LIST_FL_OP)
+	if (list_op & MSN_LIST_FL_OP && cmd->param_count == 5)
 	{
 		char **c;
 		char **tokens;
 		const char *group_nums;
 		GSList *group_ids;
 
-		group_nums = cmd->params[3];
+		group_nums = cmd->params[4];
 
 		group_ids = NULL;
 
@@ -147,16 +213,15 @@ lst_cmd(MsnCmdProc *cmdproc, MsnCommand 
 
 		for (c = tokens; *c != NULL; c++)
 		{
-			int id;
-
-			id = atoi(*c);
-			group_ids = g_slist_append(group_ids, GINT_TO_POINTER(id));
+			const char *gid = *c;
+			group_ids = g_slist_append(group_ids, g_strdup(gid));
 		}
 
 		g_strfreev(tokens);
 
 		msn_got_lst_user(session, user, list_op, group_ids);
 
+		g_slist_foreach(group_ids, msn_free_group_id, NULL);
 		g_slist_free(group_ids);
 	}
 	else
@@ -166,15 +231,7 @@ lst_cmd(MsnCmdProc *cmdproc, MsnCommand 
 
 	session->sync->num_users++;
 
-	if (session->sync->num_users == session->sync->total_users)
-	{
-		cmdproc->cbs_table = session->sync->old_cbs_table;
-
-		msn_session_finish_login(session);
-
-		msn_sync_destroy(session->sync);
-		session->sync = NULL;
-	}
+	msn_check_sync_done(cmdproc);
 }
 
 static void
Index: src/protocols/msn/user.c
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/user.c,v
retrieving revision 1.25
diff -u -p -r1.25 user.c
--- src/protocols/msn/user.c	12 Mar 2005 01:10:37 -0000	1.25
+++ src/protocols/msn/user.c	30 Jun 2005 23:12:41 -0000
@@ -50,6 +50,11 @@ msn_user_new(MsnUserList *userlist, cons
 	return user;
 }
 
+static void msn_free_group_id(void *group_id, gpointer unused)
+{
+  free(group_id);
+}
+
 void
 msn_user_destroy(MsnUser *user)
 {
@@ -59,7 +64,10 @@ msn_user_destroy(MsnUser *user)
 		g_hash_table_destroy(user->clientcaps);
 
 	if (user->group_ids != NULL)
+	{
+		g_list_foreach(user->group_ids, msn_free_group_id, NULL);
 		g_list_free(user->group_ids);
+	}
 
 	if (user->msnobj != NULL)
 		msn_object_destroy(user->msnobj);
@@ -73,6 +81,9 @@ msn_user_destroy(MsnUser *user)
 	if (user->store_name != NULL)
 		g_free(user->store_name);
 
+	if (user->guid != NULL)
+		g_free(user->guid);
+
 	if (user->phone.home != NULL)
 		g_free(user->phone.home);
 
@@ -162,6 +173,17 @@ msn_user_set_store_name(MsnUser *user, c
 }
 
 void
+msn_user_set_guid(MsnUser *user, const char *guid)
+{
+	g_return_if_fail(user != NULL);
+
+	if (user->guid != NULL)
+		g_free(user->guid);
+
+	user->guid = g_strdup(guid);
+}
+
+void
 msn_user_set_buddy_icon(MsnUser *user, const char *filename)
 {
 	struct stat st;
@@ -244,7 +266,7 @@ msn_user_set_buddy_icon(MsnUser *user, c
 }
 
 void
-msn_user_add_group_id(MsnUser *user, int id)
+msn_user_add_group_id(MsnUser *user, const char *id)
 {
 	MsnUserList *userlist;
 	GaimAccount *account;
@@ -254,9 +276,9 @@ msn_user_add_group_id(MsnUser *user, int
 	const char *group_name;
 
 	g_return_if_fail(user != NULL);
-	g_return_if_fail(id >= 0);
+	g_return_if_fail(id != NULL);
 
-	user->group_ids = g_list_append(user->group_ids, GINT_TO_POINTER(id));
+	user->group_ids = g_list_append(user->group_ids, g_strdup(id));
 
 	userlist = user->userlist;
 	account = userlist->session->account;
@@ -266,7 +288,7 @@ msn_user_add_group_id(MsnUser *user, int
 
 	g = gaim_find_group(group_name);
 
-	if ((id == 0) && (g == NULL))
+	if ((strcmp(id,"00000000-0000-0000-0000-000000000000") == 0) && (g == NULL))
 	{
 		g = gaim_group_new(group_name);
 		gaim_blist_add_group(g, NULL);
@@ -285,12 +307,12 @@ msn_user_add_group_id(MsnUser *user, int
 }
 
 void
-msn_user_remove_group_id(MsnUser *user, int id)
+msn_user_remove_group_id(MsnUser *user, const char *id)
 {
 	g_return_if_fail(user != NULL);
-	g_return_if_fail(id >= 0);
+	g_return_if_fail(id != NULL);
 
-	user->group_ids = g_list_remove(user->group_ids, GINT_TO_POINTER(id));
+	user->group_ids = g_list_remove(user->group_ids, id);
 }
 
 void
@@ -352,6 +374,15 @@ msn_user_set_client_caps(MsnUser *user, 
 	user->clientcaps = info;
 }
 
+void
+msn_user_set_mobile_enable(MsnUser *user, int enable)
+{
+	g_return_if_fail(user != NULL);
+
+	user->phone.enable = enable;
+}
+
+
 const char *
 msn_user_get_passport(const MsnUser *user)
 {
Index: src/protocols/msn/user.h
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/user.h,v
retrieving revision 1.16
diff -u -p -r1.16 user.h
--- src/protocols/msn/user.h	30 Dec 2004 15:55:19 -0000	1.16
+++ src/protocols/msn/user.h	30 Jun 2005 23:12:41 -0000
@@ -44,6 +44,7 @@ struct _MsnUser
 	char *passport;         /**< The passport account.          */
 	char *store_name;       /**< The name stored in the server. */
 	char *friendly_name;    /**< The friendly name.             */
+	char *guid;		/**< Unique identifier (GUID)       */
 
 	const char *status;     /**< The state of the user.         */
 	gboolean idle;          /**< The idle state of the user.    */
@@ -53,6 +54,7 @@ struct _MsnUser
 		char *home;         /**< Home phone number.             */
 		char *work;         /**< Work phone number.             */
 		char *mobile;       /**< Mobile phone number.           */
+		int   enable;       /**< Mobile phone enable.           */
 
 	} phone;
 
@@ -135,6 +137,14 @@ void msn_user_set_friendly_name(MsnUser 
 void msn_user_set_store_name(MsnUser *user, const char *name);
 
 /**
+ * Sets the GUID for a user.
+ *
+ * @param user The user.
+ * @param guid The GUID.
+ */
+void msn_user_set_guid(MsnUser *user, const char *guid);
+
+/**
  * Sets the buddy icon for a local user.
  *
  * @param user     The user.
@@ -156,7 +166,7 @@ void msn_user_set_group_ids(MsnUser *use
  * @param user The user.
  * @param id   The group ID.
  */
-void msn_user_add_group_id(MsnUser *user, int id);
+void msn_user_add_group_id(MsnUser *user, const char *id);
 
 /**
  * Removes the group ID from a user.
@@ -164,7 +174,7 @@ void msn_user_add_group_id(MsnUser *user
  * @param user The user.
  * @param id   The group ID.
  */
-void msn_user_remove_group_id(MsnUser *user, int id);
+void msn_user_remove_group_id(MsnUser *user, const char *id);
 
 /**
  * Sets the home phone number for a user.
@@ -206,6 +216,14 @@ void msn_user_set_object(MsnUser *user, 
  */
 void msn_user_set_client_caps(MsnUser *user, GHashTable *info);
 
+/**
+ * Sets if the mobile phone can be use for a user.
+ *
+ * @param user   The user.
+ * @param enable 1 (for enable) or 0 (for disabled)
+ */
+void msn_user_set_mobile_enable(MsnUser *user, int enable);
+
 
 /**
  * Returns the passport account for a user.
Index: src/protocols/msn/userlist.c
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/userlist.c,v
retrieving revision 1.25
diff -u -p -r1.25 userlist.c
--- src/protocols/msn/userlist.c	2 Apr 2005 17:18:42 -0000	1.25
+++ src/protocols/msn/userlist.c	30 Jun 2005 23:12:42 -0000
@@ -108,22 +108,22 @@ got_new_entry(GaimConnection *gc, const 
  **************************************************************************/
 
 static gboolean
-user_is_in_group(MsnUser *user, int group_id)
+user_is_in_group(MsnUser *user, const char *group_id)
 {
 	if (user == NULL)
 		return FALSE;
 
-	if (group_id < 0)
+	if (group_id == NULL)
 		return FALSE;
 
-	if (g_list_find(user->group_ids, GINT_TO_POINTER(group_id)))
+	if (g_list_find(user->group_ids, group_id))
 		return TRUE;
 
 	return FALSE;
 }
 
 static gboolean
-user_is_there(MsnUser *user, int list_id, int group_id)
+user_is_there(MsnUser *user, int list_id, const char *group_id)
 {
 	int list_op;
 
@@ -137,7 +137,7 @@ user_is_there(MsnUser *user, int list_id
 
 	if (list_id == MSN_LIST_FL)
 	{
-		if (group_id >= 0)
+		if (group_id)
 			return user_is_in_group(user, group_id);
 	}
 
@@ -218,7 +218,7 @@ msn_get_list_id(const char *list)
 
 void
 msn_got_add_user(MsnSession *session, MsnUser *user,
-				 MsnListId list_id, int group_id)
+				 MsnListId list_id, const char *group_id)
 {
 	GaimAccount *account;
 	const char *passport;
@@ -237,7 +237,7 @@ msn_got_add_user(MsnSession *session, Ms
 
 		serv_got_alias(gc, passport, friendly);
 
-		if (group_id >= 0)
+		if (group_id)
 		{
 			msn_user_add_group_id(user, group_id);
 			return;
@@ -277,7 +277,7 @@ msn_got_add_user(MsnSession *session, Ms
 
 void
 msn_got_rem_user(MsnSession *session, MsnUser *user,
-				 MsnListId list_id, int group_id)
+				 MsnListId list_id, const char *group_id)
 {
 	GaimAccount *account;
 	const char *passport;
@@ -289,7 +289,7 @@ msn_got_rem_user(MsnSession *session, Ms
 	if (list_id == MSN_LIST_FL)
 	{
 		/* TODO: When is the user totally removed? */
-		if (group_id >= 0)
+		if (group_id)
 		{
 			msn_user_remove_group_id(user, group_id);
 			return;
@@ -345,8 +345,8 @@ msn_got_lst_user(MsnSession *session, Ms
 		GSList *c;
 		for (c = group_ids; c != NULL; c = g_slist_next(c))
 		{
-			int group_id;
-			group_id = GPOINTER_TO_INT(c->data);
+			const char *group_id;
+			group_id = c->data;
 			msn_user_add_group_id(user, group_id);
 		}
 
@@ -480,18 +480,18 @@ msn_userlist_remove_group(MsnUserList *u
 }
 
 MsnGroup *
-msn_userlist_find_group_with_id(MsnUserList *userlist, int id)
+msn_userlist_find_group_with_id(MsnUserList *userlist, const char *id)
 {
 	GList *l;
 
 	g_return_val_if_fail(userlist != NULL, NULL);
-	g_return_val_if_fail(id       >= 0,    NULL);
+	g_return_val_if_fail(id       != NULL, NULL);
 
 	for (l = userlist->groups; l != NULL; l = l->next)
 	{
 		MsnGroup *group = l->data;
 
-		if (group->id == id)
+		if (strcmp(group->id, id) == 0)
 			return group;
 	}
 
@@ -517,7 +517,7 @@ msn_userlist_find_group_with_name(MsnUse
 	return NULL;
 }
 
-int
+const char *
 msn_userlist_find_group_id(MsnUserList *userlist, const char *group_name)
 {
 	MsnGroup *group;
@@ -527,11 +527,11 @@ msn_userlist_find_group_id(MsnUserList *
 	if (group != NULL)
 		return msn_group_get_id(group);
 	else
-		return -1;
+		return NULL;
 }
 
 const char *
-msn_userlist_find_group_name(MsnUserList *userlist, int group_id)
+msn_userlist_find_group_name(MsnUserList *userlist, const char *group_id)
 {
 	MsnGroup *group;
 
@@ -544,7 +544,7 @@ msn_userlist_find_group_name(MsnUserList
 }
 
 void
-msn_userlist_rename_group_id(MsnUserList *userlist, int group_id,
+msn_userlist_rename_group_id(MsnUserList *userlist, const char *group_id,
 							 const char *new_name)
 {
 	MsnGroup *group;
@@ -556,7 +556,7 @@ msn_userlist_rename_group_id(MsnUserList
 }
 
 void
-msn_userlist_remove_group_id(MsnUserList *userlist, int group_id)
+msn_userlist_remove_group_id(MsnUserList *userlist, const char *group_id)
 {
 	MsnGroup *group;
 
@@ -574,17 +574,17 @@ msn_userlist_rem_buddy(MsnUserList *user
 					   const char *who, int list_id, const char *group_name)
 {
 	MsnUser *user;
-	int group_id;
+	const char *group_id;
 	const char *list;
 
 	user = msn_userlist_find_user(userlist, who);
-	group_id = -1;
+	group_id = NULL;
 
 	if (group_name != NULL)
 	{
 		group_id = msn_userlist_find_group_id(userlist, group_name);
 
-		if (group_id < 0)
+		if (group_id == NULL)
 		{
 			/* Whoa, there is no such group. */
 			gaim_debug_error("msn", "Group doesn't exist: %s\n", group_name);
@@ -613,22 +613,20 @@ msn_userlist_add_buddy(MsnUserList *user
 					   const char *group_name)
 {
 	MsnUser *user;
-	int group_id;
+	const char *group_id;
 	const char *list;
 	const char *store_name;
 
-	group_id = -1;
+	group_id = NULL;
 
 	if (group_name != NULL)
-	{
 		group_id = msn_userlist_find_group_id(userlist, group_name);
 
-		if (group_id < 0)
-		{
-			/* Whoa, we must add that group first. */
-			msn_request_add_group(userlist, who, NULL, group_name);
-			return;
-		}
+	if (group_id == NULL)
+	{
+		/* Whoa, we must add that group first. */
+		msn_request_add_group(userlist, who, NULL, group_name);
+		return;
 	}
 
 	user = msn_userlist_find_user(userlist, who);
@@ -654,11 +652,11 @@ void
 msn_userlist_move_buddy(MsnUserList *userlist, const char *who,
 						const char *old_group_name, const char *new_group_name)
 {
-	int new_group_id;
+	const char *new_group_id;
 
 	new_group_id = msn_userlist_find_group_id(userlist, new_group_name);
 
-	if (new_group_id < 0)
+	if (new_group_id == NULL)
 	{
 		msn_request_add_group(userlist, who, old_group_name, new_group_name);
 		return;
Index: src/protocols/msn/userlist.h
===================================================================
RCS file: /cvsroot/gaim/gaim/src/protocols/msn/userlist.h,v
retrieving revision 1.3
diff -u -p -r1.3 userlist.h
--- src/protocols/msn/userlist.h	25 Aug 2004 01:43:54 -0000	1.3
+++ src/protocols/msn/userlist.h	30 Jun 2005 23:12:42 -0000
@@ -66,9 +66,9 @@ struct _MsnUserList
 MsnListId msn_get_list_id(const char *list);
 
 void msn_got_add_user(MsnSession *session, MsnUser *user,
-					  MsnListId list_id, int group_id);
+					  MsnListId list_id, const char *group_id);
 void msn_got_rem_user(MsnSession *session, MsnUser *user,
-					  MsnListId list_id, int group_id);
+					  MsnListId list_id, const char *group_id);
 void msn_got_lst_user(MsnSession *session, MsnUser *user,
 					  int list_op, GSList *group_ids);
 
@@ -80,16 +80,16 @@ MsnUser *msn_userlist_find_user(MsnUserL
 								const char *passport);
 void msn_userlist_add_group(MsnUserList *userlist, MsnGroup *group);
 void msn_userlist_remove_group(MsnUserList *userlist, MsnGroup *group);
-MsnGroup *msn_userlist_find_group_with_id(MsnUserList *userlist, int id);
+MsnGroup *msn_userlist_find_group_with_id(MsnUserList *userlist, const char *id);
 MsnGroup *msn_userlist_find_group_with_name(MsnUserList *userlist,
 											const char *name);
-int msn_userlist_find_group_id(MsnUserList *userlist,
+const char *msn_userlist_find_group_id(MsnUserList *userlist,
 							   const char *group_name);
 const char *msn_userlist_find_group_name(MsnUserList *userlist,
-										 int group_id);
-void msn_userlist_rename_group_id(MsnUserList *userlist, int group_id,
+										 const char *group_id);
+void msn_userlist_rename_group_id(MsnUserList *userlist, const char *group_id,
 								  const char *new_name);
-void msn_userlist_remove_group_id(MsnUserList *userlist, int group_id);
+void msn_userlist_remove_group_id(MsnUserList *userlist, const char *group_id);
 
 void msn_userlist_rem_buddy(MsnUserList *userlist, const char *who,
 							int list_id, const char *group_name);

