changeset 23631:b33b5e56a482

merge of '0d858a8978355a1e8b7305b64b87db51e44e9978' and '4837767868c0defe45efc50e8d0639be2ed4ad7d'
author Ethan Blanton <elb@pidgin.im>
date Fri, 01 Aug 2008 19:45:08 +0000
parents 46cc31494ff4 (diff) aac5753e2528 (current diff)
children c6033a3031bb
files libpurple/protocols/msn/slpsession.c libpurple/protocols/msn/slpsession.h
diffstat 50 files changed, 665 insertions(+), 551 deletions(-) [+]
line wrap: on
line diff
--- a/AUTHORS	Sun Jul 27 13:29:26 2008 +0000
+++ b/AUTHORS	Fri Aug 01 19:45:08 2008 +0000
@@ -24,6 +24,7 @@
 Bartosz Oler - Developer
 Etan 'deryni' Reisner - Developer
 Tim 'marv' Ringenbach - Developer
+Elliott 'QuLogic' Sales de Andrade - Developer
 Luke 'LSchiere' Schierer - Support
 Megan 'Cae' Schneider - support/QA
 Evan Schoenberg - Developer
@@ -37,7 +38,6 @@
 Felipe 'shx' Contreras
 Dennis 'EvilDennisR' Ristuccia
 Peter 'Fmoo' Ruibal
-Elliott 'QuLogic' Sales de Andrade
 Gabriel 'Nix' Schulhof
 Jorge 'Masca' Villaseñor
 
--- a/ChangeLog.win32	Sun Jul 27 13:29:26 2008 +0000
+++ b/ChangeLog.win32	Fri Aug 01 19:45:08 2008 +0000
@@ -1,5 +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).
+	* Upgrade SILC to use the 1.1.7 toolkit
 
 version 2.4.3 (07/01/2008):
 	* No changes
--- a/doc/pidgin.1.in	Sun Jul 27 13:29:26 2008 +0000
+++ b/doc/pidgin.1.in	Fri Aug 01 19:45:08 2008 +0000
@@ -582,6 +582,8 @@
 .br
   Tim 'marv' Ringenbach (developer) <\fImarv_sf@users.sf.net\fR>
 .br
+  Elliott 'QuLogic' Sales de Andrade (developer)
+.br
   Luke 'LSchiere' Schierer (support)
 .br
   Megan 'Cae' Schneider (support/QA)
@@ -606,8 +608,6 @@
 .br
   Peter 'fmoo' Ruibal
 .br
-  Elliott 'QuLogic' Sales de Andrade
-.br
   Gabriel 'Nix' Schulhof
 .br
   Jorge 'Masca' Villaseñor
--- a/libpurple/plugins/perl/Makefile.mingw	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/plugins/perl/Makefile.mingw	Fri Aug 01 19:45:08 2008 +0000
@@ -47,7 +47,7 @@
 			-lws2_32 \
 			-lintl \
 			-lpurple \
-			-lperl58
+			-lperl510
 
 include $(PIDGIN_COMMON_RULES)
 
--- a/libpurple/plugins/perl/common/Makefile.mingw	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/plugins/perl/common/Makefile.mingw	Fri Aug 01 19:45:08 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/common/Prefs.xs	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/plugins/perl/common/Prefs.xs	Fri Aug 01 19:45:08 2008 +0000
@@ -1,4 +1,5 @@
 #include "module.h"
+#include "../perl-handlers.h"
 
 MODULE = Purple::Prefs  PACKAGE = Purple::Prefs  PREFIX = purple_prefs_
 PROTOTYPES: ENABLE
@@ -62,13 +63,28 @@
 void
 purple_prefs_destroy()
 
+guint
+purple_prefs_connect_callback(plugin, name, callback, data = 0);
+	Purple::Plugin plugin
+	const char *name
+	SV *callback
+	SV *data
+CODE:
+	RETVAL = purple_perl_prefs_connect_callback(plugin, name, callback, data);
+OUTPUT:
+	RETVAL
+
 void
-purple_prefs_disconnect_by_handle(handle)
-	void * handle
+purple_prefs_disconnect_by_handle(plugin)
+	Purple::Plugin plugin
+CODE:
+	purple_perl_pref_cb_clear_for_plugin(plugin);
 
 void
 purple_prefs_disconnect_callback(callback_id)
 	guint callback_id
+CODE:
+	purple_perl_prefs_disconnect_callback(callback_id);
 
 gboolean
 purple_prefs_exists(name)
--- a/libpurple/plugins/perl/perl-common.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/plugins/perl/perl-common.c	Fri Aug 01 19:45:08 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	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/plugins/perl/perl-common.h	Fri Aug 01 19:45:08 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-handlers.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/plugins/perl/perl-handlers.c	Fri Aug 01 19:45:08 2008 +0000
@@ -5,9 +5,10 @@
 #include "signals.h"
 
 extern PerlInterpreter *my_perl;
-static GList *cmd_handlers = NULL;
-static GList *signal_handlers = NULL;
-static GList *timeout_handlers = NULL;
+static GSList *cmd_handlers = NULL;
+static GSList *signal_handlers = NULL;
+static GSList *timeout_handlers = NULL;
+static GSList *pref_handlers = NULL;
 
 /* perl < 5.8.0 doesn't define PERL_MAGIC_ext */
 #ifndef PERL_MAGIC_ext
@@ -70,7 +71,7 @@
 	STRLEN na;
 	dSP;
 
-	gps = (PurplePerlScript *)plugin->info->extra_info;
+	gps = plugin->info->extra_info;
 
 	ENTER;
 	SAVETMPS;
@@ -131,7 +132,7 @@
 	STRLEN na;
 	dSP;
 
-	gps = (PurplePerlScript *)plugin->info->extra_info;
+	gps = plugin->info->extra_info;
 
 	ENTER;
 	SAVETMPS;
@@ -212,7 +213,7 @@
 {
 	gboolean ret = FALSE;
 
-	timeout_handlers = g_list_remove(timeout_handlers, handler);
+	timeout_handlers = g_slist_remove(timeout_handlers, handler);
 
 	if (handler->iotag > 0)
 		ret = purple_timeout_remove(handler->iotag);
@@ -231,7 +232,7 @@
 static void
 destroy_signal_handler(PurplePerlSignalHandler *handler)
 {
-	signal_handlers = g_list_remove(signal_handlers, handler);
+	signal_handlers = g_slist_remove(signal_handlers, handler);
 
 	if (handler->callback != NULL)
 		SvREFCNT_dec(handler->callback);
@@ -246,7 +247,7 @@
 static gboolean
 perl_timeout_cb(gpointer data)
 {
-	PurplePerlTimeoutHandler *handler = (PurplePerlTimeoutHandler *)data;
+	PurplePerlTimeoutHandler *handler = data;
 	gboolean ret = FALSE;
 	STRLEN na;
 
@@ -282,7 +283,7 @@
 static void *
 perl_signal_cb(va_list args, void *data)
 {
-	PurplePerlSignalHandler *handler = (PurplePerlSignalHandler *)data;
+	PurplePerlSignalHandler *handler = data;
 	void *ret_val = NULL;
 	int i;
 	int count;
@@ -414,10 +415,10 @@
 find_signal_handler(PurplePlugin *plugin, void *instance, const char *signal)
 {
 	PurplePerlSignalHandler *handler;
-	GList *l;
+	GSList *l;
 
 	for (l = signal_handlers; l != NULL; l = l->next) {
-		handler = (PurplePerlSignalHandler *)l->data;
+		handler = l->data;
 
 		if (handler->plugin == plugin &&
 			handler->instance == instance &&
@@ -447,9 +448,9 @@
 	handler->data     = (data != NULL && data != &PL_sv_undef
 	                     ? newSVsv(data) : NULL);
 
-	timeout_handlers = g_list_append(timeout_handlers, handler);
+	timeout_handlers = g_slist_append(timeout_handlers, handler);
 
-	handler->iotag = purple_timeout_add(seconds * 1000, perl_timeout_cb, handler);
+	handler->iotag = purple_timeout_add_seconds(seconds, perl_timeout_cb, handler);
 
 	return handler->iotag;
 }
@@ -457,15 +458,13 @@
 gboolean
 purple_perl_timeout_remove(guint handle)
 {
-	GList *l, *l_next;
+	PurplePerlTimeoutHandler *handler;
+	GSList *l, *l_next;
 
 	for (l = timeout_handlers; l != NULL; l = l_next) {
-		PurplePerlTimeoutHandler *handler;
-
+		handler =  l->data;
 		l_next = l->next;
 
-		handler = (PurplePerlTimeoutHandler *)l->data;
-
 		if (handler->iotag == handle)
 			return destroy_timeout_handler(handler);
 	}
@@ -478,15 +477,13 @@
 void
 purple_perl_timeout_clear_for_plugin(PurplePlugin *plugin)
 {
-	GList *l, *l_next;
+	PurplePerlTimeoutHandler *handler;
+	GSList *l, *l_next;
 
 	for (l = timeout_handlers; l != NULL; l = l_next) {
-		PurplePerlTimeoutHandler *handler;
-
+		handler = l->data;
 		l_next = l->next;
 
-		handler = (PurplePerlTimeoutHandler *)l->data;
-
 		if (handler->plugin == plugin)
 			destroy_timeout_handler(handler);
 	}
@@ -516,7 +513,7 @@
 	handler->data     = (data != NULL &&
 	                     data != &PL_sv_undef ? newSVsv(data) : NULL);
 
-	signal_handlers = g_list_append(signal_handlers, handler);
+	signal_handlers = g_slist_append(signal_handlers, handler);
 
 	purple_signal_connect_priority_vargs(instance, signal, plugin,
 	                                   PURPLE_CALLBACK(perl_signal_cb),
@@ -544,12 +541,11 @@
 purple_perl_signal_clear_for_plugin(PurplePlugin *plugin)
 {
 	PurplePerlSignalHandler *handler;
-	GList *l, *l_next;
+	GSList *l, *l_next;
 
 	for (l = signal_handlers; l != NULL; l = l_next) {
 		l_next = l->next;
-
-		handler = (PurplePerlSignalHandler *)l->data;
+		handler = l->data;
 
 		if (handler->plugin == plugin)
 			destroy_signal_handler(handler);
@@ -570,7 +566,7 @@
 	int i = 0, count, ret_value = PURPLE_CMD_RET_OK;
 	STRLEN na;
 	SV *cmdSV, *tmpSV, *convSV;
-	PurplePerlCmdHandler *handler = (PurplePerlCmdHandler *)data;
+	PurplePerlCmdHandler *handler = data;
 
 	dSP;
 	ENTER;
@@ -645,7 +641,7 @@
 	else
 		handler->data = NULL;
 
-	cmd_handlers = g_list_append(cmd_handlers, handler);
+	cmd_handlers = g_slist_append(cmd_handlers, handler);
 
 	handler->id = purple_cmd_register(command, args, priority, flag, prpl_id,
 	                                PURPLE_CMD_FUNC(perl_cmd_cb), helpstr,
@@ -657,7 +653,7 @@
 static void
 destroy_cmd_handler(PurplePerlCmdHandler *handler)
 {
-	cmd_handlers = g_list_remove(cmd_handlers, handler);
+	cmd_handlers = g_slist_remove(cmd_handlers, handler);
 
 	if (handler->callback != NULL)
 		SvREFCNT_dec(handler->callback);
@@ -673,11 +669,11 @@
 void
 purple_perl_cmd_clear_for_plugin(PurplePlugin *plugin)
 {
-	GList *l, *l_next;
+	PurplePerlCmdHandler *handler;
+	GSList *l, *l_next;
 
 	for (l = cmd_handlers; l != NULL; l = l_next) {
-		PurplePerlCmdHandler *handler = (PurplePerlCmdHandler *)l->data;
-
+		handler = l->data;
 		l_next = l->next;
 
 		if (handler->plugin == plugin)
@@ -688,10 +684,11 @@
 static PurplePerlCmdHandler *
 find_cmd_handler(PurpleCmdId id)
 {
-	GList *l;
+	PurplePerlCmdHandler *handler;
+	GSList *l;
 
 	for (l = cmd_handlers; l != NULL; l = l->next) {
-		PurplePerlCmdHandler *handler = (PurplePerlCmdHandler *)l->data;
+		handler = (PurplePerlCmdHandler *)l->data;
 
 		if (handler->id == id)
 			return handler;
@@ -715,3 +712,141 @@
 	purple_cmd_unregister(id);
 	destroy_cmd_handler(handler);
 }
+
+static void
+perl_pref_cb(const char *name, PurplePrefType type, gconstpointer value,
+			 gpointer data)
+{
+	PurplePerlPrefsHandler *handler = data;
+	STRLEN na;
+
+	dSP;
+	ENTER;
+	SAVETMPS;
+	PUSHMARK(sp);
+	XPUSHs(sv_2mortal(newSVpv(name, 0)));
+
+	XPUSHs(sv_2mortal(newSViv(type)));
+
+	switch(type) {
+		case PURPLE_PREF_INT:
+			XPUSHs(sv_2mortal(newSViv(GPOINTER_TO_INT(value))));
+			break;
+		case PURPLE_PREF_BOOLEAN:
+			XPUSHs((GPOINTER_TO_INT(value) == FALSE) ? &PL_sv_no : &PL_sv_yes);
+			break;
+		case PURPLE_PREF_STRING:
+		case PURPLE_PREF_PATH:
+			XPUSHs(sv_2mortal(newSVGChar(value)));
+			break;
+		case PURPLE_PREF_STRING_LIST:
+		case PURPLE_PREF_PATH_LIST:
+			{
+				AV* av = newAV();
+				const GList *l = value;
+
+				/* Append stuff backward to preserve order */
+				while (l && l->next) l = l->next;
+				while (l) {
+					av_push(av, sv_2mortal(newSVGChar(l->data)));
+					l = l->prev;
+				}
+				XPUSHs(sv_2mortal(newRV_noinc((SV *) av)));
+			} break;
+		default:
+		case PURPLE_PREF_NONE:
+			XPUSHs(&PL_sv_undef);
+			break;
+	}
+
+	XPUSHs((SV *)handler->data);
+	PUTBACK;
+	call_sv(handler->callback, G_EVAL | G_VOID | G_DISCARD);
+	SPAGAIN;
+
+	if (SvTRUE(ERRSV)) {
+		purple_debug_error("perl",
+		                 "Perl prefs callback function exited abnormally: %s\n",
+		                 SvPV(ERRSV, na));
+	}
+
+	PUTBACK;
+	FREETMPS;
+	LEAVE;
+}
+
+guint
+purple_perl_prefs_connect_callback(PurplePlugin *plugin, const char *name,
+								   SV *callback, SV *data)
+{
+	PurplePerlPrefsHandler *handler;
+
+	if (plugin == NULL) {
+		croak("Invalid handle in adding perl prefs handler.\n");
+		return 0;
+	}
+
+	handler = g_new0(PurplePerlPrefsHandler, 1);
+
+	handler->plugin   = plugin;
+	handler->callback = (callback != NULL && callback != &PL_sv_undef
+	                     ? newSVsv(callback) : NULL);
+	handler->data     = (data != NULL && data != &PL_sv_undef
+	                     ? newSVsv(data) : NULL);
+
+	pref_handlers = g_slist_prepend(pref_handlers, handler);
+
+	handler->iotag = purple_prefs_connect_callback(plugin, name, perl_pref_cb, handler);
+
+	return handler->iotag;
+}
+
+static void
+destroy_prefs_handler(PurplePerlPrefsHandler *handler)
+{
+	pref_handlers = g_slist_remove(pref_handlers, handler);
+
+	if (handler->iotag > 0)
+		purple_prefs_disconnect_callback(handler->iotag);
+
+	if (handler->callback != NULL)
+		SvREFCNT_dec(handler->callback);
+
+	if (handler->data != NULL)
+		SvREFCNT_dec(handler->data);
+
+	g_free(handler);
+}
+
+void purple_perl_prefs_disconnect_callback(guint callback_id)
+{
+	GSList *l, *l_next;
+	PurplePerlPrefsHandler *handler;
+
+	for (l = pref_handlers; l != NULL; l = l_next) {
+		l_next = l->next;
+		handler = l->data;
+
+		if (handler->iotag == callback_id) {
+			destroy_prefs_handler(handler);
+			return;
+		}
+	}
+
+	purple_debug_info("perl", "No prefs handler found with handle %u.\n",
+	                  callback_id);
+}
+
+void purple_perl_pref_cb_clear_for_plugin(PurplePlugin *plugin)
+{
+	GSList *l, *l_next;
+	PurplePerlPrefsHandler *handler;
+
+	for (l = pref_handlers; l != NULL; l = l_next) {
+		l_next = l->next;
+		handler = l->data;
+
+		if (handler->plugin == plugin)
+			destroy_prefs_handler(handler);
+	}
+}
--- a/libpurple/plugins/perl/perl-handlers.h	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/plugins/perl/perl-handlers.h	Fri Aug 01 19:45:08 2008 +0000
@@ -15,8 +15,8 @@
 	PurpleCmdId id;
 	SV *callback;
 	SV *data;
-	char *prpl_id;
-	char *cmd;
+	gchar *prpl_id;
+	gchar *cmd;
 	PurplePlugin *plugin;
 } PurplePerlCmdHandler;
 
@@ -31,7 +31,7 @@
 
 typedef struct
 {
-	char *signal;
+	gchar *signal;
 	SV *callback;
 	SV *data;
 	void *instance;
@@ -39,8 +39,17 @@
 
 } PurplePerlSignalHandler;
 
+typedef struct
+{
+	SV *callback;
+	SV *data;
+	PurplePlugin *plugin;
+	int iotag;
+
+} PurplePerlPrefsHandler;
+
 void purple_perl_plugin_action_cb(PurplePluginAction * gpa);
-GList *purple_perl_plugin_actions(PurplePlugin *plugin, gpointer context); 
+GList *purple_perl_plugin_actions(PurplePlugin *plugin, gpointer context);
 
 PurplePluginPrefFrame *purple_perl_get_plugin_frame(PurplePlugin *plugin);
 
@@ -69,4 +78,8 @@
 void purple_perl_cmd_unregister(PurpleCmdId id);
 void purple_perl_cmd_clear_for_plugin(PurplePlugin *plugin);
 
+guint purple_perl_prefs_connect_callback(PurplePlugin *plugin, const char *name, SV *callback, SV *data);
+void purple_perl_prefs_disconnect_callback(guint callback_id);
+void purple_perl_pref_cb_clear_for_plugin(PurplePlugin *plugin);
+
 #endif /* _PURPLE_PERL_HANDLERS_H_ */
--- a/libpurple/plugins/perl/perl.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/plugins/perl/perl.c	Fri Aug 01 19:45:08 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,20 +248,66 @@
 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, ret;
+	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
+
+	ret = perl_parse(prober, xs_init, argc, argv, NULL);
 
-	perl_run(prober);
+	if (ret != 0) {
+		STRLEN len;
+		const char * errmsg = "Unknown error";
+		if (SvTRUE(ERRSV))
+			errmsg = SvPV(ERRSV, len);
+		purple_debug_error("perl", "Unable to parse plugin %s (%d:%s)\n",
+						   plugin->path, ret, errmsg);
+		goto cleanup;
+	}
+
+	ret = perl_run(prober);
+
+	if (ret != 0) {
+		STRLEN len;
+		const char * errmsg = "Unknown error";
+		if (SvTRUE(ERRSV))
+			errmsg = SvPV(ERRSV, len);
+		purple_debug_error("perl", "Unable to run perl interpreter on plugin %s (%d:%s)\n",
+						   plugin->path, ret, errmsg);
+		goto cleanup;
+	}
 
 	plugin_info = perl_get_hv("PLUGIN_INFO", FALSE);
 
@@ -401,6 +455,7 @@
 		}
 	}
 
+	cleanup:
 	PL_perl_destruct_level = 1;
 	PERL_SET_CONTEXT(prober);
 	perl_destruct(prober);
@@ -523,6 +578,7 @@
 	purple_perl_cmd_clear_for_plugin(plugin);
 	purple_perl_signal_clear_for_plugin(plugin);
 	purple_perl_timeout_clear_for_plugin(plugin);
+	purple_perl_pref_cb_clear_for_plugin(plugin);
 
 	destroy_package(gps->package);
 
@@ -578,7 +634,7 @@
 	load_perl_plugin,                                 /**< load           */
 	unload_perl_plugin,                               /**< unload         */
 	destroy_perl_plugin,                              /**< destroy        */
-	
+
 	/* padding */
 	NULL,
 	NULL,
--- a/libpurple/plugins/perl/scripts/plugin_pref.pl	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/plugins/perl/scripts/plugin_pref.pl	Fri Aug 01 19:45:08 2008 +0000
@@ -44,8 +44,8 @@
 	$ppref = Purple::PluginPref->new_with_name_and_label(
 	    "/plugins/core/perl_test/choice", "Choice Preference");
 	$ppref->set_type(1);
-	$ppref->add_choice("ch0", $frame);
-	$ppref->add_choice("ch1", $frame);
+	$ppref->add_choice("ch0", "ch0-val");
+	$ppref->add_choice("ch1", "ch1-val");
 	$frame->add($ppref);
 	
 	$ppref = Purple::PluginPref->new_with_name_and_label(
@@ -56,12 +56,17 @@
 	return $frame;
 }
 
+sub pref_cb {
+	my ($pref, $type, $value, $data) = @_;
+	
+	print "pref changed: [$pref]($type)=$value data=$data\n";
+}
+
 sub plugin_init { 
 	
 	return %PLUGIN_INFO; 
 } 
 
-
 # This is the sub defined in %PLUGIN_INFO to be called when the plugin is loaded
 #	Note: The plugin has a reference to itself on top of the argument stack.
 sub plugin_load { 
@@ -75,7 +80,11 @@
 	Purple::Prefs::add_bool("/plugins/core/perl_test/bool", 1);	
 	Purple::Prefs::add_string("/plugins/core/perl_test/choice", "ch1");	
 	Purple::Prefs::add_string("/plugins/core/perl_test/text", "Foobar");	
-	
+
+	Purple::Prefs::connect_callback($plugin, "/plugins/core/perl_test", \&pref_cb, "none");
+	Purple::Prefs::connect_callback($plugin, "/plugins/core/perl_test/bool", \&pref_cb, "bool");
+	Purple::Prefs::connect_callback($plugin, "/plugins/core/perl_test/choice", \&pref_cb, "choice");
+	Purple::Prefs::connect_callback($plugin, "/plugins/core/perl_test/text", \&pref_cb, "text");
 
 	print "\n\n" . "#" x 80 . "\n\n";
 } 
--- a/libpurple/protocols/jabber/Makefile.mingw	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/jabber/Makefile.mingw	Fri Aug 01 19:45:08 2008 +0000
@@ -88,10 +88,6 @@
 LIB_PATHS += -L$(CYRUS_SASL_TOP)/bin
 LIBS += -llibsasl
 CYRUS_SASL_DLLS = \
-			$(CYRUS_SASL_TOP)/bin/comerr32.dll \
-			$(CYRUS_SASL_TOP)/bin/gssapi32.dll \
-			$(CYRUS_SASL_TOP)/bin/k5sprt32.dll \
-			$(CYRUS_SASL_TOP)/bin/krb5_32.dll \
 			$(CYRUS_SASL_TOP)/bin/libsasl.dll
 
 CYRUS_SASL_PLUGINS = \
--- a/libpurple/protocols/jabber/disco.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/jabber/disco.c	Fri Aug 01 19:45:08 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	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Fri Aug 01 19:45:08 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)
 {
@@ -520,15 +521,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)
@@ -563,37 +572,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);
 	}
 }
 
@@ -675,7 +709,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);
@@ -1156,7 +1190,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",
@@ -1327,7 +1361,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	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Fri Aug 01 19:45:08 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	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Fri Aug 01 19:45:08 2008 +0000
@@ -194,6 +194,7 @@
 {
 #ifdef HAVE_CYRUS_SASL
 #ifdef _WIN32
+	UINT old_error_mode;
 	gchar *sasldir;
 #endif
 	int ret;
@@ -236,7 +237,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);
 
@@ -250,10 +251,16 @@
 	sasldir = g_build_filename(wpurple_install_dir(), "sasl2", NULL);
 	sasl_set_path(SASL_PATH_TYPE_PLUGIN, sasldir);
 	g_free(sasldir);
+	/* Suppress error popups for failing to load sasl plugins */
+	old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
 #endif
 	if ((ret = sasl_client_init(NULL)) != SASL_OK) {
 		purple_debug_error("xmpp", "Error (%d) initializing SASL.\n", ret);
 	}
+#ifdef _WIN32
+	/* Restore the original error mode */
+	SetErrorMode(old_error_mode);
+#endif
 #endif
 	jabber_register_commands();
 	
--- a/libpurple/protocols/jabber/si.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/jabber/si.c	Fri Aug 01 19:45:08 2008 +0000
@@ -721,7 +721,6 @@
 	JabberSIXfer *jsx;
 	JabberIq *iq;
 	xmlnode *query, *streamhost;
-	const char *ft_proxies;
 	char port[6];
 	GList *tmp;
 	JabberBytestreamsStreamhost *sh, *sh2;
@@ -785,52 +784,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/Makefile.am	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/Makefile.am	Fri Aug 01 19:45:08 2008 +0000
@@ -48,8 +48,6 @@
 	slplink.h \
 	slpmsg.c \
 	slpmsg.h \
-	slpsession.c \
-	slpsession.h \
 	soap.c \
 	soap.h \
 	state.c \
--- a/libpurple/protocols/msn/Makefile.mingw	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/Makefile.mingw	Fri Aug 01 19:45:08 2008 +0000
@@ -59,7 +59,6 @@
 			slpcall.c \
 			slplink.c \
 			slpmsg.c \
-			slpsession.c \
 			soap.c\
 			state.c \
 			switchboard.c \
--- a/libpurple/protocols/msn/contact.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/contact.c	Fri Aug 01 19:45:08 2008 +0000
@@ -228,8 +228,8 @@
 	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_ADD_ADDRESSBOOK_SOAP_ACTION,
 			xmlnode_from_str(body, -1)),
-		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, msn_create_address_cb,
-		session);
+		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, FALSE,
+		msn_create_address_cb, session);
 
 	g_free(body);
 }
@@ -415,7 +415,7 @@
 	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_GET_CONTACT_SOAP_ACTION,
 			xmlnode_from_str(body, -1)),
-		MSN_CONTACT_SERVER, MSN_GET_CONTACT_POST_URL,
+		MSN_CONTACT_SERVER, MSN_GET_CONTACT_POST_URL, FALSE,
 		msn_get_contact_list_cb, g_memdup(&cb_data, sizeof(cb_data)));
 
 	g_free(update_str);
@@ -815,8 +815,8 @@
 	msn_soap_message_send(session,
 		msn_soap_message_new(MSN_GET_ADDRESS_SOAP_ACTION,
 			xmlnode_from_str(body, -1)),
-		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, msn_get_address_cb,
-		session);
+		MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, FALSE,
+		msn_get_address_cb, session);
 
 	g_free(update_str);
 	g_free(body);
@@ -917,7 +917,8 @@
 		msn_nexus_get_token_str(state->session->nexus, MSN_AUTH_CONTACTS), -1);
 	msn_soap_message_send(state->session,
 		msn_soap_message_new(state->post_action, xmlnode_copy(state->body)),
-		MSN_CONTACT_SERVER, state->post_url, msn_contact_request_cb, state);
+		MSN_CONTACT_SERVER, state->post_url, FALSE,
+		msn_contact_request_cb, state);
 	return FALSE;
 }
 
--- a/libpurple/protocols/msn/msn.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/msn.c	Fri Aug 01 19:45:08 2008 +0000
@@ -428,25 +428,27 @@
 	gc = (PurpleConnection *) action->context;
 	session = gc->proto_data;
 
+	if (!session->passport_info.email_enabled) {
+		purple_notify_error(gc, NULL,
+						  _("This account does not have email enabled."), NULL);
+		return;
+	}
+
 	/** apparently the correct value is 777, use 750 as a failsafe */ 
-	if (time (NULL) - session->passport_info.mail_timestamp >= 750) {
+	if ((session->passport_info.mail_url == NULL)
+		|| (time (NULL) - session->passport_info.mail_timestamp >= 750)) {
 		MsnTransaction *trans;
 		MsnCmdProc *cmdproc;
 
 		cmdproc = session->notification->cmdproc;
 
 		trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX");
-		msn_transaction_set_data(trans, GUINT_TO_POINTER (TRUE));
+		msn_transaction_set_data(trans, GUINT_TO_POINTER(TRUE));
 
 		msn_cmdproc_send_trans(cmdproc, trans);
 
-	} else if (session->passport_info.file != NULL) {
-		purple_notify_uri(gc, session->passport_info.file);
-
-	} else {
-		purple_notify_error(gc, NULL,
-						  _("This Hotmail account may not be active."), NULL);
-	}
+	} else
+		purple_notify_uri(gc, session->passport_info.mail_url);
 }
 
 static void
@@ -581,17 +583,26 @@
 msn_can_receive_file(PurpleConnection *gc, const char *who)
 {
 	PurpleAccount *account;
-	char *normal;
+	gchar *normal;
 	gboolean ret;
 
 	account = purple_connection_get_account(gc);
 
 	normal = g_strdup(msn_normalize(account, purple_account_get_username(account)));
-
 	ret = strcmp(normal, msn_normalize(account, who));
-
 	g_free(normal);
 
+	if (ret) {
+		MsnSession *session = gc->proto_data;
+		if (session) {
+			MsnUser *user = msn_userlist_find_user(session->userlist, who);
+			if (user)
+				/* Include these too: MSN_CLIENT_CAP_MSNMOBILE|MSN_CLIENT_CAP_MSNDIRECT ? */
+				ret = (user->clientid & MSN_CLIENT_CAP_WEBMSGR) == 0;
+		} else
+			ret = FALSE;
+	}
+
 	return ret;
 }
 
@@ -614,14 +625,14 @@
 		if (user->clientid & MSN_CLIENT_CAP_BOT)
 			return "bot";
 		if (user->clientid & MSN_CLIENT_CAP_WIN_MOBILE)
-			return "hiptop"; /* XXX: Rename to Mobile / Use different icon? */
+			return "mobile";
 #if 0
 		/* XXX: Since we don't support this, there's no point in showing it just yet */
 		if (user->clientid & MSN_CLIENT_CAP_SCHANNEL)
 			return "secure";
 #endif
 		if (user->clientid & MSN_CLIENT_CAP_WEBMSGR)
-			return "web";
+			return "external";
 		if (user->networkid == MSN_NETWORK_YAHOO)
 			return "yahoo";
 	}
@@ -1343,6 +1354,7 @@
 
 	if (group_id >= 0)
 	{
+		/* This is wrong... user->group_ids contains g_strdup()'d data now */
 		user->group_ids = g_list_append(user->group_ids,
 										GINT_TO_POINTER(group_id));
 	}
--- a/libpurple/protocols/msn/nexus.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/nexus.c	Fri Aug 01 19:45:08 2008 +0000
@@ -390,7 +390,7 @@
 	msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE);
 
 	username = purple_account_get_username(session->account);
-	password = g_strndup(purple_connection_get_password(session->account->gc), 16);
+	password = g_markup_escape_text(purple_connection_get_password(session->account->gc), 16);
 
 	purple_debug_info("msn", "Logging on %s, with policy '%s', nonce '%s'\n",
 	                  username, nexus->policy, nexus->nonce);
@@ -411,7 +411,7 @@
 
 	soap = msn_soap_message_new(NULL, xmlnode_from_str(request, -1));
 	g_free(request);
-	msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL,
+	msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL, TRUE,
 	                      nexus_got_response_cb, nexus);
 }
 
@@ -597,7 +597,7 @@
 
 	soap = msn_soap_message_new(NULL, xmlnode_from_str(request, -1));
 	g_free(request);
-	msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL,
+	msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL, TRUE,
 	                      nexus_got_update_cb, ud);
 }
 
--- a/libpurple/protocols/msn/notification.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/notification.c	Fri Aug 01 19:45:08 2008 +0000
@@ -1289,7 +1289,6 @@
 	const char *url;
 	PurpleCipherContext *cipher;
 	gchar digest[33];
-	FILE *fd;
 	char *buf;
 
 	gulong tmp_timestamp;
@@ -1316,111 +1315,19 @@
 
 	g_free(buf);
 
-	if (session->passport_info.file != NULL)
-	{
-		g_unlink(session->passport_info.file);
-		g_free(session->passport_info.file);
-	}
-
-	if ((fd = purple_mkstemp(&session->passport_info.file, FALSE)) == NULL)
-	{
-		purple_debug_error("msn",
-						 "Error opening temp passport file: %s\n",
-						 g_strerror(errno));
-		/* The user wanted to check his or her email */
-		if (cmd->trans && cmd->trans->data)
-			/* TODO: This error might be a bit technical... */
-			purple_notify_error(gc, NULL,
-							  _("Error opening temporary passport file."), NULL);
-	}
-	else
-	{
-#ifdef _WIN32
-		fputs("<!-- saved from url=(0013)about:internet -->\n", fd);
-#endif
-		fputs("<html>\n"
-			  "<head>\n"
-			  "<noscript>\n"
-			  "<meta http-equiv=\"Refresh\" content=\"0; "
-			  "url=http://www.hotmail.com\">\n"
-			  "</noscript>\n"
-			  "</head>\n\n",
-			  fd);
+	g_free(session->passport_info.mail_url);
+	session->passport_info.mail_url = g_strdup_printf("%s&auth=%s&creds=%s&sl=%ld&username=%s&mode=ttl&sid=%s&id=2&rru=%ssvc_mail&js=yes",
+                                                        url,
+                                                        session->passport_info.mspauth ? session->passport_info.mspauth : "BOGUS",
+                                                        buf,
+                                                        tmp_timestamp,
+                                                        msn_user_get_passport(session->user),
+                                                        session->passport_info.sid,
+                                                        rru);
 
-		fprintf(fd, "<body onload=\"document.pform.submit(); \">\n");
-		fprintf(fd, "<form name=\"pform\" action=\"%s\" method=\"POST\">\n\n",
-				url);
-		fprintf(fd, "<input type=\"hidden\" name=\"mode\" value=\"ttl\">\n");
-		fprintf(fd, "<input type=\"hidden\" name=\"login\" value=\"%s\">\n",
-				purple_account_get_username(account));
-		fprintf(fd, "<input type=\"hidden\" name=\"username\" value=\"%s\">\n",
-				purple_account_get_username(account));
-		if (session->passport_info.sid != NULL)
-			fprintf(fd, "<input type=\"hidden\" name=\"sid\" value=\"%s\">\n",
-					session->passport_info.sid);
-		if (session->passport_info.kv != NULL)
-			fprintf(fd, "<input type=\"hidden\" name=\"kv\" value=\"%s\">\n",
-					session->passport_info.kv);
-		fprintf(fd, "<input type=\"hidden\" name=\"id\" value=\"2\">\n");
-		fprintf(fd, "<input type=\"hidden\" name=\"sl\" value=\"%ld\">\n",
-				tmp_timestamp);
-		fprintf(fd, "<input type=\"hidden\" name=\"rru\" value=\"%s\">\n",
-				rru);
-		if (session->passport_info.mspauth != NULL)
-			fprintf(fd, "<input type=\"hidden\" name=\"auth\" value=\"%s\">\n",
-					session->passport_info.mspauth);
-		fprintf(fd, "<input type=\"hidden\" name=\"creds\" value=\"%s\">\n",
-				digest); /* TODO Digest me (huh? -- ChipX86) */
-		fprintf(fd, "<input type=\"hidden\" name=\"svc\" value=\"mail\">\n");
-		fprintf(fd, "<input type=\"hidden\" name=\"js\" value=\"yes\">\n");
-		fprintf(fd, "</form></body>\n");
-		fprintf(fd, "</html>\n");
-
-		if (fclose(fd))
-		{
-			purple_debug_error("msn",
-							 "Error closing temp passport file: %s\n",
-							 g_strerror(errno));
-
-			/* The user wanted to check his or her email */
-			if (cmd->trans && cmd->trans->data)
-				/* TODO: This error might be a bit technical... */
-				purple_notify_error(gc, NULL,
-								  _("Error closing temporary passport file."), NULL);
-
-			g_unlink(session->passport_info.file);
-			g_free(session->passport_info.file);
-			session->passport_info.file = NULL;
-		}
-#ifdef _WIN32
-		else
-		{
-			/*
-			 * Renaming file with .html extension, so that the
-			 * win32 open_url will work.
-			 */
-			char *tmp;
-
-			if ((tmp =
-				g_strdup_printf("%s.html",
-					session->passport_info.file)) != NULL)
-			{
-				if (g_rename(session->passport_info.file,
-							tmp) == 0)
-				{
-					g_free(session->passport_info.file);
-					session->passport_info.file = tmp;
-				}
-				else
-					g_free(tmp);
-			}
-		}
-#endif
-
-		/* The user wants to check his or her email */
-		if (cmd->trans && cmd->trans->data)
-			purple_notify_uri(purple_account_get_connection(account), session->passport_info.file);
-	}
+	/* The user wants to check his or her email */
+	if (cmd->trans && cmd->trans->data)
+		purple_notify_uri(purple_account_get_connection(account), session->passport_info.mail_url);
 }
 /**************************************************************************
  * Switchboards
@@ -1666,6 +1573,9 @@
 	if ((value = msn_message_get_attr(msg, "LoginTime")) != NULL)
 		session->passport_info.sl = atol(value);
 
+	if ((value = msn_message_get_attr(msg, "EmailEnabled")) != NULL)
+		session->passport_info.email_enabled = (gboolean)atol(value);
+
 	/*starting retrieve the contact list*/
 	clLastChange = purple_account_get_string(session->account, "CLLastChange", NULL);
 #ifdef MSN_PARTIAL_LISTS
@@ -1696,7 +1606,7 @@
 		/* This isn't an official message. */
 		return;
 
-	if (session->passport_info.file == NULL)
+	if (session->passport_info.mail_url == NULL)
 	{
 		MsnTransaction *trans;
 		trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX");
@@ -1724,7 +1634,7 @@
 			const char *url;
 
 			passport = msn_user_get_passport(session->user);
-			url = session->passport_info.file;
+			url = session->passport_info.mail_url;
 
 			purple_notify_emails(gc, count, FALSE, NULL, NULL,
 							   &passport, &url, NULL, NULL);
@@ -1763,7 +1673,7 @@
 		return;
 	}
 
-	if (session->passport_info.file == NULL)
+	if (session->passport_info.mail_url == NULL)
 	{
 		MsnTransaction *trans;
 		trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX");
@@ -1793,7 +1703,7 @@
 			const char *url;
 
 			passport = msn_user_get_passport(session->user);
-			url = session->passport_info.file;
+			url = session->passport_info.mail_url;
 
 			purple_notify_emails(gc, count, FALSE, NULL, NULL,
 							   &passport, &url, NULL, NULL);
@@ -1825,7 +1735,7 @@
 		/* This isn't an official message. */
 		return;
 
-	if (session->passport_info.file == NULL)
+	if (session->passport_info.mail_url == NULL)
 	{
 		MsnTransaction *trans;
 		trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX");
@@ -1855,7 +1765,7 @@
 					  (subject != NULL ? subject : ""),
 					  (from != NULL ?  from : ""),
 					  msn_user_get_passport(session->user),
-					  session->passport_info.file, NULL, NULL);
+					  session->passport_info.mail_url, NULL, NULL);
 
 	g_free(from);
 	g_free(subject);
--- a/libpurple/protocols/msn/oim.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/oim.c	Fri Aug 01 19:45:08 2008 +0000
@@ -219,7 +219,8 @@
 
 	msn_soap_message_send(session,
 		msn_soap_message_new(data->action, xmlnode_copy(data->body)),
-		data->host, data->url, msn_oim_request_cb, data);
+		data->host, data->url, FALSE,
+		msn_oim_request_cb, data);
 }
 
 
@@ -692,7 +693,7 @@
 	{
 		char *unread = xmlnode_get_data(iu_node);
 		const char *passport = msn_user_get_passport(session->user);
-		const char *url = session->passport_info.file;
+		const char *url = session->passport_info.mail_url;
 		int count = atoi(unread);
 
 		/* XXX/khc: pretty sure this is wrong */
--- a/libpurple/protocols/msn/servconn.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/servconn.c	Fri Aug 01 19:45:08 2008 +0000
@@ -391,7 +391,8 @@
 	session = servconn->session;
 
 	len = read(servconn->fd, buf, sizeof(buf) - 1);
-	servconn->session->account->gc->last_received = time(NULL);
+	if (servconn->type == MSN_SERVCONN_NS)
+		servconn->session->account->gc->last_received = time(NULL);
 
 	if (len < 0 && errno == EAGAIN) {
 		return;
--- a/libpurple/protocols/msn/session.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/session.c	Fri Aug 01 19:45:08 2008 +0000
@@ -80,11 +80,7 @@
 	g_free(session->passport_info.mspauth);
 	g_free(session->passport_info.client_ip);
 
-	if (session->passport_info.file != NULL)
-	{
-		g_unlink(session->passport_info.file);
-		g_free(session->passport_info.file);
-	}
+	g_free(session->passport_info.mail_url);
 
 	if (session->sync != NULL)
 		msn_sync_destroy(session->sync);
--- a/libpurple/protocols/msn/session.h	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/session.h	Fri Aug 01 19:45:08 2008 +0000
@@ -115,10 +115,11 @@
 		char *sid;
 		char *mspauth;
 		unsigned long sl;
-		char *file;
 		char *client_ip;
 		int client_port;
+		char *mail_url;
 		gulong mail_timestamp;
+		gboolean email_enabled;
 	} passport_info;
 
 	GHashTable *soap_table;
--- a/libpurple/protocols/msn/slp.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/slp.c	Fri Aug 01 19:45:08 2008 +0000
@@ -25,7 +25,6 @@
 #include "slp.h"
 #include "slpcall.h"
 #include "slpmsg.h"
-#include "slpsession.h"
 
 #include "object.h"
 #include "user.h"
@@ -256,7 +255,6 @@
 		/* Emoticon or UserDisplay */
 		char *content;
 		gsize len;
-		MsnSlpSession *slpsession;
 		MsnSlpLink *slplink;
 		MsnSlpMessage *slpmsg;
 		MsnObject *obj;
@@ -306,14 +304,10 @@
 			g_return_if_reached();
 		}
 
-		slpsession = msn_slplink_find_slp_session(slplink,
-												  slpcall->session_id);
-
 		/* DATA PREP */
 		slpmsg = msn_slpmsg_new(slplink);
 		slpmsg->slpcall = slpcall;
-		slpmsg->slpsession = slpsession;
-		slpmsg->session_id = slpsession->id;
+		slpmsg->session_id = slpcall->session_id;
 		msn_slpmsg_set_body(slpmsg, NULL, 4);
 #ifdef MSN_DEBUG_SLP
 		slpmsg->info = "SLP DATA PREP";
@@ -323,7 +317,6 @@
 		/* DATA */
 		slpmsg = msn_slpmsg_new(slplink);
 		slpmsg->slpcall = slpcall;
-		slpmsg->slpsession = slpsession;
 		slpmsg->flags = 0x20;
 #ifdef MSN_DEBUG_SLP
 		slpmsg->info = "SLP DATA";
--- a/libpurple/protocols/msn/slpcall.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/slpcall.c	Fri Aug 01 19:45:08 2008 +0000
@@ -24,7 +24,6 @@
 #include "msn.h"
 #include "msnutils.h"
 #include "slpcall.h"
-#include "slpsession.h"
 
 #include "slp.h"
 
@@ -115,12 +114,8 @@
 void
 msn_slp_call_session_init(MsnSlpCall *slpcall)
 {
-	MsnSlpSession *slpsession;
-
-	slpsession = msn_slp_session_new(slpcall);
-
 	if (slpcall->session_init_cb)
-		slpcall->session_init_cb(slpsession);
+		slpcall->session_init_cb(slpcall);
 
 	slpcall->started = TRUE;
 }
--- a/libpurple/protocols/msn/slpcall.h	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/slpcall.h	Fri Aug 01 19:45:08 2008 +0000
@@ -29,7 +29,6 @@
 typedef struct _MsnSlpCall MsnSlpCall;
 
 #include "slplink.h"
-#include "slpsession.h"
 
 /* The official client seems to timeout slp calls after 5 minutes */
 #define MSN_SLPCALL_TIMEOUT 300000
@@ -66,7 +65,7 @@
 
 	void (*progress_cb)(MsnSlpCall *slpcall,
 						gsize total_length, gsize len, gsize offset);
-	void (*session_init_cb)(MsnSlpSession *slpsession);
+	void (*session_init_cb)(MsnSlpCall *slpcall);
 
 	/* Can be checksum, or smile */
 	char *data_info;
--- a/libpurple/protocols/msn/slplink.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/slplink.c	Fri Aug 01 19:45:08 2008 +0000
@@ -154,23 +154,6 @@
 	return slplink;
 }
 
-MsnSlpSession *
-msn_slplink_find_slp_session(MsnSlpLink *slplink, long session_id)
-{
-	GList *l;
-	MsnSlpSession *slpsession;
-
-	for (l = slplink->slp_sessions; l != NULL; l = l->next)
-	{
-		slpsession = l->data;
-
-		if (slpsession->id == session_id)
-			return slpsession;
-	}
-
-	return NULL;
-}
-
 void
 msn_slplink_add_slpcall(MsnSlpLink *slplink, MsnSlpCall *slpcall)
 {
@@ -394,12 +377,12 @@
 	}
 	else if (slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030)
 	{
-		MsnSlpSession *slpsession;
-		slpsession = slpmsg->slpsession;
+		MsnSlpCall *slpcall;
+		slpcall = slpmsg->slpcall;
 
-		g_return_if_fail(slpsession != NULL);
-		msg->msnslp_header.session_id = slpsession->id;
-		msg->msnslp_footer.value = slpsession->app_id;
+		g_return_if_fail(slpcall != NULL);
+		msg->msnslp_header.session_id = slpcall->session_id;
+		msg->msnslp_footer.value = slpcall->app_id;
 		msg->msnslp_header.ack_id = rand() % 0xFFFFFF00;
 	}
 	else if (slpmsg->flags == 0x100)
@@ -476,18 +459,15 @@
 }
 
 static void
-send_file_cb(MsnSlpSession *slpsession)
+send_file_cb(MsnSlpCall *slpcall)
 {
-	MsnSlpCall *slpcall;
 	MsnSlpMessage *slpmsg;
 	struct stat st;
 	PurpleXfer *xfer;
 
-	slpcall = slpsession->slpcall;
 	slpmsg = msn_slpmsg_new(slpcall->slplink);
 	slpmsg->slpcall = slpcall;
 	slpmsg->flags = 0x1000030;
-	slpmsg->slpsession = slpsession;
 #ifdef MSN_DEBUG_SLP
 	slpmsg->info = "SLP FILE";
 #endif
--- a/libpurple/protocols/msn/slplink.h	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/slplink.h	Fri Aug 01 19:45:08 2008 +0000
@@ -53,7 +53,6 @@
 	MsnDirectConn *directconn;
 
 	GList *slp_calls;
-	GList *slp_sessions;
 	GList *slp_msgs;
 
 	GQueue *slp_msg_queue;
@@ -74,8 +73,6 @@
  */
 MsnSlpLink *msn_session_get_slplink(MsnSession *session, const char *username);
 
-MsnSlpSession *msn_slplink_find_slp_session(MsnSlpLink *slplink,
-											long session_id);
 void msn_slplink_add_slpcall(MsnSlpLink *slplink, MsnSlpCall *slpcall);
 void msn_slplink_remove_slpcall(MsnSlpLink *slplink, MsnSlpCall *slpcall);
 MsnSlpCall *msn_slplink_find_slp_call(MsnSlpLink *slplink,
--- a/libpurple/protocols/msn/slpmsg.h	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/slpmsg.h	Fri Aug 01 19:45:08 2008 +0000
@@ -28,7 +28,6 @@
 
 #include "imgstore.h"
 
-#include "slpsession.h"
 #include "slpcall.h"
 #include "slplink.h"
 #include "session.h"
@@ -42,7 +41,6 @@
  */
 struct _MsnSlpMessage
 {
-	MsnSlpSession *slpsession;
 	MsnSlpCall *slpcall; /**< The slpcall to which this slp message belongs (if applicable). */
 	MsnSlpLink *slplink; /**< The slplink through which this slp message is being sent. */
 	MsnSession *session;
--- a/libpurple/protocols/msn/slpsession.c	Sun Jul 27 13:29:26 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/**
- * @file slpsession.h SLP Session functions
- *
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-#include "slpsession.h"
-
-/**************************************************************************
- * SLP Session
- **************************************************************************/
-
-MsnSlpSession *
-msn_slp_session_new(MsnSlpCall *slpcall)
-{
-	MsnSlpSession *slpsession;
-
-	g_return_val_if_fail(slpcall != NULL, NULL);
-
-	slpsession = g_new0(MsnSlpSession, 1);
-
-	slpsession->slpcall = slpcall;
-	slpsession->id = slpcall->session_id;
-	slpsession->app_id = slpcall->app_id;
-
-	slpcall->slplink->slp_sessions =
-		g_list_append(slpcall->slplink->slp_sessions, slpsession);
-
-	return slpsession;
-}
-
-void
-msn_slp_session_destroy(MsnSlpSession *slpsession)
-{
-	g_return_if_fail(slpsession != NULL);
-
-	slpsession->slpcall->slplink->slp_sessions =
-		g_list_remove(slpsession->slpcall->slplink->slp_sessions, slpsession);
-
-	g_free(slpsession);
-}
-
-#if 0
-static void
-msn_slp_session_send_slpmsg(MsnSlpSession *slpsession, MsnSlpMessage *slpmsg)
-{
-	slpmsg->slpsession = slpsession;
-
-#if 0
-	slpmsg->session_id = slpsession->id;
-	slpmsg->app_id = slpsession->app_id;
-#endif
-
-	msn_slplink_send_slpmsg(slpsession->slpcall->slplink, slpmsg);
-}
-#endif
--- a/libpurple/protocols/msn/slpsession.h	Sun Jul 27 13:29:26 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/**
- * @file slpsession.h SLP Session functions
- *
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-#ifndef _MSN_SLPSESSION_H_
-#define _MSN_SLPSESSION_H_
-
-typedef struct _MsnSlpSession MsnSlpSession;
-
-#include "slpcall.h"
-#include "slpsession.h"
-#include "slpmsg.h"
-
-struct _MsnSlpSession
-{
-	/* MsnSlpLink *slplink; */
-	MsnSlpCall *slpcall;
-
-	long id;
-
-	long app_id;
-};
-
-MsnSlpSession *msn_slp_session_new(MsnSlpCall *slpcall);
-void msn_slp_session_destroy(MsnSlpSession *slpsession);
-void msn_slpsession_send_slpmsg(MsnSlpSession *slpsession,
-								MsnSlpMessage *slpmsg);
-#endif /* _MSN_SLPSESSION_H_ */
--- a/libpurple/protocols/msn/soap.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/soap.c	Fri Aug 01 19:45:08 2008 +0000
@@ -38,10 +38,11 @@
 #endif
 
 #define SOAP_TIMEOUT (5 * 60)
-
+#define MSN_UNSAFE_DEBUG 1
 typedef struct _MsnSoapRequest {
 	char *path;
 	MsnSoapMessage *message;
+	gboolean secure;
 	MsnSoapCallback cb;
 	gpointer cb_data;
 } MsnSoapRequest;
@@ -76,8 +77,8 @@
 static void msn_soap_connection_handle_next(MsnSoapConnection *conn);
 static void msn_soap_connection_destroy(MsnSoapConnection *conn);
 
-static void msn_soap_message_send_internal(MsnSession *session,
-	MsnSoapMessage *message, const char *host, const char *path,
+static void msn_soap_message_send_internal(MsnSession *session, MsnSoapMessage *message,
+	const char *host, const char *path, gboolean secure,
 	MsnSoapCallback cb, gpointer cb_data, gboolean first);
 
 static void msn_soap_request_destroy(MsnSoapRequest *req, gboolean keep_message);
@@ -187,8 +188,8 @@
 	char *path;
 
 	if (purple_url_parse(url, &host, NULL, &path, NULL, NULL)) {
-		msn_soap_message_send_internal(conn->session,
-			conn->current_request->message,	host, path,
+		msn_soap_message_send_internal(conn->session, conn->current_request->message,
+			host, path, conn->current_request->secure,
 			conn->current_request->cb, conn->current_request->cb_data, TRUE);
 
 		msn_soap_request_destroy(conn->current_request, TRUE);
@@ -309,6 +310,11 @@
 	char *cursor;
 	char *linebreak;
 
+#ifndef MSN_UNSAFE_DEBUG
+	if (conn->current_request->secure)
+		purple_debug_info("soap", "Received secure request.\n");
+	else
+#endif
 	purple_debug_info("soap", "current %s\n", conn->buf->str);
 
 	cursor = conn->buf->str + conn->handled_len;
@@ -506,6 +512,11 @@
 			g_string_append(conn->buf, "\r\n");
 			g_string_append(conn->buf, body);
 
+#ifndef MSN_UNSAFE_DEBUG
+			if (req->secure)
+				purple_debug_info("soap", "Sending secure request.\n");
+			else
+#endif
 			purple_debug_info("soap", "%s\n", conn->buf->str);
 
 			conn->handled_len = 0;
@@ -534,16 +545,16 @@
 
 void
 msn_soap_message_send(MsnSession *session, MsnSoapMessage *message,
-	const char *host, const char *path,
+	const char *host, const char *path, gboolean secure,
 	MsnSoapCallback cb, gpointer cb_data)
 {
-	msn_soap_message_send_internal(session, message, host, path, cb, cb_data,
-		FALSE);
+	msn_soap_message_send_internal(session, message, host, path, secure,
+		cb, cb_data, FALSE);
 }
 
 static void
-msn_soap_message_send_internal(MsnSession *session,
-	MsnSoapMessage *message, const char *host, const char *path,
+msn_soap_message_send_internal(MsnSession *session, MsnSoapMessage *message,
+	const char *host, const char *path, gboolean secure,
 	MsnSoapCallback cb, gpointer cb_data, gboolean first)
 {
 	MsnSoapConnection *conn = msn_soap_get_connection(session, host);
@@ -551,6 +562,7 @@
 
 	req->path = g_strdup(path);
 	req->message = message;
+	req->secure = secure;
 	req->cb = cb;
 	req->cb_data = cb_data;
 
--- a/libpurple/protocols/msn/soap.h	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/soap.h	Fri Aug 01 19:45:08 2008 +0000
@@ -47,8 +47,8 @@
 void msn_soap_message_add_header(MsnSoapMessage *req,
 	const char *name, const char *value);
 
-void msn_soap_message_send(MsnSession *session,
-	MsnSoapMessage *message, const char *host, const char *path,
+void msn_soap_message_send(MsnSession *session, MsnSoapMessage *message,
+	const char *host, const char *path, gboolean secure,
 	MsnSoapCallback cb, gpointer cb_data);
 
 void msn_soap_message_destroy(MsnSoapMessage *message);
--- a/libpurple/protocols/msn/user.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/msn/user.c	Fri Aug 01 19:45:08 2008 +0000
@@ -235,21 +235,19 @@
 
 /*add group id to User object*/
 void
-msn_user_add_group_id(MsnUser *user, const char* id)
+msn_user_add_group_id(MsnUser *user, const char* group_id)
 {
 	MsnUserList *userlist;
 	PurpleAccount *account;
 	PurpleBuddy *b;
 	PurpleGroup *g;
 	const char *passport;
-	char *group_id;
 	const char *group_name;
 
 	g_return_if_fail(user != NULL);
-	g_return_if_fail(id != NULL);
+	g_return_if_fail(group_id != NULL);
 
-	group_id = g_strdup(id);
-	user->group_ids = g_list_append(user->group_ids, group_id);
+	user->group_ids = g_list_append(user->group_ids, g_strdup(group_id));
 
 	userlist = user->userlist;
 	account = userlist->session->account;
@@ -261,7 +259,7 @@
 
 	g = purple_find_group(group_name);
 
-	if ((id == NULL) && (g == NULL))
+	if ((group_id == NULL) && (g == NULL))
 	{
 		g = purple_group_new(group_name);
 		purple_blist_add_group(g, NULL);
--- a/libpurple/protocols/oscar/family_locate.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/oscar/family_locate.c	Fri Aug 01 19:45:08 2008 +0000
@@ -63,7 +63,8 @@
 	 {0x09, 0x46, 0x00, 0x01, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{OSCAR_CAPABILITY_XHTML_IM,
+	/* OSCAR_CAPABILITY_XHTML_IM */
+	{OSCAR_CAPABILITY_GENERICUNKNOWN,
 	 {0x09, 0x46, 0x00, 0x02, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
@@ -82,7 +83,8 @@
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
 	/* "Microphone" support in Windows AIM 5.5.3501 and newer */
-	{OSCAR_CAPABILITY_MICROPHONE,
+	/* OSCAR_CAPABILITY_MICROPHONE */
+	{OSCAR_CAPABILITY_GENERICUNKNOWN,
 	 {0x09, 0x46, 0x01, 0x03, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
--- a/libpurple/protocols/oscar/oscar.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Fri Aug 01 19:45:08 2008 +0000
@@ -1512,6 +1512,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."));
@@ -3136,7 +3137,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	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.h	Fri Aug 01 19:45:08 2008 +0000
@@ -357,15 +357,13 @@
 	OSCAR_CAPABILITY_HIPTOP               = 0x00100000,
 	OSCAR_CAPABILITY_SECUREIM             = 0x00200000,
 	OSCAR_CAPABILITY_SMS                  = 0x00400000,
-	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_XHTML_IM             = 0x20000000,
-	OSCAR_CAPABILITY_GENERICUNKNOWN       = 0x40000000,
-	OSCAR_CAPABILITY_LAST                 = 0x80000000
+	OSCAR_CAPABILITY_VIDEO                = 0x00800000,
+	OSCAR_CAPABILITY_ICHATAV              = 0x01000000,
+	OSCAR_CAPABILITY_LIVEVIDEO            = 0x02000000,
+	OSCAR_CAPABILITY_CAMERA               = 0x04000000,
+	OSCAR_CAPABILITY_ICHAT_SCREENSHARE    = 0x08000000,
+	OSCAR_CAPABILITY_GENERICUNKNOWN       = 0x10000000,
+	OSCAR_CAPABILITY_LAST                 = 0x20000000
 } OscarCapability;
 
 /*
--- a/libpurple/win32/global.mak	Sun Jul 27 13:29:26 2008 +0000
+++ b/libpurple/win32/global.mak	Fri Aug 01 19:45:08 2008 +0000
@@ -19,8 +19,8 @@
 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
-SILC_TOOLKIT ?= $(WIN32_DEV_TOP)/silc-toolkit-1.1.5
+PERL_LIB_TOP ?= $(WIN32_DEV_TOP)/perl-5.10.0
+SILC_TOOLKIT ?= $(WIN32_DEV_TOP)/silc-toolkit-1.1.7
 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/pidgin/gtkdialogs.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/pidgin/gtkdialogs.c	Fri Aug 01 19:45:08 2008 +0000
@@ -73,7 +73,8 @@
 	{"John 'rekkanoryo' Bailey",	N_("developer"), NULL},
 	{"Ethan 'Paco-Paco' Blanton",	N_("developer"), NULL},
 	{"Thomas Butter",				N_("developer"), NULL},
-	{"Ka-Hing Cheung",				N_("developer"), NULL},
+	/* feel free to not translate this */
+	{N_("Ka-Hing Cheung"),			N_("developer"), NULL},
 	{"Sadrul Habib Chowdhury",		N_("developer"), NULL},
 	{"Mark 'KingAnt' Doliner",		N_("developer"), "mark@kingant.net"},
 	{"Sean Egan",					N_("developer"), "sean.egan@gmail.com"},
@@ -85,6 +86,7 @@
 	{"Bartosz Oler",		N_("developer"), NULL},
 	{"Etan 'deryni' Reisner",       N_("developer"), NULL},
 	{"Tim 'marv' Ringenbach",		N_("developer"), NULL},
+	{"Elliott 'QuLogic' Sales de Andrade",	N_("developer"),	NULL},
 	{"Luke 'LSchiere' Schierer",	N_("support"), "lschiere@users.sf.net"},
 	{"Megan 'Cae' Schneider",       N_("support/QA"), NULL},
 	{"Evan Schoenberg",		N_("developer"), NULL},
@@ -100,7 +102,6 @@
 	{"Felipe 'shx' Contreras",		NULL,	NULL},
 	{"Dennis 'EvilDennisR' Ristuccia",	N_("Senior Contributor/QA"),	NULL},
 	{"Peter 'Fmoo' Ruibal",		NULL,	NULL},
-	{"Elliott 'QuLogic' Sales de Andrade",	NULL,	NULL},
 	{"Gabriel 'Nix' Schulhof", 	NULL, 	NULL},
 	{"Jorge 'Masca' Villaseñor", 	NULL, 	NULL},
 	{NULL, NULL, NULL}
@@ -424,11 +425,11 @@
 	for (i = 0; developers[i].name != NULL; i++) {
 		if (developers[i].email != NULL) {
 			g_string_append_printf(str, "  %s (%s) &lt;<a href=\"mailto:%s\">%s</a>&gt;<br/>",
-					developers[i].name, _(developers[i].role),
+					_(developers[i].name), _(developers[i].role),
 					developers[i].email, developers[i].email);
 		} else {
 			g_string_append_printf(str, "  %s (%s)<br/>",
-					developers[i].name, _(developers[i].role));
+					_(developers[i].name), _(developers[i].role));
 		}
 	}
 	g_string_append(str, "<BR/>");
--- a/pidgin/gtkroomlist.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/pidgin/gtkroomlist.c	Fri Aug 01 19:45:08 2008 +0000
@@ -53,7 +53,6 @@
 	PurpleRoomlist *roomlist;
 
 	gboolean pg_needs_pulse;
-	gboolean pg_to_active;
 	guint pg_update_to;
 } PidginRoomlistDialog;
 
@@ -84,32 +83,34 @@
 
 static gint delete_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d)
 {
-	PidginRoomlistDialog *dialog;
-
-	dialog = (PidginRoomlistDialog *) d;
+	PidginRoomlistDialog *dialog = d;
 
 	if (dialog->roomlist && purple_roomlist_get_in_progress(dialog->roomlist))
 		purple_roomlist_cancel_get_list(dialog->roomlist);
 
+	if (dialog->pg_update_to > 0)
+		purple_timeout_remove(dialog->pg_update_to);
+
 	if (dialog->roomlist) {
-		if (dialog->pg_to_active) {
-			purple_timeout_remove(dialog->pg_update_to);
-			dialog->pg_to_active = FALSE;
+		PidginRoomlist *rl = dialog->roomlist->ui_data;
+
+		if (dialog->pg_update_to > 0)
 			/* yes, that's right, unref it twice. */
 			purple_roomlist_unref(dialog->roomlist);
-		}
+
+		if (rl)
+			rl->dialog = NULL;
+		purple_roomlist_unref(dialog->roomlist);
 	}
 
-	/* free stuff here */
-	if (dialog->roomlist)
-		purple_roomlist_unref(dialog->roomlist);
+	dialog->progress = NULL;
 	g_free(dialog);
 
 	return FALSE;
 }
 
 static void dialog_select_account_cb(GObject *w, PurpleAccount *account,
-                                     PidginRoomlistDialog *dialog)
+				     PidginRoomlistDialog *dialog)
 {
 	dialog->account = account;
 }
@@ -186,9 +187,7 @@
 	GValue val;
 	PurpleRoomlistRoom *room;
 	static struct _menu_cb_info *info;
-	PidginRoomlistDialog *dialog;
-
-	dialog = grl->dialog;
+	PidginRoomlistDialog *dialog = grl->dialog;
 
 	if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
 		val.g_type = 0;
@@ -239,9 +238,7 @@
 {
 	PurpleRoomlist *rl = dialog->roomlist;
 	PidginRoomlist *grl = rl->ui_data;
-	struct _menu_cb_info *info;
-
-	info = (struct _menu_cb_info*)g_object_get_data(G_OBJECT(button), "room-info");
+	struct _menu_cb_info *info = g_object_get_data(G_OBJECT(button), "room-info");
 
 	if(info != NULL)
 		do_add_room_cb(grl->tree, info);
@@ -256,9 +253,7 @@
 {
 	PurpleRoomlist *rl = dialog->roomlist;
 	PidginRoomlist *grl = rl->ui_data;
-	struct _menu_cb_info *info;
-
-	info = (struct _menu_cb_info*)g_object_get_data(G_OBJECT(button), "room-info");
+	struct _menu_cb_info *info = g_object_get_data(G_OBJECT(button), "room-info");
 
 	if(info != NULL)
 		do_join_cb(grl->tree, info);
@@ -490,12 +485,13 @@
 
 static gboolean account_filter_func(PurpleAccount *account)
 {
-	PurpleConnection *gc = purple_account_get_connection(account);
+	PurpleConnection *conn = purple_account_get_connection(account);
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	if (conn)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(conn->prpl);
 
-	return (prpl_info->roomlist_get_list != NULL);
+	return (prpl_info && prpl_info->roomlist_get_list != NULL);
 }
 
 gboolean
@@ -518,10 +514,7 @@
 pidgin_roomlist_dialog_new_with_account(PurpleAccount *account)
 {
 	PidginRoomlistDialog *dialog;
-	GtkWidget *window;
-	GtkWidget *vbox;
-	GtkWidget *vbox2;
-	GtkWidget *bbox;
+	GtkWidget *window, *vbox, *vbox2, *bbox;
 
 	dialog = g_new0(PidginRoomlistDialog, 1);
 	dialog->account = account;
@@ -611,9 +604,8 @@
 
 void pidgin_roomlist_dialog_show_with_account(PurpleAccount *account)
 {
-	PidginRoomlistDialog *dialog;
+	PidginRoomlistDialog *dialog = pidgin_roomlist_dialog_new_with_account(account);
 
-	dialog = pidgin_roomlist_dialog_new_with_account(account);
 	if (!dialog)
 		return;
 
@@ -627,9 +619,7 @@
 
 static void pidgin_roomlist_new(PurpleRoomlist *list)
 {
-	PidginRoomlist *rl;
-
-	rl = g_new0(PidginRoomlist, 1);
+	PidginRoomlist *rl = g_new0(PidginRoomlist, 1);
 
 	list->ui_data = rl;
 
@@ -802,7 +792,7 @@
 
 	if (!rl || !rl->dialog || !rl->dialog->pg_needs_pulse) {
 		if (rl && rl->dialog)
-			rl->dialog->pg_to_active = FALSE;
+			rl->dialog->pg_update_to = 0;
 		purple_roomlist_unref(list);
 		return FALSE;
 	}
@@ -827,15 +817,14 @@
 		rl->num_rooms++;
 
 	if (rl->dialog) {
-		if (!rl->dialog->pg_to_active) {
-			rl->dialog->pg_to_active = TRUE;
+		if (rl->dialog->pg_update_to == 0) {
 			purple_roomlist_ref(list);
 			rl->dialog->pg_update_to = g_timeout_add(100, pidgin_progress_bar_pulse, list);
 			gtk_progress_bar_pulse(GTK_PROGRESS_BAR(rl->dialog->progress));
-		} else {
+		} else
 			rl->dialog->pg_needs_pulse = TRUE;
-		}
 	}
+
 	if (room->parent) {
 		parentrr = g_hash_table_lookup(rl->cats, room->parent);
 		path = gtk_tree_row_reference_get_path(parentrr);
@@ -881,14 +870,14 @@
 	}
 }
 
-static void pidgin_roomlist_in_progress(PurpleRoomlist *list, gboolean flag)
+static void pidgin_roomlist_in_progress(PurpleRoomlist *list, gboolean in_progress)
 {
 	PidginRoomlist *rl = list->ui_data;
 
 	if (!rl || !rl->dialog)
 		return;
 
-	if (flag) {
+	if (in_progress) {
 		if (rl->dialog->account_widget)
 			gtk_widget_set_sensitive(rl->dialog->account_widget, FALSE);
 		gtk_widget_set_sensitive(rl->dialog->stop_button, TRUE);
@@ -905,12 +894,10 @@
 
 static void pidgin_roomlist_destroy(PurpleRoomlist *list)
 {
-	PidginRoomlist *rl;
+	PidginRoomlist *rl = list->ui_data;
 
 	roomlists = g_list_remove(roomlists, list);
 
-	rl = list->ui_data;
-
 	g_return_if_fail(rl != NULL);
 
 	g_hash_table_destroy(rl->cats);
--- a/pidgin/plugins/perl/common/Makefile.mingw	Sun Jul 27 13:29:26 2008 +0000
+++ b/pidgin/plugins/perl/common/Makefile.mingw	Fri Aug 01 19:45:08 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	Sun Jul 27 13:29:26 2008 +0000
+++ b/pidgin/win32/nsis/pidgin-installer.nsi	Fri Aug 01 19:45:08 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"
 
@@ -376,7 +376,7 @@
     StrCmp $R0 "2" +2 ; Upgrade isn't optional
     MessageBox MB_YESNO $(GTK_UPGRADE_PROMPT) /SD IDYES IDNO done
     ClearErrors
-    ExecWait '"$TEMP\gtk-runtime.exe" /L=$LANGUAGE /S /D=$GTK_FOLDER'
+    ExecWait '"$TEMP\gtk-runtime.exe" /L=$LANGUAGE $ISSILENT /D=$GTK_FOLDER'
     IfErrors gtk_install_error done
 
     gtk_install_error:
@@ -515,10 +515,6 @@
       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"
@@ -1315,12 +1311,12 @@
   ;Reset ShellVarContext because we may have changed it
   SetShellVarContext "current"
 
-  StrCpy $ISSILENT "/NOUI"
+  StrCpy $ISSILENT "/S"
 
   ; GTK installer has two silent states.. one with Message boxes, one without
   ; If pidgin installer was run silently, we want to supress gtk installer msg boxes.
   IfSilent 0 set_gtk_normal
-      StrCpy $ISSILENT "/S"
+      StrCpy $ISSILENT "/NOUI"
   set_gtk_normal:
 
   ${GetParameters} $R0
--- a/pidgin/win32/winpidgin.c	Sun Jul 27 13:29:26 2008 +0000
+++ b/pidgin/win32/winpidgin.c	Fri Aug 01 19:45:08 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,82 @@
 
 	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_stuff_to_path() {
+	char perl_path[MAX_PATH + 1];
+	char *ppath = NULL;
+	char mit_kerberos_path[MAX_PATH + 1];
+	char *mpath = NULL;
+	DWORD plen;
+
+	printf("%s", "Looking for Perl... ");
+
+	plen = sizeof(perl_path);
+	if (read_reg_string(HKEY_LOCAL_MACHINE, "SOFTWARE\\Perl", "",
+			    (LPBYTE) &perl_path, &plen)) {
+		/* 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");
+
+		ppath = perl_path;
+	} else
+		printf("%s", "not found.\n");
+
+	printf("%s", "Looking for MIT Kerberos... ");
+
+	plen = sizeof(mit_kerberos_path);
+	if (read_reg_string(HKEY_LOCAL_MACHINE, "SOFTWARE\\MIT\\Kerberos", "InstallDir",
+			    (LPBYTE) &mit_kerberos_path, &plen)) {
+		/* We *could* check for gssapi32.dll */
+		printf("found in '%s'.\n", mit_kerberos_path);
+
+		if (mit_kerberos_path[strlen(mit_kerberos_path) - 1] != '\\')
+			strcat(mit_kerberos_path, "\\");
+		strcat(mit_kerberos_path, "bin");
+
+		mpath = mit_kerberos_path;
+	} else
+		printf("%s", "not found.\n");
+
+	if (ppath != NULL || mpath != NULL) {
+		const char *path = getenv("PATH");
+		BOOL add_ppath = ppath != NULL && (path == NULL || !strstr(path, ppath));
+		BOOL add_mpath = mpath != NULL && (path == NULL || !strstr(path, mpath));
+		char *newpath;
+		int newlen;
+
+		if (add_ppath || add_mpath) {
+			/* Enough to add "PATH=" + path + ";"  + ppath + ";" + mpath + \0 */
+			newlen = 6 + (path ? strlen(path) + 1 : 0);
+			if (add_ppath)
+				newlen += strlen(ppath) + 1;
+			if (add_mpath)
+				newlen += strlen(mpath) + 1;
+			newpath = malloc(newlen);
+			*newpath = '\0';
+
+			_snprintf(newpath, newlen, "PATH=%s%s%s%s%s%s",
+				  path ? path : "",
+				  path ? ";" : "",
+				  add_ppath ? ppath : "",
+				  add_ppath ? ";" : "",
+				  add_mpath ? mpath : "",
+				  add_mpath ? ";" : "");
+
+			printf("New PATH: %s\n", newpath);
+
+			_putenv(newpath);
+			free(newpath);
+		}
+	}
 }
 
 #define PIDGIN_WM_FOCUS_REQUEST (WM_APP + 13)
@@ -598,10 +670,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 +703,9 @@
 		dll_prep();
 
 	winpidgin_set_locale();
+
+	winpidgin_add_stuff_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 +720,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;
--- a/po/zh_CN.po	Sun Jul 27 13:29:26 2008 +0000
+++ b/po/zh_CN.po	Fri Aug 01 19:45:08 2008 +0000
@@ -17454,3 +17454,8 @@
 msgid "This plugin is useful for debbuging XMPP servers or clients."
 msgstr "此插件用于调试 XMPP 服务器或客户端。"
 
+#. feel free to not translate this
+#: ../pidgin/gtkdialogs.c:77
+msgid "Ka-Hing Cheung"
+msgstr "张家兴"
+
--- a/po/zh_TW.po	Sun Jul 27 13:29:26 2008 +0000
+++ b/po/zh_TW.po	Fri Aug 01 19:45:08 2008 +0000
@@ -13684,6 +13684,11 @@
 msgid "This plugin is useful for debbuging XMPP servers or clients."
 msgstr "幫助為 XMPP 伺服器或客戶端進行除錯。"
 
+#. feel free to not translate this
+#: ../pidgin/gtkdialogs.c:77
+msgid "Ka-Hing Cheung"
+msgstr "張家興"
+
 #~ msgid "_Resume"
 #~ msgstr "恢復(_R)"