changeset 27826:5f9ca519ea9f

propagate from branch 'im.pidgin.pidgin' (head 90011f8844f95be26206d5698b603f1692f319a0) to branch 'im.pidgin.pidgin.yaz' (head e4862d866bc0b147e783d27c1faa51f1d3e0b58a)
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Thu, 24 Apr 2008 02:28:24 +0000
parents 80c87908ff1d (diff) 86634df8facf (current diff)
children eeee264cd325
files libpurple/protocols/msnp9/switchboard.c pidgin/gtkconv.c
diffstat 26 files changed, 277 insertions(+), 103 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Tue Apr 22 01:04:23 2008 +0000
+++ b/COPYRIGHT	Thu Apr 24 02:28:24 2008 +0000
@@ -360,6 +360,7 @@
 Dossy Shiobara
 Michael Shkutkov
 Shreevatsa R
+Dylan Simon <dylan@dylex.net>
 Ettore Simone
 John Silvestri
 Craig Slusher
--- a/ChangeLog.API	Tue Apr 22 01:04:23 2008 +0000
+++ b/ChangeLog.API	Thu Apr 24 02:28:24 2008 +0000
@@ -1,5 +1,17 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.x.x:
+	perl:
+		Added:
+		* Purple::Prefs::get_children_names.
+		* Purple::timeout_remove.
+		Changed:
+		* Purple::timeout_add now returns a handle which can be used
+		  to remove the timeout.
+		* Callbacks to Purple::Util::fetch_url and the
+		  Purple::Request::* functions can now be specified as both
+		  strings (the name of the callback function) and as coderefs.
+
 version 2.4.0 (02/29/2008):
 	libpurple:
 		Added:
--- a/finch/gntconv.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/finch/gntconv.c	Thu Apr 24 02:28:24 2008 +0000
@@ -682,7 +682,7 @@
 	ggc->active_conv = conv;
 	FINCH_SET_DATA(conv, ggc);
 
-	if (cc && FINCH_GET_DATA(cc)) {
+	if (cc && FINCH_GET_DATA(cc) && cc != conv) {
 		finch_conversation_set_active(conv);
 		return;
 	}
--- a/finch/libgnt/gntentry.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/finch/libgnt/gntentry.c	Thu Apr 24 02:28:24 2008 +0000
@@ -238,8 +238,15 @@
 		destroy_suggest(entry);
 		return FALSE;
 	} else if (count == 1) {
+		char *store = g_strndup(entry->start, entry->end - entry->start);
+		gboolean ret;
+
 		destroy_suggest(entry);
-		return complete_suggest(entry, sgst);
+		complete_suggest(entry, sgst);
+
+		ret = (strncmp(store, entry->start, entry->end - entry->start) != 0);
+		g_free(store);
+		return ret;
 	} else {
 		if (max > 0) {
 			GntWidget *ddown = entry->ddown;
--- a/finch/libgnt/gntmain.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/finch/libgnt/gntmain.c	Thu Apr 24 02:28:24 2008 +0000
@@ -245,8 +245,11 @@
 	}
 
 	rd += HOLDING_ESCAPE;
-	if (HOLDING_ESCAPE)
+	if (HOLDING_ESCAPE) {
 		keys[0] = '\033';
+		g_source_remove(escape_stuff.timer);
+		escape_stuff.timer = 0;
+	}
 	keys[rd] = 0;
 	gnt_wm_set_event_stack(wm, TRUE);
 
@@ -271,12 +274,6 @@
 		int p;
 
 		if (k[0] == '\033' && rd == 1) {
-			if (escape_stuff.timer) {
-				gnt_wm_process_input(wm, "\033\033");
-				g_source_remove(escape_stuff.timer);
-				escape_stuff.timer = 0;
-				break;
-			}
 			escape_stuff.timer = g_timeout_add(250, escape_timeout, NULL);
 			break;
 		}
--- a/libpurple/account.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/account.c	Thu Apr 24 02:28:24 2008 +0000
@@ -1359,8 +1359,12 @@
 		return;
 	}
 
-	if (orig_pass == NULL || new_pass_1 == NULL || new_pass_2 == NULL ||
-		*orig_pass == '\0' || *new_pass_1 == '\0' || *new_pass_2 == '\0')
+	if ((purple_request_fields_is_field_required(fields, "password") &&
+			(orig_pass == NULL || *orig_pass == '\0')) ||
+		(purple_request_fields_is_field_required(fields, "new_password_1") &&
+			(new_pass_1 == NULL || *new_pass_1 == '\0')) ||
+		(purple_request_fields_is_field_required(fields, "new_password_2") &&
+			(new_pass_2 == NULL || *new_pass_2 == '\0')))
 	{
 		purple_notify_error(account, NULL,
 						  _("Fill out all fields completely."), NULL);
@@ -1376,11 +1380,20 @@
 	PurpleRequestFields *fields;
 	PurpleRequestFieldGroup *group;
 	PurpleRequestField *field;
+	PurpleConnection *gc;
+	PurplePlugin *prpl = NULL;
+	PurplePluginProtocolInfo *prpl_info = NULL;
 	char primary[256];
 
 	g_return_if_fail(account != NULL);
 	g_return_if_fail(purple_account_is_connected(account));
 
+	gc = purple_account_get_connection(account);
+	if (gc != NULL)
+		prpl = purple_connection_get_prpl(gc);
+	if (prpl != NULL)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
 	fields = purple_request_fields_new();
 
 	group = purple_request_field_group_new(NULL);
@@ -1389,21 +1402,24 @@
 	field = purple_request_field_string_new("password", _("Original password"),
 										  NULL, FALSE);
 	purple_request_field_string_set_masked(field, TRUE);
-	purple_request_field_set_required(field, TRUE);
+	if (!(prpl_info && (prpl_info->options | OPT_PROTO_PASSWORD_OPTIONAL)))
+		purple_request_field_set_required(field, TRUE);
 	purple_request_field_group_add_field(group, field);
 
 	field = purple_request_field_string_new("new_password_1",
 										  _("New password"),
 										  NULL, FALSE);
 	purple_request_field_string_set_masked(field, TRUE);
-	purple_request_field_set_required(field, TRUE);
+	if (!(prpl_info && (prpl_info->options | OPT_PROTO_PASSWORD_OPTIONAL)))
+		purple_request_field_set_required(field, TRUE);
 	purple_request_field_group_add_field(group, field);
 
 	field = purple_request_field_string_new("new_password_2",
 										  _("New password (again)"),
 										  NULL, FALSE);
 	purple_request_field_string_set_masked(field, TRUE);
-	purple_request_field_set_required(field, TRUE);
+	if (!(prpl_info && (prpl_info->options | OPT_PROTO_PASSWORD_OPTIONAL)))
+		purple_request_field_set_required(field, TRUE);
 	purple_request_field_group_add_field(group, field);
 
 	g_snprintf(primary, sizeof(primary), _("Change password for %s"),
--- a/libpurple/blist.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/blist.c	Thu Apr 24 02:28:24 2008 +0000
@@ -2238,6 +2238,8 @@
 				pce = parts->data;
 				chat_name = g_hash_table_lookup(chat->components,
 												pce->identifier);
+				g_list_foreach(parts, (GFunc)g_free, NULL);
+				g_list_free(parts);
 
 				if (chat->account == account && chat_name != NULL &&
 					name != NULL && !strcmp(chat_name, name)) {
--- a/libpurple/log.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/log.c	Thu Apr 24 02:28:24 2008 +0000
@@ -1758,6 +1758,7 @@
 			lastoff = offset;
 
 			g_snprintf(convostart, length, "%s", temp);
+			memset(&tm, 0, sizeof(tm));
 			sscanf(convostart, "%*s %s %d %d:%d:%d %d",
 			       month, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &tm.tm_year);
 			/* Ugly hack, in case current locale is not English */
--- a/libpurple/plugins/perl/Makefile.am	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/plugins/perl/Makefile.am	Thu Apr 24 02:28:24 2008 +0000
@@ -90,7 +90,7 @@
 common/Makefile: common/Makefile.PL
 	@if test "x${top_srcdir}" != "x${top_builddir}"; then \
 		for f in ${common_sources}; do \
-			${LN_S} -f ../${srcdir}/$$f $$f; \
+			${LN_S} -f ${srcdir}/$$f $$f; \
 		done; \
 	fi
 	@cd common && $(perlpath) Makefile.PL $(PERL_MM_PARAMS)
@@ -148,7 +148,7 @@
 
 	@if test "x${top_srcdir}" != "x${top_builddir}"; then \
 		for f in ${common_sources}; do \
-			${LN_S} -f ../${srcdir}/$$f $$f; \
+			${LN_S} -f ${srcdir}/$$f $$f; \
 		done; \
 	fi
 
--- a/libpurple/plugins/perl/common/Notify.xs	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/plugins/perl/common/Notify.xs	Thu Apr 24 02:28:24 2008 +0000
@@ -172,10 +172,10 @@
 void purple_notify_user_info_remove_last_item(user_info)
 	Purple::NotifyUserInfo user_info
 
-gchar *
+const gchar *
 purple_notify_user_info_entry_get_label(user_info_entry)
 	Purple::NotifyUserInfoEntry user_info_entry
 
-gchar *
+const gchar *
 purple_notify_user_info_entry_get_value(user_info_entry)
 	Purple::NotifyUserInfoEntry user_info_entry
--- a/libpurple/plugins/perl/common/Purple.xs	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/plugins/perl/common/Purple.xs	Thu Apr 24 02:28:24 2008 +0000
@@ -74,14 +74,24 @@
 	PURPLE_PERL_BOOT(Util);
 	PURPLE_PERL_BOOT(XMLNode);
 
-void
+guint
 timeout_add(plugin, seconds, callback, data = 0)
 	Purple::Plugin plugin
 	int seconds
 	SV *callback
 	SV *data
 CODE:
-	purple_perl_timeout_add(plugin, seconds, callback, data);
+	RETVAL = purple_perl_timeout_add(plugin, seconds, callback, data);
+OUTPUT:
+	RETVAL
+
+gboolean
+timeout_remove(handle)
+	guint handle
+CODE:
+	RETVAL = purple_perl_timeout_remove(handle);
+OUTPUT:
+	RETVAL
 
 void
 deinit()
--- a/libpurple/plugins/perl/common/Request.xs	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/plugins/perl/common/Request.xs	Thu Apr 24 02:28:24 2008 +0000
@@ -15,10 +15,20 @@
 
 
 typedef struct {
-	char *cancel_cb;
-	char *ok_cb;
+	SV *ok_fun;
+	SV *cancel_fun;
 } PurplePerlRequestData;
 
+static void
+purple_perl_request_data_free(PurplePerlRequestData *ppr)
+{
+	if (ppr->ok_fun)
+		SvREFCNT_dec(ppr->ok_fun);
+	if (ppr->cancel_fun)
+		SvREFCNT_dec(ppr->cancel_fun);
+	g_free(ppr);
+}
+
 /********************************************************/
 /*                                                      */
 /* Callback function that calls a perl subroutine       */
@@ -39,23 +49,19 @@
 
 	XPUSHs(purple_perl_bless_object(fields, "Purple::Request::Fields"));
 	PUTBACK;
-
-	call_pv(gpr->ok_cb, G_EVAL | G_SCALAR);
+	call_sv(gpr->ok_fun, G_EVAL | G_SCALAR);
 	SPAGAIN;
 
 	PUTBACK;
 	FREETMPS;
 	LEAVE;
 
-	g_free(gpr->ok_cb);
-	g_free(gpr->cancel_cb);
-	g_free(gpr);
+	purple_perl_request_data_free(gpr);
 }
 
 static void
 purple_perl_request_cancel_cb(void * data, PurpleRequestFields *fields)
 {
-
 	PurplePerlRequestData *gpr = (PurplePerlRequestData *)data;
 
 	dSP;
@@ -65,16 +71,14 @@
 
 	XPUSHs(purple_perl_bless_object(fields, "Purple::Request::Fields"));
 	PUTBACK;
-	call_pv(gpr->cancel_cb, G_EVAL | G_SCALAR);
+	call_sv(gpr->cancel_fun, G_EVAL | G_SCALAR);
 	SPAGAIN;
 
 	PUTBACK;
 	FREETMPS;
 	LEAVE;
 
-	g_free(gpr->ok_cb);
-	g_free(gpr->cancel_cb);
-	g_free(gpr);
+	purple_perl_request_data_free(gpr);
 }
 
 MODULE = Purple::Request  PACKAGE = Purple::Request  PREFIX = purple_request_
@@ -131,14 +135,13 @@
 	SV * cancel_cb
 CODE:
 	PurplePerlRequestData *gpr;
-	STRLEN len;
 	char *basename;
 
 	basename = g_path_get_basename(handle->path);
 	purple_perl_normalize_script_name(basename);
 	gpr = g_new(PurplePerlRequestData, 1);
-	gpr->ok_cb = g_strdup_printf("Purple::Script::%s::%s", basename, SvPV(ok_cb, len));
-	gpr->cancel_cb = g_strdup_printf("Purple::Script::%s::%s", basename, SvPV(cancel_cb, len));
+	gpr->ok_fun = purple_perl_sv_from_fun(handle, ok_cb);
+	gpr->cancel_fun = purple_perl_sv_from_fun(handle, cancel_cb);
 	g_free(basename);
 
 	RETVAL = purple_request_input(handle, title, primary, secondary, default_value, multiline, masked, hint, ok_text, G_CALLBACK(purple_perl_request_ok_cb), cancel_text, G_CALLBACK(purple_perl_request_cancel_cb), NULL, NULL, NULL, gpr);
@@ -155,14 +158,13 @@
 	SV * cancel_cb
 CODE:
 	PurplePerlRequestData *gpr;
-	STRLEN len;
 	char *basename;
 
 	basename = g_path_get_basename(handle->path);
 	purple_perl_normalize_script_name(basename);
 	gpr = g_new(PurplePerlRequestData, 1);
-	gpr->ok_cb = g_strdup_printf("Purple::Script::%s::%s", basename, SvPV(ok_cb, len));
-	gpr->cancel_cb = g_strdup_printf("Purple::Script::%s::%s", basename, SvPV(cancel_cb, len));
+	gpr->ok_fun = purple_perl_sv_from_fun(handle, ok_cb);
+	gpr->cancel_fun = purple_perl_sv_from_fun(handle, cancel_cb);
 	g_free(basename);
 
 	RETVAL = purple_request_file(handle, title, filename, savedialog, G_CALLBACK(purple_perl_request_ok_cb), G_CALLBACK(purple_perl_request_cancel_cb), NULL, NULL, NULL, gpr);
@@ -182,14 +184,13 @@
 	SV * cancel_cb
 CODE:
 	PurplePerlRequestData *gpr;
-	STRLEN len;
 	char *basename;
 
 	basename = g_path_get_basename(handle->path);
 	purple_perl_normalize_script_name(basename);
 	gpr = g_new(PurplePerlRequestData, 1);
-	gpr->ok_cb = g_strdup_printf("Purple::Script::%s::%s", basename, SvPV(ok_cb, len));
-	gpr->cancel_cb = g_strdup_printf("Purple::Script::%s::%s", basename, SvPV(cancel_cb, len));
+	gpr->ok_fun = purple_perl_sv_from_fun(handle, ok_cb);
+	gpr->cancel_fun = purple_perl_sv_from_fun(handle, cancel_cb);
 	g_free(basename);
 
 	RETVAL = purple_request_fields(handle, title, primary, secondary, fields, ok_text, G_CALLBACK(purple_perl_request_ok_cb), cancel_text, G_CALLBACK(purple_perl_request_cancel_cb), NULL, NULL, NULL, gpr);
--- a/libpurple/plugins/perl/common/Util.xs	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/plugins/perl/common/Util.xs	Thu Apr 24 02:28:24 2008 +0000
@@ -257,29 +257,13 @@
 	gboolean http11
 	SV * cb
 CODE:
-	SV *sv = NULL;
-
-
-	if (SvTYPE(cb) == SVt_RV) {
-		SV *cbsv = SvRV(cb);
-
-		if (SvTYPE(cbsv) == SVt_PVCV) {
-			sv = newSVsv(cb);
-		} else {
-			purple_debug_warning("perl", "Callback not a valid coderef in purple_util_fetch_url.\n");
-		}
-	} else if (SvTYPE(cb) == SVt_PV) {
-		PurplePerlScript *gps;
-
-		gps = (PurplePerlScript *)PURPLE_PLUGIN_LOADER_INFO(plugin);
-		sv = newSVpvf("%s::%s", gps->package, SvPV_nolen(cb));
-	} else {
-		purple_debug_warning("perl", "Callback not a valid type, only strings and coderefs allowed in purple_util_fetch_url.\n");
-	}
+	SV *sv = purple_perl_sv_from_fun(plugin, cb);
 
 	if (sv != NULL) {
 		purple_util_fetch_url(url, full, user_agent, http11,
 		                      purple_perl_util_url_cb, sv);
+	} else {
+		purple_debug_warning("perl", "Callback not a valid type, only strings and coderefs allowed in purple_util_fetch_url.\n");
 	}
 
 void
--- a/libpurple/plugins/perl/perl-common.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/plugins/perl/perl-common.c	Thu Apr 24 02:28:24 2008 +0000
@@ -616,3 +616,26 @@
 
 	return NULL;
 }
+
+SV *purple_perl_sv_from_fun(PurplePlugin *plugin, SV *callback)
+{
+	SV *sv = NULL;
+
+	if (SvTYPE(callback) == SVt_RV) {
+		SV *cbsv = SvRV(callback);
+
+		if (SvTYPE(cbsv) == SVt_PVCV) {
+			sv = newSVsv(callback);
+		}
+	} else if (SvTYPE(callback) == SVt_PV) {
+		PurplePerlScript *gps;
+
+		gps = (PurplePerlScript *)PURPLE_PLUGIN_LOADER_INFO(plugin);
+		sv = newSVpvf("%s::%s", gps->package, SvPV_nolen(callback));
+	} else {
+		purple_debug_warning("perl", "Callback not a valid type, only strings and coderefs allowed.\n");
+	}
+
+	return sv;
+}
+
--- a/libpurple/plugins/perl/perl-common.h	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/plugins/perl/perl-common.h	Thu Apr 24 02:28:24 2008 +0000
@@ -67,5 +67,5 @@
 void *purple_perl_data_from_sv(PurpleValue *value, SV *sv);
 SV *purple_perl_sv_from_vargs(const PurpleValue *value, va_list *args,
                             void ***copy_arg);
-
+SV *purple_perl_sv_from_fun(PurplePlugin *plugin, SV *callback);
 #endif /* _PURPLE_PERL_COMMON_H_ */
--- a/libpurple/plugins/perl/perl-handlers.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/plugins/perl/perl-handlers.c	Thu Apr 24 02:28:24 2008 +0000
@@ -207,13 +207,15 @@
 	return ret_frame;
 }
 
-static void
+static gboolean
 destroy_timeout_handler(PurplePerlTimeoutHandler *handler)
 {
+	gboolean ret = FALSE;
+
 	timeout_handlers = g_list_remove(timeout_handlers, handler);
 
 	if (handler->iotag > 0)
-		purple_timeout_remove(handler->iotag);
+		ret = purple_timeout_remove(handler->iotag);
 
 	if (handler->callback != NULL)
 		SvREFCNT_dec(handler->callback);
@@ -222,6 +224,8 @@
 		SvREFCNT_dec(handler->data);
 
 	g_free(handler);
+
+	return ret;
 }
 
 static void
@@ -301,8 +305,8 @@
 
 	for (i = 0; i < value_count; i++) {
 		sv_args[i] = purple_perl_sv_from_vargs(values[i],
-		                                     (va_list*)&args,
-		                                     &copy_args[i]);
+		                                       (va_list*)&args,
+		                                       &copy_args[i]);
 
 		XPUSHs(sv_args[i]);
 	}
@@ -422,14 +426,14 @@
 	return NULL;
 }
 
-void
+guint
 purple_perl_timeout_add(PurplePlugin *plugin, int seconds, SV *callback, SV *data)
 {
 	PurplePerlTimeoutHandler *handler;
 
 	if (plugin == NULL) {
 		croak("Invalid handle in adding perl timeout handler.\n");
-		return;
+		return 0;
 	}
 
 	handler = g_new0(PurplePerlTimeoutHandler, 1);
@@ -443,15 +447,39 @@
 	timeout_handlers = g_list_append(timeout_handlers, handler);
 
 	handler->iotag = purple_timeout_add(seconds * 1000, perl_timeout_cb, handler);
+
+	return handler->iotag;
+}
+
+gboolean
+purple_perl_timeout_remove(guint handle)
+{
+	GList *l, *l_next;
+
+	for (l = timeout_handlers; l != NULL; l = l_next) {
+		PurplePerlTimeoutHandler *handler;
+
+		l_next = l->next;
+
+		handler = (PurplePerlTimeoutHandler *)l->data;
+
+		if (handler->iotag == handle)
+			return destroy_timeout_handler(handler);
+	}
+
+	purple_debug_info("perl", "No timeout handler found with handle %u.\n",
+	                  handle);
+	return FALSE;
 }
 
 void
 purple_perl_timeout_clear_for_plugin(PurplePlugin *plugin)
 {
-	PurplePerlTimeoutHandler *handler;
 	GList *l, *l_next;
 
 	for (l = timeout_handlers; l != NULL; l = l_next) {
+		PurplePerlTimeoutHandler *handler;
+
 		l_next = l->next;
 
 		handler = (PurplePerlTimeoutHandler *)l->data;
--- a/libpurple/plugins/perl/perl-handlers.h	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/plugins/perl/perl-handlers.h	Thu Apr 24 02:28:24 2008 +0000
@@ -48,8 +48,9 @@
 GtkWidget *purple_perl_gtk_get_plugin_frame(PurplePlugin *plugin);
 #endif
 
-void purple_perl_timeout_add(PurplePlugin *plugin, int seconds, SV *callback,
-                           SV *data);
+guint purple_perl_timeout_add(PurplePlugin *plugin, int seconds, SV *callback,
+                              SV *data);
+gboolean purple_perl_timeout_remove(guint handle);
 void purple_perl_timeout_clear_for_plugin(PurplePlugin *plugin);
 void purple_perl_timeout_clear(void);
 
--- a/libpurple/protocols/msnp9/nexus.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/protocols/msnp9/nexus.c	Thu Apr 24 02:28:24 2008 +0000
@@ -337,7 +337,8 @@
 	username =
 		g_strdup(purple_url_encode(purple_account_get_username(session->account)));
 
-	password = g_strndup(purple_connection_get_password(session->account->gc), 16);
+	password = g_utf8_strncpy(g_strdup(purple_connection_get_password(session->account->gc)),
+							  purple_connection_get_password(session->account->gc), 16);
 	encpass = g_strdup(purple_url_encode(password));
 	g_free(password);
 
--- a/libpurple/protocols/msnp9/slplink.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/protocols/msnp9/slplink.c	Thu Apr 24 02:28:24 2008 +0000
@@ -118,6 +118,8 @@
 	while (slplink->slp_calls != NULL)
 		msn_slp_call_destroy(slplink->slp_calls->data);
 
+	g_queue_free(slplink->slp_msg_queue);
+
 	session->slplinks =
 		g_list_remove(session->slplinks, slplink);
 
--- a/libpurple/protocols/msnp9/switchboard.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/protocols/msnp9/switchboard.c	Thu Apr 24 02:28:24 2008 +0000
@@ -111,6 +111,9 @@
 	for (l = swboard->users; l != NULL; l = l->next)
 		g_free(l->data);
 
+	if (swboard->users != NULL)
+		g_list_free(swboard->users);
+
 	session = swboard->session;
 	session->switches = g_list_remove(session->switches, swboard);
 
--- a/libpurple/protocols/silc/silc.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/protocols/silc/silc.c	Thu Apr 24 02:28:24 2008 +0000
@@ -380,14 +380,6 @@
 
 	client = sg->client;
 
-	/* Progress */
-	if (params.detach_data) {
-		purple_connection_update_progress(gc, _("Resuming session"), 2, 5);
-		sg->resuming = TRUE;
-	} else {
-		purple_connection_update_progress(gc, _("Performing key exchange"), 2, 5);
-	}
-
 	/* Get session detachment data, if available */
 	memset(&params, 0, sizeof(params));
 	dfile = silcpurple_session_file(purple_account_get_username(sg->account));
@@ -397,6 +389,14 @@
 	params.ignore_requested_attributes = FALSE;
 	params.pfs = purple_account_get_bool(sg->account, "pfs", FALSE);
 
+	/* Progress */
+	if (params.detach_data) {
+		purple_connection_update_progress(gc, _("Resuming session"), 2, 5);
+		sg->resuming = TRUE;
+	} else {
+		purple_connection_update_progress(gc, _("Performing key exchange"), 2, 5);
+	}
+
 	/* Perform SILC Key Exchange. */
 	silc_client_key_exchange(sg->client, &params, sg->public_key,
 				 sg->private_key, stream, SILC_CONN_SERVER,
@@ -433,6 +433,83 @@
 				      silcpurple_stream_created, gc);
 }
 
+static void silcpurple_continue_running(SilcPurple sg)
+{
+	PurpleConnection *gc = sg->gc;
+	PurpleAccount *account = purple_connection_get_account(gc);
+
+	/* Connect to the SILC server */
+	if (purple_proxy_connect(gc, account,
+				 purple_account_get_string(account, "server",
+							   "silc.silcnet.org"),
+				 purple_account_get_int(account, "port", 706),
+				 silcpurple_login_connected, gc) == NULL)
+	{
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+		                             _("Unable to create connection"));
+		gc->proto_data = NULL;
+		silc_free(sg);
+		return;
+	}
+}
+
+static void silcpurple_got_password_cb(PurpleConnection *gc, PurpleRequestFields *fields)
+{
+	SilcPurple sg = (SilcPurple)gc->proto_data;
+	PurpleAccount *account = purple_connection_get_account(gc);
+	char pkd[256], prd[256];
+	const char *password;
+	gboolean remember;
+
+	/* The password prompt dialog doesn't get disposed if the account disconnects */
+	if (!PURPLE_CONNECTION_IS_VALID(gc))
+		return;
+
+	password = purple_request_fields_get_string(fields, "password");
+	remember = purple_request_fields_get_bool(fields, "remember");
+
+	if (!password || !*password)
+	{
+		purple_notify_error(gc, NULL, _("Password is required to sign on."), NULL);
+		gc->proto_data = NULL;
+		silc_free(sg);
+		return;
+	}
+
+	if (remember)
+		purple_account_set_remember_password(account, TRUE);
+
+	purple_account_set_password(account, password);
+
+	/* Load SILC key pair */
+	g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir());
+	g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir());
+	if (!silc_load_key_pair((char *)purple_account_get_string(account, "public-key", pkd),
+				(char *)purple_account_get_string(account, "private-key", prd),
+				password,
+				&sg->public_key, &sg->private_key)) {
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
+		                             _("Could not load SILC key pair"));
+		gc->proto_data = NULL;
+		silc_free(sg);
+		return;
+	}
+	silcpurple_continue_running(sg);
+}
+
+static void silcpurple_no_password_cb(PurpleConnection *gc, PurpleRequestFields *fields)
+{
+	SilcPurple sg;
+	/* The password prompt dialog doesn't get disposed if the account disconnects */
+	if (!PURPLE_CONNECTION_IS_VALID(gc))
+		return;
+	sg = gc->proto_data;
+	purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
+			_("Could not load SILC key pair"));
+	gc->proto_data = NULL;
+	silc_free(sg);
+}
+
 static void silcpurple_running(SilcClient client, void *context)
 {
 	SilcPurple sg = context;
@@ -451,26 +528,18 @@
 				(char *)purple_account_get_string(account, "private-key", prd),
 				(gc->password == NULL) ? "" : gc->password,
 				&sg->public_key, &sg->private_key)) {
+		if (!purple_account_get_password(account)) {
+			purple_account_request_password(account, G_CALLBACK(silcpurple_got_password_cb),
+											G_CALLBACK(silcpurple_no_password_cb), gc);
+			return;
+		}
 		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
 		                             _("Could not load SILC key pair"));
 		gc->proto_data = NULL;
 		silc_free(sg);
 		return;
 	}
-
-	/* Connect to the SILC server */
-	if (purple_proxy_connect(gc, account,
-				 purple_account_get_string(account, "server",
-							   "silc.silcnet.org"),
-				 purple_account_get_int(account, "port", 706),
-				 silcpurple_login_connected, gc) == NULL)
-	{
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-		                             _("Unable to create connection"));
-		gc->proto_data = NULL;
-		silc_free(sg);
-		return;
-	}
+	silcpurple_continue_running(sg);
 }
 
 static void
@@ -550,8 +619,12 @@
 		                             _("Cannot initialize SILC protocol"));
 		gc->proto_data = NULL;
 		silc_free(sg);
+		free(hostname);
+		free(username);
 		return;
 	}
+	free(hostname);
+	free(username);
 
 	/* Check the ~/.silc dir and create it, and new key pair if necessary. */
 	if (!silcpurple_check_silc_dir(gc)) {
@@ -1188,11 +1261,11 @@
 static void
 silcpurple_change_passwd(PurpleConnection *gc, const char *old, const char *new)
 {
-        char prd[256];
+	char prd[256];
 	g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.pub", silcpurple_silcdir());
 	silc_change_private_key_passphrase(purple_account_get_string(gc->account,
 								     "private-key",
-								     prd), old, new);
+								     prd), old ? old : "", new ? new : "");
 }
 
 static void
--- a/libpurple/protocols/silc10/silc.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/libpurple/protocols/silc10/silc.c	Thu Apr 24 02:28:24 2008 +0000
@@ -962,11 +962,11 @@
 static void
 silcpurple_change_passwd(PurpleConnection *gc, const char *old, const char *new)
 {
-        char prd[256];
+	char prd[256];
 	g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.pub", silcpurple_silcdir());
 	silc_change_private_key_passphrase(purple_account_get_string(gc->account,
 								   "private-key",
-								   prd), old, new);
+								   prd), old ? old : "", new ? new : "");
 }
 
 static void
--- a/pidgin/gtkblist.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/pidgin/gtkblist.c	Thu Apr 24 02:28:24 2008 +0000
@@ -695,6 +695,7 @@
 	{
 		purple_blist_node_set_bool(node, "show_offline",
 		                           !purple_blist_node_get_bool(node, "show_offline"));
+		pidgin_blist_update(purple_get_blist(), node);
 	}
 	else if (PURPLE_BLIST_NODE_IS_CONTACT(node))
 	{
@@ -704,6 +705,7 @@
 		purple_blist_node_set_bool(node, "show_offline", setting);
 		for (bnode = node->child; bnode != NULL; bnode = bnode->next) {
 			purple_blist_node_set_bool(bnode, "show_offline", setting);
+			pidgin_blist_update(purple_get_blist(), bnode);
 		}
 	} else if (PURPLE_BLIST_NODE_IS_GROUP(node)) {
 		PurpleBlistNode *cnode, *bnode;
@@ -714,10 +716,10 @@
 			purple_blist_node_set_bool(cnode, "show_offline", setting);
 			for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) {
 				purple_blist_node_set_bool(bnode, "show_offline", setting);
+				pidgin_blist_update(purple_get_blist(), bnode);
 			}
 		}
 	}
-	pidgin_blist_update(purple_get_blist(), node);
 }
 
 static void gtk_blist_show_systemlog_cb(void)
--- a/pidgin/gtkconv.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/pidgin/gtkconv.c	Thu Apr 24 02:28:24 2008 +0000
@@ -4723,6 +4723,7 @@
 	gtkconv->infopane_model = gtk_list_store_new(CONV_NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF);
 	gtk_cell_view_set_model(GTK_CELL_VIEW(gtkconv->infopane), 
 				GTK_TREE_MODEL(gtkconv->infopane_model));
+	g_object_unref(gtkconv->infopane_model);
 	gtk_list_store_append(gtkconv->infopane_model, &(gtkconv->infopane_iter));
 	gtk_box_pack_start(GTK_BOX(gtkconv->infopane_hbox), gtkconv->infopane, TRUE, TRUE, 0);
 	path = gtk_tree_path_new_from_string("0");
--- a/pidgin/gtkmenutray.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/pidgin/gtkmenutray.c	Thu Apr 24 02:28:24 2008 +0000
@@ -134,8 +134,6 @@
 	if(!GTK_IS_WIDGET(menu_tray->tray))
 		menu_tray->tray = gtk_hbox_new(FALSE, 0);
 
-	menu_tray->tooltips = gtk_tooltips_new();
-
 #if GTK_CHECK_VERSION(2,2,0)
 	settings =
 		gtk_settings_get_for_screen(gtk_widget_get_screen(widget));
@@ -235,7 +233,7 @@
 pidgin_menu_tray_set_tooltip(PidginMenuTray *menu_tray, GtkWidget *widget, const char *tooltip)
 {
 	if (!menu_tray->tooltips)
-		return;
+		menu_tray->tooltips = gtk_tooltips_new();
 
 	/* Should we check whether widget is a child of menu_tray? */
 
--- a/pidgin/gtkstatusbox.c	Tue Apr 22 01:04:23 2008 +0000
+++ b/pidgin/gtkstatusbox.c	Thu Apr 24 02:28:24 2008 +0000
@@ -74,6 +74,7 @@
 static void remove_typing_cb(PidginStatusBox *box);
 static void update_size (PidginStatusBox *box);
 static gint get_statusbox_index(PidginStatusBox *box, PurpleSavedStatus *saved_status);
+static PurpleAccount* check_active_accounts_for_identical_statuses(void);
 
 static void pidgin_status_box_pulse_typing(PidginStatusBox *status_box);
 static void pidgin_status_box_refresh(PidginStatusBox *status_box);
@@ -497,6 +498,10 @@
 		break;
 	case PROP_ACCOUNT:
 		statusbox->account = g_value_get_pointer(value);
+		if (statusbox->account)
+			statusbox->token_status_account = NULL;
+		else
+			statusbox->token_status_account = check_active_accounts_for_identical_statuses();
 
 		pidgin_status_box_regenerate(statusbox);
 
@@ -628,7 +633,7 @@
 	GdkPixbuf *pixbuf, *emblem = NULL;
 	GtkTreePath *path;
 	gboolean account_status = FALSE;
-	PurpleAccount *acct = (status_box->token_status_account) ? status_box->token_status_account : status_box->account;
+	PurpleAccount *acct = (status_box->account) ? status_box->account : status_box->token_status_account;
 
 	icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL);
 
@@ -1228,9 +1233,13 @@
 								     icon_size, "PidginStatusBox");
 }
 
-static void account_enabled_cb(PurpleAccount *acct, PidginStatusBox *status_box) {
+static void account_enabled_cb(PurpleAccount *acct, PidginStatusBox *status_box)
+{
 	PurpleAccount *initial_token_acct = status_box->token_status_account;
 
+	if (status_box->account)
+		return;
+
 	status_box->token_status_account = check_active_accounts_for_identical_statuses();
 
 	/* Regenerate the list if it has changed */
@@ -1714,6 +1723,8 @@
 	gtk_cell_view_set_model(GTK_CELL_VIEW(status_box->cell_view), GTK_TREE_MODEL(status_box->store));
 	gtk_list_store_append(status_box->store, &(status_box->iter));
 
+	atk_object_set_name(gtk_widget_get_accessible(status_box->toggle_button), _("Status Selector"));
+
 	gtk_container_add(GTK_CONTAINER(status_box->toggle_button), status_box->hbox);
 	gtk_box_pack_start(GTK_BOX(status_box->hbox), status_box->cell_view, TRUE, TRUE, 0);
 	gtk_box_pack_start(GTK_BOX(status_box->hbox), status_box->vsep, FALSE, FALSE, 0);