changeset 27864:e81f0d1966db

propagate from branch 'im.pidgin.pidgin' (head fedb7de8d5fe70aa0cd0ee66f32050b68f5fd230) to branch 'im.pidgin.pidgin.yaz' (head 408cc507c692410048dc0b6fd409bb65b04b45cd)
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 28 Jul 2008 06:18:51 +0000
parents 57727a140609 (current diff) d1d32f318ce9 (diff)
children 86e7e2b5e59a
files configure.ac libpurple/protocols/irc/irc.c libpurple/protocols/irc/parse.c libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/si.c libpurple/protocols/msn/switchboard.c libpurple/protocols/oscar/oscar.c libpurple/protocols/oscar/oscar.h libpurple/protocols/yahoo/yahoo_profile.c libpurple/server.c
diffstat 41 files changed, 700 insertions(+), 263 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Fri Jul 18 08:45:31 2008 +0000
+++ b/COPYRIGHT	Mon Jul 28 06:18:51 2008 +0000
@@ -157,6 +157,7 @@
 Konrad Gräfe
 Miah Gregory
 David Grohmann
+Vladislav Guberinić
 Gideon N. Guillen
 Christian Hammond
 Erick Hamness
--- a/ChangeLog	Fri Jul 18 08:45:31 2008 +0000
+++ b/ChangeLog	Mon Jul 28 06:18:51 2008 +0000
@@ -10,6 +10,9 @@
 	  we don't install our SSL CA certs, so it's important that the
 	  libpurple package depend on the CA certificates.
 
+	IRC:
+	* /ctcp command (Vladislav Guberinić)
+
 	MSN:
 	* Update MSN support to protocol 15 (Elliott Sales de Andrade, Jorge
 	  Villaseñor, Mike Ruprecht, Carlos Silva, Ma Yuan, Daniel Ljungborg
--- a/ChangeLog.win32	Fri Jul 18 08:45:31 2008 +0000
+++ b/ChangeLog.win32	Mon Jul 28 06:18:51 2008 +0000
@@ -1,3 +1,8 @@
+version 2.5.0 (??/??/2008):
+	* Don't install the GSSAPI SASL plugin on NT4 to avoid an error popup.
+	* Upgrade to Perl 5.10 (System Perl runtime must be upgraded for Perl
+	  plugins to continue to work).
+
 version 2.4.3 (07/01/2008):
 	* No changes
 
--- a/configure.ac	Fri Jul 18 08:45:31 2008 +0000
+++ b/configure.ac	Mon Jul 28 06:18:51 2008 +0000
@@ -47,7 +47,7 @@
 m4_define([purple_major_version], [2])
 m4_define([purple_minor_version], [5])
 m4_define([purple_micro_version], [0])
-m4_define([purple_version_suffix], [])
+m4_define([purple_version_suffix], [devel])
 m4_define([purple_version],
           [purple_major_version.purple_minor_version.purple_micro_version])
 m4_define([purple_display_version], purple_version[]m4_ifdef([purple_version_suffix],[purple_version_suffix]))
@@ -56,7 +56,7 @@
 m4_define([gnt_major_version], [2])
 m4_define([gnt_minor_version], [5])
 m4_define([gnt_micro_version], [0])
-m4_define([gnt_version_suffix], [])
+m4_define([gnt_version_suffix], [devel])
 m4_define([gnt_version],
           [gnt_major_version.gnt_minor_version.gnt_micro_version])
 m4_define([gnt_display_version], gnt_version[]m4_ifdef([gnt_version_suffix],[gnt_version_suffix]))
--- a/doc/funniest_home_convos.txt	Fri Jul 18 08:45:31 2008 +0000
+++ b/doc/funniest_home_convos.txt	Mon Jul 28 06:18:51 2008 +0000
@@ -510,3 +510,8 @@
 12:58 <staggered_ranks> why hasn't support for napster been removed?
 12:58 <deryni> It has.
 12:59 <staggered_ranks> oh.. ok
+
+
+14:39 <rrobbertt> Does anyone know a way to get text to speech with pidgin?
+14:41 <elb> do you want to be rooted sooner, or later?
+14:42 <seanegan> good question"; rm -rf ~
--- a/libpurple/plugins/perl/Makefile.mingw	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/plugins/perl/Makefile.mingw	Mon Jul 28 06:18:51 2008 +0000
@@ -47,7 +47,7 @@
 			-lws2_32 \
 			-lintl \
 			-lpurple \
-			-lperl58
+			-lperl510
 
 include $(PIDGIN_COMMON_RULES)
 
--- a/libpurple/plugins/perl/common/Makefile.mingw	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/plugins/perl/common/Makefile.mingw	Mon Jul 28 06:18:51 2008 +0000
@@ -5,6 +5,7 @@
 #
 
 PIDGIN_TREE_TOP := ../../../..
+GCCWARNINGS := -Wno-comment -Waggregate-return -Wcast-align -Wdeclaration-after-statement -Werror-implicit-function-declaration -Wextra -Wno-sign-compare -Wno-unused-parameter -Winit-self -Wmissing-declarations -Wmissing-prototypes -Wpointer-arith -Wundef -Wno-unused
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
 TARGET = Purple
@@ -12,8 +13,6 @@
 EXTUTILS ?= C:/perl/lib/ExtUtils
 PERL_PLUGIN_TOP := ..
 
-CFLAGS += -Wno-comment -Wno-unused
-
 ##
 ## INCLUDE PATHS
 ##
@@ -77,7 +76,7 @@
 ##
 ## LIBRARIES
 ##
-LIBS =			-lperl58 \
+LIBS =			-lperl510 \
 			-lperl \
 			-lpurple \
 			-lglib-2.0
--- a/libpurple/plugins/perl/perl-common.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/plugins/perl/perl-common.c	Mon Jul 28 06:18:51 2008 +0000
@@ -32,7 +32,10 @@
 
 static MGVTBL vtbl_free_object =
 {
-	NULL, NULL, NULL, NULL, magic_free_object, NULL, NULL
+	0, 0, 0, 0, magic_free_object, 0, 0
+#if PERL_API_REVISION > 5 || (PERL_API_REVISION == 5 && PERL_API_VERSION >= 10)
+	, 0
+#endif
 };
 
 static SV *
--- a/libpurple/plugins/perl/perl-common.h	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/plugins/perl/perl-common.h	Mon Jul 28 06:18:51 2008 +0000
@@ -5,9 +5,9 @@
 #ifdef _WIN32
 #undef pipe
 #endif
-#include <XSUB.h>
 #include <EXTERN.h>
 #include <perl.h>
+#include <XSUB.h>
 
 /* XXX: perl defines it's own _ but I think it's safe to undef it */
 #undef _
--- a/libpurple/plugins/perl/perl.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/plugins/perl/perl.c	Mon Jul 28 06:18:51 2008 +0000
@@ -67,6 +67,10 @@
 #undef group
 
 /* perl module support */
+#ifdef _WIN32
+EXTERN_C void boot_Win32CORE (pTHX_ CV* cv);
+#endif
+
 #ifdef OLD_PERL
 extern void boot_DynaLoader _((CV * cv));
 #else
@@ -127,10 +131,14 @@
 #endif
 {
 	char *file = __FILE__;
+	dXSUB_SYS;
 
 	/* This one allows dynamic loading of perl modules in perl scripts by
 	 * the 'use perlmod;' construction */
 	newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
+#ifdef _WIN32
+	newXS("Win32CORE::bootstrap", boot_Win32CORE, file);
+#endif
 }
 
 static void
@@ -240,18 +248,44 @@
 static gboolean
 probe_perl_plugin(PurplePlugin *plugin)
 {
-	/* XXX This would be much faster if I didn't create a new
-	 *     PerlInterpreter every time I probed a plugin */
 
-	PerlInterpreter *prober = perl_alloc();
-	char *argv[] = {"", plugin->path };
+	char *args[] = {"", plugin->path };
+	char **argv = args;
+	int argc = 2;
+	PerlInterpreter *prober;
 	gboolean status = TRUE;
 	HV *plugin_info;
+
+	PERL_SYS_INIT(&argc, &argv);
+
+	/* XXX This would be much faster if we didn't create a new
+	 *     PerlInterpreter every time we probe a plugin */
+	prober = perl_alloc();
+
 	PERL_SET_CONTEXT(prober);
+
 	PL_perl_destruct_level = 1;
 	perl_construct(prober);
 
-	perl_parse(prober, xs_init, 2, argv, NULL);
+/* Fix IO redirection to match where pidgin's is going.
+ * Without this, we lose stdout/stderr unless we redirect to a file */
+#ifdef _WIN32
+{
+	PerlIO* newprlIO = PerlIO_open("CONOUT$", "w");
+	if (newprlIO) {
+		int stdout_fd = PerlIO_fileno(PerlIO_stdout());
+		int stderr_fd = PerlIO_fileno(PerlIO_stderr());
+		PerlIO_close(PerlIO_stdout());
+		PerlIO_close(PerlIO_stderr());
+		PerlLIO_dup2(PerlIO_fileno(newprlIO), stdout_fd);
+		PerlLIO_dup2(PerlIO_fileno(newprlIO), stderr_fd);
+
+		PerlIO_close(newprlIO);
+	}
+}
+#endif
+
+	perl_parse(prober, xs_init, argc, argv, NULL);
 
 	perl_run(prober);
 
@@ -578,7 +612,7 @@
 	load_perl_plugin,                                 /**< load           */
 	unload_perl_plugin,                               /**< unload         */
 	destroy_perl_plugin,                              /**< destroy        */
-	
+
 	/* padding */
 	NULL,
 	NULL,
--- a/libpurple/protocols/bonjour/jabber.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Mon Jul 28 06:18:51 2008 +0000
@@ -672,7 +672,6 @@
 bonjour_jabber_start(BonjourJabber *jdata)
 {
 	struct sockaddr_in my_addr;
-	int yes = 1;
 	int i;
 	gboolean bind_successful;
 
@@ -686,16 +685,6 @@
 		return -1;
 	}
 
-	/* Make the socket reusable */
-	if (setsockopt(jdata->socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
-	{
-		purple_debug_error("bonjour", "Error setting socket options: %s\n", g_strerror(errno));
-		purple_connection_error_reason (jdata->account->gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Error setting socket options"));
-		return -1;
-	}
-
 	memset(&my_addr, 0, sizeof(struct sockaddr_in));
 	my_addr.sin_family = AF_INET;
 
@@ -709,6 +698,8 @@
 			bind_successful = TRUE;
 			break;
 		}
+
+		purple_debug_info("bonjour", "Unable to bind to port %u.(%s)\n", jdata->port, g_strerror(errno));
 		jdata->port++;
 	}
 
--- a/libpurple/protocols/irc/cmds.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/irc/cmds.c	Mon Jul 28 06:18:51 2008 +0000
@@ -68,6 +68,31 @@
 	return 0;
 }
 
+int irc_cmd_ctcp(struct irc_conn *irc, const char *cmd, const char *target, const char **args)
+{
+	/* we have defined args as args[0] is target and args[1] is ctcp command */
+        char *buf;
+	GString *string;
+	
+	/* check if we have args */
+	if (!args || !args[0] || !args[1])
+		return 0;
+
+	/* TODO:strip newlines or send each line as separate ctcp or something
+	 * actually, this shouldn't be done here but somewhere else since irc should support escaping newlines */
+
+	string = g_string_new(args[1]);
+	g_string_prepend_c (string,'\001');
+	g_string_append_c (string,'\001');
+	buf = irc_format(irc, "vn:", "PRIVMSG", args[0], string->str);
+	g_string_free(string,TRUE);
+
+	irc_send(irc, buf);
+	g_free(buf);
+	
+	return 1;
+}
+
 int irc_cmd_ctcp_action(struct irc_conn *irc, const char *cmd, const char *target, const char **args)
 {
 	PurpleConnection *gc = purple_account_get_connection(irc->account);
--- a/libpurple/protocols/irc/irc.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/irc/irc.c	Mon Jul 28 06:18:51 2008 +0000
@@ -360,7 +360,8 @@
 
 static gboolean do_login(PurpleConnection *gc) {
 	char *buf, *tmp = NULL;
-	const char *hostname;
+	char *hostname, *server;
+	const char *hosttmp;
 	const char *username, *realname;
 	struct irc_conn *irc = gc->proto_data;
 	const char *pass = purple_connection_get_password(gc);
@@ -374,7 +375,6 @@
 		g_free(buf);
 	}
 
-	hostname = purple_get_host_name();
 	realname = purple_account_get_string(irc->account, "realname", "");
 	username = purple_account_get_string(irc->account, "username", "");
 
@@ -389,9 +389,29 @@
 		}
 	}
 
-	buf = irc_format(irc, "vvvv:", "USER", tmp ? tmp : username, hostname, irc->server,
-			      strlen(realname) ? realname : IRC_DEFAULT_ALIAS);
+	hosttmp = purple_get_host_name();
+	if (*hosttmp == ':') {
+		/* This is either an IPv6 address, or something which
+		 * doesn't belong here.  Either way, we need to escape
+		 * it. */
+		hostname = g_strdup_printf("0%s", hosttmp);
+	} else {
+		/* Ugly, I know. */
+		hostname = g_strdup(hosttmp);
+	}
+
+	if (*irc->server == ':') {
+		/* Same as hostname, above. */
+		server = g_strdup_printf("0%s", irc->server);
+	} else {
+		server = g_strdup(irc->server);
+	}
+
+	buf = irc_format(irc, "vvvv:", "USER", tmp ? tmp : username, hostname, server,
+	                 strlen(realname) ? realname : IRC_DEFAULT_ALIAS);
 	g_free(tmp);
+	g_free(hostname);
+	g_free(server);
 	if (irc_send(irc, buf) < 0) {
 		g_free(buf);
 		return FALSE;
--- a/libpurple/protocols/irc/irc.h	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/irc/irc.h	Mon Jul 28 06:18:51 2008 +0000
@@ -164,6 +164,7 @@
 
 int irc_cmd_default(struct irc_conn *irc, const char *cmd, const char *target, const char **args);
 int irc_cmd_away(struct irc_conn *irc, const char *cmd, const char *target, const char **args);
+int irc_cmd_ctcp(struct irc_conn *irc, const char *cmd, const char *target, const char **args);
 int irc_cmd_ctcp_action(struct irc_conn *irc, const char *cmd, const char *target, const char **args);
 int irc_cmd_ctcp_version(struct irc_conn *irc, const char *cmd, const char *target, const char **args);
 int irc_cmd_invite(struct irc_conn *irc, const char *cmd, const char *target, const char **args);
--- a/libpurple/protocols/irc/parse.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/irc/parse.c	Mon Jul 28 06:18:51 2008 +0000
@@ -123,6 +123,7 @@
 } _irc_cmds[] = {
 	{ "action", ":", irc_cmd_ctcp_action, N_("action &lt;action to perform&gt;:  Perform an action.") },
 	{ "away", ":", irc_cmd_away, N_("away [message]:  Set an away message, or use no message to return from being away.") },
+	{ "ctcp", "t:", irc_cmd_ctcp, N_("ctcp <nick> <msg>: sends ctcp msg to nick.") },
 	{ "chanserv", ":", irc_cmd_service, N_("chanserv: Send a command to chanserv") },
 	{ "deop", ":", irc_cmd_op, N_("deop &lt;nick1&gt; [nick2] ...:  Remove channel operator status from someone. You must be a channel operator to do this.") },
 	{ "devoice", ":", irc_cmd_op, N_("devoice &lt;nick1&gt; [nick2] ...:  Remove channel voice status from someone, preventing them from speaking if the channel is moderated (+m). You must be a channel operator to do this.") },
--- a/libpurple/protocols/jabber/disco.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/jabber/disco.c	Mon Jul 28 06:18:51 2008 +0000
@@ -73,6 +73,15 @@
 			  "jid='%s' host='%s' port='%d' zeroconf='%s'\n",
 			   from ? from : "", sh->host ? sh->host : "",
 			   sh->port, sh->zeroconf ? sh->zeroconf : "");
+
+	/* TODO: When we support zeroconf proxies, fix this to handle them */
+	if (!(sh->jid && sh->host && sh->port > 0)) {
+		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);
+	}
 }
 
 
@@ -329,6 +338,7 @@
 static void
 jabber_disco_finish_server_info_result_cb(JabberStream *js)
 {
+	const char *ft_proxies;
 
 	jabber_vcard_fetch_mine(js);
 
@@ -339,11 +349,44 @@
 
 	/* Send initial presence; this will trigger receipt of presence for contacts on the roster */
 	jabber_presence_send(js->gc->account, NULL);
-	
+
 	if (js->server_caps & JABBER_CAP_ADHOC) {
 		/* The server supports ad-hoc commands, so let's request the list */
 		jabber_adhoc_server_get_list(js);
 	}
+
+	/* If there are manually specified bytestream proxies, query them */
+	ft_proxies = purple_account_get_string(js->gc->account, "ft_proxies", NULL);
+	if (ft_proxies) {
+		JabberIq *iq;
+		JabberBytestreamsStreamhost *sh;
+		int i;
+		char *tmp;
+		gchar **ft_proxy_list = g_strsplit(ft_proxies, ",", 0);
+
+		for(i = 0; ft_proxy_list[i]; i++) {
+			g_strstrip(ft_proxy_list[i]);
+			if(!(*ft_proxy_list[i]))
+				continue;
+
+			/* We used to allow specifying a port directly here; get rid of it */
+			if((tmp = strchr(ft_proxy_list[i], ':')))
+				*tmp = '\0';
+
+			sh = g_new0(JabberBytestreamsStreamhost, 1);
+			sh->jid = g_strdup(ft_proxy_list[i]);
+			js->bs_proxies = g_list_prepend(js->bs_proxies, sh);
+
+			iq = jabber_iq_new_query(js, JABBER_IQ_GET,
+						 "http://jabber.org/protocol/bytestreams");
+			xmlnode_set_attrib(iq->node, "to", sh->jid);
+			jabber_iq_set_callback(iq, jabber_disco_bytestream_server_cb, sh);
+			jabber_iq_send(iq);
+		}
+
+		g_strfreev(ft_proxy_list);
+	}
+
 }
 
 static void
--- a/libpurple/protocols/jabber/jabber.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Mon Jul 28 06:18:51 2008 +0000
@@ -63,6 +63,7 @@
 GList *jabber_features = NULL;
 
 static void jabber_unregister_account_cb(JabberStream *js);
+static void try_srv_connect(JabberStream *js);
 
 static void jabber_stream_init(JabberStream *js)
 {
@@ -522,15 +523,23 @@
 	JabberStream *js = gc->proto_data;
 
 	if (source < 0) {
-		gchar *tmp;
-		tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"),
-				error);
-		purple_connection_error_reason (gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
+		if (js->srv_rec != NULL) {
+			purple_debug_error("jabber", "Unable to connect to server: %s.  Trying next SRV record.\n", error);
+			try_srv_connect(js);
+		} else {
+			gchar *tmp;
+			tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"),
+					      error);
+			purple_connection_error_reason(gc,
+					PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
+			g_free(tmp);
+		}
 		return;
 	}
 
+	g_free(js->srv_rec);
+	js->srv_rec = NULL;
+
 	js->fd = source;
 
 	if(js->state == JABBER_STREAM_CONNECTING)
@@ -565,37 +574,62 @@
 			jabber_login_callback_ssl, jabber_ssl_connect_failure, js->certificate_CN, js->gc);
 }
 
-static void jabber_login_connect(JabberStream *js, const char *domain, const char *host, int port)
+static gboolean jabber_login_connect(JabberStream *js, const char *domain, const char *host, int port,
+				 gboolean fatal_failure)
 {
 	/* host should be used in preference to domain to
 	 * allow SASL authentication to work with FQDN of the server,
 	 * but we use domain as fallback for when users enter IP address
 	 * in connect server */
+	g_free(js->serverFQDN);
 	if (purple_ip_address_is_valid(host))
 		js->serverFQDN = g_strdup(domain);
 	else
 		js->serverFQDN = g_strdup(host);
 
 	if (purple_proxy_connect(js->gc, js->gc->account, host,
-			port, jabber_login_callback, js->gc) == NULL)
-		purple_connection_error_reason (js->gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Unable to create socket"));
+			port, jabber_login_callback, js->gc) == NULL) {
+		if (fatal_failure) {
+			purple_connection_error_reason (js->gc,
+				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+				_("Unable to create socket"));
+		}
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void try_srv_connect(JabberStream *js)
+{
+	while (js->srv_rec != NULL && js->srv_rec_idx < js->max_srv_rec_idx) {
+		PurpleSrvResponse *tmp_resp = js->srv_rec + (js->srv_rec_idx++);
+		if (jabber_login_connect(js, tmp_resp->hostname, tmp_resp->hostname, tmp_resp->port, FALSE))
+			return;
+	}
+
+	g_free(js->srv_rec);
+	js->srv_rec = NULL;
+
+	/* Fall back to the defaults (I'm not sure if we should actually do this) */
+	jabber_login_connect(js, js->user->domain, js->user->domain,
+		purple_account_get_int(js->gc->account, "port", 5222), TRUE);
 }
 
 static void srv_resolved_cb(PurpleSrvResponse *resp, int results, gpointer data)
 {
-	JabberStream *js;
-
-	js = data;
+	JabberStream *js = data;
 	js->srv_query_data = NULL;
 
 	if(results) {
-		jabber_login_connect(js, resp->hostname, resp->hostname, resp->port);
-		g_free(resp);
+		js->srv_rec = resp;
+		js->srv_rec_idx = 0;
+		js->max_srv_rec_idx = results;
+		try_srv_connect(js);
 	} else {
 		jabber_login_connect(js, js->user->domain, js->user->domain,
-			purple_account_get_int(js->gc->account, "port", 5222));
+			purple_account_get_int(js->gc->account, "port", 5222), TRUE);
 	}
 }
 
@@ -677,7 +711,7 @@
 	 * invoke the magic of SRV lookups, to figure out host and port */
 	if(!js->gsc) {
 		if(connect_server[0]) {
-			jabber_login_connect(js, js->user->domain, connect_server, purple_account_get_int(account, "port", 5222));
+			jabber_login_connect(js, js->user->domain, connect_server, purple_account_get_int(account, "port", 5222), TRUE);
 		} else {
 			js->srv_query_data = purple_srv_resolve("xmpp-client",
 					"tcp", js->user->domain, srv_resolved_cb, js);
@@ -1158,7 +1192,7 @@
 		if (connect_server[0]) {
 			jabber_login_connect(js, js->user->domain, server,
 			                     purple_account_get_int(account,
-			                                          "port", 5222));
+			                                          "port", 5222), TRUE);
 		} else {
 			js->srv_query_data = purple_srv_resolve("xmpp-client",
 			                                      "tcp",
@@ -1329,7 +1363,10 @@
 
 	if (js->keepalive_timeout != -1)
 		purple_timeout_remove(js->keepalive_timeout);
-	
+
+	g_free(js->srv_rec);
+	js->srv_rec = NULL;
+
 	g_free(js);
 
 	gc->proto_data = NULL;
--- a/libpurple/protocols/jabber/jabber.h	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Mon Jul 28 06:18:51 2008 +0000
@@ -201,6 +201,10 @@
 	
 	/* A purple timeout tag for the keepalive */
 	int keepalive_timeout;
+
+	PurpleSrvResponse *srv_rec;
+	guint srv_rec_idx;
+	guint max_srv_rec_idx;
 };
 
 typedef gboolean (JabberFeatureEnabled)(JabberStream *js, const gchar *shortname, const gchar *namespace);
--- a/libpurple/protocols/jabber/libxmpp.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Mon Jul 28 06:18:51 2008 +0000
@@ -236,7 +236,7 @@
 	option = purple_account_option_string_new(_("File transfer proxies"),
 						  "ft_proxies",
 						/* TODO: Is this an acceptable default? */
-						  "proxy.jabber.org:7777");
+						  "proxy.jabber.org");
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
 						  option);
 
--- a/libpurple/protocols/jabber/si.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/jabber/si.c	Mon Jul 28 06:18:51 2008 +0000
@@ -723,7 +723,6 @@
 	JabberSIXfer *jsx;
 	JabberIq *iq;
 	xmlnode *query, *streamhost;
-	const char *ft_proxies;
 	char port[6];
 	GList *tmp;
 	JabberBytestreamsStreamhost *sh, *sh2;
@@ -787,52 +786,6 @@
 				jabber_si_xfer_bytestreams_send_connected_cb, xfer);
 	}
 
-	/* insert proxies here */
-	ft_proxies = purple_account_get_string(xfer->account, "ft_proxies", NULL);
-	if (ft_proxies) {
-		int i, portnum;
-		char *tmp;
-		gchar **ft_proxy_list = g_strsplit(ft_proxies, ",", 0);
-
-		g_list_foreach(jsx->streamhosts, jabber_si_free_streamhost, NULL);
-		g_list_free(jsx->streamhosts);
-		jsx->streamhosts = NULL;
-
-		for(i = 0; ft_proxy_list[i]; i++) {
-			g_strstrip(ft_proxy_list[i]);
-			if(!(*ft_proxy_list[i]))
-				continue;
-
-			if((tmp = strchr(ft_proxy_list[i], ':'))) {
-				portnum = atoi(tmp + 1);
-				*tmp = '\0';
-			} else
-				portnum = 7777;
-
-			g_snprintf(port, sizeof(port), "%hu", portnum);
-
-			purple_debug_info("jabber", "jabber_si_xfer_bytestreams_listen_cb() will be looking at jsx %p: jsx->streamhosts %p and ft_proxy_list[%i] %p\n",
-							  jsx, jsx->streamhosts, i, ft_proxy_list[i]);
-			if(g_list_find_custom(jsx->streamhosts, ft_proxy_list[i], jabber_si_compare_jid) != NULL)
-				continue;
-
-			streamhost_count++;
-			streamhost = xmlnode_new_child(query, "streamhost");
-			xmlnode_set_attrib(streamhost, "jid", ft_proxy_list[i]);
-			xmlnode_set_attrib(streamhost, "host", ft_proxy_list[i]);
-			xmlnode_set_attrib(streamhost, "port", port);
-
-			sh = g_new0(JabberBytestreamsStreamhost, 1);
-			sh->jid = g_strdup(ft_proxy_list[i]);
-			sh->host = g_strdup(ft_proxy_list[i]);
-			sh->port = portnum;
-
-			jsx->streamhosts = g_list_prepend(jsx->streamhosts, sh);
-		}
-
-		g_strfreev(ft_proxy_list);
-	}
-
 	for (tmp = jsx->js->bs_proxies; tmp; tmp = tmp->next) {
 		sh = tmp->data;
 
--- a/libpurple/protocols/msn/notification.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/msn/notification.c	Mon Jul 28 06:18:51 2008 +0000
@@ -989,7 +989,8 @@
 	PurpleConnection *gc;
 	MsnUserList *userlist;
 	char *who = NULL, *text = NULL;
-	xmlnode *payloadNode, *from, *textNode;
+	const char *id = NULL;
+	xmlnode *payloadNode, *from, *msg, *textNode;
 
 	purple_debug_misc("msn", "Incoming Page: {%s}\n", payload);
 
@@ -1014,9 +1015,27 @@
 	   </NOTIFICATION>
 	*/
 
+	/* This is the payload if your message was too long:
+	   <NOTIFICATION id="TrID" siteid="111100400" siteurl="http://mobile.msn.com/">
+	     <TO name="passport@example.com">
+	       <VIA agent="mobile"/>
+	     </TO>
+	     <FROM name="tel:+XXXXXXXXXXX"/>
+	     <MSG pri="1" id="407">
+	       <CAT Id="110110001"/>
+	       <ACTION url="2wayIM.asp"/>
+	       <SUBSCR url="2wayIM.asp"/>
+	       <BODY lcid="1033">
+	         <TEXT></TEXT>
+	       </BODY>
+	     </MSG>
+	   </NOTIFICATION>
+	*/
+
 	if (!(payloadNode = xmlnode_from_str(payload, len)) ||
 		!(from = xmlnode_get_child(payloadNode, "FROM")) ||
-		!(textNode = xmlnode_get_child(payloadNode, "MSG/BODY/TEXT")))
+		!(msg = xmlnode_get_child(payloadNode, "MSG")) ||
+		!(textNode = xmlnode_get_child(msg, "BODY/TEXT")))
 		return;
 
 	who = g_strdup(xmlnode_get_attrib(from, "name"));
@@ -1026,7 +1045,7 @@
 
 	/* Match number to user's mobile number, FROM is a phone number if the
 	   other side page you using your phone number */
-	if(!strncmp(who, "tel:+", 5)) {
+	if (!strncmp(who, "tel:+", 5)) {
 		MsnUser *user =
 			msn_userlist_find_user_with_mobile_phone(userlist, who + 4);
 
@@ -1036,7 +1055,20 @@
 		}
 	}
 
-	serv_got_im(gc, who, text, 0, time(NULL));
+	id = xmlnode_get_attrib(msg, "id");
+
+	if (id && !strcmp(id, "407")) {
+		/* TODO: Use this to NAK the transaction, maybe print the text, too.
+		unsigned int trId;
+		id = xmlnode_get_attrib(payloadNode, "id");
+		trId = atol(id);
+		*/
+		purple_conv_present_error(who, gc->account,
+			_("Mobile message was not sent because it was too long."));
+
+	} else {
+		serv_got_im(gc, who, text, 0, time(NULL));
+	}
 
 	g_free(text);
 	g_free(who);
--- a/libpurple/protocols/msn/oim.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/msn/oim.c	Mon Jul 28 06:18:51 2008 +0000
@@ -381,11 +381,11 @@
 
 					} else if (g_str_equal(faultcode_str, "q0:InvalidContent")) {
 						str_reason = _("Message was not sent because an unknown "
-						               "encoding error occured.");
+						               "encoding error occurred.");
 
 					} else {
 						str_reason = _("Message was not sent because an unknown "
-						               "error occured.");
+						               "error occurred.");
 					}
 					
 					msn_session_report_user(oim->session, msg->to_member, 
--- a/libpurple/protocols/msn/page.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/msn/page.c	Mon Jul 28 06:18:51 2008 +0000
@@ -53,9 +53,9 @@
 
 	g_return_val_if_fail(page != NULL, NULL);
 
-	str =
-		g_strdup_printf("<TEXT xml:space=\"preserve\" enc=\"utf-8\">%s</TEXT>",
-						msn_page_get_body(page));
+	str = g_markup_printf_escaped(
+			"<TEXT xml:space=\"preserve\" enc=\"utf-8\">%s</TEXT>",
+			msn_page_get_body(page));
 
 	if (ret_size != NULL)
 		*ret_size = strlen(str);
--- a/libpurple/protocols/msn/switchboard.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/msn/switchboard.c	Mon Jul 28 06:18:51 2008 +0000
@@ -982,7 +982,13 @@
 		account = cmdproc->session->account;
 		user = msg->remote_user;
 
-		serv_got_attention(account->gc, user, MSN_NUDGE);
+		if (swboard->current_users > 1 ||
+			((swboard->conv != NULL) &&
+			 purple_conversation_get_type(swboard->conv) == PURPLE_CONV_TYPE_CHAT))
+			purple_prpl_got_attention_in_chat(account->gc, swboard->chat_id, user, MSN_NUDGE);
+
+		else
+			purple_prpl_got_attention(account->gc, user, MSN_NUDGE);
 
 	} else if (!strcmp(id, "2")) {
 		/* Wink */
--- a/libpurple/protocols/oscar/family_icq.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/oscar/family_icq.c	Mon Jul 28 06:18:51 2008 +0000
@@ -36,6 +36,8 @@
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
 		return -EINVAL;
 
+	purple_debug_info("oscar", "Requesting offline messages from %s", od->sn);
+
 	bslen = 2 + 4 + 2 + 2;
 
 	byte_stream_new(&bs, 4 + bslen);
@@ -68,6 +70,8 @@
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
 		return -EINVAL;
 
+	purple_debug_info("oscar", "Acknowledged receipt of offline messages from %s", od->sn);
+
 	bslen = 2 + 4 + 2 + 2;
 
 	byte_stream_new(&bs, 4 + bslen);
@@ -214,7 +218,7 @@
 	byte_stream_putle16(&bs, 0x04b2); /* shrug. */
 	byte_stream_putle32(&bs, atoi(uin));
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
+	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
 
 	byte_stream_destroy(&bs);
 
@@ -242,6 +246,8 @@
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
 		return -EINVAL;
 
+	purple_debug_info("oscar", "Requesting ICQ alias for %s", uin);
+
 	bslen = 2 + 4 + 2 + 2 + 2 + 4;
 
 	byte_stream_new(&bs, 4 + bslen);
@@ -259,7 +265,7 @@
 	byte_stream_putle16(&bs, 0x04ba); /* shrug. */
 	byte_stream_putle32(&bs, atoi(uin));
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
+	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
 
 	byte_stream_destroy(&bs);
 
@@ -303,7 +309,7 @@
 	byte_stream_putle16(&bs, 0x051f); /* shrug. */
 	byte_stream_putle32(&bs, atoi(uin));
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
+	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
 
 	byte_stream_destroy(&bs);
 
@@ -497,7 +503,7 @@
 	byte_stream_put16(&bs, strlen(uin));
 	byte_stream_putstr(&bs, uin);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x000, snacid, &bs);
+	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x000, snacid, &bs, FALSE);
 
 	byte_stream_destroy(&bs);
 
@@ -877,7 +883,7 @@
 				info->next = od->icq_info;
 				od->icq_info = info;
 
-				flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs);
+				flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs, FALSE);
 
 				byte_stream_destroy(&bs);
 			}
--- a/libpurple/protocols/oscar/family_locate.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/oscar/family_locate.c	Mon Jul 28 06:18:51 2008 +0000
@@ -53,10 +53,9 @@
 	 * These are in ascending numerical order.
 	 */
 
-	/*
-	 * Perhaps better called OSCAR_CAPABILITY_SHORTCAPS
-	 */
-	{OSCAR_CAPABILITY_ICHAT,
+	/* Client understands short caps, a UUID of the form
+	 * 0946XXYY-4C7F-11D1-8222-444553540000 where XXYY is the short cap. */
+	{OSCAR_CAPABILITY_SHORTCAPS,
 	 {0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
@@ -64,11 +63,15 @@
 	 {0x09, 0x46, 0x00, 0x01, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
+	{OSCAR_CAPABILITY_XHTML_IM,
+	 {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" support in Windows AIM 5.5.3501 and newer */
+	/* "Live Video" (SIP/RTC Video) support in Windows AIM 5.5.3501 and newer */
 	{OSCAR_CAPABILITY_LIVEVIDEO,
 	 {0x09, 0x46, 0x01, 0x01, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
@@ -78,9 +81,15 @@
 	 {0x09, 0x46, 0x01, 0x02, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	/* In Windows AIM 5.5.3501 and newer */
+	/* "Microphone" support in Windows AIM 5.5.3501 and newer */
+	{OSCAR_CAPABILITY_MICROPHONE,
+	 {0x09, 0x46, 0x01, 0x03, 0x4c, 0x7f, 0x11, 0xd1,
+	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
+
+	/* Supports RTC Audio */
+	/* OSCAR_CAPABILITY_RTCAUDIO */
 	{OSCAR_CAPABILITY_GENERICUNKNOWN,
-	 {0x09, 0x46, 0x01, 0x03, 0x4c, 0x7f, 0x11, 0xd1,
+	 {0x09, 0x46, 0x01, 0x04, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
 	/* In iChatAV (version numbers...?) */
@@ -88,12 +97,21 @@
 	 {0x09, 0x46, 0x01, 0x05, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x45, 0x53, 0x54, 0x00}},
 
-	/*
-	 * Not really sure about this one.  In an email from
-	 * 26 Sep 2003, Matthew Sachs suggested that, "this
-	 * is probably the capability for the SMS features."
-	 */
-	{OSCAR_CAPABILITY_SMS,
+	/* Supports "new status message features" (Who advertises this one?) */
+	/* OSCAR_CAPABILITY_HOST_STATUS_TEXT_AWARE */ 
+	{OSCAR_CAPABILITY_GENERICUNKNOWN,
+	 {0x09, 0x46, 0x01, 0x0a, 0x4c, 0x7f, 0x11, 0xd1,
+	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
+
+	/* Supports "see as I type" (Who advertises this one?) */
+	/* OSCAR_CAPABILITY_SEE_AS_I_TYPE */
+	{OSCAR_CAPABILITY_GENERICUNKNOWN,
+	 {0x09, 0x46, 0x01, 0x0b, 0x4c, 0x7f, 0x11, 0xd1,
+	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
+
+	/* Client only asserts caps for services in which it is participating */
+	/* OSCAR_CAPABILITY_SMARTCAPS */ 
+	{OSCAR_CAPABILITY_GENERICUNKNOWN,
 	 {0x09, 0x46, 0x01, 0xff, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
@@ -1386,7 +1404,7 @@
 	byte_stream_putstr(&bs, sn);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, sn, strlen(sn)+1);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, snacid, &bs);
+	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, snacid, &bs, FALSE);
 
 	byte_stream_destroy(&bs);
 
--- a/libpurple/protocols/oscar/flap_connection.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/oscar/flap_connection.c	Mon Jul 28 06:18:51 2008 +0000
@@ -107,21 +107,21 @@
 	return MIN(((rateclass->current * (rateclass->windowsize - 1)) + timediff) / rateclass->windowsize, rateclass->max);
 }
 
-static gboolean flap_connection_send_queued(gpointer data)
+/*
+ * Attempt to send the contents of a given queue
+ *
+ * @return TRUE if the queue was completely emptied or was initially
+ *         empty; FALSE if rate limiting prevented it from being
+ *         emptied.
+ */
+static gboolean flap_connection_send_snac_queue(FlapConnection *conn, struct timeval now, GQueue *queue)
 {
-	FlapConnection *conn;
-	struct timeval now;
-
-	conn = data;
-	gettimeofday(&now, NULL);
-
-	purple_debug_info("oscar", "Attempting to send %u queued SNACs for %p\n", g_queue_get_length(conn->queued_snacs), conn);
-	while (!g_queue_is_empty(conn->queued_snacs))
+	while (!g_queue_is_empty(queue))
 	{
 		QueuedSnac *queued_snac;
 		struct rateclass *rateclass;
 
-		queued_snac = g_queue_peek_head(conn->queued_snacs);
+		queued_snac = g_queue_peek_head(queue);
 
 		rateclass = flap_connection_get_rateclass(conn, queued_snac->family, queued_snac->subtype);
 		if (rateclass != NULL)
@@ -133,7 +133,7 @@
 			/* (Add 100ms padding to account for inaccuracies in the calculation) */
 			if (new_current < rateclass->alert + 100)
 				/* Not ready to send this SNAC yet--keep waiting. */
-				return TRUE;
+				return FALSE;
 
 			rateclass->current = new_current;
 			rateclass->last.tv_sec = now.tv_sec;
@@ -142,11 +142,35 @@
 
 		flap_connection_send(conn, queued_snac->frame);
 		g_free(queued_snac);
-		g_queue_pop_head(conn->queued_snacs);
+		g_queue_pop_head(queue);
 	}
 
-	conn->queued_timeout = 0;
-	return FALSE;
+	/* We emptied the queue */
+	return TRUE;
+}
+
+static gboolean flap_connection_send_queued(gpointer data)
+{
+	FlapConnection *conn;
+	struct timeval now;
+
+	conn = data;
+	gettimeofday(&now, NULL);
+
+	purple_debug_info("oscar", "Attempting to send %u queued SNACs and %u queued low-priority SNACs for %p\n",
+					  (conn->queued_snacs ? g_queue_get_length(conn->queued_snacs) : 0),
+					  (conn->queued_lowpriority_snacs ? g_queue_get_length(conn->queued_lowpriority_snacs) : 0),
+					  conn);
+	if (!conn->queued_snacs || flap_connection_send_snac_queue(conn, now, conn->queued_snacs)) {
+		if (!conn->queued_lowpriority_snacs || flap_connection_send_snac_queue(conn, now, conn->queued_lowpriority_snacs)) {
+			/* Both queues emptied. */
+			conn->queued_timeout = 0;
+			return FALSE;
+		}
+	}
+
+	/* We couldn't send all our SNACs. Keep trying */
+	return TRUE;
 }
 
 /**
@@ -157,9 +181,12 @@
  *
  * @param data The optional bytestream that makes up the data portion
  *        of this SNAC.  For empty SNACs this should be NULL.
+ * @param high_priority If TRUE, the SNAC will be queued normally if
+ *        needed. If FALSE, it wil be queued separately, to be sent
+ *        only if all high priority SNACs have been sent.
  */
 void
-flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data)
+flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data, gboolean high_priority)
 {
 	FlapFrame *frame;
 	guint32 length;
@@ -213,7 +240,16 @@
 		queued_snac->family = family;
 		queued_snac->subtype = subtype;
 		queued_snac->frame = frame;
-		g_queue_push_tail(conn->queued_snacs, queued_snac);
+
+		if (high_priority) {
+			if (!conn->queued_snacs)
+				conn->queued_snacs = g_queue_new();
+			g_queue_push_tail(conn->queued_snacs, queued_snac);
+		} else {
+			if (!conn->queued_lowpriority_snacs)
+				conn->queued_lowpriority_snacs = g_queue_new();
+			g_queue_push_tail(conn->queued_lowpriority_snacs, queued_snac);
+		}
 
 		if (conn->queued_timeout == 0)
 			conn->queued_timeout = purple_timeout_add(500, flap_connection_send_queued, conn);
@@ -224,6 +260,12 @@
 	flap_connection_send(conn, frame);
 }
 
+void
+flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data)
+{
+	flap_connection_send_snac_with_priority(od, conn, family, subtype, flags, snacid, data, TRUE);
+}
+
 /**
  * This sends an empty channel 4 FLAP.  This is sent to signify
  * that we're logging off.  This shouldn't really be necessary--
@@ -275,7 +317,6 @@
 	conn->fd = -1;
 	conn->subtype = -1;
 	conn->type = type;
-	conn->queued_snacs = g_queue_new();
 
 	od->oscar_connections = g_slist_prepend(od->oscar_connections, conn);
 
@@ -434,14 +475,28 @@
 		conn->rateclasses = g_slist_delete_link(conn->rateclasses, conn->rateclasses);
 	}
 
-	while (!g_queue_is_empty(conn->queued_snacs))
-	{
-		QueuedSnac *queued_snac;
-		queued_snac = g_queue_pop_head(conn->queued_snacs);
-		flap_frame_destroy(queued_snac->frame);
-		g_free(queued_snac);
+	if (conn->queued_snacs) {
+		while (!g_queue_is_empty(conn->queued_snacs))
+		{
+			QueuedSnac *queued_snac;
+			queued_snac = g_queue_pop_head(conn->queued_snacs);
+			flap_frame_destroy(queued_snac->frame);
+			g_free(queued_snac);
+		}
+		g_queue_free(conn->queued_snacs);
 	}
-	g_queue_free(conn->queued_snacs);
+
+	if (conn->queued_lowpriority_snacs) {
+		while (!g_queue_is_empty(conn->queued_lowpriority_snacs))
+		{
+			QueuedSnac *queued_snac;
+			queued_snac = g_queue_pop_head(conn->queued_lowpriority_snacs);
+			flap_frame_destroy(queued_snac->frame);
+			g_free(queued_snac);
+		}
+		g_queue_free(conn->queued_lowpriority_snacs);
+	}
+
 	if (conn->queued_timeout > 0)
 		purple_timeout_remove(conn->queued_timeout);
 
@@ -998,4 +1053,3 @@
 	sendframe_flap(conn, frame);
 	flap_frame_destroy(frame);
 }
-
--- a/libpurple/protocols/oscar/oscar.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Mon Jul 28 06:18:51 2008 +0000
@@ -66,7 +66,9 @@
 
 #define OSCAR_CONNECT_STEPS 6
 
-static OscarCapability purple_caps = OSCAR_CAPABILITY_CHAT | OSCAR_CAPABILITY_BUDDYICON | OSCAR_CAPABILITY_DIRECTIM | OSCAR_CAPABILITY_SENDFILE | OSCAR_CAPABILITY_UNICODE | OSCAR_CAPABILITY_INTEROPERATE | OSCAR_CAPABILITY_ICHAT;
+static OscarCapability purple_caps = (OSCAR_CAPABILITY_CHAT | OSCAR_CAPABILITY_BUDDYICON | OSCAR_CAPABILITY_DIRECTIM |
+									  OSCAR_CAPABILITY_SENDFILE | OSCAR_CAPABILITY_UNICODE | OSCAR_CAPABILITY_INTEROPERATE |
+									  OSCAR_CAPABILITY_SHORTCAPS);
 
 static guint8 features_aim[] = {0x01, 0x01, 0x01, 0x02};
 static guint8 features_icq[] = {0x01, 0x06};
@@ -1538,6 +1540,7 @@
 			/* Suspended account */
 			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Your account is currently suspended."));
 			break;
+		case 0x02:
 		case 0x14:
 			/* service temporarily unavailable */
 			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("The AOL Instant Messenger service is temporarily unavailable."));
@@ -1921,6 +1924,38 @@
 	return 1;
 }
 
+static gboolean purple_requesticqstatusnote(gpointer data)
+{
+	PurpleConnection *gc = data;
+	OscarData *od = gc->proto_data;
+
+	while (od->statusnotes_queue != NULL)
+	{
+		char *sn;
+		struct aim_ssi_item *ssi_item;
+		aim_tlv_t *note_hash;
+
+		sn = od->statusnotes_queue->data;
+
+		ssi_item = aim_ssi_itemlist_finditem(od->ssi.local,
+											 NULL, sn, AIM_SSI_TYPE_BUDDY);
+		if (ssi_item != NULL)
+		{
+			note_hash = aim_tlv_gettlv(ssi_item->data, 0x015c, 1);
+			if (note_hash != NULL) {
+				aim_icq_getstatusnote(od, sn, note_hash->value, note_hash->length);
+			}
+		}
+
+		od->statusnotes_queue = g_slist_remove(od->statusnotes_queue, sn);
+		g_free(sn);
+	}
+
+	od->statusnotes_queue_timer = 0;
+	return FALSE;
+}
+
+
 static int purple_parse_oncoming(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
 	PurpleConnection *gc;
@@ -2102,8 +2137,28 @@
 		if (ssi_item != NULL)
 		{
 			note_hash = aim_tlv_gettlv(ssi_item->data, 0x015c, 1);
-			if (note_hash != NULL)
-				aim_icq_getstatusnote(od, info->sn, note_hash->value, note_hash->length);
+			if (note_hash != NULL) {
+				/* We do automatic rate limiting at the FLAP level, so
+				 * a flood of requests won't disconnect us.  However,
+				 * it WOULD mean that we would have to wait a
+				 * potentially long time to be able to message in real
+				 * time again.  Also, since we're requesting with every
+				 * purple_parse_oncoming() call, which often come in
+				 * groups, we should coalesce to do only one lookup per
+				 * buddy.
+				 */
+				if (od->statusnotes_queue == NULL ||
+					g_slist_find_custom(od->statusnotes_queue, info->sn, (GCompareFunc)strcmp) == NULL)
+				{
+					od->statusnotes_queue = g_slist_prepend(od->statusnotes_queue,
+							g_strdup(info->sn));
+
+					if (od->statusnotes_queue_timer > 0)
+						purple_timeout_remove(od->statusnotes_queue_timer);
+					od->statusnotes_queue_timer = purple_timeout_add_seconds(3,
+							purple_requesticqstatusnote, gc);
+				}
+			}
 		}
 	}
 
@@ -3115,7 +3170,7 @@
 
 	oscar_user_info_append_status(gc, user_info, /* PurpleBuddy */ NULL, userinfo, /* strip_html_tags */ FALSE);
 
-	if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
+	if ((userinfo->present & AIM_USERINFO_PRESENT_IDLE) && userinfo->idletime != 0) {
 		tmp = purple_str_seconds_to_string(userinfo->idletime*60);
 		oscar_user_info_add_pair(user_info, _("Idle"), tmp);
 		g_free(tmp);
--- a/libpurple/protocols/oscar/oscar.h	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.h	Mon Jul 28 06:18:51 2008 +0000
@@ -353,17 +353,19 @@
 	OSCAR_CAPABILITY_TRILLIANCRYPT        = 0x00010000,
 	OSCAR_CAPABILITY_UNICODE              = 0x00020000,
 	OSCAR_CAPABILITY_INTEROPERATE         = 0x00040000,
-	OSCAR_CAPABILITY_ICHAT                = 0x00080000,
+	OSCAR_CAPABILITY_SHORTCAPS            = 0x00080000,
 	OSCAR_CAPABILITY_HIPTOP               = 0x00100000,
 	OSCAR_CAPABILITY_SECUREIM             = 0x00200000,
 	OSCAR_CAPABILITY_SMS                  = 0x00400000,
-	OSCAR_CAPABILITY_GENERICUNKNOWN       = 0x00800000,
+	OSCAR_CAPABILITY_MICROPHONE           = 0x00800000,
 	OSCAR_CAPABILITY_VIDEO                = 0x01000000,
 	OSCAR_CAPABILITY_ICHATAV              = 0x02000000,
 	OSCAR_CAPABILITY_LIVEVIDEO            = 0x04000000,
 	OSCAR_CAPABILITY_CAMERA               = 0x08000000,
-	OSCAR_CAPABILITY_ICHAT_SCREENSHARE	  = 0x10000000,
-	OSCAR_CAPABILITY_LAST                 = 0x20000000
+	OSCAR_CAPABILITY_ICHAT_SCREENSHARE    = 0x10000000,
+	OSCAR_CAPABILITY_XHTML_IM             = 0x20000000,
+	OSCAR_CAPABILITY_GENERICUNKNOWN       = 0x40000000,
+	OSCAR_CAPABILITY_LAST                 = 0x80000000
 } OscarCapability;
 
 /*
@@ -433,6 +435,7 @@
 	GSList *rateclasses; /* Contains nodes of struct rateclass. */
 
 	GQueue *queued_snacs; /**< Contains QueuedSnacs. */
+	GQueue *queued_lowpriority_snacs; /**< Contains QueuedSnacs to send only once queued_snacs is empty */
 	guint queued_timeout;
 
 	void *internal; /* internal conn-specific libfaim data */
@@ -543,6 +546,10 @@
 
 	/** A linked list containing PeerConnections. */
 	GSList *peer_connections;
+
+	/** Queue of ICQ Status Notes to request. */
+	GSList *statusnotes_queue;
+	guint statusnotes_queue_timer;
 };
 
 /* Valid for calling aim_icq_setstatus() and for aim_userinfo_t->icqinfo.status */
@@ -625,6 +632,7 @@
 void flap_connection_send_version(OscarData *od, FlapConnection *conn);
 void flap_connection_send_version_with_cookie(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy);
 void flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data);
+void flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data, gboolean high_priority);
 void flap_connection_send_keepalive(OscarData *od, FlapConnection *conn);
 FlapFrame *flap_frame_new(OscarData *od, guint16 channel, int datalen);
 
--- a/libpurple/protocols/oscar/oscar_data.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/oscar/oscar_data.c	Mon Jul 28 06:18:51 2008 +0000
@@ -88,10 +88,17 @@
 
 	while (od->requesticon)
 	{
-		gchar *sn = od->requesticon->data;
-		od->requesticon = g_slist_remove(od->requesticon, sn);
-		g_free(sn);
+		g_free(od->requesticon->data);
+		od->requesticon = g_slist_delete_link(od->requesticon, od->requesticon);
 	}
+	while (od->statusnotes_queue)
+	{
+		g_free(od->statusnotes_queue->data);
+		od->statusnotes_queue = g_slist_delete_link(od->statusnotes_queue,
+				od->statusnotes_queue);
+	}
+	if (od->statusnotes_queue_timer > 0)
+		purple_timeout_remove(od->statusnotes_queue_timer);
 	g_free(od->email);
 	g_free(od->newp);
 	g_free(od->oldp);
--- a/libpurple/protocols/yahoo/yahoo_profile.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_profile.c	Mon Jul 28 06:18:51 2008 +0000
@@ -1291,6 +1291,10 @@
 	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/prpl.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/prpl.c	Mon Jul 28 06:18:51 2008 +0000
@@ -389,6 +389,110 @@
 	return statuses;
 }
 
+void
+purple_prpl_send_attention(PurpleConnection *gc, const char *who, guint type_code)
+{
+	PurpleAttentionType *attn;
+	PurpleMessageFlags flags;
+	PurplePlugin *prpl;
+	PurpleConversation *conv;
+	gboolean (*send_attention)(PurpleConnection *, const char *, guint);
+	PurpleBuddy *buddy;
+	const char *alias;	
+	gchar *description;
+	time_t mtime;
+
+	g_return_if_fail(gc != NULL);
+	g_return_if_fail(who != NULL);
+
+	prpl = purple_find_prpl(purple_account_get_protocol_id(gc->account));
+	send_attention = PURPLE_PLUGIN_PROTOCOL_INFO(prpl)->send_attention;
+	g_return_if_fail(send_attention != NULL);
+
+	mtime = time(NULL);
+
+	attn = purple_get_attention_type_from_code(gc->account, type_code);
+
+	if ((buddy = purple_find_buddy(purple_connection_get_account(gc), who)) != NULL)
+		alias = purple_buddy_get_contact_alias(buddy);
+	else
+		alias = who;
+
+	if (attn && purple_attention_type_get_outgoing_desc(attn)) {
+		description = g_strdup_printf(purple_attention_type_get_outgoing_desc(attn), alias);
+	} else {
+		description = g_strdup_printf(_("Requesting %s's attention..."), alias);
+	}
+	
+	flags = PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_NOTIFY | PURPLE_MESSAGE_SYSTEM;
+
+	purple_debug_info("server", "serv_send_attention: sending '%s' to %s\n",
+			description, who);
+
+	if (!send_attention(gc, who, type_code))
+		return;
+
+	conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, gc->account, who);
+	purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, description, flags, mtime);
+
+	g_free(description);
+}
+
+static void
+got_attention(PurpleConnection *gc, int id, const char *who, guint type_code)
+{
+	PurpleMessageFlags flags;
+	PurpleAttentionType *attn;
+	PurpleBuddy *buddy;
+	const char *alias;
+	gchar *description;
+	time_t mtime;
+
+	mtime = time(NULL);
+
+	attn = purple_get_attention_type_from_code(gc->account, type_code);
+
+	/* PURPLE_MESSAGE_NOTIFY is for attention messages. */
+	flags = PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NOTIFY | PURPLE_MESSAGE_RECV;
+
+	/* TODO: if (attn->icon_name) is non-null, use it to lookup an emoticon and display
+	 * it next to the attention command. And if it is null, display a generic icon. */
+
+	if ((buddy = purple_find_buddy(purple_connection_get_account(gc), who)) != NULL)
+		alias = purple_buddy_get_contact_alias(buddy);
+	else
+		alias = who;
+
+	if (attn && purple_attention_type_get_incoming_desc(attn)) {
+		description = g_strdup_printf(purple_attention_type_get_incoming_desc(attn), alias);
+	} else {
+		description = g_strdup_printf(_("%s has requested your attention!"), alias);
+	}
+
+	purple_debug_info("server", "got_attention: got '%s' from %s\n",
+			description, who);
+
+	if (id == -1)
+		serv_got_im(gc, who, description, flags, mtime);
+	else
+		serv_got_chat_in(gc, id, who, flags, description, mtime);
+
+	/* TODO: sounds (depending on PurpleAttentionType), shaking, etc. */
+
+	g_free(description);
+}
+
+void
+purple_prpl_got_attention(PurpleConnection *gc, const char *who, guint type_code)
+{
+	got_attention(gc, -1, who, type_code);
+}
+
+void
+purple_prpl_got_attention_in_chat(PurpleConnection *gc, int id, const char *who, guint type_code)
+{
+	got_attention(gc, id, who, type_code);
+}
 
 /**************************************************************************
  * Protocol Plugin Subsystem API
--- a/libpurple/prpl.h	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/prpl.h	Mon Jul 28 06:18:51 2008 +0000
@@ -693,6 +693,41 @@
  */
 GList *purple_prpl_get_statuses(PurpleAccount *account, PurplePresence *presence);
 
+/** Send an attention request message.
+ *
+ * @param gc The connection to send the message on.
+ * @param who Whose attention to request.
+ * @param type_code An index into the prpl's attention_types list determining the type
+ * 	of the attention request command to send. 0 if prpl only defines one
+ * 	(for example, Yahoo and MSN), but some protocols define more (MySpaceIM).
+ *
+ * Note that you can't send arbitrary PurpleAttentionType's, because there is
+ * only a fixed set of attention commands.
+ * @since 2.5.0
+ */
+void purple_prpl_send_attention(PurpleConnection *gc, const char *who, guint type_code);
+
+/** Process an incoming attention message. 
+ *
+ * @param gc The connection that received the attention message.
+ * @param who Who requested your attention.
+ * @param type_code An index into the prpl's attention_types list determining the type
+ * 	of the attention request command to send.
+ * @since 2.5.0
+ */
+void purple_prpl_got_attention(PurpleConnection *gc, const char *who, guint type_code);
+
+/** Process an incoming attention message in a chat. 
+ *
+ * @param gc The connection that received the attention message.
+ * @param id The chat id.
+ * @param who Who requested your attention.
+ * @param type_code An index into the prpl's attention_types list determining the type
+ * 	of the attention request command to send. 
+ * @since 2.5.0
+ */
+void purple_prpl_got_attention_in_chat(PurpleConnection *gc, int id, const char *who, guint type_code);
+
 /*@}*/
 
 /**************************************************************************/
--- a/libpurple/server.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/server.c	Mon Jul 28 06:18:51 2008 +0000
@@ -335,91 +335,13 @@
 void
 serv_send_attention(PurpleConnection *gc, const char *who, guint type_code)
 {
-	PurpleAttentionType *attn;
-	PurpleMessageFlags flags;
-	PurplePlugin *prpl;
-	PurpleConversation *conv;
-	gboolean (*send_attention)(PurpleConnection *, const char *, guint);
-	PurpleBuddy *buddy;
-	const char *alias;	
-	gchar *description;
-	time_t mtime;
-
-	g_return_if_fail(gc != NULL);
-	g_return_if_fail(who != NULL);
-
-	prpl = purple_find_prpl(purple_account_get_protocol_id(gc->account));
-	send_attention = PURPLE_PLUGIN_PROTOCOL_INFO(prpl)->send_attention;
-	g_return_if_fail(send_attention != NULL);
-
-	mtime = time(NULL);
-
-	attn = purple_get_attention_type_from_code(gc->account, type_code);
-
-	if ((buddy = purple_find_buddy(purple_connection_get_account(gc), who)) != NULL)
-		alias = purple_buddy_get_contact_alias(buddy);
-	else
-		alias = who;
-
-	if (attn && purple_attention_type_get_outgoing_desc(attn)) {
-		description = g_strdup_printf(purple_attention_type_get_outgoing_desc(attn), alias);
-	} else {
-		description = g_strdup_printf(_("Requesting %s's attention..."), alias);
-	}
-	
-	flags = PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_NOTIFY | PURPLE_MESSAGE_SYSTEM;
-
-	purple_debug_info("server", "serv_send_attention: sending '%s' to %s\n",
-			description, who);
-
-	if (!send_attention(gc, who, type_code))
-		return;
-
-	conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, gc->account, who);
-	purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, description, flags, mtime);
-
-	g_free(description);
+	purple_prpl_send_attention(gc, who, type_code);
 }
 
 void
 serv_got_attention(PurpleConnection *gc, const char *who, guint type_code)
 {
-	PurpleMessageFlags flags;
-	PurpleAttentionType *attn;
-	PurpleBuddy *buddy;
-	const char *alias;
-	gchar *description;
-	time_t mtime;
-
-	mtime = time(NULL);
-
-	attn = purple_get_attention_type_from_code(gc->account, type_code);
-
-	/* PURPLE_MESSAGE_NOTIFY is for attention messages. */
-	flags = PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NOTIFY | PURPLE_MESSAGE_RECV;
-
-	/* TODO: if (attn->icon_name) is non-null, use it to lookup an emoticon and display
-	 * it next to the attention command. And if it is null, display a generic icon. */
-
-	if ((buddy = purple_find_buddy(purple_connection_get_account(gc), who)) != NULL)
-		alias = purple_buddy_get_contact_alias(buddy);
-	else
-		alias = who;
-
-	if (attn && purple_attention_type_get_incoming_desc(attn)) {
-		description = g_strdup_printf(purple_attention_type_get_incoming_desc(attn), alias);
-	} else {
-		description = g_strdup_printf(_("%s has requested your attention!"), alias);
-	}
-
-	purple_debug_info("server", "serv_got_attention: got '%s' from %s\n",
-			description, who);
-
-	serv_got_im(gc, who, description, flags, mtime);
-	
-	/* TODO: sounds (depending on PurpleAttentionType), shaking, etc. */
-
-	g_free(description);
+	purple_prpl_got_attention(gc, who, type_code);
 }
 
 
--- a/libpurple/server.h	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/server.h	Mon Jul 28 06:18:51 2008 +0000
@@ -63,6 +63,8 @@
 
 /** Send an attention request message.
  *
+ * @deprecated Use purple_prpl_send_attention() instead.
+ *
  * @param gc The connection to send the message on.
  * @param who Whose attention to request.
  * @param type_code An index into the prpl's attention_types list determining the type
@@ -76,6 +78,8 @@
 
 /** Process an incoming attention message. 
  *
+ * @deprecated Use purple_prpl_got_attention() instead.
+ *
  * @param gc The connection that received the attention message.
  * @param who Who requested your attention.
  * @param type_code An index into the prpl's attention_types list determining the type
--- a/libpurple/win32/global.mak	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/win32/global.mak	Mon Jul 28 06:18:51 2008 +0000
@@ -19,7 +19,7 @@
 MEANWHILE_TOP ?= $(WIN32_DEV_TOP)/meanwhile-1.0.2_daa1
 NSPR_TOP ?= $(WIN32_DEV_TOP)/nspr-4.6.4
 NSS_TOP ?= $(WIN32_DEV_TOP)/nss-3.11.4
-PERL_LIB_TOP ?= $(WIN32_DEV_TOP)/perl58
+PERL_LIB_TOP ?= $(WIN32_DEV_TOP)/perl-5.10.0
 SILC_TOOLKIT ?= $(WIN32_DEV_TOP)/silc-toolkit-1.1.5
 TCL_LIB_TOP ?= $(WIN32_DEV_TOP)/tcl-8.4.5
 GSTREAMER_TOP ?= $(WIN32_DEV_TOP)/gstreamer-0.10.13
@@ -56,7 +56,7 @@
 PIDGIN_EXE := $(PIDGIN_TOP)/pidgin.exe
 PIDGIN_PORTABLE_EXE := $(PIDGIN_TOP)/pidgin-portable.exe
 
-GCCWARNINGS := -Waggregate-return -Wcast-align -Wdeclaration-after-statement -Werror-implicit-function-declaration -Wextra -Wno-sign-compare -Wno-unused-parameter -Winit-self -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wpointer-arith -Wundef
+GCCWARNINGS ?= -Waggregate-return -Wcast-align -Wdeclaration-after-statement -Werror-implicit-function-declaration -Wextra -Wno-sign-compare -Wno-unused-parameter -Winit-self -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wpointer-arith -Wundef
 
 # parse the version number from the configure.ac file if it is newer
 #m4_define([purple_major_version], [2])
--- a/libpurple/win32/libc_interface.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/libpurple/win32/libc_interface.c	Mon Jul 28 06:18:51 2008 +0000
@@ -327,9 +327,12 @@
 			case WSAETIMEDOUT: /* 10060 */
 				g_snprintf(errbuf, sizeof(errbuf), _("Connection timed out."));
 				break;
-			case WSAECONNREFUSED: /*10061 */
+			case WSAECONNREFUSED: /* 10061 */
 				g_snprintf(errbuf, sizeof(errbuf), _("Connection refused."));
 				break;
+			case WSAEADDRINUSE: /* 10048 */
+				g_snprintf(errbuf, sizeof(errbuf), _("Address already in use."));
+				break;
 			default:
 				g_snprintf(errbuf, sizeof(errbuf), "Windows socket error #%d", errornum);
 		}
--- a/pidgin/pidgintooltip.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/pidgin/pidgintooltip.c	Mon Jul 28 06:18:51 2008 +0000
@@ -59,6 +59,7 @@
 destroy_tooltip_data(PidginTooltipData *data)
 {
 	gtk_tree_path_free(data->common.treeview.path);
+	pidgin_tooltip_destroy();
 	g_free(data);
 }
 
--- a/pidgin/plugins/perl/common/Makefile.mingw	Fri Jul 18 08:45:31 2008 +0000
+++ b/pidgin/plugins/perl/common/Makefile.mingw	Mon Jul 28 06:18:51 2008 +0000
@@ -5,13 +5,12 @@
 #
 
 PIDGIN_TREE_TOP := ../../../..
+GCCWARNINGS := -Wno-comment -Waggregate-return -Wcast-align -Wdeclaration-after-statement -Werror-implicit-function-declaration -Wextra -Wno-sign-compare -Wno-unused-parameter -Winit-self -Wmissing-declarations -Wmissing-prototypes -Wpointer-arith -Wundef -Wno-unused
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
 TARGET = Pidgin
 EXTUTILS ?= C:/perl/lib/ExtUtils
 
-CFLAGS += -Wno-comment -Wno-unused
-
 ##
 ## INCLUDE PATHS
 ##
@@ -72,7 +71,7 @@
 ##
 ## LIBRARIES
 ##
-LIBS =			-lperl58 \
+LIBS =			-lperl510 \
 			-lperl \
 			-lpurple \
 			-lpidgin \
--- a/pidgin/win32/nsis/pidgin-installer.nsi	Fri Jul 18 08:45:31 2008 +0000
+++ b/pidgin/win32/nsis/pidgin-installer.nsi	Mon Jul 28 06:18:51 2008 +0000
@@ -72,7 +72,7 @@
 !define GTK_MIN_VERSION				"2.6.10"
 !define GTK_REG_KEY				"SOFTWARE\GTK\2.0"
 !define PERL_REG_KEY				"SOFTWARE\Perl"
-!define PERL_DLL				"perl58.dll"
+!define PERL_DLL				"perl510.dll"
 !define GTK_DEFAULT_INSTALL_PATH		"$COMMONFILES\GTK\2.0"
 !define GTK_RUNTIME_INSTALLER			"..\..\..\..\gtk_installer\gtk-runtime*.exe"
 
@@ -505,11 +505,20 @@
     ; If this is under NT4, delete the SILC support stuff
     ; there is a bug that will prevent any account from connecting
     ; See https://lists.silcnet.org/pipermail/silc-devel/2005-January/001588.html
+    ; Also, remove the GSSAPI SASL plugin and associated files as they aren't
+    ; compatible with NT4.
     ${If} ${IsNT}
     ${AndIf} ${IsWinNT4}
+      ;SILC
       Delete "$INSTDIR\plugins\libsilc.dll"
       Delete "$INSTDIR\libsilcclient-1-1-2.dll"
       Delete "$INSTDIR\libsilc-1-1-2.dll"
+      ;GSSAPI
+      Delete "$INSTDIR\sasl2\saslGSSAPI.dll"
+      Delete "$INSTDIR\gssapi32.dll"
+      Delete "$INSTDIR\k5sprt32.dll"
+      Delete "$INSTDIR\krb5_32.dll"
+      Delete "$INSTDIR\comerr32.dll"
     ${EndIf}
 
     SetOutPath "$INSTDIR"
@@ -704,6 +713,8 @@
     Push "ymsgr"
     Call un.UnregisterURIHandler
 
+    Delete "$INSTDIR\ca-certs\CAcert_Class3.pem"
+    Delete "$INSTDIR\ca-certs\CAcert_Root.pem"
     Delete "$INSTDIR\ca-certs\Equifax_Secure_CA.pem"
     Delete "$INSTDIR\ca-certs\GTE_CyberTrust_Global_Root.pem"
     Delete "$INSTDIR\ca-certs\Microsoft_Secure_Server_Authority.pem"
--- a/pidgin/win32/winpidgin.c	Fri Jul 18 08:45:31 2008 +0000
+++ b/pidgin/win32/winpidgin.c	Mon Jul 28 06:18:51 2008 +0000
@@ -89,9 +89,8 @@
 			const char *err_msg = get_win32_error_message(retv);
 
 			printf("Could not read reg key '%s' subkey '%s' value: '%s'.\nMessage: (%ld) %s\n",
-					((key == HKEY_LOCAL_MACHINE) ? "HKLM" :
-					 (key == HKEY_CURRENT_USER) ? "HKCU" :
-					 "???"),
+					(key == HKEY_LOCAL_MACHINE) ? "HKLM"
+					 : ((key == HKEY_CURRENT_USER) ? "HKCU" : "???"),
 					sub_key, val_name, retv, err_msg);
 		}
 		RegCloseKey(hkey);
@@ -216,13 +215,13 @@
 
 	/* Set up the settings dir base to be \\path\to
 	 * The actual settings dir will be \\path\to\.purple */
-	snprintf(path2, sizeof(path2), "PURPLEHOME=%s", path);
+	_snprintf(path2, sizeof(path2), "PURPLEHOME=%s", path);
 	printf("Setting settings dir: %s\n", path2);
-	putenv(path2);
+	_putenv(path2);
 
-	snprintf(path2, sizeof(path2), "PIDGIN_ASPELL_DIR=%s\\Aspell\\bin", path);
+	_snprintf(path2, sizeof(path2), "PIDGIN_ASPELL_DIR=%s\\Aspell\\bin", path);
 	printf("%s\n", path2);
-	putenv(path2);
+	_putenv(path2);
 
 	/* set the GTK+ path to be \\path\to\GTK\bin */
 	strcat(path, "\\GTK\\bin");
@@ -437,9 +436,50 @@
 
 	locale = winpidgin_get_locale();
 
-	snprintf(envstr, 25, "LANG=%s", locale);
+	_snprintf(envstr, 25, "LANG=%s", locale);
 	printf("Setting locale: %s\n", envstr);
-	putenv(envstr);
+	_putenv(envstr);
+}
+
+static void winpidgin_add_perl_to_path() {
+	char perl_path[MAX_PATH + 1];
+	DWORD plen = sizeof(perl_path);
+
+	printf("%s", "Looking for Perl... ");
+
+	if (read_reg_string(HKEY_LOCAL_MACHINE, "SOFTWARE\\Perl", "",
+			    (LPBYTE) &perl_path, &plen)) {
+		const char *path = getenv("PATH");
+		/* Enough to add "PATH=" + ";"  + perl_path + "\\bin" + \0 */
+
+		/* We *could* check for perl510.dll, but it seems unnecessary. */
+
+		printf("found in '%s'.\n", perl_path);
+
+		if (perl_path[strlen(perl_path) - 1] != '\\') {
+			strcat(perl_path, "\\");
+		}
+		strcat(perl_path, "bin");
+
+		if (!strstr(path, perl_path)) {
+			int newlen = (path ? strlen(path) : 0) + strlen(perl_path) + 10;
+			char *newpath = malloc(newlen);
+			*newpath = '\0';
+
+			_snprintf(newpath, newlen, "PATH=%s%s%s",
+				  path ? path : "",
+				  path ? ";" : "",
+				  perl_path);
+
+			printf("Adding Perl to PATH: %s\n", newpath);
+
+			_putenv(newpath);
+			free(newpath);
+		} else
+			printf("%s\n", "Perl already in PATH.");
+	} else
+		printf("%s", "not found.\n");
+
 }
 
 #define PIDGIN_WM_FOCUS_REQUEST (WM_APP + 13)
@@ -598,10 +638,10 @@
 	} else {
 		DWORD dw = GetLastError();
 		const char *err_msg = get_win32_error_message(dw);
-		snprintf(errbuf, 512,
+		_snprintf(errbuf, 512,
 			"Error getting module filename.\nError: (%u) %s",
 			(UINT) dw, err_msg);
-		printf("%s", errbuf);
+		printf("%s\n", errbuf);
 		MessageBox(NULL, errbuf, NULL, MB_OK | MB_TOPMOST);
 		pidgin_dir[0] = '\0';
 	}
@@ -631,6 +671,9 @@
 		dll_prep();
 
 	winpidgin_set_locale();
+
+	winpidgin_add_perl_to_path();
+
 	/* If help, version or multiple flag used, do not check Mutex */
 	if (!strstr(lpszCmdLine, "-h") && !strstr(lpszCmdLine, "-v"))
 		if (!winpidgin_set_running(getenv("PIDGIN_MULTI_INST") == NULL && strstr(lpszCmdLine, "-m") == NULL))
@@ -645,11 +688,11 @@
 		BOOL mod_not_found = (dw == ERROR_MOD_NOT_FOUND || dw == ERROR_DLL_NOT_FOUND);
 		const char *err_msg = get_win32_error_message(dw);
 
-		snprintf(errbuf, 512, "Error loading pidgin.dll.\nError: (%u) %s%s%s",
+		_snprintf(errbuf, 512, "Error loading pidgin.dll.\nError: (%u) %s%s%s",
 			(UINT) dw, err_msg,
 			mod_not_found ? "\n" : "",
 			mod_not_found ? "This probably means that GTK+ can't be found." : "");
-		printf("%s", errbuf);
+		printf("%s\n", errbuf);
 		MessageBox(NULL, errbuf, TEXT("Error"), MB_OK | MB_TOPMOST);
 
 		return 0;