changeset 26921:3e83f63b16b4

merge of '1696adf9dd410d4b67f782058165fbf61cb53c61' and '690c7c4a76e71e487456cfb56e90f63a76e5d1c7'
author Etan Reisner <pidgin@unreliablesource.net>
date Wed, 20 May 2009 01:09:04 +0000
parents a6a4b440e5ae (diff) 108455a3c019 (current diff)
children ef132bfb0793
files
diffstat 18 files changed, 216 insertions(+), 401 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon May 18 03:29:40 2009 +0000
+++ b/ChangeLog	Wed May 20 01:09:04 2009 +0000
@@ -14,6 +14,8 @@
 	libpurple:
 	* Various memory cleanups when unloading libpurple. (Nick Hebner)
 	* Report idle time 'From last message sent' should work properly.
+	* Show the invite message for buddies that requested authorization
+	  from you on MSN.
 
 	XMPP:
 	* Voice & Video support with Jingle (XEP-0166, 0167, 0176, & 0177), and
--- a/libpurple/protocols/jabber/buddy.c	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Wed May 20 01:09:04 2009 +0000
@@ -1460,49 +1460,50 @@
 				if(seconds) {
 					char *end = NULL;
 					long sec = strtol(seconds, &end, 10);
-                    JabberBuddy *jb = NULL;
-                    char *resource = NULL;
-                    char *buddy_name = NULL;
+					JabberBuddy *jb = NULL;
+					char *resource = NULL;
+					char *buddy_name = NULL;
 					JabberBuddyResource *jbr = NULL;
 
-                    if(end != seconds) {
+					if(end != seconds) {
 						JabberBuddyInfoResource *jbir = g_hash_table_lookup(jbi->resources, resource_name);
 						if(jbir) {
 							jbir->idle_seconds = sec;
 						}
 					}
-                    /* Update the idle time of the buddy resource, if we got it. 
-                     This will correct the value when a server doesn't mark 
-                     delayed presence and we got the presence when signing on */
-                    jb = jabber_buddy_find(js, from, FALSE);
-                    if (jb) {
-                        resource = jabber_get_resource(from);
-                        buddy_name = jabber_get_bare_jid(from);
-                        /* if the resource already has an idle time set, we
-                         must have gotten it originally from a presence. In
-                         this case we update it. Otherwise don't update it, to
-                         avoid setting an idle and not getting informed about
-                         the resource getting unidle */
-                        if (resource && buddy_name) {
-                            jbr = jabber_buddy_find_resource(jb, resource);
-                            
-                            if (jbr->idle) {
-                                if (sec) {
-                                    jbr->idle = time(NULL) - sec;
-                                } else {
-                                    jbr->idle = 0;
-                                }
-                            
-                                if (jbr == 
-                                    jabber_buddy_find_resource(jb, NULL)) {
-                                    purple_prpl_got_user_idle(js->gc->account, 
-                                        buddy_name, jbr->idle, jbr->idle);
-                                }
-                            }
-                        }
-                        g_free(resource);
-                        g_free(buddy_name);
-                    }
+					/* Update the idle time of the buddy resource, if we got it. 
+					 This will correct the value when a server doesn't mark 
+					 delayed presence and we got the presence when signing on */
+					jb = jabber_buddy_find(js, from, FALSE);
+					if (jb) {
+						resource = jabber_get_resource(from);
+						buddy_name = jabber_get_bare_jid(from);
+						/* if the resource already has an idle time set, we
+						 must have gotten it originally from a presence. In
+						 this case we update it. Otherwise don't update it, to
+						 avoid setting an idle and not getting informed about
+						 the resource getting unidle */
+						if (resource && buddy_name) {
+							jbr = jabber_buddy_find_resource(jb, resource);
+							if (jbr) {
+								if (jbr->idle) {
+									if (sec) {
+										jbr->idle = time(NULL) - sec;
+									} else {
+										jbr->idle = 0;
+									}
+
+									if (jbr == 
+										jabber_buddy_find_resource(jb, NULL)) {
+										purple_prpl_got_user_idle(js->gc->account, 
+											buddy_name, jbr->idle, jbr->idle);
+									}
+								}
+							}
+						}
+						g_free(resource);
+						g_free(buddy_name);
+					}
 				}
 			}
 		}
--- a/libpurple/protocols/jabber/jabber.c	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Wed May 20 01:09:04 2009 +0000
@@ -483,7 +483,7 @@
 	JabberStream *js = gc->proto_data;
 
 	if (js->keepalive_timeout == -1) {
-		jabber_ping_jid(js, js->user->domain);
+		jabber_keepalive_ping(js);
 		js->keepalive_timeout = purple_timeout_add_seconds(120,
 				(GSourceFunc)(jabber_keepalive_timeout), gc);
 	}
--- a/libpurple/protocols/jabber/jabber.h	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Wed May 20 01:09:04 2009 +0000
@@ -75,7 +75,7 @@
 /* Index into attention_types list */
 #define JABBER_BUZZ 0
 
-PurplePlugin *jabber_plugin;
+extern PurplePlugin *jabber_plugin;
 
 typedef enum {
 	JABBER_STREAM_OFFLINE,
--- a/libpurple/protocols/jabber/ping.c	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/jabber/ping.c	Wed May 20 01:09:04 2009 +0000
@@ -28,7 +28,9 @@
 #include "ping.h"
 #include "iq.h"
 
-static void jabber_keepalive_pong_cb(JabberStream *js)
+static void jabber_keepalive_pong_cb(JabberStream *js, const char *from,
+                                     JabberIqType type, const char *id,
+                                     xmlnode *packet, gpointer data)
 {
 	if (js->keepalive_timeout >= 0) {
 		purple_timeout_remove(js->keepalive_timeout);
@@ -57,16 +59,23 @@
                                   JabberIqType type, const char *id,
                                   xmlnode *packet, gpointer data)
 {
-	if (purple_strequal(from, js->user->domain))
-		/* If the pong is from the server, assume it's a result of the
-		 * keepalive functions */
-		jabber_keepalive_pong_cb(js);
-	else {
-		if (type == JABBER_IQ_RESULT)
-			purple_debug_info("jabber", "PONG!\n");
-		else
-			purple_debug_info("jabber", "ping not supported\n");
-	}
+	if (type == JABBER_IQ_RESULT)
+		purple_debug_info("jabber", "PONG!\n");
+	else
+		purple_debug_info("jabber", "ping not supported\n");
+}
+
+void jabber_keepalive_ping(JabberStream *js)
+{
+	JabberIq *iq;
+	xmlnode *ping;
+
+	iq = jabber_iq_new(js, JABBER_IQ_GET);
+	ping = xmlnode_new_child(iq->node, "ping");
+	xmlnode_set_namespace(ping, "urn:xmpp:ping");
+
+	jabber_iq_set_callback(iq, jabber_keepalive_pong_cb, NULL);
+	jabber_iq_send(iq);
 }
 
 gboolean jabber_ping_jid(JabberStream *js, const char *jid)
--- a/libpurple/protocols/jabber/ping.h	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/jabber/ping.h	Wed May 20 01:09:04 2009 +0000
@@ -29,5 +29,6 @@
 void jabber_ping_parse(JabberStream *js, const char *from,
                        JabberIqType, const char *id, xmlnode *child);
 gboolean jabber_ping_jid(JabberStream *js, const char *jid);
+void jabber_keepalive_ping(JabberStream *js);
 
 #endif /* PURPLE_JABBER_PING_H_ */
--- a/libpurple/protocols/jabber/si.c	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/jabber/si.c	Wed May 20 01:09:04 2009 +0000
@@ -441,9 +441,11 @@
 		purple_xfer_cancel_remote(xfer);
 		return;
 	} else if(jsx->rxlen - 5 <  jsx->rxqueue[4] + 2) {
-		purple_debug_info("jabber", "reading %u bytes for DST.ADDR + port num (trying to read %u now)\n",
-				  jsx->rxqueue[4] + 2, jsx->rxqueue[4] + 2 - (jsx->rxlen - 5));
-		len = read(source, buffer, jsx->rxqueue[4] + 2 - (jsx->rxlen - 5));
+		/* Upper-bound of 257 (jsx->rxlen = 5, jsx->rxqueue[4] = 0xFF) */
+		unsigned short to_read = jsx->rxqueue[4] + 2 - (jsx->rxlen - 5);
+		purple_debug_info("jabber", "reading %u bytes for DST.ADDR + port num (trying to read %hu now)\n",
+				  jsx->rxqueue[4] + 2, to_read);
+		len = read(source, buffer, to_read);
 		if(len < 0 && errno == EAGAIN)
 			return;
 		else if(len <= 0) {
@@ -586,10 +588,12 @@
 		memcpy(jsx->rxqueue + jsx->rxlen, buffer, len);
 		jsx->rxlen += len;
 		return;
-	} else if(jsx->rxlen - 2 <  jsx->rxqueue[1]) {
-		purple_debug_info("jabber", "reading %u bytes for auth methods (trying to read %u now)\n",
-				  jsx->rxqueue[1], jsx->rxqueue[1] - (jsx->rxlen - 2));
-		len = read(source, buffer, jsx->rxqueue[1] - (jsx->rxlen - 2));
+	} else if(jsx->rxlen - 2 < jsx->rxqueue[1]) {
+		/* Has a maximum value of 255 (jsx->rxlen = 2, jsx->rxqueue[1] = 0xFF) */
+		unsigned short to_read = jsx->rxqueue[1] - (jsx->rxlen - 2);
+		purple_debug_info("jabber", "reading %u bytes for auth methods (trying to read %hu now)\n",
+				  jsx->rxqueue[1], to_read);
+		len = read(source, buffer, to_read);
 		if(len < 0 && errno == EAGAIN)
 			return;
 		else if(len <= 0) {
--- a/libpurple/protocols/msn/contact.c	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/msn/contact.c	Wed May 20 01:09:04 2009 +0000
@@ -357,29 +357,36 @@
 	MsnUser *user = msn_userlist_find_add_user(session->userlist, passport, NULL);
 	xmlnode *annotation;
 	guint nid = MSN_NETWORK_UNKNOWN;
+	char *invite = NULL;
 
-	/* For EmailMembers, the network must be found in the annotations. */
-	if (!strcmp(node, "PassportName")) {
+	for (annotation = xmlnode_get_child(member, "Annotations/Annotation");
+	     annotation;
+	     annotation = xmlnode_get_next_twin(annotation)) {
+		char *name = xmlnode_get_data(xmlnode_get_child(annotation, "Name"));
+		char *value = xmlnode_get_data(xmlnode_get_child(annotation, "Value"));
+		if (name && value) {
+			if (!strcmp(name, "MSN.IM.BuddyType")) {
+				nid = strtoul(value, NULL, 10);
+			}
+			else if (!strcmp(name, "MSN.IM.InviteMessage")) {
+				invite = value;
+				value = NULL;
+			}
+		}
+		g_free(name);
+		g_free(value);
+	}
+
+	/* For EmailMembers, the network must be found in the annotations, above.
+	   Otherwise, PassportMembers are on the Passport network. */
+	if (!strcmp(node, "PassportName"))
 		nid = MSN_NETWORK_PASSPORT;
-	} else {
-		for (annotation = xmlnode_get_child(member, "Annotations/Annotation");
-		     annotation;
-		     annotation = xmlnode_get_next_twin(annotation)) {
-			char *name = xmlnode_get_data(xmlnode_get_child(annotation, "Name"));
-			if (name && !strcmp(name, "MSN.IM.BuddyType")) {
-				char *value = xmlnode_get_data(xmlnode_get_child(annotation, "Value"));
-				if (value != NULL)
-					nid = strtoul(value, NULL, 10);
-				g_free(value);
-			}
-			g_free(name);
-		}
-	}
 
 	purple_debug_info("msn", "CL: %s name: %s, Type: %s, MembershipID: %s, NetworkID: %u\n",
 		node, passport, type, member_id == NULL ? "(null)" : member_id, nid);
 
 	msn_user_set_network(user, nid);
+	msn_user_set_invite_message(user, invite);
 
 	if (member_id) {
 		user->membership_id[list] = atoi(member_id);
@@ -390,6 +397,7 @@
 	g_free(passport);
 	g_free(type);
 	g_free(member_id);
+	g_free(invite);
 }
 
 static void
@@ -717,8 +725,6 @@
 					g_free(msnEnabled);
 				}
 			}
-			if (passport == NULL) /* Couldn't find anything */
-				continue;
 		} else {
 			xmlnode *messenger_user;
 			/* ignore non-messenger contacts */
@@ -736,6 +742,7 @@
 			passport = xmlnode_get_data(passportName);
 		}
 
+		/* Couldn't find anything */
 		if (passport == NULL)
 			continue;
 
--- a/libpurple/protocols/msn/notification.c	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/msn/notification.c	Wed May 20 01:09:04 2009 +0000
@@ -149,48 +149,6 @@
 }
 
 /**************************************************************************
- * 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 ? 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
  **************************************************************************/
 
@@ -1102,38 +1060,6 @@
 }
 
 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 be moved to this group */
-	if (cmd->trans->data)
-	{
-		/* msn_userlist_move_buddy(); */
-		MsnUserList *userlist = cmdproc->session->userlist;
-		MsnCallbackState *data = cmd->trans->data;
-
-		if (data->old_group_name != NULL)
-		{
-			msn_userlist_move_buddy(userlist, data->who, data->old_group_name, group_name);
-			g_free(data->old_group_name);
-		} else {
-			/* msn_add_contact_to_group(userlist, data, data->who, group_name); */
-		}
-	}
-}
-
-static void
 qng_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	/* TODO: Call PNG after the timeout specified. */
@@ -1468,61 +1394,6 @@
 	}
 }
 
-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
-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 = params[0];
-
-	group_error_helper(cmdproc->session, _("Unable to delete group"), group_id, error);
-
-	g_strfreev(params);
-}
-
 /**************************************************************************
  * Misc commands
  **************************************************************************/
@@ -2149,9 +2020,6 @@
 	msn_table_add_cmd(cbs_table, "VER", "VER", ver_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, "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 */
@@ -2187,8 +2055,6 @@
 	msn_table_add_error(cbs_table, "ADD", add_error);
 	msn_table_add_error(cbs_table, "ADL", adl_error);
 	msn_table_add_error(cbs_table, "FQY", fqy_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, "USR", usr_error);
 
 	msn_table_add_msg_type(cbs_table,
--- a/libpurple/protocols/msn/user.c	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/msn/user.c	Wed May 20 01:09:04 2009 +0000
@@ -74,6 +74,7 @@
 	g_free(user->media.title);
 	g_free(user->media.album);
 	g_free(user->statusline);
+	g_free(user->invite_message);
 
 	g_free(user);
 }
@@ -426,6 +427,15 @@
 	user->clientcaps = info;
 }
 
+void
+msn_user_set_invite_message(MsnUser *user, const char *message)
+{
+	g_return_if_fail(user != NULL);
+
+	g_free(user->invite_message);
+	user->invite_message = g_strdup(message);
+}
+
 const char *
 msn_user_get_passport(const MsnUser *user)
 {
@@ -489,3 +499,12 @@
 
 	return user->clientcaps;
 }
+
+const char *
+msn_user_get_invite_message(const MsnUser *user)
+{
+	g_return_val_if_fail(user != NULL, NULL);
+
+	return user->invite_message;
+}
+
--- a/libpurple/protocols/msn/user.h	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/msn/user.h	Wed May 20 01:09:04 2009 +0000
@@ -105,6 +105,8 @@
 
 	guint membership_id[5];	/**< The membershipId sent by the contacts server,
 				     indexed by the list it belongs to		*/
+
+	char *invite_message;   /**< Invite message of user request */
 };
 
 /**************************************************************************
@@ -290,6 +292,14 @@
  */
 void msn_user_set_client_caps(MsnUser *user, GHashTable *info);
 
+/**
+ * Sets the invite message for a user.
+ *
+ * @param user    The user.
+ * @param message The invite message for a user.
+ */
+void msn_user_set_invite_message(MsnUser *user, const char *message);
+
 
 /**
  * Returns the passport account for a user.
@@ -373,6 +383,15 @@
 GHashTable *msn_user_get_client_caps(const MsnUser *user);
 
 /**
+ * Returns the invite message for a user.
+ *
+ * @param user The user.
+ *
+ * @return The user's invite message.
+ */
+const char *msn_user_get_invite_message(const MsnUser *user);
+
+/**
  * check to see if user is online
  */
 gboolean
--- a/libpurple/protocols/msn/userlist.c	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/msn/userlist.c	Wed May 20 01:09:04 2009 +0000
@@ -86,7 +86,7 @@
 }
 
 static void
-got_new_entry(PurpleConnection *gc, const char *passport, const char *friendly)
+got_new_entry(PurpleConnection *gc, const char *passport, const char *friendly, const char *message)
 {
 	PurpleAccount *acct;
 	MsnPermitAdd *pa;
@@ -97,7 +97,7 @@
 	pa->gc = gc;
 
 	acct = purple_connection_get_account(gc);
-	purple_account_request_authorization(acct, passport, NULL, friendly, NULL,
+	purple_account_request_authorization(acct, passport, NULL, friendly, message,
 										 purple_find_buddy(acct, passport) != NULL,
 										 msn_accept_add_cb, msn_cancel_add_cb, pa);
 
@@ -142,155 +142,6 @@
  * Server functions
  **************************************************************************/
 
-MsnListId
-msn_get_list_id(const char *list)
-{
-	if (list[0] == 'F')
-		return MSN_LIST_FL;
-	else if (list[0] == 'A')
-		return MSN_LIST_AL;
-	else if (list[0] == 'B')
-		return MSN_LIST_BL;
-	else if (list[0] == 'R')
-		return MSN_LIST_RL;
-
-	return -1;
-}
-
-/* this function msn_got_add_user isn't called anywhere */
-void
-msn_got_add_user(MsnSession *session, MsnUser *user,
-				 MsnListId list_id, const char * group_id)
-{
-	PurpleAccount *account;
-	const char *passport;
-	const char *friendly;
-
-	purple_debug_info("msn", "got add user...\n");
-	account = session->account;
-
-	passport = msn_user_get_passport(user);
-	friendly = msn_user_get_friendly_name(user);
-
-	if (list_id == MSN_LIST_FL)
-	{
-		PurpleConnection *gc;
-
-		gc = purple_account_get_connection(account);
-
-		serv_got_alias(gc, passport, friendly);
-
-		if (group_id != NULL)
-		{
-			msn_user_add_group_id(user, group_id);
-		}
-	}
-	else if (list_id == MSN_LIST_AL)
-	{
-		purple_privacy_permit_add(account, passport, TRUE);
-	}
-	else if (list_id == MSN_LIST_BL)
-	{
-		purple_privacy_deny_add(account, passport, TRUE);
-	}
-	else if (list_id == MSN_LIST_RL)
-	{
-		PurpleConversation *convo;
-
-		purple_debug_info("msn",
-						"%s has added you to his or her buddy list.\n",
-						passport);
-
- 		convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, passport, account);
- 		if (convo) {
- 			PurpleBuddy *buddy;
- 			char *msg;
-
- 			buddy = purple_find_buddy(account, passport);
- 			msg = g_strdup_printf(
- 				_("%s has added you to his or her buddy list."),
- 				buddy ? purple_buddy_get_contact_alias(buddy) : passport);
- 			purple_conv_im_write(PURPLE_CONV_IM(convo), passport, msg,
- 				PURPLE_MESSAGE_SYSTEM, time(NULL));
- 			g_free(msg);
- 		}
-
-		if (!(user->list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP)))
-		{
-			/*
-			 * TODO: The friendly name was NULL for me when I
-			 *       looked at this.  Maybe we should use the store
-			 *       name instead? --KingAnt
-			 */
-/*			got_new_entry(gc, passport, friendly); */
-		}
-	}
-
-	user->list_op |= (1 << list_id);
-	/* purple_user_add_list_id (user, list_id); */
-}
-
-void
-msn_got_rem_user(MsnSession *session, MsnUser *user,
-				 MsnListId list_id, const char * group_id)
-{
-	PurpleAccount *account;
-	const char *passport;
-
-	account = session->account;
-
-	passport = msn_user_get_passport(user);
-
-	if (list_id == MSN_LIST_FL)
-	{
-		/* TODO: When is the user totally removed? */
-		if (group_id != NULL)
-		{
-			msn_user_remove_group_id(user, group_id);
-			return;
-		}
-	}
-	else if (list_id == MSN_LIST_AL)
-	{
-		purple_privacy_permit_remove(account, passport, TRUE);
-	}
-	else if (list_id == MSN_LIST_BL)
-	{
-		purple_privacy_deny_remove(account, passport, TRUE);
-	}
-	else if (list_id == MSN_LIST_RL)
-	{
-		PurpleConversation *convo;
-
-		purple_debug_info("msn",
-						"%s has removed you from his or her buddy list.\n",
-						passport);
-
-		convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, passport, account);
-		if (convo) {
-			PurpleBuddy *buddy;
-			char *msg;
-
-			buddy = purple_find_buddy(account, passport);
-			msg = g_strdup_printf(
-				_("%s has removed you from his or her buddy list."),
-				buddy ? purple_buddy_get_contact_alias(buddy) : passport);
-			purple_conv_im_write(PURPLE_CONV_IM(convo), passport, msg,
-				PURPLE_MESSAGE_SYSTEM, time(NULL));
-			g_free(msg);
-		}
-	}
-
-	user->list_op &= ~(1 << list_id);
-	/* purple_user_remove_list_id (user, list_id); */
-
-	if (user->list_op == 0)
-	{
-		purple_debug_info("msn", "Buddy '%s' shall be deleted?.\n",
-						passport);
-	}
-}
-
 void
 msn_got_lst_user(MsnSession *session, MsnUser *user,
 				 int list_op, GSList *group_ids)
@@ -299,12 +150,14 @@
 	PurpleAccount *account;
 	const char *passport;
 	const char *store;
+	const char *message;
 
 	account = session->account;
 	gc = purple_account_get_connection(account);
 
 	passport = msn_user_get_passport(user);
 	store = msn_user_get_friendly_name(user);
+	message = msn_user_get_invite_message(user);
 
 	msn_user_set_op(user, list_op);
 
@@ -348,13 +201,13 @@
 
 		if (!(list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP)))
 		{
-/*			got_new_entry(gc, passport, store); */
+/*			got_new_entry(gc, passport, store, NULL); */
 		}
 	}
 
 	if (list_op & MSN_LIST_PL_OP)
 	{
-		got_new_entry(gc, passport, store);
+		got_new_entry(gc, passport, store, message);
 	}
 }
 
--- a/libpurple/protocols/msn/userlist.h	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/msn/userlist.h	Wed May 20 01:09:04 2009 +0000
@@ -57,12 +57,7 @@
 
 gboolean msn_userlist_user_is_in_group(MsnUser *user, const char * group_id);
 gboolean msn_userlist_user_is_in_list(MsnUser *user, MsnListId list_id);
-MsnListId msn_get_list_id(const char *list);
 
-void msn_got_add_user(MsnSession *session, MsnUser *user,
-					  MsnListId list_id, const char *group_id);
-void msn_got_rem_user(MsnSession *session, MsnUser *user,
-					  MsnListId list_id, const char *group_id);
 void msn_got_lst_user(MsnSession *session, MsnUser *user,
 					  int list_op, GSList *group_ids);
 
--- a/libpurple/protocols/oscar/family_locate.c	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/oscar/family_locate.c	Wed May 20 01:09:04 2009 +0000
@@ -68,8 +68,12 @@
 	 {0x09, 0x46, 0x00, 0x02, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
+	{OSCAR_CAPABILITY_VIDEO,
+	 {0x09, 0x46, 0x01, 0x00, 0x4c, 0x7f, 0x11, 0xd1,
+	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
+
 	/* "Live Video" (SIP/RTC Video) support in Windows AIM 5.5.3501 and newer */
-	{OSCAR_CAPABILITY_VIDEO,
+	{OSCAR_CAPABILITY_LIVEVIDEO,
 	 {0x09, 0x46, 0x01, 0x01, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
--- a/libpurple/protocols/oscar/oscar.c	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Wed May 20 01:09:04 2009 +0000
@@ -714,6 +714,9 @@
 			case OSCAR_CAPABILITY_ICHATAV:
 				tmp = _("iChat AV");
 				break;
+			case OSCAR_CAPABILITY_LIVEVIDEO:
+				tmp = _("Live Video");
+				break;
 			case OSCAR_CAPABILITY_CAMERA:
 				tmp = _("Camera");
 				break;
--- a/libpurple/protocols/oscar/oscar.h	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/protocols/oscar/oscar.h	Wed May 20 01:09:04 2009 +0000
@@ -369,11 +369,12 @@
 	OSCAR_CAPABILITY_SMS                  = 0x00400000,
 	OSCAR_CAPABILITY_VIDEO                = 0x00800000,
 	OSCAR_CAPABILITY_ICHATAV              = 0x01000000,
-	OSCAR_CAPABILITY_CAMERA               = 0x02000000,
-	OSCAR_CAPABILITY_ICHAT_SCREENSHARE    = 0x04000000,
-	OSCAR_CAPABILITY_TYPING               = 0x08000000,
-	OSCAR_CAPABILITY_GENERICUNKNOWN       = 0x10000000,
-	OSCAR_CAPABILITY_LAST                 = 0x20000000
+	OSCAR_CAPABILITY_LIVEVIDEO            = 0x02000000,
+	OSCAR_CAPABILITY_CAMERA               = 0x04000000,
+	OSCAR_CAPABILITY_ICHAT_SCREENSHARE    = 0x08000000,
+	OSCAR_CAPABILITY_TYPING               = 0x10000000,
+	OSCAR_CAPABILITY_GENERICUNKNOWN       = 0x20000000,
+	OSCAR_CAPABILITY_LAST                 = 0x40000000
 } OscarCapability;
 
 /*
--- a/libpurple/prpl.h	Mon May 18 03:29:40 2009 +0000
+++ b/libpurple/prpl.h	Wed May 20 01:09:04 2009 +0000
@@ -126,10 +126,10 @@
 typedef enum
 {
 	/**
-	 * Use a unique name, not an alias, for chat rooms.
+	 * User names are unique to a chat and are not shared between rooms.
 	 *
-	 * XMPP lets you choose what name you want for chat.
-	 * So it shouldn't be pulling the alias for when you're in chat;
+	 * XMPP lets you choose what name you want in chats, so it shouldn't
+	 * be pulling the aliases from the buddy list for the chat list;
 	 * it gets annoying.
 	 */
 	OPT_PROTO_UNIQUE_CHATNAME = 0x00000004,
--- a/pidgin/gtkconv.c	Mon May 18 03:29:40 2009 +0000
+++ b/pidgin/gtkconv.c	Wed May 20 01:09:04 2009 +0000
@@ -2700,7 +2700,7 @@
 	scale_width = gdk_pixbuf_get_width(buf);
 	scale_height = gdk_pixbuf_get_height(buf);
 
-	gtk_widget_get_size_request(gtkconv->infopane_hbox, NULL, &size);
+	gtk_widget_get_size_request(gtkconv->u.im->icon_container, NULL, &size);
 	size = MIN(size, MIN(scale_width, scale_height));
 	size = CLAMP(size, BUDDYICON_SIZE_MIN, BUDDYICON_SIZE_MAX);
 
@@ -2758,13 +2758,22 @@
 static void
 remove_icon(GtkWidget *widget, PidginConversation *gtkconv)
 {
+	GList *children;
+	GtkWidget *event;
 	PurpleConversation *conv = gtkconv->active_conv;
 	PidginWindow *gtkwin;
 
 	g_return_if_fail(conv != NULL);
 
-	if (gtkconv->u.im->icon_container != NULL)
-		gtk_widget_destroy(gtkconv->u.im->icon_container);
+	gtk_widget_set_size_request(gtkconv->u.im->icon_container, -1, BUDDYICON_SIZE_MIN);
+	children = gtk_container_get_children(GTK_CONTAINER(gtkconv->u.im->icon_container));
+	if (children) {
+		/* We know there's only one child here. It'd be nice to shortcut to the
+		   event box, but we can't change the PidginConversation until 3.0 */
+		event = (GtkWidget *)children->data;
+		gtk_container_remove(GTK_CONTAINER(gtkconv->u.im->icon_container), event);
+		g_list_free(children);
+	}
 
 	if (gtkconv->u.im->anim != NULL)
 		g_object_unref(G_OBJECT(gtkconv->u.im->anim));
@@ -2779,7 +2788,6 @@
 	gtkconv->u.im->icon = NULL;
 	gtkconv->u.im->anim = NULL;
 	gtkconv->u.im->iter = NULL;
-	gtkconv->u.im->icon_container = NULL;
 	gtkconv->u.im->show_icon = FALSE;
 
 	gtkwin = gtkconv->win;
@@ -2840,7 +2848,7 @@
 	PurpleConversation *conv = gtkconv->active_conv;
 	GSList *buddies;
 
-	gtk_widget_get_size_request(gtkconv->infopane_hbox, NULL, &size);
+	gtk_widget_get_size_request(gtkconv->u.im->icon_container, NULL, &size);
 
 	if (size == BUDDYICON_SIZE_MAX) {
 		size = BUDDYICON_SIZE_MIN;
@@ -2848,7 +2856,7 @@
 		size = BUDDYICON_SIZE_MAX;
 	}
 
-	gtk_widget_set_size_request(gtkconv->infopane_hbox, -1, size);
+	gtk_widget_set_size_request(gtkconv->u.im->icon_container, -1, size);
 	pidgin_conv_update_buddy_icon(conv);
 
 	buddies = purple_find_buddies(purple_conversation_get_account(conv),
@@ -4629,6 +4637,7 @@
 		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
 
 		gtkchat->topic_text = gtk_entry_new();
+		gtk_widget_set_size_request(gtkchat->topic_text, -1, BUDDYICON_SIZE_MIN);
 
 		if(prpl_info->set_chat_topic == NULL) {
 			gtk_editable_set_editable(GTK_EDITABLE(gtkchat->topic_text), FALSE);
@@ -4847,15 +4856,37 @@
 	gtk_cell_view_set_displayed_row(GTK_CELL_VIEW(gtkconv->infopane), path);
 	gtk_tree_path_free(path);
 
-	if ((buddy = purple_find_buddy(purple_conversation_get_account(conv),
-					purple_conversation_get_name(conv))) != NULL) {
-		PurpleContact *contact = purple_buddy_get_contact(buddy);
-		if (contact) {
-			buddyicon_size = purple_blist_node_get_int((PurpleBlistNode*)contact, "pidgin-infopane-iconsize");
-		}
-	}
-	buddyicon_size = CLAMP(buddyicon_size, BUDDYICON_SIZE_MIN, BUDDYICON_SIZE_MAX);
-	gtk_widget_set_size_request(gtkconv->infopane_hbox, -1, buddyicon_size);
+	if (chat) {
+		/* This empty widget is used to ensure that the infopane is consistently
+		   sized for chat windows. The correct fix is to put an icon in the chat
+		   window as well, because that would make "Set Custom Icon" consistent
+		   for both the buddy list and the chat window, but PidginConversation
+		   is pretty much stuck until 3.0. */
+		GtkWidget *sizing_vbox;
+		sizing_vbox = gtk_vbox_new(FALSE, 0);
+		gtk_widget_set_size_request(sizing_vbox, -1, BUDDYICON_SIZE_MIN);
+		gtk_box_pack_start(GTK_BOX(gtkconv->infopane_hbox), sizing_vbox, FALSE, FALSE, 0);
+		gtk_widget_show(sizing_vbox);
+	}
+	else {
+		gtkconv->u.im->icon_container = gtk_vbox_new(FALSE, 0);
+
+		if ((buddy = purple_find_buddy(purple_conversation_get_account(conv),
+						purple_conversation_get_name(conv))) != NULL) {
+			PurpleContact *contact = purple_buddy_get_contact(buddy);
+			if (contact) {
+				buddyicon_size = purple_blist_node_get_int((PurpleBlistNode*)contact, "pidgin-infopane-iconsize");
+			}
+		}
+		buddyicon_size = CLAMP(buddyicon_size, BUDDYICON_SIZE_MIN, BUDDYICON_SIZE_MAX);
+		gtk_widget_set_size_request(gtkconv->u.im->icon_container, -1, buddyicon_size);
+
+		gtk_box_pack_start(GTK_BOX(gtkconv->infopane_hbox),
+				   gtkconv->u.im->icon_container, FALSE, FALSE, 0);
+
+		gtk_widget_show(gtkconv->u.im->icon_container);
+	}
+
 	gtk_widget_show(gtkconv->infopane);
 
 	rend = gtk_cell_renderer_pixbuf_new();
@@ -6310,7 +6341,7 @@
 		return;
 
 	smiley->data = g_realloc(smiley->data, smiley->datasize + size);
-	g_memmove(smiley->data + smiley->datasize, data, size);
+	g_memmove((guchar *)smiley->data + smiley->datasize, data, size);
 	smiley->datasize += size;
 
 	loader = smiley->loader;
@@ -6909,6 +6940,7 @@
 
 	GdkPixbuf *buf;
 
+	GList *children;
 	GtkWidget *event;
 	GdkPixbuf *scale;
 	int scale_width, scale_height;
@@ -6936,9 +6968,14 @@
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(account->gc->prpl);
 
 	/* Remove the current icon stuff */
-	if (gtkconv->u.im->icon_container != NULL)
-		gtk_widget_destroy(gtkconv->u.im->icon_container);
-	gtkconv->u.im->icon_container = NULL;
+	children = gtk_container_get_children(GTK_CONTAINER(gtkconv->u.im->icon_container));
+	if (children) {
+		/* We know there's only one child here. It'd be nice to shortcut to the
+		   event box, but we can't change the PidginConversation until 3.0 */
+		event = (GtkWidget *)children->data;
+		gtk_container_remove(GTK_CONTAINER(gtkconv->u.im->icon_container), event);
+		g_list_free(children);
+	}
 
 	if (gtkconv->u.im->anim != NULL)
 		g_object_unref(G_OBJECT(gtkconv->u.im->anim));
@@ -7026,7 +7063,7 @@
 	scale_width = gdk_pixbuf_get_width(buf);
 	scale_height = gdk_pixbuf_get_height(buf);
 
-	gtk_widget_get_size_request(gtkconv->infopane_hbox, NULL, &size);
+	gtk_widget_get_size_request(gtkconv->u.im->icon_container, NULL, &size);
 	size = MIN(size, MIN(scale_width, scale_height));
 
 	/* Some sanity checks */
@@ -7045,7 +7082,6 @@
 	g_object_unref(buf);
 	if (pidgin_gdk_pixbuf_is_opaque(scale))
 		pidgin_gdk_pixbuf_make_round(scale);
-	gtkconv->u.im->icon_container = gtk_vbox_new(FALSE, 0);
 
 	event = gtk_event_box_new();
 	gtk_container_add(GTK_CONTAINER(gtkconv->u.im->icon_container), event);
@@ -7066,11 +7102,6 @@
 
 	g_object_unref(G_OBJECT(scale));
 
-	gtk_box_pack_start(GTK_BOX(gtkconv->infopane_hbox),
-			   gtkconv->u.im->icon_container, FALSE, FALSE, 0);
-
-	gtk_widget_show(gtkconv->u.im->icon_container);
-
 	/* The buddy icon code needs badly to be fixed. */
 	if(pidgin_conv_window_is_active_conversation(conv))
 	{