changeset 28140:5ac0a83f0b21

merged with im.pidgin.pidgin
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Sun, 02 Aug 2009 16:43:49 +0900
parents 784013acc2f3 (current diff) 5b21007cf503 (diff)
children 2222357e5f45
files libpurple/certificate.c libpurple/protocols/jabber/google.c libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/si.c libpurple/protocols/yahoo/libymsg.c libpurple/protocols/yahoo/util.c libpurple/protocols/yahoo/yahoo_filexfer.c libpurple/protocols/yahoo/yahoo_packet.c pidgin/gtkblist.c pidgin/gtkimhtml.c pidgin/gtkprefs.c
diffstat 31 files changed, 328 insertions(+), 245 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Aug 01 14:55:12 2009 +0900
+++ b/ChangeLog	Sun Aug 02 16:43:49 2009 +0900
@@ -43,6 +43,8 @@
 	  against the GNU IDN library.
 	* Install scalable versions of the main Pidgin icon, the protocol icons,
 	  the dialog icons, and the Buddy List emblems.
+	* Build properly on Hurd.  (Marc Dequènes)
+	* Various memory leaks fixed as reported by Josh Mueller.
 
 	AIM and ICQ:
 	* Preliminary support for a new authentication scheme called
--- a/libpurple/certificate.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/certificate.c	Sun Aug 02 16:43:49 2009 +0900
@@ -1375,7 +1375,7 @@
 		return;
 	} /* if (name mismatch) */
 
-	if (had_ca_pool) {
+	if (!had_ca_pool) {
 		/* The subject name is correct, but we weren't able to verify the
 		 * chain because there was no pool of root CAs found. Prompt the user
 		 * to validate it.
--- a/libpurple/cipher.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/cipher.c	Sun Aug 02 16:43:49 2009 +0900
@@ -2727,8 +2727,6 @@
 
 		cipher = PURPLE_CIPHER(l->data);
 		purple_ciphers_unregister_cipher(cipher);
-
-		ciphers = g_list_remove(ciphers, cipher);
 	}
 
 	g_list_free(ciphers);
--- a/libpurple/desktopitem.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/desktopitem.c	Sun Aug 02 16:43:49 2009 +0900
@@ -831,11 +831,10 @@
 static char *
 try_english_key (PurpleDesktopItem *item, const char *key)
 {
-	char *str;
+	char *str = NULL;
 	char *locales[] = { "en_US", "en_GB", "en_AU", "en", NULL };
 	int i;
 
-	str = NULL;
 	for (i = 0; locales[i] != NULL && str == NULL; i++) {
 		str = g_strdup (lookup_locale (item, key, locales[i]));
 	}
--- a/libpurple/ft.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/ft.c	Sun Aug 02 16:43:49 2009 +0900
@@ -953,15 +953,15 @@
 			if (wc != r) {
 				purple_debug_error("filetransfer", "Unable to write whole buffer.\n");
 				purple_xfer_cancel_local(xfer);
+				g_free(buffer);
 				return;
 			}
 		} else if(r < 0) {
 			purple_xfer_cancel_remote(xfer);
+			g_free(buffer);
 			return;
 		}
-	}
-
-	if (condition & PURPLE_INPUT_WRITE) {
+	} else if (condition & PURPLE_INPUT_WRITE) {
 		size_t result;
 		size_t s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size);
 
--- a/libpurple/protocols/bonjour/mdns_avahi.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/bonjour/mdns_avahi.c	Sun Aug 02 16:43:49 2009 +0900
@@ -200,8 +200,8 @@
 			}
 
 			if (!bonjour_buddy_check(bb)) {
+				b_impl->resolvers = g_slist_remove(b_impl->resolvers, rd);
 				_cleanup_resolver_data(rd);
-				b_impl->resolvers = g_slist_remove(b_impl->resolvers, rd);
 				/* If this was the last resolver, remove the buddy */
 				if (b_impl->resolvers == NULL) {
 					if (pb != NULL)
--- a/libpurple/protocols/gg/lib/libgadu.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/gg/lib/libgadu.c	Sun Aug 02 16:43:49 2009 +0900
@@ -790,6 +790,7 @@
 		gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess->fd, buf + sizeof(h) + offset, size, ret);
 		if (!ret) {
 			gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed: connection broken\n");
+			free(buf);
 			errno = ECONNRESET;
 			return NULL;
 		}
--- a/libpurple/protocols/jabber/bosh.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/jabber/bosh.c	Sun Aug 02 16:43:49 2009 +0900
@@ -31,6 +31,7 @@
 
 #define MAX_HTTP_CONNECTIONS      2
 #define MAX_FAILED_CONNECTIONS    3
+#define BUFFER_SEND_IN_SECS       1
 
 typedef struct _PurpleHTTPConnection PurpleHTTPConnection;
 
@@ -40,55 +41,63 @@
 static char *bosh_useragent = NULL;
 
 typedef enum {
+	PACKET_NORMAL,
 	PACKET_TERMINATE,
-	PACKET_STREAM_RESTART,
-	PACKET_NORMAL,
+	PACKET_FLUSH,
 } PurpleBOSHPacketType;
 
 struct _PurpleBOSHConnection {
 	JabberStream *js;
+	PurpleHTTPConnection *connections[MAX_HTTP_CONNECTIONS];
+
+	PurpleCircBuffer *pending;
+	PurpleBOSHConnectionConnectFunction connect_cb;
+	PurpleBOSHConnectionReceiveFunction receive_cb;
+
+	/* Must be big enough to hold 2^53 - 1 */
+	char *sid;
+	guint64 rid;
+
+	/* decoded URL */
+	char *host;
+	char *path;
+	guint16 port;
+
 	gboolean pipelining;
-	PurpleHTTPConnection *connections[MAX_HTTP_CONNECTIONS];
-	unsigned short failed_connections;
+	gboolean ssl;
+	gboolean needs_restart;
 
 	enum {
 		BOSH_CONN_OFFLINE,
 		BOSH_CONN_BOOTING,
 		BOSH_CONN_ONLINE
 	} state;
-	gboolean ssl;
-	gboolean needs_restart;
+	guint8 failed_connections;
 
-	/* decoded URL */
-	char *host;
-	int port;
-	char *path;
-
-	/* Must be big enough to hold 2^53 - 1 */
-	guint64 rid;
-	char *sid;
-
-	unsigned int inactivity_timer;
 	int max_inactivity;
 	int wait;
 
-	PurpleCircBuffer *pending;
 	int max_requests;
 	int requests;
 
-	PurpleBOSHConnectionConnectFunction connect_cb;
-	PurpleBOSHConnectionReceiveFunction receive_cb;
+	guint inactivity_timer;
+	guint send_timer;
 };
 
 struct _PurpleHTTPConnection {
 	PurpleBOSHConnection *bosh;
 	PurpleSslConnection *psc;
+
+	PurpleCircBuffer *write_buf;
+	GString *read_buf;
+
+	gsize handled_len;
+	gsize body_len;
+
 	int fd;
 	guint readh;
 	guint writeh;
 
-	PurpleCircBuffer *write_buffer;
-
 	enum {
 		HTTP_CONN_OFFLINE,
 		HTTP_CONN_CONNECTING,
@@ -96,16 +105,14 @@
 	} state;
 	int requests; /* number of outstanding HTTP requests */
 
-	GString *buf;
 	gboolean headers_done;
-	gsize handled_len;
-	gsize body_len;
 
 };
 
 static void http_connection_connect(PurpleHTTPConnection *conn);
 static void http_connection_send_request(PurpleHTTPConnection *conn,
                                          const GString *req);
+static gboolean send_timer_cb(gpointer data);
 
 void jabber_bosh_init(void)
 {
@@ -140,7 +147,7 @@
 	conn->fd = -1;
 	conn->state = HTTP_CONN_OFFLINE;
 
-	conn->write_buffer = purple_circ_buffer_new(0 /* default grow size */);
+	conn->write_buf = purple_circ_buffer_new(0 /* default grow size */);
 
 	return conn;
 }
@@ -148,11 +155,11 @@
 static void
 jabber_bosh_http_connection_destroy(PurpleHTTPConnection *conn)
 {
-	if (conn->buf)
-		g_string_free(conn->buf, TRUE);
+	if (conn->read_buf)
+		g_string_free(conn->read_buf, TRUE);
 
-	if (conn->write_buffer)
-		purple_circ_buffer_destroy(conn->write_buffer);
+	if (conn->write_buf)
+		purple_circ_buffer_destroy(conn->write_buf);
 	if (conn->readh)
 		purple_input_remove(conn->readh);
 	if (conn->writeh)
@@ -227,6 +234,8 @@
 	g_free(conn->host);
 	g_free(conn->path);
 
+	if (conn->send_timer)
+		purple_timeout_remove(conn->send_timer);
 	if (conn->inactivity_timer)
 		purple_timeout_remove(conn->inactivity_timer);
 
@@ -250,6 +259,19 @@
 {
 	int i;
 
+	if (purple_debug_is_verbose()) {
+		for (i = 0; i < MAX_HTTP_CONNECTIONS; ++i) {
+			PurpleHTTPConnection *httpconn = conn->connections[i];
+			if (httpconn == NULL)
+				purple_debug_misc("jabber", "BOSH %p->connections[%d] = (nil)\n",
+				                  conn, i);
+			else
+				purple_debug_misc("jabber", "BOSH %p->connections[%d] = %p, state = %d"
+				                  ", requests = %d\n", conn, i, httpconn,
+				                  httpconn->state, httpconn->requests);
+		}
+	}
+
 	/* Easy solution: Does everyone involved support pipelining? Hooray! Just use
 	 * one TCP connection! */
 	if (conn->pipelining)
@@ -282,6 +304,8 @@
 		}
 	}
 
+	purple_debug_warning("jabber", "Could not find a HTTP connection!\n");
+
 	/* None available. */
 	return NULL;
 }
@@ -293,9 +317,29 @@
 	PurpleHTTPConnection *chosen;
 	GString *packet = NULL;
 
+	if (type != PACKET_FLUSH && type != PACKET_TERMINATE) {
+		/*
+		 * Unless this is a flush (or session terminate, which needs to be
+		 * sent immediately), queue up the data and start a timer to flush
+		 * the buffer.
+		 */
+		if (data) {
+			int len = data ? strlen(data) : 0;
+			purple_circ_buffer_append(conn->pending, data, len);
+		}
+
+		if (purple_debug_is_verbose())
+			purple_debug_misc("jabber", "bosh: %p has %" G_GSIZE_FORMAT " bytes in "
+			                  "the buffer.\n", conn, conn->pending->bufused);
+		if (conn->send_timer == 0)
+			conn->send_timer = purple_timeout_add_seconds(BUFFER_SEND_IN_SECS,
+					send_timer_cb, conn);
+		return;
+	}
+
 	chosen = find_available_http_connection(conn);
 
-	if (type != PACKET_NORMAL && !chosen) {
+	if (!chosen) {
 		/*
 		 * For non-ordinary traffic, we can't 'buffer' it, so use the
 		 * first connection.
@@ -303,25 +347,16 @@
 		chosen = conn->connections[0];
 
 		if (chosen->state != HTTP_CONN_CONNECTED) {
-			purple_debug_info("jabber", "Unable to find a ready BOSH "
+			purple_debug_warning("jabber", "Unable to find a ready BOSH "
 					"connection. Ignoring send of type 0x%02x.\n", type);
 			return;
 		}
 	}
 
-	if (type == PACKET_NORMAL && (!chosen ||
-	        (conn->max_requests > 0 && conn->requests == conn->max_requests))) {
-		/*
-		 * For normal data, send up to max_requests requests at a time or there is no
-		 * connection ready (likely, we're currently opening a second connection and
-		 * will send these packets when connected).
-		 */
-		if (data) {
-			int len = data ? strlen(data) : 0;
-			purple_circ_buffer_append(conn->pending, data, len);
-		}
-
-		return;
+	/* We're flushing the send buffer, so remove the send timer */
+	if (conn->send_timer != 0) {
+		purple_timeout_remove(conn->send_timer);
+		conn->send_timer = 0;
 	}
 
 	packet = g_string_new(NULL);
@@ -337,7 +372,7 @@
 	                conn->sid,
 	                conn->js->user->domain);
 
-	if (type == PACKET_STREAM_RESTART) {
+	if (conn->needs_restart) {
 		packet = g_string_append(packet, " xmpp:restart='true'/>");
 		/* TODO: Do we need to wait for a response? */
 		conn->needs_restart = FALSE;
@@ -369,7 +404,7 @@
 static void jabber_bosh_connection_stream_restart(PurpleBOSHConnection *conn)
 {
 	conn->needs_restart = TRUE;
-	jabber_bosh_connection_send(conn, PACKET_STREAM_RESTART, NULL);
+	jabber_bosh_connection_send(conn, PACKET_NORMAL, NULL);
 }
 
 static gboolean jabber_bosh_connection_error_check(PurpleBOSHConnection *conn, xmlnode *node) {
@@ -388,12 +423,46 @@
 }
 
 static gboolean
+send_timer_cb(gpointer data)
+{
+	PurpleBOSHConnection *bosh;
+
+	bosh = data;
+	bosh->send_timer = 0;
+
+	jabber_bosh_connection_send(bosh, PACKET_FLUSH, NULL);
+
+	return FALSE;
+}
+
+static gboolean
 bosh_inactivity_cb(gpointer data)
 {
 	PurpleBOSHConnection *bosh = data;
+	bosh->inactivity_timer = 0;
 
-	jabber_bosh_connection_send(bosh, PACKET_NORMAL, NULL);
-	return TRUE;
+	if (bosh->send_timer != 0)
+		purple_timeout_remove(bosh->send_timer);
+
+	/* clears bosh->send_timer */
+	send_timer_cb(bosh);
+
+	return FALSE;
+}
+
+static void
+restart_inactivity_timer(PurpleBOSHConnection *conn)
+{
+	if (conn->inactivity_timer != 0) {
+		purple_timeout_remove(conn->inactivity_timer);
+		conn->inactivity_timer = 0;
+	}
+
+	if (conn->max_inactivity != 0) {
+		conn->inactivity_timer =
+			purple_timeout_add_seconds(conn->max_inactivity - 5 /* rounding */,
+			                           bosh_inactivity_cb, conn);
+	}
 }
 
 static void jabber_bosh_connection_received(PurpleBOSHConnection *conn, xmlnode *node) {
@@ -490,18 +559,18 @@
 
 	if (inactivity) {
 		conn->max_inactivity = atoi(inactivity);
-		if (conn->max_inactivity <= 2) {
+		if (conn->max_inactivity <= 5) {
 			purple_debug_warning("jabber", "Ignoring bogusly small inactivity: %s\n",
 			                     inactivity);
 			conn->max_inactivity = 0;
 		} else {
 			/* TODO: Integrate this with jabber.c keepalive checks... */
+			/* TODO: Can this check fail? It shouldn't */
 			if (conn->inactivity_timer == 0) {
-				purple_debug_misc("jabber", "Starting BOSH inactivity timer for %d secs (compensating for rounding)\n",
+				purple_debug_misc("jabber", "Starting BOSH inactivity timer "
+						"for %d secs (compensating for rounding)\n",
 						conn->max_inactivity - 5);
-				conn->inactivity_timer = purple_timeout_add_seconds(
-						conn->max_inactivity - 5 /* rounding */,
-						bosh_inactivity_cb, conn);
+				restart_inactivity_timer(conn);
 			}
 		}
 	}
@@ -512,7 +581,6 @@
 	/* FIXME: Depending on receiving features might break with some hosts */
 	packet = xmlnode_get_child(node, "features");
 	conn->state = BOSH_CONN_ONLINE;
-	conn->js->use_bosh = TRUE;
 	conn->receive_cb = auth_response_cb;
 	jabber_stream_features_parse(conn->js, packet);
 }
@@ -578,10 +646,14 @@
 {
 	/* Indicate we're ready and reset some variables */
 	conn->state = HTTP_CONN_CONNECTED;
+	if (conn->requests != 0)
+		purple_debug_error("jabber", "bosh: httpconn %p has %d requests, != 0\n",
+		                   conn, conn->requests);
+
 	conn->requests = 0;
-	if (conn->buf) {
-		g_string_free(conn->buf, TRUE);
-		conn->buf = NULL;
+	if (conn->read_buf) {
+		g_string_free(conn->read_buf, TRUE);
+		conn->read_buf = NULL;
 	}
 	conn->headers_done = FALSE;
 	conn->handled_len = conn->body_len = 0;
@@ -592,22 +664,12 @@
 		purple_debug_info("jabber", "BOSH session already exists. Trying to reuse it.\n");
 		if (conn->bosh->requests == 0 || conn->bosh->pending->bufused > 0) {
 			/* Send the pending data */
-			jabber_bosh_connection_send(conn->bosh, PACKET_NORMAL, NULL);
+			jabber_bosh_connection_send(conn->bosh, PACKET_FLUSH, NULL);
 		}
-#if 0
-		conn->bosh->receive_cb = jabber_bosh_connection_received;
-		if (conn->bosh->connect_cb)
-			conn->bosh->connect_cb(conn->bosh);
-#endif
 	} else
 		jabber_bosh_connection_boot(conn->bosh);
 }
 
-void jabber_bosh_connection_refresh(PurpleBOSHConnection *conn)
-{
-	jabber_bosh_connection_send(conn, PACKET_NORMAL, NULL);
-}
-
 static void http_connection_disconnected(PurpleHTTPConnection *conn)
 {
 	/*
@@ -633,6 +695,12 @@
 		conn->writeh = 0;
 	}
 
+	if (conn->requests > 0 && conn->read_buf->len == 0) {
+		purple_debug_error("jabber", "bosh: Adjusting BOSHconn requests (%d) to %d\n",
+		                   conn->bosh->requests, conn->bosh->requests - conn->requests);
+		conn->bosh->requests -= conn->requests;
+		conn->requests = 0;
+	}
 	if (conn->bosh->pipelining)
 		/* Hmmmm, fall back to multiple connections */
 		conn->bosh->pipelining = FALSE;
@@ -661,7 +729,7 @@
 {
 	const char *cursor;
 
-	cursor = conn->buf->str + conn->handled_len;
+	cursor = conn->read_buf->str + conn->handled_len;
 
 	if (!conn->headers_done) {
 		const char *content_length = purple_strcasestr(cursor, "\r\nContent-Length");
@@ -690,26 +758,26 @@
 
 		if (end_of_headers) {
 			conn->headers_done = TRUE;
-			conn->handled_len = end_of_headers - conn->buf->str + 4;
+			conn->handled_len = end_of_headers - conn->read_buf->str + 4;
 			cursor = end_of_headers + 4;
 		} else {
-			conn->handled_len = conn->buf->len;
+			conn->handled_len = conn->read_buf->len;
 			return;
 		}
 	}
 
 	/* Have we handled everything in the buffer? */
-	if (conn->handled_len >= conn->buf->len)
+	if (conn->handled_len >= conn->read_buf->len)
 		return;
 
 	/* Have we read all that the Content-Length promised us? */
-	if (conn->buf->len - conn->handled_len < conn->body_len)
+	if (conn->read_buf->len - conn->handled_len < conn->body_len)
 		return;
 
 	--conn->requests;
 	--conn->bosh->requests;
 
-	http_received_cb(conn->buf->str + conn->handled_len, conn->body_len,
+	http_received_cb(conn->read_buf->str + conn->handled_len, conn->body_len,
 	                 conn->bosh);
 
 	if (conn->bosh->state == BOSH_CONN_ONLINE &&
@@ -718,8 +786,8 @@
 		jabber_bosh_connection_send(conn->bosh, PACKET_NORMAL, NULL);
 	}
 
-	g_string_free(conn->buf, TRUE);
-	conn->buf = NULL;
+	g_string_free(conn->read_buf, TRUE);
+	conn->read_buf = NULL;
 	conn->headers_done = FALSE;
 	conn->handled_len = conn->body_len = 0;
 }
@@ -734,8 +802,8 @@
 	char buffer[1025];
 	int cnt, count = 0;
 
-	if (!conn->buf)
-		conn->buf = g_string_new(NULL);
+	if (!conn->read_buf)
+		conn->read_buf = g_string_new(NULL);
 
 	do {
 		if (conn->psc)
@@ -745,7 +813,7 @@
 
 		if (cnt > 0) {
 			count += cnt;
-			g_string_append_len(conn->buf, buffer, cnt);
+			g_string_append_len(conn->read_buf, buffer, cnt);
 		}
 	} while (cnt > 0);
 
@@ -765,7 +833,7 @@
 		/* Process what we do have */
 	}
 
-	if (conn->buf->len > 0)
+	if (conn->read_buf->len > 0)
 		jabber_bosh_http_connection_process(conn);
 }
 
@@ -879,7 +947,7 @@
 {
 	PurpleHTTPConnection *conn = data;
 	int ret;
-	int writelen = purple_circ_buffer_get_max_read(conn->write_buffer);
+	int writelen = purple_circ_buffer_get_max_read(conn->write_buf);
 
 	if (writelen == 0) {
 		purple_input_remove(conn->writeh);
@@ -887,7 +955,7 @@
 		return;
 	}
 
-	ret = http_connection_do_send(conn, conn->write_buffer->outptr, writelen);
+	ret = http_connection_do_send(conn, conn->write_buf->outptr, writelen);
 
 	if (ret < 0 && errno == EAGAIN)
 		return;
@@ -906,7 +974,7 @@
 		return;
 	}
 
-	purple_circ_buffer_mark_read(conn->write_buffer, ret);
+	purple_circ_buffer_mark_read(conn->write_buf, ret);
 }
 
 static void
@@ -916,6 +984,9 @@
 	int ret;
 	size_t len;
 
+	/* Sending something to the server, restart the inactivity timer */
+	restart_inactivity_timer(conn->bosh);
+
 	data = g_strdup_printf("POST %s HTTP/1.1\r\n"
 	                       "Host: %s\r\n"
 	                       "User-Agent: %s\r\n"
@@ -930,6 +1001,10 @@
 	++conn->requests;
 	++conn->bosh->requests;
 
+	if (purple_debug_is_unsafe() && purple_debug_is_verbose())
+		/* Will contain passwords for SASL PLAIN and is verbose */
+		purple_debug_misc("jabber", "BOSH: Sending %s\n", data);
+
 	if (conn->writeh == 0)
 		ret = http_connection_do_send(conn, data, len);
 	else {
@@ -956,7 +1031,7 @@
 		if (conn->writeh == 0)
 			conn->writeh = purple_input_add(conn->psc ? conn->psc->fd : conn->fd,
 					PURPLE_INPUT_WRITE, http_connection_send_cb, conn);
-		purple_circ_buffer_append(conn->write_buffer, data + ret, len - ret);
+		purple_circ_buffer_append(conn->write_buf, data + ret, len - ret);
 	}
 }
 
--- a/libpurple/protocols/jabber/bosh.h	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/jabber/bosh.h	Sun Aug 02 16:43:49 2009 +0900
@@ -37,5 +37,4 @@
 void jabber_bosh_connection_connect(PurpleBOSHConnection *conn);
 void jabber_bosh_connection_close(PurpleBOSHConnection *conn);
 void jabber_bosh_connection_send_raw(PurpleBOSHConnection *conn, const char *data);
-void jabber_bosh_connection_refresh(PurpleBOSHConnection *conn);
 #endif /* PURPLE_JABBER_BOSH_H_ */
--- a/libpurple/protocols/jabber/buddy.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/jabber/buddy.c	Sun Aug 02 16:43:49 2009 +0900
@@ -1765,9 +1765,7 @@
 	if(!jb)
 		return m;
 
-	/* XXX: fix the NOT ME below */
-
-	if(js->protocol_version == JABBER_PROTO_0_9 /* && NOT ME */) {
+	if (js->protocol_version == JABBER_PROTO_0_9 && jb != js->user_jb) {
 		if(jb->invisible & JABBER_INVIS_BUDDY) {
 			act = purple_menu_action_new(_("Un-hide From"),
 			                           PURPLE_CALLBACK(jabber_buddy_make_visible),
@@ -1780,7 +1778,7 @@
 		m = g_list_append(m, act);
 	}
 
-	if(jb->subscription & JABBER_SUB_FROM /* && NOT ME */) {
+	if(jb->subscription & JABBER_SUB_FROM && jb != js->user_jb) {
 		act = purple_menu_action_new(_("Cancel Presence Notification"),
 		                           PURPLE_CALLBACK(jabber_buddy_cancel_presence_notification),
 		                           NULL, NULL);
@@ -1793,7 +1791,7 @@
 		                           NULL, NULL);
 		m = g_list_append(m, act);
 
-	} else /* if(NOT ME) */{
+	} else if (jb != js->user_jb) {
 
 		/* shouldn't this just happen automatically when the buddy is
 		   removed? */
--- a/libpurple/protocols/jabber/buddy.h	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/jabber/buddy.h	Sun Aug 02 16:43:49 2009 +0900
@@ -33,10 +33,12 @@
 	JABBER_BUDDY_STATE_DND
 } JabberBuddyState;
 
+typedef struct _JabberBuddy JabberBuddy;
+
 #include "jabber.h"
 #include "caps.h"
 
-typedef struct _JabberBuddy {
+struct _JabberBuddy {
 	GList *resources;
 	char *error_msg;
 	enum {
@@ -52,7 +54,7 @@
 		JABBER_SUB_BOTH    = (JABBER_SUB_TO | JABBER_SUB_FROM),
 		JABBER_SUB_REMOVE  = 1 << 4
 	} subscription;
-} JabberBuddy;
+};
 
 typedef struct _JabberAdHocCommands {
 	char *jid;
--- a/libpurple/protocols/jabber/disco.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/jabber/disco.c	Sun Aug 02 16:43:49 2009 +0900
@@ -85,11 +85,11 @@
 
 	/* TODO: When we support zeroconf proxies, fix this to handle them */
 	if (!(sh->jid && sh->host && sh->port > 0)) {
+		js->bs_proxies = g_list_remove(js->bs_proxies, sh);
 		g_free(sh->jid);
 		g_free(sh->host);
 		g_free(sh->zeroconf);
 		g_free(sh);
-		js->bs_proxies = g_list_remove(js->bs_proxies, sh);
 	}
 }
 
--- a/libpurple/protocols/jabber/google.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/jabber/google.c	Sun Aug 02 16:43:49 2009 +0900
@@ -431,7 +431,7 @@
 	return (session->media != NULL) ? TRUE : FALSE;
 }
 
-static void
+static gboolean
 google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
 {
 	JabberIq *result;
@@ -444,7 +444,7 @@
 
 	if (session->state != UNINIT) {
 		purple_debug_error("jabber", "Received initiate for active session.\n");
-		return;
+		return FALSE;
 	}
 
 	desc_element = xmlnode_get_child(sess, "description");
@@ -457,7 +457,7 @@
 	else {
 		purple_debug_error("jabber", "Received initiate with "
 				"invalid namespace %s.\n", xmlns);
-		return;
+		return FALSE;
 	}
 
 	session->media = purple_media_manager_create_media(
@@ -481,7 +481,7 @@
 				PURPLE_MEDIA_INFO_HANGUP, NULL, NULL, TRUE);
 		google_session_send_terminate(session);
 		g_free(params);
-		return;
+		return FALSE;
 	}
 
 	g_free(params);
@@ -552,6 +552,8 @@
 	jabber_iq_set_id(result, iq_id);
 	xmlnode_set_attrib(result->node, "to", session->remote_jid);
 	jabber_iq_send(result);
+
+	return TRUE;
 }
 
 static void
@@ -777,7 +779,8 @@
 	session->js = js;
 	session->remote_jid = g_strdup(session->id.initiator);
 
-	google_session_parse_iq(js, session, session_node, iq_id);
+	if (!google_session_handle_initiate(js, session, session_node, iq_id))
+		google_session_destroy(session);
 }
 #endif /* USE_VV */
 
--- a/libpurple/protocols/jabber/jabber.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/jabber/jabber.c	Sun Aug 02 16:43:49 2009 +0900
@@ -132,15 +132,19 @@
 		xmlnode *jid;
 		char *full_jid;
 		if((jid = xmlnode_get_child(bind, "jid")) && (full_jid = xmlnode_get_data(jid))) {
-			JabberBuddy *my_jb = NULL;
 			jabber_id_free(js->user);
-			if(!(js->user = jabber_id_new(full_jid))) {
+
+			js->user = jabber_id_new(full_jid);
+			if (js->user == NULL) {
 				purple_connection_error_reason(js->gc,
 					PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 					_("Invalid response from server"));
+				g_free(full_jid);
+				return;
 			}
-			if((my_jb = jabber_buddy_find(js, full_jid, TRUE)))
-				my_jb->subscription |= JABBER_SUB_BOTH;
+
+			js->user_jb = jabber_buddy_find(js, full_jid, TRUE);
+			js->user_jb->subscription |= JABBER_SUB_BOTH;
 
 			purple_connection_set_display_name(js->gc, full_jid);
 
@@ -441,7 +445,7 @@
 	if (len == -1)
 		len = strlen(data);
 
-	if (js->use_bosh)
+	if (js->bosh)
 		jabber_bosh_connection_send_raw(js->bosh, data);
 	else
 		do_jabber_send_raw(js, data, len);
@@ -466,7 +470,7 @@
 		return;
 
 	js = purple_connection_get_protocol_data(pc);
-	if (js->use_bosh)
+	if (js->bosh)
 		if (g_str_equal((*packet)->name, "message") ||
 				g_str_equal((*packet)->name, "iq") ||
 				g_str_equal((*packet)->name, "presence"))
@@ -634,7 +638,6 @@
 		if (!strcmp(token[0], "_xmpp-client-xbosh")) {
 			purple_debug_info("jabber","Found alternative connection method using %s at %s.\n", token[0], token[1]);
 			js->bosh = jabber_bosh_connection_init(js, token[1]);
-			js->use_bosh = TRUE;
 			g_strfreev(token);
 			break;
 		}
@@ -778,7 +781,6 @@
 {
 	PurpleConnection *gc = purple_account_get_connection(account);
 	JabberStream *js;
-	JabberBuddy *my_jb;
 	PurplePresence *presence;
 	gchar *user;
 	gchar *slash;
@@ -813,9 +815,9 @@
 	js->buddies = g_hash_table_new_full(g_str_hash, g_str_equal,
 			g_free, (GDestroyNotify)jabber_buddy_free);
 
-	my_jb = jabber_buddy_find(js, user, TRUE);
+	js->user_jb = jabber_buddy_find(js, user, TRUE);
 	g_free(user);
-	if (!my_jb) {
+	if (!js->user_jb) {
 		/* This basically *can't* fail, but for good measure... */
 		purple_connection_error_reason(gc,
 			PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
@@ -824,7 +826,7 @@
 		g_return_val_if_reached(NULL);
 	}
 
-	my_jb->subscription |= JABBER_SUB_BOTH;
+	js->user_jb->subscription |= JABBER_SUB_BOTH;
 
 	js->iq_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal,
 			g_free, g_free);
@@ -867,7 +869,6 @@
 	 * attached to that choice, though.
 	 */
 	if (*bosh_url) {
-		js->use_bosh = TRUE;
 		js->bosh = jabber_bosh_connection_init(js, bosh_url);
 		if (js->bosh)
 			jabber_bosh_connection_connect(js->bosh);
@@ -1447,7 +1448,7 @@
 	 * on some SSL backends.
 	 */
 	if (!gc->disconnect_timeout) {
-		if (js->use_bosh)
+		if (js->bosh)
 			jabber_bosh_connection_close(js->bosh);
 		else if ((js->gsc && js->gsc->fd > 0) || js->fd > 0)
 			jabber_send_raw(js, "</stream:stream>", -1);
--- a/libpurple/protocols/jabber/jabber.h	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/jabber/jabber.h	Sun Aug 02 16:43:49 2009 +0900
@@ -164,6 +164,8 @@
 	time_t old_idle;
 
 	JabberID *user;
+	JabberBuddy *user_jb;
+
 	PurpleConnection *gc;
 	PurpleSslConnection *gsc;
 
@@ -253,7 +255,6 @@
 	guint max_srv_rec_idx;
 
 	/* BOSH stuff */
-	gboolean use_bosh;
 	PurpleBOSHConnection *bosh;
 
 	/**
--- a/libpurple/protocols/jabber/roster.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/jabber/roster.c	Sun Aug 02 16:43:49 2009 +0900
@@ -66,7 +66,7 @@
 }
 
 static void add_purple_buddy_to_groups(JabberStream *js, const char *jid,
-		const char *alias, GSList *groups, const char *own_jid)
+		const char *alias, GSList *groups)
 {
 	GSList *buddies, *l;
 	GSList *pool = NULL;
@@ -162,12 +162,6 @@
 		purple_blist_add_buddy(b, NULL, g, NULL);
 		purple_blist_alias_buddy(b, alias);
 
-		/* If we just learned about ourself, then fake our status,
-		 * because we won't be receiving a normal presence message
-		 * about ourself. */
-		if(!strcmp(purple_buddy_get_name(b), own_jid))
-			jabber_presence_fake_to_self(js, NULL);
-
 		g_free(groups->data);
 		groups = g_slist_delete_link(groups, groups);
 	}
@@ -187,7 +181,6 @@
                          JabberIqType type, const char *id, xmlnode *query)
 {
 	xmlnode *item, *group;
-	gchar *own_jid;
 
 	if (!jabber_is_own_account(js, from)) {
 		purple_debug_warning("jabber", "Received bogon roster push from %s\n",
@@ -197,8 +190,6 @@
 
 	js->currently_parsing_roster_push = TRUE;
 
-	own_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain);
-
 	for(item = xmlnode_get_child(query, "item"); item; item = xmlnode_get_next_twin(item))
 	{
 		const char *jid, *name, *subscription, *ask;
@@ -216,11 +207,7 @@
 			continue;
 
 		if(subscription) {
-			gboolean me = FALSE;
-
-			me = g_str_equal(own_jid, jabber_normalize(js->gc->account, jid));
-
-			if(me)
+			if (jb == js->user_jb)
 				jb->subscription = JABBER_SUB_BOTH;
 			else if(!strcmp(subscription, "none"))
 				jb->subscription = JABBER_SUB_NONE;
@@ -260,11 +247,12 @@
 				groups = g_slist_prepend(groups, group_name);
 			}
 
-			add_purple_buddy_to_groups(js, jid, name, groups, own_jid);
+			add_purple_buddy_to_groups(js, jid, name, groups);
+			if (jb == js->user_jb)
+				jabber_presence_fake_to_self(js, NULL);
 		}
 	}
 
-	g_free(own_jid);
 	js->currently_parsing_roster_push = FALSE;
 
 	/* if we're just now parsing the roster for the first time,
@@ -348,7 +336,6 @@
 	char *who;
 	JabberBuddy *jb;
 	JabberBuddyResource *jbr;
-	char *own_jid;
 	const char *name;
 
 	/* If we haven't received the roster yet, ignore any adds */
@@ -366,8 +353,7 @@
 
 	jabber_roster_update(js, who, NULL);
 
-	own_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain);
-	if (g_str_equal(who, own_jid)) {
+	if (jb == js->user_jb) {
 		jabber_presence_fake_to_self(js, NULL);
 	} else if(!jb || !(jb->subscription & JABBER_SUB_TO)) {
 		jabber_presence_subscription_set(js, who, "subscribe");
@@ -377,7 +363,6 @@
 				"priority", jbr->priority, jbr->status ? "message" : NULL, jbr->status, NULL);
 	}
 
-	g_free(own_jid);
 	g_free(who);
 }
 
--- a/libpurple/protocols/jabber/si.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/jabber/si.c	Sun Aug 02 16:43:49 2009 +0900
@@ -1359,6 +1359,8 @@
 			fclose(jsx->fp);
 		}
 
+		purple_debug_info("jabber", "jabber_si_xfer_free(): freeing jsx %p\n", jsx);
+
 		g_free(jsx->stream_id);
 		g_free(jsx->iq_id);
 		/* XXX: free other stuff */
@@ -1366,7 +1368,6 @@
 		g_free(jsx);
 		xfer->data = NULL;
 
-		purple_debug_info("jabber", "jabber_si_xfer_free(): freeing jsx %p\n", jsx);
 	}
 }
 
--- a/libpurple/protocols/msn/directconn.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/msn/directconn.c	Sun Aug 02 16:43:49 2009 +0900
@@ -351,6 +351,8 @@
 
 		msn_directconn_destroy(directconn);
 	}
+
+	g_free(body);
 }
 
 static void
--- a/libpurple/protocols/msnp9/directconn.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/msnp9/directconn.c	Sun Aug 02 16:43:49 2009 +0900
@@ -355,6 +355,8 @@
 
 		msn_directconn_destroy(directconn);
 	}
+
+	g_free(body);
 }
 
 static void
--- a/libpurple/protocols/oscar/family_icq.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/oscar/family_icq.c	Sun Aug 02 16:43:49 2009 +0900
@@ -735,14 +735,6 @@
 
 				info = g_new0(struct aim_icq_info, 1);
 
-				if (info == NULL)
-				{
-					g_free(uin);
-					g_free(status_note_title);
-
-					break;
-				}
-
 				bslen = 13 + strlen(uin) + 30 + 6 + 4 + 55 + 85 + 4;
 				byte_stream_new(&bs, 4 + bslen);
 
--- a/libpurple/protocols/yahoo/libymsg.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/yahoo/libymsg.c	Sun Aug 02 16:43:49 2009 +0900
@@ -1836,6 +1836,7 @@
 			g_free(error_reason);
 			g_free(auth_data->seed);
 			g_free(auth_data);
+			g_free(token);
 		}
 		else {
 			/* OK to login, correct information provided */
@@ -2088,6 +2089,12 @@
 		msg = g_strdup(_("Your account is locked, please log in to the Yahoo! website."));
 		reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
 		break;
+	case 52:
+		/* See #9660. As much as we know, reconnecting shouldn't hurt */
+		purple_debug_info("yahoo", "Got error 52, Set to autoreconnect\n");
+		msg = g_strdup_printf(_("Unknown error"));
+		reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
+		break;
 	case 1013:
 		msg = g_strdup(_("Invalid username"));
 		reason = PURPLE_CONNECTION_ERROR_INVALID_USERNAME;
--- a/libpurple/protocols/yahoo/util.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/yahoo/util.c	Sun Aug 02 16:43:49 2009 +0900
@@ -763,6 +763,8 @@
 					} else if (!g_ascii_strncasecmp(&src[i+1], "A HREF=\"", j - i - 1)) {
 						j += 7;
 						g_string_append(dest, "\033[lm");
+						if (purple_str_has_prefix(src + j, "mailto:"))
+							j += sizeof("mailto:") - 1;
 						while (1) {
 							g_string_append_c(dest, src[j]);
 							if (++j >= src_len) {
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c	Sun Aug 02 16:43:49 2009 +0900
@@ -889,46 +889,48 @@
 
 	/* Build the file transfer handle. */
 	xfer = purple_xfer_new(gc->account, PURPLE_XFER_RECEIVE, from);
-	if (xfer)
-	{
-		xfer->data = xfer_data;
+	if (xfer == NULL) {
+		g_free(xfer_data);
+		g_return_if_reached();
+	}
+
+	xfer->data = xfer_data;
 
-		/* Set the info about the incoming file. */
-		if (filename) {
-			char *utf8_filename = yahoo_string_decode(gc, filename, TRUE);
+	/* Set the info about the incoming file. */
+	if (filename) {
+		char *utf8_filename = yahoo_string_decode(gc, filename, TRUE);
+		purple_xfer_set_filename(xfer, utf8_filename);
+		g_free(utf8_filename);
+	} else {
+		gchar *start, *end;
+		start = g_strrstr(xfer_data->path, "/");
+		if (start)
+			start++;
+		end = g_strrstr(xfer_data->path, "?");
+		if (start && *start && end) {
+			char *utf8_filename;
+			filename = g_strndup(start, end - start);
+			utf8_filename = yahoo_string_decode(gc, filename, TRUE);
+			g_free(filename);
 			purple_xfer_set_filename(xfer, utf8_filename);
 			g_free(utf8_filename);
-		} else {
-			gchar *start, *end;
-			start = g_strrstr(xfer_data->path, "/");
-			if (start)
-				start++;
-			end = g_strrstr(xfer_data->path, "?");
-			if (start && *start && end) {
-				char *utf8_filename;
-				filename = g_strndup(start, end - start);
-				utf8_filename = yahoo_string_decode(gc, filename, TRUE);
-				g_free(filename);
-				purple_xfer_set_filename(xfer, utf8_filename);
-				g_free(utf8_filename);
-				filename = NULL;
-			}
+			filename = NULL;
 		}
+	}
 
-		purple_xfer_set_size(xfer, filesize);
+	purple_xfer_set_size(xfer, filesize);
 
-		/* Setup our I/O op functions */
-		purple_xfer_set_init_fnc(xfer,        yahoo_xfer_init);
-		purple_xfer_set_start_fnc(xfer,       yahoo_xfer_start);
-		purple_xfer_set_end_fnc(xfer,         yahoo_xfer_end);
-		purple_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send);
-		purple_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv);
-		purple_xfer_set_read_fnc(xfer,        yahoo_xfer_read);
-		purple_xfer_set_write_fnc(xfer,       yahoo_xfer_write);
+	/* Setup our I/O op functions */
+	purple_xfer_set_init_fnc(xfer,        yahoo_xfer_init);
+	purple_xfer_set_start_fnc(xfer,       yahoo_xfer_start);
+	purple_xfer_set_end_fnc(xfer,         yahoo_xfer_end);
+	purple_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send);
+	purple_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv);
+	purple_xfer_set_read_fnc(xfer,        yahoo_xfer_read);
+	purple_xfer_set_write_fnc(xfer,       yahoo_xfer_write);
 
-		/* Now perform the request */
-		purple_xfer_request(xfer);
-	}
+	/* Now perform the request */
+	purple_xfer_request(xfer);
 }
 
 PurpleXfer *yahoo_new_xfer(PurpleConnection *gc, const char *who)
@@ -943,19 +945,22 @@
 
 	/* Build the file transfer handle. */
 	xfer = purple_xfer_new(gc->account, PURPLE_XFER_SEND, who);
-	if (xfer)
+	if (xfer == NULL)
 	{
-		xfer->data = xfer_data;
+		g_free(xfer_data);
+		g_return_val_if_reached(NULL);
+	}
+
+	xfer->data = xfer_data;
 
-		/* Setup our I/O op functions */
-		purple_xfer_set_init_fnc(xfer,        yahoo_xfer_init);
-		purple_xfer_set_start_fnc(xfer,       yahoo_xfer_start);
-		purple_xfer_set_end_fnc(xfer,         yahoo_xfer_end);
-		purple_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send);
-		purple_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv);
-		purple_xfer_set_read_fnc(xfer,        yahoo_xfer_read);
-		purple_xfer_set_write_fnc(xfer,       yahoo_xfer_write);
-	}
+	/* Setup our I/O op functions */
+	purple_xfer_set_init_fnc(xfer,        yahoo_xfer_init);
+	purple_xfer_set_start_fnc(xfer,       yahoo_xfer_start);
+	purple_xfer_set_end_fnc(xfer,         yahoo_xfer_end);
+	purple_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send);
+	purple_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv);
+	purple_xfer_set_read_fnc(xfer,        yahoo_xfer_read);
+	purple_xfer_set_write_fnc(xfer,       yahoo_xfer_write);
 
 	return xfer;
 }
@@ -1593,6 +1598,7 @@
 	char *service = NULL;
 	char *filename = NULL;
 	char *xfer_peer_idstring = NULL;
+	char *utf8_filename;
 	unsigned long filesize = 0L;
 	GSList *l;
 	GSList *filename_list = NULL;
@@ -1719,42 +1725,44 @@
 
 	/* Build the file transfer handle. */
 	xfer = purple_xfer_new(gc->account, PURPLE_XFER_RECEIVE, from);
+	if (xfer == NULL)
+	{
+		g_free(xfer_data);
+		g_return_if_reached();
+	}
+
 	xfer->message = NULL;
 
-	if (xfer)
-	{
-		/* Set the info about the incoming file. */
-		char *utf8_filename = yahoo_string_decode(gc, filename, TRUE);
-		purple_xfer_set_filename(xfer, utf8_filename);
-		g_free(utf8_filename);
-		purple_xfer_set_size(xfer, filesize);
+	/* Set the info about the incoming file. */
+	utf8_filename = yahoo_string_decode(gc, filename, TRUE);
+	purple_xfer_set_filename(xfer, utf8_filename);
+	g_free(utf8_filename);
+	purple_xfer_set_size(xfer, filesize);
 
-		xfer->data = xfer_data;
-
+	xfer->data = xfer_data;
 
-		/* Setup our I/O op functions */
-		purple_xfer_set_init_fnc(xfer,        yahoo_xfer_init_15);
-		purple_xfer_set_start_fnc(xfer,       yahoo_xfer_start);
-		purple_xfer_set_end_fnc(xfer,         yahoo_xfer_end);
-		purple_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send);
-		purple_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv);
-		purple_xfer_set_read_fnc(xfer,        yahoo_xfer_read);
-		purple_xfer_set_write_fnc(xfer,       yahoo_xfer_write);
-		purple_xfer_set_request_denied_fnc(xfer,yahoo_xfer_cancel_recv);
+	/* Setup our I/O op functions */
+	purple_xfer_set_init_fnc(xfer,        yahoo_xfer_init_15);
+	purple_xfer_set_start_fnc(xfer,       yahoo_xfer_start);
+	purple_xfer_set_end_fnc(xfer,         yahoo_xfer_end);
+	purple_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send);
+	purple_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv);
+	purple_xfer_set_read_fnc(xfer,        yahoo_xfer_read);
+	purple_xfer_set_write_fnc(xfer,       yahoo_xfer_write);
+	purple_xfer_set_request_denied_fnc(xfer,yahoo_xfer_cancel_recv);
 
-		g_hash_table_insert(yd->xfer_peer_idstring_map,
-							xfer_data->xfer_peer_idstring,
-							xfer);
+	g_hash_table_insert(yd->xfer_peer_idstring_map,
+						xfer_data->xfer_peer_idstring,
+						xfer);
 
-		if(nooffiles > 1) {
-			gchar* message;
-			message = g_strdup_printf(_("%s is trying to send you a group of %d files.\n"), xfer->who, nooffiles);
-			purple_xfer_conversation_write(xfer, message, FALSE);
-			g_free(message);
-		}
-		/* Now perform the request */
-		purple_xfer_request(xfer);
+	if(nooffiles > 1) {
+		gchar* message;
+		message = g_strdup_printf(_("%s is trying to send you a group of %d files.\n"), xfer->who, nooffiles);
+		purple_xfer_conversation_write(xfer, message, FALSE);
+		g_free(message);
 	}
+	/* Now perform the request */
+	purple_xfer_request(xfer);
 }
 
 void yahoo_process_filetrans_info_15(PurpleConnection *gc, struct yahoo_packet *pkt)
--- a/libpurple/protocols/yahoo/yahoo_packet.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/yahoo/yahoo_packet.c	Sun Aug 02 16:43:49 2009 +0900
@@ -403,7 +403,7 @@
 		struct yahoo_pair *pair = pkt->hash->data;
 		g_free(pair->value);
 		g_free(pair);
-		pkt->hash = g_slist_remove(pkt->hash, pair);
+		pkt->hash = g_slist_delete_link(pkt->hash, pkt->hash);
 	}
 	g_free(pkt);
 }
--- a/libpurple/protocols/zephyr/internal.h	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/protocols/zephyr/internal.h	Sun Aug 02 16:43:49 2009 +0900
@@ -23,6 +23,12 @@
 
 #define ETIMEDOUT WSAETIMEDOUT
 #define EADDRINUSE WSAEADDRINUSE
+#else /* !WIN32 */
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 4096
+#endif
+
 #endif
 
 #ifdef ZEPHYR_USES_HESIOD
--- a/libpurple/signals.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/libpurple/signals.c	Sun Aug 02 16:43:49 2009 +0900
@@ -363,8 +363,8 @@
 		{
 			g_free(handler_data);
 
-			signal_data->handlers = g_list_remove(signal_data->handlers,
-												  handler_data);
+			signal_data->handlers = g_list_delete_link(signal_data->handlers,
+												       l);
 			signal_data->handler_count--;
 
 			found = TRUE;
@@ -398,8 +398,8 @@
 			g_free(handler_data);
 
 			signal_data->handler_count--;
-			signal_data->handlers = g_list_remove(signal_data->handlers,
-												  handler_data);
+			signal_data->handlers = g_list_delete_link(signal_data->handlers,
+			                                           l);
 		}
 	}
 }
--- a/pidgin/gtkblist.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/pidgin/gtkblist.c	Sun Aug 02 16:43:49 2009 +0900
@@ -3566,7 +3566,7 @@
 			}
 
 			g_free(pce);
-			cur = g_list_remove(cur, pce);
+			cur = g_list_delete_link(cur, cur);
 		}
 	}
 	else if (PURPLE_BLIST_NODE_IS_CONTACT(node) || PURPLE_BLIST_NODE_IS_BUDDY(node))
--- a/pidgin/gtkimhtml.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/pidgin/gtkimhtml.c	Sun Aug 02 16:43:49 2009 +0900
@@ -5853,9 +5853,9 @@
 		if (activate) {
 			return FALSE;
 		}
+		klass->protocols = g_list_remove(klass->protocols, proto);
 		g_free(proto->name);
 		g_free(proto);
-		klass->protocols = g_list_remove(klass->protocols, proto);
 		return TRUE;
 	} else if (!activate) {
 		return FALSE;
--- a/pidgin/gtkprefs.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/pidgin/gtkprefs.c	Sun Aug 02 16:43:49 2009 +0900
@@ -698,7 +698,8 @@
 		g_free(original_name);
 		g_free(info);
 		return;
-	} else g_free(info);
+	} else
+		g_free(info);
 
 	is_archive = !g_ascii_strcasecmp(tail, ".gz") || !g_ascii_strcasecmp(tail, ".tgz");
 
@@ -1032,8 +1033,6 @@
 	info->original_name = NULL;
 
 	theme_install_theme(theme_file_name, info);
-
-	g_free(info);
 }
 
 static void
--- a/pidgin/gtkthemes.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/pidgin/gtkthemes.c	Sun Aug 02 16:43:49 2009 +0900
@@ -183,7 +183,7 @@
 			}
 			g_free(uio->smile);
 			g_free(uio);
-			wer->smileys = g_slist_remove(wer->smileys, uio);
+			wer->smileys = g_slist_delete_link(wer->smileys, wer->smileys);
 		}
 		theme->list = wer->next;
 		g_free(wer->sml);
@@ -229,7 +229,6 @@
 	struct smiley_list *list = NULL;
 	GSList *lst = smiley_themes;
 	char *dirname;
-	gboolean new_theme = FALSE;
 
 	if (!f)
 		return;
@@ -243,16 +242,18 @@
 		lst = lst->next;
 	}
 
-	if (!theme) {
-		new_theme = TRUE;
-		theme = g_new0(struct smiley_theme, 1);
-		theme->path = g_strdup(file);
-	} else if (theme == current_smiley_theme) {
+	if (theme != NULL && theme == current_smiley_theme) {
 		/* Don't reload the theme if it is already loaded */
 		fclose(f);
 		return;
 	}
 
+	if (theme == NULL) {
+		theme = g_new0(struct smiley_theme, 1);
+		theme->path = g_strdup(file);
+		smiley_themes = g_slist_prepend(smiley_themes, theme);
+	}
+
 	dirname = g_path_get_dirname(file);
 
 	while (!feof(f)) {
@@ -341,14 +342,11 @@
 	if (!theme->name || !theme->desc || !theme->author) {
 		purple_debug_error("gtkthemes", "Invalid file format, not loading smiley theme from '%s'\n", file);
 
+		smiley_themes = g_slist_remove(smiley_themes, theme);
 		pidgin_themes_destroy_smiley_theme(theme);
 		return;
 	}
 
-	if (new_theme) {
-		smiley_themes = g_slist_prepend(smiley_themes, theme);
-	}
-
 	if (load) {
 		GList *cnv;
 
--- a/pidgin/plugins/crazychat/glm.c	Sat Aug 01 14:55:12 2009 +0900
+++ b/pidgin/plugins/crazychat/glm.c	Sun Aug 02 16:43:49 2009 +0900
@@ -543,6 +543,8 @@
     fprintf(file, "Ns %f\n", material->shininess / 128.0 * 1000.0);
     fprintf(file, "\n");
   }
+
+  fclose(file);
 }