changeset 23102:dcb26bb0be73

merge of '487397995e13465f3b2c9d4748f832eaa17b2f9f' and '7cd7197fa3237ff97089c9ca567c7d87b9457769'
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Fri, 23 May 2008 16:46:19 +0000
parents 53821935cab4 (current diff) bce10d146dd4 (diff)
children 388e96b79206
files
diffstat 21 files changed, 225 insertions(+), 172 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed May 21 15:47:21 2008 +0000
+++ b/ChangeLog	Fri May 23 16:46:19 2008 +0000
@@ -1,6 +1,9 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
 version 2.4.3 (??/??/2008):
+	libpurple:
+	* Yahoo! Japan now uses UTF-8, matching the behavior of official clients
+	  and restoring compatibility with the web messenger (Yusuke Odate)
 
 version 2.4.2 (05/17/2008):
 	libpurple:
--- a/doc/pidgin.1.in	Wed May 21 15:47:21 2008 +0000
+++ b/doc/pidgin.1.in	Fri May 23 16:46:19 2008 +0000
@@ -19,9 +19,9 @@
 .\" License along with this manual; if not, write to the Free
 .\" Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 .\" Boston, MA  02111-1301  USA.
-.TH pidgin 1
+.TH pidgin 1 "" "Pidgin v@VERSION@"
 .SH NAME
-Pidgin v@VERSION@ \- Instant Messaging client
+pidgin \- Instant Messaging client
 .SH SYNOPSIS
 .TP 5
 \fBpidgin \fI[options]\fR
--- a/libpurple/network.c	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/network.c	Fri May 23 16:46:19 2008 +0000
@@ -663,6 +663,7 @@
 
 	if (!dbus_g_proxy_call(nm_proxy, "state", &err, G_TYPE_INVALID, G_TYPE_UINT, &state, G_TYPE_INVALID)) {
 		/* XXX: Print an error? */
+		g_error_free(err);
 		return NM_STATE_UNKNOWN;
 	}
 
--- a/libpurple/protocols/bonjour/bonjour.c	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c	Fri May 23 16:46:19 2008 +0000
@@ -413,6 +413,15 @@
 }
 
 static gboolean
+bonjour_can_receive_file(PurpleConnection *connection, const char *who)
+{
+	PurpleBuddy *buddy = purple_find_buddy(connection->account, who);
+
+	return (buddy != NULL && buddy->proto_data != NULL);
+
+}
+
+static gboolean
 plugin_unload(PurplePlugin *plugin)
 {
 	/* These shouldn't happen here because they are allocated in _init() */
@@ -483,7 +492,7 @@
 	NULL,                                                    /* roomlist_get_list */
 	NULL,                                                    /* roomlist_cancel */
 	NULL,                                                    /* roomlist_expand_category */
-	NULL,                                                    /* can_receive_file */
+	bonjour_can_receive_file,                                /* can_receive_file */
 	bonjour_send_file,                                       /* send_file */
 	bonjour_new_xfer,                                        /* new_xfer */
 	NULL,                                                    /* offline_message */
--- a/libpurple/protocols/bonjour/bonjour_ft.c	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/protocols/bonjour/bonjour_ft.c	Fri May 23 16:46:19 2008 +0000
@@ -47,9 +47,8 @@
 static void
 xep_ft_si_reject(BonjourData *bd, const char *id, const char *to, const char *error_code, const char *error_type)
 {
-	xmlnode *error_node = NULL;
-	xmlnode *tmp_node = NULL;
-	XepIq *iq = NULL;
+	xmlnode *error_node;
+	XepIq *iq;
 
 	g_return_if_fail(error_code != NULL);
 	g_return_if_fail(error_type != NULL);
@@ -68,14 +67,14 @@
 
 	/* TODO: Make this better */
 	if (!strcmp(error_code, "403")) {
-		tmp_node = xmlnode_new_child(error_node, "forbidden");
+		xmlnode *tmp_node = xmlnode_new_child(error_node, "forbidden");
 		xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas");
 
 		tmp_node = xmlnode_new_child(error_node, "text");
 		xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas");
 		xmlnode_insert_data(tmp_node, "Offer Declined", -1);
 	} else if (!strcmp(error_code, "404")) {
-		tmp_node = xmlnode_new_child(error_node, "item-not-found");
+		xmlnode *tmp_node = xmlnode_new_child(error_node, "item-not-found");
 		xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas");
 	}
 
@@ -90,11 +89,10 @@
 
 static void bonjour_xfer_request_denied(PurpleXfer *xfer)
 {
-	XepXfer *xf = NULL;
+	XepXfer *xf = xfer->data;
 
 	purple_debug_info("bonjour", "Bonjour-xfer-request-denied.\n");
 
-	xf = xfer->data;
 	if(xf)
 		xep_ft_si_reject(xf->data, xf->sid, xfer->who, "403", "cancel");
 
@@ -149,9 +147,9 @@
 static PurpleXfer*
 bonjour_si_xfer_find(BonjourData *bd, const char *sid, const char *from)
 {
-	GSList *xfers = NULL;
-	PurpleXfer *xfer = NULL;
-	XepXfer *xf = NULL;
+	GSList *xfers;
+	PurpleXfer *xfer;
+	XepXfer *xf;
 
 	if(!sid || !from || !bd)
 		return NULL;
@@ -179,19 +177,12 @@
 static void
 xep_ft_si_offer(PurpleXfer *xfer, const gchar *to)
 {
-	xmlnode *si_node = NULL;
-	xmlnode *feature = NULL;
-	xmlnode *field = NULL;
-	xmlnode *option = NULL;
-	xmlnode *value = NULL;
-	xmlnode *file = NULL;
-	xmlnode *x = NULL;
-	XepIq *iq = NULL;
-	XepXfer *xf = NULL;
+	xmlnode *si_node, *feature, *field, *file, *x;
+	XepIq *iq;
+	XepXfer *xf = xfer->data;
 	BonjourData *bd = NULL;
 	char buf[32];
 
-	xf = xfer->data;
 	if(!xf)
 		return;
 
@@ -234,13 +225,13 @@
 	xmlnode_set_attrib(field, "type", "list-single");
 
 	if (xf->mode & XEP_BYTESTREAMS) {
-		option = xmlnode_new_child(field, "option");
-		value = xmlnode_new_child(option, "value");
+		xmlnode *option = xmlnode_new_child(field, "option");
+		xmlnode *value = xmlnode_new_child(option, "value");
 		xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1);
 	}
 	if (xf->mode & XEP_IBB) {
-		option = xmlnode_new_child(field, "option");
-		value = xmlnode_new_child(option, "value");
+		xmlnode *option = xmlnode_new_child(field, "option");
+		xmlnode *value = xmlnode_new_child(option, "value");
 		xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1);
 	}
 
@@ -250,13 +241,9 @@
 static void
 xep_ft_si_result(PurpleXfer *xfer, char *to)
 {
-	xmlnode *si_node = NULL;
-	xmlnode *feature = NULL;
-	xmlnode *field = NULL;
-	xmlnode *value = NULL;
-	xmlnode *x = NULL;
-	XepIq *iq = NULL;
-	XepXfer *xf = NULL;
+	xmlnode *si_node, *feature, *field, *value, *x;
+	XepIq *iq;
+	XepXfer *xf;
 	BonjourData *bd;
 
 	if(!to || !xfer)
@@ -295,8 +282,7 @@
 static void
 bonjour_free_xfer(PurpleXfer *xfer)
 {
-	XepXfer *xf = NULL;
-	BonjourData *bd = NULL;
+	XepXfer *xf;
 
 	if(xfer == NULL) {
 		purple_debug_info("bonjour", "bonjour-free-xfer-null.\n");
@@ -307,7 +293,7 @@
 
 	xf = (XepXfer*)xfer->data;
 	if(xf != NULL) {
-		bd = (BonjourData*)xf->data;
+		BonjourData *bd = (BonjourData*)xf->data;
 		if(bd != NULL) {
 			bd->xfer_lists = g_slist_remove(bd->xfer_lists, xfer);
 			purple_debug_info("bonjour", "B free xfer from lists(%p).\n", bd->xfer_lists);
@@ -332,8 +318,8 @@
 bonjour_new_xfer(PurpleConnection *gc, const char *who)
 {
 	PurpleXfer *xfer;
-	XepXfer *xep_xfer = NULL;
-	BonjourData *bd = NULL;
+	XepXfer *xep_xfer;
+	BonjourData *bd;
 
 	if(who == NULL || gc == NULL)
 		return NULL;
@@ -367,7 +353,7 @@
 void
 bonjour_send_file(PurpleConnection *gc, const char *who, const char *file)
 {
-	PurpleXfer *xfer = NULL;
+	PurpleXfer *xfer;
 
 	g_return_if_fail(gc != NULL);
 	g_return_if_fail(who != NULL);
@@ -386,9 +372,9 @@
 static void
 bonjour_xfer_init(PurpleXfer *xfer)
 {
-	PurpleBuddy *buddy = NULL;
-	BonjourBuddy *bb = NULL;
-	XepXfer *xf = NULL;
+	PurpleBuddy *buddy;
+	BonjourBuddy *bb;
+	XepXfer *xf;
 
 	xf = (XepXfer*)xfer->data;
 	if(xf == NULL)
@@ -398,7 +384,7 @@
 
 	buddy = purple_find_buddy(xfer->account, xfer->who);
 	/* this buddy is offline. */
-	if (buddy == NULL)
+	if (buddy == NULL || buddy->proto_data == NULL)
 		return;
 
 	bb = (BonjourBuddy *)buddy->proto_data;
@@ -420,8 +406,8 @@
 xep_si_parse(PurpleConnection *pc, xmlnode *packet, PurpleBuddy *pb)
 {
 	const char *type, *id;
-	BonjourData *bd = NULL;
-	PurpleXfer *xfer = NULL;
+	BonjourData *bd;
+	PurpleXfer *xfer;
 
 	if(pc == NULL || packet == NULL || pb == NULL)
 		return;
@@ -496,12 +482,9 @@
 void
 xep_bytestreams_parse(PurpleConnection *pc, xmlnode *packet, PurpleBuddy *pb)
 {
-	const char *type = NULL, *from = NULL;
-	xmlnode *query = NULL, *streamhost = NULL;
-	BonjourData *bd = NULL;
-	PurpleXfer *xfer = NULL;
-	XepXfer *xf = NULL;
-	int portnum;
+	const char *type, *from;
+	xmlnode *query;
+	BonjourData *bd;
 
 	if(pc == NULL || packet == NULL || pb == NULL)
 		return;
@@ -519,6 +502,7 @@
 		if(!strcmp(type, "set")) {
 			const char *iq_id, *sid;
 			gboolean found = FALSE;
+			PurpleXfer *xfer;
 
 			purple_debug_info("bonjour", "bytestream offer Message type - SET.\n");
 
@@ -529,6 +513,9 @@
 
 			if(xfer) {
 				const char *jid, *host, *port;
+				xmlnode *streamhost;
+				int portnum;
+				XepXfer *xf = NULL;
 
 				xf = (XepXfer*)xfer->data;
 				for(streamhost = xmlnode_get_child(query, "streamhost");
@@ -577,9 +564,9 @@
 bonjour_xfer_receive(PurpleConnection *pc, const char *id, const char *sid, const char *from,
 		     const int filesize, const char *filename, int option)
 {
-	PurpleXfer *xfer = NULL;
-	XepXfer *xf = NULL;
-	BonjourData *bd = NULL;
+	PurpleXfer *xfer;
+	XepXfer *xf;
+	BonjourData *bd;
 
 	if(pc == NULL || id == NULL || from == NULL)
 		return;
@@ -614,11 +601,10 @@
 bonjour_sock5_request_cb(gpointer data, gint source, PurpleInputCondition cond)
 {
 	PurpleXfer *xfer = data;
-	XepXfer *xf = NULL;
+	XepXfer *xf = xfer->data;
 	int acceptfd;
 	int len = 0;
 
-	xf = xfer->data;
 	if(xf == NULL)
 		return;
 
@@ -745,10 +731,9 @@
 	XepXfer *xf;
 	XepIq *iq;
 	xmlnode *query, *streamhost;
-	char *port;
-	const char *next_ip;
-	const char *local_ip = NULL;
-	char token [] = ";";
+	gchar *port;
+	const char *next_ip, *local_ip;
+	const char token [] = ";";
 	BonjourData *bd;
 
 	purple_debug_info("bonjour", "Bonjour-bytestreams-listen. sock=%d.\n", sock);
@@ -793,7 +778,7 @@
 static void
 bonjour_bytestreams_init(PurpleXfer *xfer)
 {
-	XepXfer *xf = NULL;
+	XepXfer *xf;
 	if(xfer == NULL)
 		return;
 	purple_debug_info("bonjour", "Bonjour-bytestreams-init.\n");
@@ -813,7 +798,7 @@
 {
 	PurpleXfer *xfer = data;
 	XepXfer *xf = xfer->data;
-	XepIq *iq = NULL;
+	XepIq *iq;
 	xmlnode *q_node, *tmp_node;
 	BonjourData *bd;
 
@@ -849,10 +834,10 @@
 static void
 bonjour_bytestreams_connect(PurpleXfer *xfer, PurpleBuddy *pb)
 {
-	XepXfer *xf = NULL;
+	XepXfer *xf;
 	char dstaddr[41];
 	unsigned char hashval[20];
-	char *p = NULL;
+	char *p;
 	int i;
 
 	if(xfer == NULL)
--- a/libpurple/protocols/bonjour/buddy.c	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/protocols/bonjour/buddy.c	Fri May 23 16:46:19 2008 +0000
@@ -156,9 +156,9 @@
 		purple_blist_node_set_flags((PurpleBlistNode *)buddy, PURPLE_BLIST_NODE_FLAG_NO_SAVE);
 		purple_blist_add_buddy(buddy, NULL, group, NULL);
 	}
-	
+
 	buddy->proto_data = bonjour_buddy;
-	
+
 	/* Create the alias for the buddy using the first and the last name */
 	if (bonjour_buddy->nick)
 		serv_got_alias(purple_account_get_connection(account), buddy->name, bonjour_buddy->nick);
@@ -206,10 +206,12 @@
  * If the buddy is being saved, mark as offline, otherwise delete
  */
 void bonjour_buddy_signed_off(PurpleBuddy *pb) {
-	if (PURPLE_BLIST_NODE_SHOULD_SAVE(pb))
+	if (PURPLE_BLIST_NODE_SHOULD_SAVE(pb)) {
 		purple_prpl_got_user_status(purple_buddy_get_account(pb),
 					    purple_buddy_get_name(pb), "offline", NULL);
-	else {
+		bonjour_buddy_delete(pb->proto_data);
+		pb->proto_data = NULL;
+	} else {
 		purple_account_remove_buddy(purple_buddy_get_account(pb), pb, NULL);
 		purple_blist_remove_buddy(pb);
 	}
--- a/libpurple/protocols/bonjour/jabber.c	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Fri May 23 16:46:19 2008 +0000
@@ -385,7 +385,7 @@
 			purple_debug_warning("bonjour", "receive error: %s\n", err ? err : "(null)");
 
 			bonjour_jabber_close_conversation(bconv);
-			if (bconv->pb != NULL) {
+			if (bconv->pb != NULL && bconv->pb->proto_data != NULL) {
 				BonjourBuddy *bb = bconv->pb->proto_data;
 				bb->conversation = NULL;
 			}
@@ -957,7 +957,7 @@
 	int ret;
 
 	pb = _find_or_start_conversation(jdata, to);
-	if (pb == NULL) {
+	if (pb == NULL || pb->proto_data == NULL) {
 		purple_debug_info("bonjour", "Can't send a message to an offline buddy (%s).\n", to);
 		/* You can not send a message to an offline buddy */
 		return -10000;
@@ -1103,8 +1103,10 @@
 		buddies = purple_find_buddies(jdata->account, NULL);
 		for (l = buddies; l; l = l->next) {
 			BonjourBuddy *bb = ((PurpleBuddy*) l->data)->proto_data;
-			bonjour_jabber_close_conversation(bb->conversation);
-			bb->conversation = NULL;
+			if (bb != NULL) {
+				bonjour_jabber_close_conversation(bb->conversation);
+				bb->conversation = NULL;
+			}
 		}
 
 		g_slist_free(buddies);
--- a/libpurple/protocols/jabber/auth.c	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/protocols/jabber/auth.c	Fri May 23 16:46:19 2008 +0000
@@ -945,6 +945,7 @@
 					_("Invalid challenge from server"));
 			}
 			g_free(js->expected_rspauth);
+			js->expected_rspauth = NULL;
 		} else {
 			/* assemble a response, and send it */
 			/* see RFC 2831 */
--- a/libpurple/protocols/msn/msg.c	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/protocols/msn/msg.c	Fri May 23 16:46:19 2008 +0000
@@ -151,10 +151,9 @@
 	MsnMessage *msg;
 
 	msg = msn_message_new(MSN_MSG_NUDGE);
-	/* TODO: This shouldn't have a \r\n in it, should it?? */
-	msn_message_set_content_type(msg, "text/x-msnmsgr-datacast\r\n");
+	msn_message_set_content_type(msg, "text/x-msnmsgr-datacast");
 	msn_message_set_flag(msg, 'N');
-	msn_message_set_attr(msg,"ID","1\r\n");
+	msn_message_set_bin_data(msg, "ID: 1\r\n", 7);
 
 	return msg;
 }
--- a/libpurple/protocols/msnp9/msg.c	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/protocols/msnp9/msg.c	Fri May 23 16:46:19 2008 +0000
@@ -158,10 +158,9 @@
 	MsnMessage *msg;
 
 	msg = msn_message_new(MSN_MSG_NUDGE);
-	/* TODO: This shouldn't have a \r\n in it, should it?? */
-	msn_message_set_content_type(msg, "text/x-msnmsgr-datacast\r\n");
+	msn_message_set_content_type(msg, "text/x-msnmsgr-datacast");
 	msn_message_set_flag(msg, 'N');
-	msn_message_set_attr(msg,"ID","1\r\n");
+	msn_message_set_bin_data(msg, "ID: 1\r\n", 7);
 
 	return msg;
 }
--- a/libpurple/protocols/yahoo/util.c	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/protocols/yahoo/util.c	Fri May 23 16:46:19 2008 +0000
@@ -114,18 +114,15 @@
 	char *ret;
 	const char *to_codeset;
 
-	if (yd->jp && utf8 && *utf8)
-		*utf8 = FALSE;
+	if (yd->jp)
+		return g_strdup(str);
 
 	if (utf8 && *utf8) /* FIXME: maybe don't use utf8 if it'll fit in latin1 */
 		return g_strdup(str);
 
-	if (yd->jp)
-		to_codeset = "SHIFT_JIS";
-	else
-		to_codeset = purple_account_get_string(purple_connection_get_account(gc), "local_charset",  "ISO-8859-1");
+	to_codeset = purple_account_get_string(purple_connection_get_account(gc), "local_charset",  "ISO-8859-1");
+	ret = g_convert_with_fallback(str, -1, to_codeset, "UTF-8", "?", NULL, NULL, NULL);
 
-	ret = g_convert_with_fallback(str, -1, to_codeset, "UTF-8", "?", NULL, NULL, NULL);
 	if (ret)
 		return ret;
 	else
--- a/libpurple/protocols/yahoo/yahoo_aliases.c	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_aliases.c	Fri May 23 16:46:19 2008 +0000
@@ -49,6 +49,7 @@
 struct callback_data {
 	PurpleConnection *gc;
 	gchar *id;
+	gchar *who;
 };
 
 
@@ -80,6 +81,7 @@
 
 		if (contacts == NULL) {
 			purple_debug_error("yahoo", "Badly formed Alias XML\n");
+			g_free(cb->who);
 			g_free(cb->id);
 			g_free(cb);
 			return;
@@ -130,8 +132,6 @@
 						yahoo_update_alias(cb->gc, yid, buddy_alias);
 						purple_debug_info("yahoo", "Sent updated alias '%s'\n", buddy_alias);
 					}
-				} else {
-					purple_debug_info("yahoo", "Bizarre, received alias for %s, but they are not on your list...\n", yid);
 				}
 
 				g_free(full_name);
@@ -141,6 +141,7 @@
 		xmlnode_free(contacts);
 	}
 
+	g_free(cb->who);
 	g_free(cb->id);
 	g_free(cb);
 }
@@ -205,8 +206,10 @@
 	yd->url_datas = g_slist_remove(yd->url_datas, url_data);
 
 	if (len == 0 || error_message != NULL) {
-		purple_debug_info("yahoo", "Error updating alias: %s\n",
-						  error_message ? error_message : "");
+		purple_debug_info("yahoo", "Error updating alias for %s: %s\n",
+				  cb->who,
+				  error_message ? error_message : "");
+		g_free(cb->who);
 		g_free(cb->id);
 		g_free(cb);
 		return;
@@ -214,25 +217,42 @@
 
 	result = xmlnode_from_str(url_text, -1);
 
-	purple_debug_info("yahoo", "ID: %s, Return data: %s\n", cb->id, url_text);
-
 	if (result == NULL) {
-		purple_debug_error("yahoo", "Alias update failed: Badly formed response\n");
+		purple_debug_error("yahoo", "Alias update for %s failed: Badly formed response\n",
+				   cb->who);
+		g_free(cb->who);
 		g_free(cb->id);
 		g_free(cb);
 		return;
 	}
 
 	if ((node = xmlnode_get_child(result, "ct"))) {
-		const char *update_id = xmlnode_get_attrib(node, "id");
-		if (g_ascii_strncasecmp(update_id, cb->id, strlen(cb->id)) == 0)
-			purple_debug_info("yahoo", "Alias update succeeded\n");
-		else
-			purple_debug_error("yahoo", "Alias update failed (Contact record return mismatch)\n");
-	} else {
-		purple_debug_info("yahoo", "Alias update failed (No contact record returned)\n");
-	}
+		if (cb->id == NULL) {
+			const char *new_id = xmlnode_get_attrib(node, "id");
+			if (new_id != NULL) {
+				/* We now have an addressbook id for the friend; we should save it */
+				YahooFriend *f = yahoo_friend_find(cb->gc, cb->who);
+
+				purple_debug_info("yahoo", "Alias creation for %s succeeded\n", cb->who);
 
+				if (f)
+					yahoo_friend_set_alias_id(f, new_id);
+				else
+					purple_debug_error("yahoo", "Missing YahooFriend. Unable to store new addressbook id.\n");
+			} else
+				purple_debug_error("yahoo", "Missing new addressbook id in add response for %s (weird).\n",
+						   cb->who);
+		} else {
+			if (g_ascii_strncasecmp(xmlnode_get_attrib(node, "id"), cb->id, strlen(cb->id))==0)
+				purple_debug_info("yahoo", "Alias update for %s succeeded\n", cb->who);
+			else
+				purple_debug_error("yahoo", "Alias update for %s failed (Contact record return mismatch)\n",
+						   cb->who);
+		}
+	} else
+		purple_debug_info("yahoo", "Alias update for %s failed (No contact record returned)\n", cb->who);
+
+	g_free(cb->who);
 	g_free(cb->id);
 	g_free(cb);
 	xmlnode_free(result);
@@ -242,7 +262,7 @@
 yahoo_update_alias(PurpleConnection *gc, const char *who, const char *alias)
 {
 	struct yahoo_data *yd;
-	const char *url, *alias_id;
+	const char *url;
 	gchar *content, *request, *webpage, *webaddress;
 	struct callback_data *cb;
 	PurpleUtilFetchUrlData *url_data;
@@ -260,47 +280,65 @@
 	if (alias == NULL)
 		alias = "";
 
-	purple_debug_info("yahoo", "Sending '%s' as new alias for user '%s'.\n", alias, who);
-
 	f = yahoo_friend_find(gc, who);
 	if (f == NULL) {
 		purple_debug_error("yahoo", "Missing YahooFriend. Unable to set server alias.\n");
 		return;
 	}
 
-	alias_id = yahoo_friend_get_alias_id(f);
-	if (alias_id == NULL) {
-		purple_debug_error("yahoo", "Missing Yahoo Alias ID (get_yahoo_aliases must have failed), bailing out\n");
-		return;
-	}
-
 	yd = gc->proto_data;
 
 	/* Using callback_data so I have access to gc in the callback function */
 	cb = g_new0(struct callback_data, 1);
-	cb->id = g_strdup(alias_id);
+	cb->who = g_strdup(who);
+	cb->id = g_strdup(yahoo_friend_get_alias_id(f));
 	cb->gc = gc;
 
 	/*  Build all the info to make the web request */
 	url = yd->jp ? YAHOOJP_ALIAS_UPDATE_URL: YAHOO_ALIAS_UPDATE_URL;
 	purple_url_parse(url, &webaddress, NULL, &webpage, NULL, NULL);
 
-	if (yd->jp) {
-		gchar *alias_jp = g_convert(alias, -1, "EUC-JP", "UTF-8", NULL, NULL, NULL);
-		gchar *converted_alias_jp = yahoo_convert_to_numeric(alias_jp);
-		content = g_strdup_printf("<ab k=\"%s\" cc=\"1\">\n"
-					  "<ct e=\"1\"  yi='%s' id='%s' nn='%s' pr='0' />\n</ab>\r\n",
-					   purple_account_get_username(gc->account),
-					   who, alias_id, converted_alias_jp);
-		free(converted_alias_jp);
-		g_free(alias_jp);
+	if (cb->id == NULL) {
+		/* No id for this buddy, so create an address book entry */
+		purple_debug_info("yahoo", "Creating '%s' as new alias for user '%s'\n", alias, who);
+
+		if (yd->jp) {
+			gchar *alias_jp = g_convert(alias, -1, "EUC-JP", "UTF-8", NULL, NULL, NULL);
+			gchar *converted_alias_jp = yahoo_convert_to_numeric(alias_jp);
+			content = g_strdup_printf("<ab k=\"%s\" cc=\"9\">\n"
+						  "<ct a=\"1\" yi='%s' nn='%s' />\n</ab>\r\n",
+						  purple_account_get_username(gc->account),
+						  who, converted_alias_jp);
+			free(converted_alias_jp);
+			g_free(alias_jp);
+		} else {
+			gchar *escaped_alias = g_markup_escape_text(alias, -1);
+			content = g_strdup_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?><ab k=\"%s\" cc=\"9\">\n"
+						  "<ct a=\"1\" yi='%s' nn='%s' />\n</ab>\r\n",
+						  purple_account_get_username(gc->account),
+						  who, escaped_alias);
+			g_free(escaped_alias);
+		}
 	} else {
-		gchar *escaped_alias = g_markup_escape_text(alias, -1);
-		content = g_strdup_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?><ab k=\"%s\" cc=\"1\">\n"
-					  "<ct e=\"1\"  yi='%s' id='%s' nn='%s' pr='0' />\n</ab>\r\n",
-					  purple_account_get_username(gc->account),
-					  who, alias_id, escaped_alias);
-		g_free(escaped_alias);
+		purple_debug_info("yahoo", "Updating '%s' as new alias for user '%s'\n", alias, who);
+
+		if (yd->jp) {
+			gchar *alias_jp = g_convert(alias, -1, "EUC-JP", "UTF-8", NULL, NULL, NULL);
+			gchar *converted_alias_jp = yahoo_convert_to_numeric(alias_jp);
+			content = g_strdup_printf("<ab k=\"%s\" cc=\"1\">\n"
+						  "<ct e=\"1\"  yi='%s' id='%s' nn='%s' pr='0' />\n</ab>\r\n",
+						  purple_account_get_username(gc->account),
+						  who, cb->id, converted_alias_jp);
+			free(converted_alias_jp);
+			g_free(alias_jp);
+		} else {
+			gchar *escaped_alias = g_markup_escape_text(alias, -1);
+			content = g_strdup_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?><ab k=\"%s\" cc=\"1\">\n"
+						  "<ct e=\"1\"  yi='%s' id='%s' nn='%s' pr='0' />\n</ab>\r\n",
+						  purple_account_get_username(gc->account),
+						  who, cb->id, escaped_alias);
+			g_free(escaped_alias);
+		}
 	}
 
 	request = g_strdup_printf("POST %s%s/%s HTTP/1.1\r\n"
--- a/libpurple/protocols/yahoo/yahoo_picture.c	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_picture.c	Fri May 23 16:46:19 2008 +0000
@@ -137,9 +137,6 @@
 		if (url_data != NULL) {
 			yd = gc->proto_data;
 			yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
-		} else {
-			g_free(data->who);
-			g_free(data);
 		}
 	} else if (who && send_icon_info) {
 		yahoo_send_picture_info(gc, who);
--- a/libpurple/protocols/yahoo/yahoo_profile.c	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_profile.c	Fri May 23 16:46:19 2008 +0000
@@ -946,11 +946,6 @@
 				FALSE, yahoo_got_photo, info2_data);
 		if (url_data != NULL)
 			yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
-		else {
-			g_free(info2_data->info_data->name);
-			g_free(info2_data->info_data);
-			g_free(info2_data);
-		}
 	} else {
 		/* Emulate a callback */
 		yahoo_got_photo(NULL, info2_data, NULL, 0, NULL);
@@ -1286,10 +1281,6 @@
 	url_data = purple_util_fetch_url(url, TRUE, NULL, FALSE, yahoo_got_info, data);
 	if (url_data != NULL)
 		yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
-	else {
-		g_free(data->name);
-		g_free(data);
-	}
 
 	g_free(url);
 }
--- a/libpurple/purple-remote	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/purple-remote	Fri May 23 16:46:19 2008 +0000
@@ -35,7 +35,7 @@
             raise "Error: " + self.attr + " " + str(args) + " returned " + str(result)
         return result
             
-def show_help():
+def show_help(requested=False):
     print """This program uses D-Bus to communicate with purple.
 
 Usage:
@@ -66,6 +66,10 @@
     PurpleAccountsFindConnected?name=&protocol=prpl-jabber
     PurpleAccountsFindConnected(,prpl-jabber)
 """ % sys.argv[0]
+    if (requested):
+        sys.exit(0)
+    else:
+        sys.exit(1)
 
 cpurple = CheckedObject(purple)
 
@@ -213,10 +217,11 @@
                                 raise "Don't know how to handle type \"%s\"" % type
                     return purple.__getattr__(command)(*methodparams)
             show_help()
-            raise "Unknown command: %s" % command
 
 if len(sys.argv) == 1:
     show_help()
+elif (sys.argv[1] == "--help" or sys.argv[1] == "-h"):
+    show_help(True)
 elif (obj == None):
     print "No existing libpurple instance detected."
     sys.exit(1);
--- a/libpurple/purple-url-handler	Wed May 21 15:47:21 2008 +0000
+++ b/libpurple/purple-url-handler	Fri May 23 16:46:19 2008 +0000
@@ -295,10 +295,14 @@
 
 
 def main(argv=sys.argv):
-    if len(argv) != 2:
+    if len(argv) != 2 or argv[1] == "--help" or argv[1] == "-h":
         print "Usage: %s URI" % argv[0]
         print "Example: %s \"xmpp:romeo@montague.net?message\"" % argv[0]
-        return
+
+        if len(argv) != 2:
+            sys.exit(1)
+        else:
+            return 0
 
     uri = argv[1]
     type = uri.split(":")[0]
--- a/pidgin/gtkaccount.c	Wed May 21 15:47:21 2008 +0000
+++ b/pidgin/gtkaccount.c	Fri May 23 16:46:19 2008 +0000
@@ -1470,7 +1470,8 @@
 	add_login_options(dialog, vbox);
 	add_user_options(dialog, vbox);
 
-	button = gtk_check_button_new_with_label(_("Create this new account on the server"));
+	button = gtk_check_button_new_with_mnemonic(
+		_("Create _this new account on the server"));
 	gtk_box_pack_start(GTK_BOX(main_vbox), button, FALSE, FALSE, 0);
 	gtk_widget_show(button);
 	dialog->register_button = button;
--- a/pidgin/gtkplugin.c	Wed May 21 15:47:21 2008 +0000
+++ b/pidgin/gtkplugin.c	Fri May 23 16:46:19 2008 +0000
@@ -421,6 +421,8 @@
 		"<span size=\"smaller\">%s</span>",
 		name, version);
 	gtk_label_set_markup(plugin_name, buf);
+	g_free(name);
+	g_free(version);
 	g_free(buf);
 
 	gtk_text_buffer_set_text(plugin_desc, purple_plugin_get_description(plug), -1);
@@ -694,6 +696,8 @@
 	gtk_label_set_markup(GTK_LABEL(label), _("<b>Filename:</b>"));
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
 
+	g_object_unref(sg);
+
 	return GTK_WIDGET(vbox);
 }
 
--- a/pidgin/gtkpounce.c	Wed May 21 15:47:21 2008 +0000
+++ b/pidgin/gtkpounce.c	Fri May 23 16:46:19 2008 +0000
@@ -100,6 +100,7 @@
 	GtkWidget *play_sound_entry;
 	GtkWidget *play_sound_browse;
 	GtkWidget *play_sound_test;
+	GtkWidget *play_sound_reset;
 
 	GtkWidget *save_pounce;
 
@@ -166,13 +167,26 @@
 pounce_test_sound(GtkWidget *w, GtkWidget *entry)
 {
 	const char *filename;
+	gboolean temp_mute;
+
+	temp_mute = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/sound/mute");
+
+	if (temp_mute) purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute", FALSE);
 
 	filename = gtk_entry_get_text(GTK_ENTRY(entry));
 
-	if (filename != NULL && *filename != '\0')
+	if (filename != NULL && *filename != '\0' && strcmp(filename, _("(default)")))
 		purple_sound_play_file(filename, NULL);
 	else
 		purple_sound_play_event(PURPLE_SOUND_POUNCE_DEFAULT, NULL);
+
+	if (temp_mute) purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute", TRUE);
+}
+
+static void
+pounce_reset_sound(GtkWidget *w, GtkWidget *entry)
+{
+	gtk_entry_set_text(GTK_ENTRY(entry), _("(default)"));
 }
 
 static void
@@ -304,7 +318,7 @@
 		message = NULL;
 	}
 	if (*command == '\0') command = NULL;
-	if (*sound   == '\0') sound   = NULL;
+	if (*sound   == '\0' || !strcmp(sound, _("(default)"))) sound   = NULL;
 
 	/* If the pounce has already been triggered, let's pretend it is a new one */
 	if (dialog->pounce != NULL
@@ -652,7 +666,7 @@
 	/* Create the "Action" frame. */
 	frame = pidgin_make_frame(vbox2, _("Action"));
 
-	table = gtk_table_new(3, 5, FALSE);
+	table = gtk_table_new(3, 6, FALSE);
 	gtk_container_add(GTK_CONTAINER(frame), table);
 	gtk_table_set_col_spacings(GTK_TABLE(table), PIDGIN_HIG_BORDER);
 	gtk_widget_show(table);
@@ -674,8 +688,11 @@
 	dialog->popup_entry       = gtk_entry_new();
 	dialog->exec_cmd_browse   = gtk_button_new_with_mnemonic(_("Brows_e..."));
 	dialog->play_sound_entry  = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(dialog->play_sound_entry), _("(default)"));
+	gtk_editable_set_editable(GTK_EDITABLE(dialog->play_sound_entry), FALSE);
 	dialog->play_sound_browse = gtk_button_new_with_mnemonic(_("Br_owse..."));
 	dialog->play_sound_test   = gtk_button_new_with_mnemonic(_("Pre_view"));
+	dialog->play_sound_reset  = gtk_button_new_with_mnemonic(_("Reset"));
 
 	gtk_widget_set_sensitive(send_msg_imhtml,           FALSE);
 	gtk_widget_set_sensitive(dialog->exec_cmd_entry,    FALSE);
@@ -684,6 +701,7 @@
 	gtk_widget_set_sensitive(dialog->play_sound_entry,  FALSE);
 	gtk_widget_set_sensitive(dialog->play_sound_browse, FALSE);
 	gtk_widget_set_sensitive(dialog->play_sound_test,   FALSE);
+	gtk_widget_set_sensitive(dialog->play_sound_reset,  FALSE);
 
 	g_object_unref(sg);
 
@@ -698,6 +716,7 @@
 	gtk_size_group_add_widget(sg, dialog->play_sound_entry);
 	gtk_size_group_add_widget(sg, dialog->play_sound_browse);
 	gtk_size_group_add_widget(sg, dialog->play_sound_test);
+	gtk_size_group_add_widget(sg, dialog->play_sound_reset);
 
 	g_object_unref(sg);
 	sg = NULL;
@@ -706,11 +725,11 @@
 					 GTK_FILL, 0, 0, 0);
 	gtk_table_attach(GTK_TABLE(table), dialog->popup,            0, 1, 1, 2,
 					 GTK_FILL, 0, 0, 0);
-	gtk_table_attach(GTK_TABLE(table), dialog->popup_entry,      1, 4, 1, 2,
+	gtk_table_attach(GTK_TABLE(table), dialog->popup_entry,      1, 5, 1, 2,
 					 GTK_FILL, 0, 0, 0);
-	gtk_table_attach(GTK_TABLE(table), dialog->send_msg,         0, 4, 2, 3,
+	gtk_table_attach(GTK_TABLE(table), dialog->send_msg,         0, 5, 2, 3,
 					 GTK_FILL, 0, 0, 0);
-	gtk_table_attach(GTK_TABLE(table), send_msg_imhtml,          0, 4, 3, 4,
+	gtk_table_attach(GTK_TABLE(table), send_msg_imhtml,          0, 5, 3, 4,
 					 GTK_FILL, 0, 0, 0);
 	gtk_table_attach(GTK_TABLE(table), dialog->exec_cmd,         0, 1, 4, 5,
 					 GTK_FILL, 0, 0, 0);
@@ -726,6 +745,8 @@
 					 GTK_FILL | GTK_EXPAND, 0, 0, 0);
 	gtk_table_attach(GTK_TABLE(table), dialog->play_sound_test,  3, 4, 5, 6,
 					 GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	gtk_table_attach(GTK_TABLE(table), dialog->play_sound_reset, 4, 5, 5, 6,
+					 GTK_FILL | GTK_EXPAND, 0, 0, 0);
 
 	gtk_table_set_row_spacings(GTK_TABLE(table), PIDGIN_HIG_BOX_SPACE / 2);
 
@@ -741,6 +762,7 @@
 	gtk_widget_show(dialog->play_sound_entry);
 	gtk_widget_show(dialog->play_sound_browse);
 	gtk_widget_show(dialog->play_sound_test);
+	gtk_widget_show(dialog->play_sound_reset);
 
 	g_signal_connect(G_OBJECT(dialog->message_recv), "clicked",
 					 G_CALLBACK(message_recv_toggle),
@@ -771,6 +793,7 @@
 	g_ptr_array_add(sound_widgets,dialog->play_sound_entry);
 	g_ptr_array_add(sound_widgets,dialog->play_sound_browse);
 	g_ptr_array_add(sound_widgets,dialog->play_sound_test);
+	g_ptr_array_add(sound_widgets,dialog->play_sound_reset);
 
 	g_signal_connect(G_OBJECT(dialog->play_sound), "clicked",
 					 G_CALLBACK(pidgin_toggle_sensitive_array),
@@ -781,6 +804,9 @@
 	g_signal_connect(G_OBJECT(dialog->play_sound_test), "clicked",
 					 G_CALLBACK(pounce_test_sound),
 					 dialog->play_sound_entry);
+	g_signal_connect(G_OBJECT(dialog->play_sound_reset), "clicked",
+					 G_CALLBACK(pounce_reset_sound),
+					 dialog->play_sound_entry);
 	g_object_set_data_full(G_OBJECT(dialog->window), "sound-widgets",
 				sound_widgets, (GDestroyNotify)g_ptr_array_free);
 
@@ -795,8 +821,6 @@
 					 G_CALLBACK(save_pounce_cb), dialog);
 	g_signal_connect(G_OBJECT(dialog->exec_cmd_entry), "activate",
 					 G_CALLBACK(save_pounce_cb), dialog);
-	g_signal_connect(G_OBJECT(dialog->play_sound_entry), "activate",
-					 G_CALLBACK(save_pounce_cb), dialog);
 
 	/* Create the "Options" frame. */
 	frame = pidgin_make_frame(vbox2, _("Options"));
@@ -924,7 +948,7 @@
 													  "play-sound",
 													  "filename")) != NULL)
 		{
-			gtk_entry_set_text(GTK_ENTRY(dialog->play_sound_entry), value);
+			gtk_entry_set_text(GTK_ENTRY(dialog->play_sound_entry), (value && *value != '\0') ? value : _("(default)"));
 		}
 	}
 	else
--- a/pidgin/gtkprefs.c	Wed May 21 15:47:21 2008 +0000
+++ b/pidgin/gtkprefs.c	Fri May 23 16:46:19 2008 +0000
@@ -2001,18 +2001,18 @@
 	gtk_editable_set_editable(GTK_EDITABLE(sound_entry), FALSE);
 	gtk_box_pack_start(GTK_BOX(hbox), sound_entry, FALSE, FALSE, PIDGIN_HIG_BOX_SPACE);
 
-	button = gtk_button_new_with_label(_("Test"));
+	button = gtk_button_new_with_mnemonic(_("_Browse..."));
+	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(select_sound), NULL);
+	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1);
+
+	button = gtk_button_new_with_mnemonic(_("Pre_view"));
 	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(test_sound), NULL);
 	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1);
 
-	button = gtk_button_new_with_label(_("Reset"));
+	button = gtk_button_new_with_mnemonic(_("_Reset"));
 	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(reset_sound), NULL);
 	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1);
 
-	button = gtk_button_new_with_label(_("Choose..."));
-	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(select_sound), NULL);
-	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1);
-
 	gtk_widget_show_all(ret);
 	g_object_unref(sg);
 
--- a/pidgin/gtksound.c	Wed May 21 15:47:21 2008 +0000
+++ b/pidgin/gtksound.c	Fri May 23 16:46:19 2008 +0000
@@ -491,26 +491,12 @@
 		if (purple_running_gnome()) {
 			sink = gst_element_factory_make("gconfaudiosink", "sink");
 		}
-		if (!sink)
-			sink = gst_element_factory_make("autoaudiosink", "sink");
-		if (!sink) {
-			purple_debug_error("sound", "Unable to create GStreamer audiosink.\n");
-			return;
-		}
 	}
 #ifndef _WIN32
 	else if (!strcmp(method, "esd")) {
 		sink = gst_element_factory_make("esdsink", "sink");
-		if (!sink) {
-			purple_debug_error("sound", "Unable to create GStreamer audiosink.\n");
-			return;
-		}
 	} else if (!strcmp(method, "alsa")) {
 		sink = gst_element_factory_make("alsasink", "sink");
-		if (!sink) {
-			purple_debug_error("sound", "Unable to create GStreamer audiosink.\n");
-			return;
-		}
 	}
 #endif
 	else {
@@ -518,6 +504,11 @@
 		return;
 	}
 
+	if (strcmp(method, "automatic") != 0 && !sink) {
+		purple_debug_error("sound", "Unable to create GStreamer audiosink.\n");
+		return;
+	}
+
 	play = gst_element_factory_make("playbin", "play");
 
 	if (play == NULL) {