changeset 25370:b3015da48886

merge of 'a2f94e06ea53c95077731e0833699222e6050fd0' and 'b20c44775e2aa1c5bc5e36f7f94adafc5c67b3fd'
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Sun, 25 Jan 2009 20:51:41 +0000
parents 859e5b3f5c47 (current diff) 681e58ea3a9b (diff)
children a8db457c421a b7d40ccd9997
files
diffstat 23 files changed, 220 insertions(+), 127 deletions(-) [+]
line wrap: on
line diff
--- a/AUTHORS	Sun Jan 25 09:13:28 2009 +0000
+++ b/AUTHORS	Sun Jan 25 20:51:41 2009 +0000
@@ -36,7 +36,6 @@
 Crazy Patch Writers:
 -------------------
 Paul Aurich
-Felipe 'shx' Contreras
 Marcus 'malu' Lundblad
 Dennis 'EvilDennisR' Ristuccia
 Peter 'Fmoo' Ruibal
@@ -57,6 +56,7 @@
 
 Retired Crazy Patch Writers:
 ---------------------------
+Felipe 'shx' Contreras
 Decklin Foster
 Peter 'Bleeter' Lawler
 Robert 'Robot101' McQueen
--- a/COPYRIGHT	Sun Jan 25 09:13:28 2009 +0000
+++ b/COPYRIGHT	Sun Jan 25 20:51:41 2009 +0000
@@ -63,6 +63,7 @@
 Damien Carbery
 Michael Carlson
 Keegan Carruthers-Smith
+Ludovico Cavedon
 Steve Cavilia
 Julien Cegarra
 Cerulean Studios, LLC
@@ -210,6 +211,7 @@
 Jaromír Karmazín
 John Kelm
 Jochen Kemnade
+Yann Kerherve
 Akuke Kok
 Kir Kolyshkin
 Konstantin Korikov
@@ -229,6 +231,7 @@
 Steve Láposi
 Daniel Larsson
 Peter Lawler
+Vadim Lebedev
 Ho-seok Lee
 Jean-Yves Lefort
 Moses Lei
@@ -477,6 +480,7 @@
 Dan Winship
 Michal Witkowski
 Scott Wolchok
+Rogier Wolff
 The Written Word, Inc.
 Kevin Wu Won
 Pui Lam Wong
--- a/ChangeLog.API	Sun Jan 25 09:13:28 2009 +0000
+++ b/ChangeLog.API	Sun Jan 25 20:51:41 2009 +0000
@@ -1,5 +1,12 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.5.5 (??/??/2009):
+	libpurple:
+		Changed:
+		* purple_status_type_new now defaults "saveable" to TRUE.
+		  This was necessary in order to maintain the current behavior
+		  while fixing non-saveable statuses not to be saved.
+
 version 2.5.4 (01/12/2009):
 	perl:
 		Changed:
--- a/doc/finch.1.in	Sun Jan 25 09:13:28 2009 +0000
+++ b/doc/finch.1.in	Sun Jan 25 20:51:41 2009 +0000
@@ -543,23 +543,26 @@
 \fIhttp://developer.pidgin.im/query?status=new&status=assigned&status=reopened&component=finch+%28gnt%2Fncurses%29&order=priority\fR
 
 Before sending a bug report, please verify that you have the latest
-version of \fBfinch\fR and \fBlibpurple\fR.  Many bugs (major and minor) are
+version of \fBfinch\fR and libpurple.  Many bugs (major and minor) are
 fixed at each release, and if yours is out of date, the problem may already have
 been solved.
 
-
 .SH PATCHES
 If you fix a bug in \fBfinch\fR (or otherwise enhance it), please submit a
-patch (using \fImtn diff > my.diff\fR against the latest version from the
-Monotone repository) at
-.br
-\fIhttp://developer.pidgin.im/newticket\fR
+patch (using \fBmtn diff > my.diff\fR against the latest version from the
+Monotone repository) at \fIhttp://developer.pidgin.im/simpleticket\fR
 
-You are also encouraged to drop by at \fB#pidgin\fR on \fIirc.freenode.net\fR to
-discuss development.
+You are also encouraged to drop by at \fB#pidgin\fR on \fIirc.freenode.net\fR
+to discuss development.
 
 .SH SEE ALSO
 \fIhttp://pidgin.im/\fR
+.br
+\fIhttp://developer.pidgin.im/\fR
+.br
+\fBpurple-remote\fR(1)
+.br
+\fBpidgin\fR(1)
 
 .SH LICENSE
 This program is free software; you can redistribute it and/or modify
--- a/doc/pidgin.1.in	Sun Jan 25 09:13:28 2009 +0000
+++ b/doc/pidgin.1.in	Sun Jan 25 20:51:41 2009 +0000
@@ -34,6 +34,9 @@
 many common features found in other clients, as well as many unique features.
 Pidgin is not endorsed by or affiliated with America Online, ICQ, Microsoft, or
 Yahoo.
+.PP
+Pidgin can be extended by plugins written in multiple programming languages and
+controlled through DBus or \fBpurple-remote\fR.
 
 .SH OPTIONS
 The following options are provided by Pidgin using the standard GNU
@@ -556,20 +559,28 @@
 .SH BUGS
 The bug tracker can be reached by visiting \fIhttp://developer.pidgin.im/query\fR
 
-.SH PATCHES
-If you fix a bug in Pidgin (or otherwise enhance it), please submit a
-patch (using \fImtn diff > my.diff\fR against the latest version from the
-Monotone repository) at \fIhttp://developer.pidgin.im/simpleticket\fR
-
 Before sending a bug report, please verify that you have the latest
 version of Pidgin.  Many bugs (major and minor) are fixed
 at each release, and if yours is out of date, the problem may already
 have been solved.
 
+.SH PATCHES
+If you fix a bug in Pidgin (or otherwise enhance it), please submit a
+patch (using \fBmtn diff > my.diff\fR against the latest version from the
+Monotone repository) at \fIhttp://developer.pidgin.im/simpleticket\fR
+
+You are also encouraged to drop by at \fB#pidgin\fR on \fIirc.freenode.net\fR
+to discuss development.
+
+
 .SH SEE ALSO
 \fIhttp://pidgin.im/\fR
 .br
 \fIhttp://developer.pidgin.im/\fR
+.br
+\fBpurple-remote\fR(1)
+.br
+\fBfinch\fR(1)
 
 .SH LICENSE
 This program is free software; you can redistribute it and/or modify
@@ -643,8 +654,6 @@
 .br
   Paul Aurich
 .br
-  Felipe 'shx' Contreras
-.br
   Marcus 'malu' Lundblad
 .br
   Dennis 'EvilDennisR' Ristuccia
@@ -687,6 +696,8 @@
 
 Our retired crazy patch writers include:
 .br
+  Felipe 'shx' Contreras
+.br
   Decklin Foster
 .br
   Peter 'Bleeter' Lawler
--- a/libpurple/account.c	Sun Jan 25 09:13:28 2009 +0000
+++ b/libpurple/account.c	Sun Jan 25 20:51:41 2009 +0000
@@ -257,15 +257,20 @@
 statuses_to_xmlnode(const PurplePresence *presence)
 {
 	xmlnode *node, *child;
-	GList *statuses, *status;
+	GList *statuses;
+	PurpleStatus *status;
 
 	node = xmlnode_new("statuses");
 
 	statuses = purple_presence_get_statuses(presence);
-	for (status = statuses; status != NULL; status = status->next)
+	for (; statuses != NULL; statuses = statuses->next)
 	{
-		child = status_to_xmlnode((PurpleStatus *)status->data);
-		xmlnode_insert_child(node, child);
+		status = statuses->data;
+		if (purple_status_type_is_saveable(purple_status_get_type(status)))
+		{
+			child = status_to_xmlnode(status);
+			xmlnode_insert_child(node, child);
+		}
 	}
 
 	return node;
--- a/libpurple/connection.c	Sun Jan 25 09:13:28 2009 +0000
+++ b/libpurple/connection.c	Sun Jan 25 20:51:41 2009 +0000
@@ -545,7 +545,7 @@
 	}
 
 	if (description == NULL) {
-		purple_debug_error("connection", "purple_connection_error_reason: check `description != NULL' failed\n");
+		purple_debug_error("connection", "purple_connection_error_reason called with NULL description\n");
 		description = _("Unknown error");
 	}
 
--- a/libpurple/core.c	Sun Jan 25 09:13:28 2009 +0000
+++ b/libpurple/core.c	Sun Jan 25 20:51:41 2009 +0000
@@ -137,7 +137,7 @@
 	 * subsystem right away too.
 	 */
 	purple_plugins_init();
-	
+
 	/* Initialize all static protocols. */
 	static_proto_init();
 
@@ -198,10 +198,22 @@
 	/* Transmission ends */
 	purple_connections_disconnect_all();
 
+	/* The SSL plugins must be uninit before they're unloaded */
+	purple_ssl_uninit();
+
+	/* Unload all plugins before the UI because UI plugins might call
+	 * UI-specific functions */
+	purple_debug_info("main", "Unloading all plugins\n");
+	purple_plugins_destroy_all();
+
+	/* Shut down the UI before all the subsystems */
+	ops = purple_core_get_ui_ops();
+	if (ops != NULL && ops->quit != NULL)
+		ops->quit();
+
 	/* Save .xml files, remove signals, etc. */
 	purple_smileys_uninit();
 	purple_idle_uninit();
-	purple_ssl_uninit();
 	purple_pounces_uninit();
 	purple_blist_uninit();
 	purple_ciphers_uninit();
@@ -213,7 +225,6 @@
 	purple_accounts_uninit();
 	purple_savedstatuses_uninit();
 	purple_status_uninit();
-	purple_prefs_uninit();
 	purple_sound_uninit();
 	purple_xfers_uninit();
 	purple_proxy_uninit();
@@ -221,19 +232,15 @@
 	purple_imgstore_uninit();
 	purple_network_uninit();
 
-	purple_debug_info("main", "Unloading all plugins\n");
-	purple_plugins_destroy_all();
-
-	ops = purple_core_get_ui_ops();
-	if (ops != NULL && ops->quit != NULL)
-		ops->quit();
-
+	/* Everything after this must not try to read any prefs */
+	purple_prefs_uninit();
 	purple_plugins_uninit();
 #ifdef HAVE_DBUS
 	purple_dbus_uninit();
 #endif
 
 	purple_cmds_uninit();
+	/* Everything after this cannot try to write things to the confdir */
 	purple_util_uninit();
 
 	purple_signals_uninit();
--- a/libpurple/prefs.c	Sun Jan 25 09:13:28 2009 +0000
+++ b/libpurple/prefs.c	Sun Jan 25 20:51:41 2009 +0000
@@ -693,12 +693,15 @@
 	char *name;
 	GSList *l;
 
-	if(!pref || pref == &prefs)
+	if(!pref)
 		return;
 
 	while(pref->first_child)
 		remove_pref(pref->first_child);
 
+	if(pref == &prefs)
+		return;
+
 	if(pref->parent->first_child == pref) {
 		pref->parent->first_child = pref->sibling;
 	} else {
@@ -711,7 +714,8 @@
 
 	name = pref_full_name(pref);
 
-	purple_debug_info("prefs", "removing pref %s\n", name);
+	if (prefs_loaded)
+		purple_debug_info("prefs", "removing pref %s\n", name);
 
 	g_hash_table_remove(prefs_hash, name);
 	g_free(name);
@@ -1451,6 +1455,9 @@
 		sync_prefs();
 	}
 
+	prefs_loaded = FALSE;
+	purple_prefs_destroy();
+	g_hash_table_destroy(prefs_hash);
+	prefs_hash = NULL;
 
-	prefs_loaded = FALSE;
 }
--- a/libpurple/protocols/jabber/auth.c	Sun Jan 25 09:13:28 2009 +0000
+++ b/libpurple/protocols/jabber/auth.c	Sun Jan 25 20:51:41 2009 +0000
@@ -749,8 +749,8 @@
 
 				val_end = cur;
 				while (val_end != val_start && (*val_end == ' ' || *val_end == ',' || *val_end == '\t'
-						|| *val_end == '\r' || *val_start == '\n'
-						|| *val_end == '"'))
+						|| *val_end == '\r' || *val_end == '\n'
+						|| *val_end == '"'  || *val_end == '\0'))
 					val_end--;
 
 				if (val_start != val_end)
--- a/libpurple/protocols/jabber/buddy.c	Sun Jan 25 09:13:28 2009 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Sun Jan 25 20:51:41 2009 +0000
@@ -2518,7 +2518,7 @@
 	JabberBuddyResource *jbr = jabber_buddy_find_resource((JabberBuddy*)jb, NULL);
 
 	if (!jbr) {
-		purple_debug_error("jabber",
+		purple_debug_info("jabber",
 			"Unable to find caps: buddy might be offline\n");
 		return FALSE;
 	}
--- a/libpurple/status.c	Sun Jan 25 09:13:28 2009 +0000
+++ b/libpurple/status.c	Sun Jan 25 20:51:41 2009 +0000
@@ -250,7 +250,7 @@
 {
 	g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL);
 
-	return purple_status_type_new_full(primitive, id, name, FALSE,
+	return purple_status_type_new_full(primitive, id, name, TRUE,
 			user_settable, FALSE);
 }
 
--- a/libpurple/status.h	Sun Jan 25 09:13:28 2009 +0000
+++ b/libpurple/status.h	Sun Jan 25 20:51:41 2009 +0000
@@ -199,8 +199,8 @@
 										  gboolean independent);
 
 /**
- * Creates a new status type with some default values (not
- * savable and not independent).
+ * Creates a new status type with some default values (
+ * saveable and not independent).
  *
  * @param primitive     The primitive status type.
  * @param id            The ID of the status type, or @c NULL to use the id of
--- a/pidgin/gtkaccount.c	Sun Jan 25 09:13:28 2009 +0000
+++ b/pidgin/gtkaccount.c	Sun Jan 25 20:51:41 2009 +0000
@@ -84,6 +84,13 @@
 
 typedef struct
 {
+	GtkWidget *widget;
+	gchar *setting;
+	PurplePrefType type;
+} ProtocolOptEntry;
+
+typedef struct
+{
 	PidginAccountDialogType type;
 
 	PurpleAccount *account;
@@ -548,8 +555,10 @@
 	/* Password */
 	dialog->password_entry = gtk_entry_new();
 	gtk_entry_set_visibility(GTK_ENTRY(dialog->password_entry), FALSE);
+#if !GTK_CHECK_VERSION(2,16,0)
 	if (gtk_entry_get_invisible_char(GTK_ENTRY(dialog->password_entry)) == '*')
 		gtk_entry_set_invisible_char(GTK_ENTRY(dialog->password_entry), PIDGIN_INVISIBLE_CHAR);
+#endif /* Less than GTK+ 2.16 */
 	dialog->password_box = add_pref_box(dialog, vbox, _("_Password:"),
 										  dialog->password_entry);
 
@@ -740,21 +749,22 @@
 	char *title, *tmp;
 	const char *str_value;
 	gboolean bool_value;
+	ProtocolOptEntry *opt_entry;
 
 	if (dialog->protocol_frame != NULL) {
 		gtk_widget_destroy(dialog->protocol_frame);
 		dialog->protocol_frame = NULL;
 	}
 
-	if (dialog->protocol_opt_entries != NULL) {
-		g_list_free(dialog->protocol_opt_entries);
-		dialog->protocol_opt_entries = NULL;
-	}
-
 	if (dialog->prpl_info == NULL ||
-		dialog->prpl_info->protocol_options == NULL) {
-
+			dialog->prpl_info->protocol_options == NULL)
 		return;
+
+	while (dialog->protocol_opt_entries != NULL) {
+		ProtocolOptEntry *opt_entry = dialog->protocol_opt_entries->data;
+		g_free(opt_entry->setting);
+		g_free(opt_entry);
+		dialog->protocol_opt_entries = g_list_delete_link(dialog->protocol_opt_entries, dialog->protocol_opt_entries);
 	}
 
 	account = dialog->account;
@@ -778,7 +788,11 @@
 	{
 		option = (PurpleAccountOption *)l->data;
 
-		switch (purple_account_option_get_type(option))
+		opt_entry = g_new0(ProtocolOptEntry, 1);
+		opt_entry->type = purple_account_option_get_type(option);
+		opt_entry->setting = g_strdup(purple_account_option_get_setting(option));
+
+		switch (opt_entry->type)
 		{
 			case PURPLE_PREF_BOOLEAN:
 				if (account == NULL ||
@@ -795,7 +809,7 @@
 				}
 
 				tmp = g_strconcat("_", purple_account_option_get_text(option), NULL);
-				check = gtk_check_button_new_with_mnemonic(tmp);
+				opt_entry->widget = check = gtk_check_button_new_with_mnemonic(tmp);
 				g_free(tmp);
 
 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check),
@@ -803,10 +817,6 @@
 
 				gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0);
 				gtk_widget_show(check);
-
-				dialog->protocol_opt_entries =
-					g_list_append(dialog->protocol_opt_entries, check);
-
 				break;
 
 			case PURPLE_PREF_INT:
@@ -825,19 +835,13 @@
 
 				g_snprintf(buf, sizeof(buf), "%d", int_value);
 
-				entry = gtk_entry_new();
+				opt_entry->widget = entry = gtk_entry_new();
 				gtk_entry_set_text(GTK_ENTRY(entry), buf);
 
 				title = g_strdup_printf("_%s:",
 						purple_account_option_get_text(option));
-
 				add_pref_box(dialog, vbox, title, entry);
-
 				g_free(title);
-
-				dialog->protocol_opt_entries =
-					g_list_append(dialog->protocol_opt_entries, entry);
-
 				break;
 
 			case PURPLE_PREF_STRING:
@@ -854,12 +858,14 @@
 						purple_account_option_get_default_string(option));
 				}
 
-				entry = gtk_entry_new();
+				opt_entry->widget = entry = gtk_entry_new();
 				if (purple_account_option_get_masked(option))
 				{
 					gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+#if !GTK_CHECK_VERSION(2,16,0)
 					if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*')
 						gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR);
+#endif /* Less than GTK+ 2.16 */
 				}
 
 				if (str_value != NULL)
@@ -867,14 +873,8 @@
 
 				title = g_strdup_printf("_%s:",
 						purple_account_option_get_text(option));
-
 				add_pref_box(dialog, vbox, title, entry);
-
 				g_free(title);
-
-				dialog->protocol_opt_entries =
-					g_list_append(dialog->protocol_opt_entries, entry);
-
 				break;
 
 			case PURPLE_PREF_STRING_LIST:
@@ -896,7 +896,7 @@
 
 				list = purple_account_option_get_list(option);
 				model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
-				combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
+				opt_entry->widget = combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
 
 				/* Loop through list of PurpleKeyValuePair items */
 				for (node = list; node != NULL; node = node->next) {
@@ -928,20 +928,21 @@
 
 				title = g_strdup_printf("_%s:",
 						purple_account_option_get_text(option));
-
 				add_pref_box(dialog, vbox, title, combo);
-
 				g_free(title);
-
-				dialog->protocol_opt_entries =
-					g_list_append(dialog->protocol_opt_entries, combo);
-
 				break;
 
-
 			default:
-				break;
+				purple_debug_error("gtkaccount", "Invalid Account Option pref type (%d)\n",
+						   opt_entry->type);
+				g_free(opt_entry->setting);
+				g_free(opt_entry);
+				continue;
 		}
+
+		dialog->protocol_opt_entries =
+			g_list_append(dialog->protocol_opt_entries, opt_entry);
+
 	}
 }
 
@@ -1092,8 +1093,10 @@
 	/* Password */
 	dialog->proxy_pass_entry = gtk_entry_new();
 	gtk_entry_set_visibility(GTK_ENTRY(dialog->proxy_pass_entry), FALSE);
+#if !GTK_CHECK_VERSION(2,16,0)
 	if (gtk_entry_get_invisible_char(GTK_ENTRY(dialog->proxy_pass_entry)) == '*')
 		gtk_entry_set_invisible_char(GTK_ENTRY(dialog->proxy_pass_entry), PIDGIN_INVISIBLE_CHAR);
+#endif /* Less than GTK+ 2.16 */
 	add_pref_box(dialog, vbox2, _("Pa_ssword:"), dialog->proxy_pass_entry);
 
 	if (dialog->account != NULL &&
@@ -1152,7 +1155,12 @@
 	gtk_widget_destroy(dialog->window);
 
 	g_list_free(dialog->user_split_entries);
-	g_list_free(dialog->protocol_opt_entries);
+	while (dialog->protocol_opt_entries != NULL) {
+		ProtocolOptEntry *opt_entry = dialog->protocol_opt_entries->data;
+		g_free(opt_entry->setting);
+		g_free(opt_entry);
+		dialog->protocol_opt_entries = g_list_delete_link(dialog->protocol_opt_entries, dialog->protocol_opt_entries);
+	}
 	g_free(dialog->protocol_id);
 	g_object_unref(dialog->sg);
 
@@ -1317,46 +1325,38 @@
 
 	/* Add the protocol settings */
 	if (dialog->prpl_info) {
-		for (l = dialog->prpl_info->protocol_options,
-				l2 = dialog->protocol_opt_entries;
-				l != NULL && l2 != NULL;
-				l = l->next, l2 = l2->next) {
-
-			PurplePrefType type;
-			PurpleAccountOption *option = l->data;
-			GtkWidget *widget = l2->data;
-			GtkTreeIter iter;
-			const char *setting;
-			char *value2;
-			int int_value;
-			gboolean bool_value;
-
-			type = purple_account_option_get_type(option);
-
-			setting = purple_account_option_get_setting(option);
-
-			switch (type) {
+		ProtocolOptEntry *opt_entry;
+		GtkTreeIter iter;
+		char *value2;
+		int int_value;
+		gboolean bool_value;
+
+		for (l2 = dialog->protocol_opt_entries; l2; l2 = l2->next) {
+
+			opt_entry = l2->data;
+
+			switch (opt_entry->type) {
 				case PURPLE_PREF_STRING:
-					value = gtk_entry_get_text(GTK_ENTRY(widget));
-					purple_account_set_string(account, setting, value);
+					value = gtk_entry_get_text(GTK_ENTRY(opt_entry->widget));
+					purple_account_set_string(account, opt_entry->setting, value);
 					break;
 
 				case PURPLE_PREF_INT:
-					int_value = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
-					purple_account_set_int(account, setting, int_value);
+					int_value = atoi(gtk_entry_get_text(GTK_ENTRY(opt_entry->widget)));
+					purple_account_set_int(account, opt_entry->setting, int_value);
 					break;
 
 				case PURPLE_PREF_BOOLEAN:
 					bool_value =
-						gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-					purple_account_set_bool(account, setting, bool_value);
+						gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(opt_entry->widget));
+					purple_account_set_bool(account, opt_entry->setting, bool_value);
 					break;
 
 				case PURPLE_PREF_STRING_LIST:
 					value2 = NULL;
-					if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter))
-						gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(widget)), &iter, 1, &value2, -1);
-					purple_account_set_string(account, setting, value2);
+					if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(opt_entry->widget), &iter))
+						gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(opt_entry->widget)), &iter, 1, &value2, -1);
+					purple_account_set_string(account, opt_entry->setting, value2);
 					break;
 
 				default:
--- a/pidgin/gtkblist.c	Sun Jan 25 09:13:28 2009 +0000
+++ b/pidgin/gtkblist.c	Sun Jan 25 20:51:41 2009 +0000
@@ -955,8 +955,10 @@
 			if (pce->secret)
 			{
 				gtk_entry_set_visibility(GTK_ENTRY(input), FALSE);
+#if !GTK_CHECK_VERSION(2,16,0)
 				if (gtk_entry_get_invisible_char(GTK_ENTRY(input)) == '*')
 					gtk_entry_set_invisible_char(GTK_ENTRY(input), PIDGIN_INVISIBLE_CHAR);
+#endif /* Less than GTK+ 2.16 */
 			}
 			pidgin_add_widget_to_vbox(GTK_BOX(data->entries_box), pce->label, data->sg, input, TRUE, NULL);
 			g_signal_connect(G_OBJECT(input), "changed",
@@ -6826,8 +6828,10 @@
 			if (pce->secret)
 			{
 				gtk_entry_set_visibility(GTK_ENTRY(input), FALSE);
+#if !GTK_CHECK_VERSION(2,16,0)
 				if (gtk_entry_get_invisible_char(GTK_ENTRY(input)) == '*')
 					gtk_entry_set_invisible_char(GTK_ENTRY(input), PIDGIN_INVISIBLE_CHAR);
+#endif /* Less than GTK+ 2.16 */
 			}
 			pidgin_add_widget_to_vbox(GTK_BOX(data->entries_box), pce->label, data->sg, input, TRUE, NULL);
 			g_signal_connect(G_OBJECT(input), "changed",
--- a/pidgin/gtkgaim-compat.h	Sun Jan 25 09:13:28 2009 +0000
+++ b/pidgin/gtkgaim-compat.h	Sun Jan 25 20:51:41 2009 +0000
@@ -297,7 +297,9 @@
 #define GAIM_HIG_BORDER PIDGIN_HIG_BORDER
 #define GAIM_HIG_BOX_SPACE PIDGIN_HIG_BOX_SPACE
 #define GAIM_HIG_CAT_SPACE PIDGIN_HIG_CAT_SPACE
+#if !GTK_CHECK_VERSION(2,16,0)
 #define GAIM_INVISIBLE_CHAR PIDGIN_INVISIBLE_CHAR
+#endif /* Less than GTK+ 2.16 */
 #define GAIM_IS_GTK_CONVERSATION PIDGIN_IS_PIDGIN_CONVERSATION
 #define GAIM_IS_GTK_PLUGIN PIDGIN_IS_PIDGIN_PLUGIN
 #define gaim_new_check_item pidgin_new_check_item
--- a/pidgin/gtkmain.c	Sun Jan 25 09:13:28 2009 +0000
+++ b/pidgin/gtkmain.c	Sun Jan 25 20:51:41 2009 +0000
@@ -322,9 +322,6 @@
 	pidgin_session_end();
 #endif
 
-	/* Save the plugins we have loaded for next time. */
-	pidgin_plugins_save();
-
 	/* Uninit */
 	pidgin_smileys_uninit();
 	pidgin_conversations_uninit();
@@ -787,8 +784,8 @@
 		dbus_connection_send_with_reply_and_block(conn, message, -1, NULL);
 		dbus_message_unref(message);
 #endif
-		purple_debug_info("main", "exiting because another libpurple client is already running\n");
 		purple_core_quit();
+		g_printerr(_("Exiting because another libpurple client is already running.\n"));
 #ifdef HAVE_SIGNAL_H
 		g_free(segfault_message);
 #endif
--- a/pidgin/gtkpluginpref.c	Sun Jan 25 09:13:28 2009 +0000
+++ b/pidgin/gtkpluginpref.c	Sun Jan 25 20:51:41 2009 +0000
@@ -101,8 +101,10 @@
 				if (purple_plugin_pref_get_masked(pref))
 				{
 					gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+#if !GTK_CHECK_VERSION(2,16,0)
 					if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*')
 						gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR);
+#endif /* Less than GTK+ 2.16 */
 				}
 				g_signal_connect(G_OBJECT(entry), "changed",
 								 G_CALLBACK(entry_cb),
--- a/pidgin/gtkprefs.c	Sun Jan 25 09:13:28 2009 +0000
+++ b/pidgin/gtkprefs.c	Sun Jan 25 20:51:41 2009 +0000
@@ -1412,8 +1412,10 @@
 		gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
 		gtk_table_attach(GTK_TABLE(table), entry, 3, 4, 1, 2, GTK_FILL , 0, 0, 0);
 		gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+#if !GTK_CHECK_VERSION(2,16,0)
 		if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*')
 			gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR);
+#endif /* Less than GTK+ 2.16 */
 		g_signal_connect(G_OBJECT(entry), "changed",
 				 G_CALLBACK(proxy_print_option), (void *)PROXYPASS);
 
--- a/pidgin/gtkrequest.c	Sun Jan 25 09:13:28 2009 +0000
+++ b/pidgin/gtkrequest.c	Sun Jan 25 20:51:41 2009 +0000
@@ -430,8 +430,10 @@
 			if (masked)
 			{
 				gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+#if !GTK_CHECK_VERSION(2,16,0)
 				if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*')
 					gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR);
+#endif /* Less than GTK+ 2.16 */
 			}
 		}
 		gtk_widget_show_all(vbox);
@@ -791,8 +793,10 @@
 		if (purple_request_field_string_is_masked(field))
 		{
 			gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
+#if !GTK_CHECK_VERSION(2,16,0)
 			if (gtk_entry_get_invisible_char(GTK_ENTRY(widget)) == '*')
 				gtk_entry_set_invisible_char(GTK_ENTRY(widget),	PIDGIN_INVISIBLE_CHAR);
+#endif /* Less than GTK+ 2.16 */
 		}
 
 		gtk_editable_set_editable(GTK_EDITABLE(widget),
--- a/pidgin/pidgin.h	Sun Jan 25 09:13:28 2009 +0000
+++ b/pidgin/pidgin.h	Sun Jan 25 20:51:41 2009 +0000
@@ -91,11 +91,22 @@
 #define PIDGIN_HIG_BORDER        12
 #define PIDGIN_HIG_BOX_SPACE      6
 
+#if !GTK_CHECK_VERSION(2,16,0) || !defined(PIDGIN_DISABLE_DEPRECATED)
 /*
- * See GNOME bug #307304 for some discussion about the invisible
- * character.  0x25cf is a good choice, too.
+ * Older versions of GNOME defaulted to using an asterisk as the invisible
+ * character.  But this is ugly and we want to use something nicer.
+ *
+ * The default invisible character was changed in GNOME revision 21446
+ * (GTK+ 2.16) from an asterisk to the first available character out of
+ * 0x25cf, 0x2022, 0x2731, 0x273a.  See GNOME bugs 83935 and 307304 for
+ * discussion leading up to the change.
+ *
+ * Here's the change:
+ * http://svn.gnome.org/viewvc/gtk%2B?view=revision&revision=21446
+ *
  */
-#define PIDGIN_INVISIBLE_CHAR (gunichar)0x2022
+#define PIDGIN_INVISIBLE_CHAR (gunichar)0x25cf
+#endif /* Less than GTK+ 2.16 */
 
 #endif /* _PIDGIN_H_ */
 
--- a/po/fi.po	Sun Jan 25 09:13:28 2009 +0000
+++ b/po/fi.po	Sun Jan 25 20:51:41 2009 +0000
@@ -11,7 +11,7 @@
 "Project-Id-Version: Pidgin\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2009-01-07 13:30+0200\n"
-"PO-Revision-Date: 2009-01-07 13:30+0200\n"
+"PO-Revision-Date: 2009-01-23 19:58+0200\n"
 "Last-Translator: Timo Jyrinki <timo.jyrinki@iki.fi>\n"
 "Language-Team: \n"
 "MIME-Version: 1.0\n"
@@ -1169,7 +1169,7 @@
 msgstr "Keskustelut"
 
 msgid "Logging"
-msgstr "Kirjataan lokiin"
+msgstr "Lokiinkirjaus"
 
 msgid "You must fill all the required fields."
 msgstr "Täytä kaikki vaaditut kentät."
@@ -15466,7 +15466,7 @@
 #~ "keskustelun uuden keskustelun aluksi.\n"
 #~ "\n"
 #~ "Historia-liitännäinen vaatii lokiinkirjauksen käyttöä. Loki voidaan ottaa "
-#~ "käyttöön menemällä Työkalut -> Asetukset -> Kirjataan lokiin. Lokien "
+#~ "käyttöön menemällä Työkalut -> Asetukset -> Lokiinkirjaus. Lokien "
 #~ "käyttöönotto pikaviesteille ja/tai ryhmäkeskusteluille ottaa käyttöön "
 #~ "historiatoiminnon vastaaville keskustelutyypeille."
 
--- a/po/l10n.xsl	Sun Jan 25 09:13:28 2009 +0000
+++ b/po/l10n.xsl	Sun Jan 25 20:51:41 2009 +0000
@@ -1,22 +1,47 @@
 <?xml version='1.0' ?>
 <xsl:stylesheet version='2.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
+		<xsl:output
+		method="html"
+		omit-xml-declaration="yes"
+		doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
+		doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
+		indent="yes"
+		/>
 	<xsl:template match='/project'>
-		<html>
+		<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 			<head>
 				<title><xsl:value-of select='@name'/> translation statistics</title>
+				<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 				<!-- <link rel="Stylesheet" href="/gaim.css" type="text/css" media="screen" /> -->
-				<style>
+				<style type="text/css">
 					.bargraph {
 						width: 200px;
 						height: 20px;
-						background: black;
+						background-color: red;
 						border-collapse: collapse;
 						border-spacing: 0px;
 						margin: 0px;
 						border: 0px;
 						padding: 0px;
 					}
-
+					.translated { 
+						background-color: green; 
+						padding: 0px;
+					}
+					.fuzzy { 
+						background-color: blue; 
+						padding: 0px;
+					}
+					.untranslated { 
+						background-color: red; 
+						padding: 0px;
+					}
+					td.sep {
+						padding-right: 10px;
+					}
+					th {
+						text-align: left;
+					}
 				</style>
 			</head>
 			<body>
@@ -28,21 +53,23 @@
 						<xsl:sort select='@code' />
 						<tr>
 							<td><a><xsl:attribute name='href'><xsl:value-of select='@code'/>.po</xsl:attribute><xsl:value-of select='@name'/> (<xsl:value-of select='@code'/>)</a></td>
-							<td><xsl:value-of select='@translated'/></td><td><xsl:value-of select="format-number(@translated div ../@strings * 100,'#.##')"/> %</td>
-							<td><xsl:value-of select='@fuzzy'/></td><td><xsl:value-of select="format-number(@fuzzy div ../@strings * 100,'#.##')"/> %</td>
-							<td><xsl:value-of select='../@strings - (@translated + @fuzzy)'/></td><td><xsl:value-of select="format-number((../@strings - (@translated + @fuzzy)) div ../@strings * 100,'#.##')"/> %</td>
+							<td><xsl:value-of select='@translated'/></td>
+							<td class='sep'><xsl:value-of select="format-number(@translated div ../@strings * 100,'#.##')"/> %</td>
+							<td><xsl:value-of select='@fuzzy'/></td>
+							<td class='sep'><xsl:value-of select="format-number(@fuzzy div ../@strings * 100,'#.##')"/> %</td>
+							<td><xsl:value-of select='../@strings - (@translated + @fuzzy)'/></td>
+							<td><xsl:value-of select="format-number((../@strings - (@translated + @fuzzy)) div ../@strings * 100,'#.##')"/> %</td>
 						<td>
 							<table class='bargraph'><tr>
-									<td bgcolor='green'><xsl:attribute name='width'><xsl:value-of select='round(@translated div ../@strings * 200)'/>px;</xsl:attribute></td>
-									<td bgcolor='blue'><xsl:attribute name='width'><xsl:value-of select='round(@fuzzy div ../@strings * 200)'/>px;</xsl:attribute></td>
-									<!-- <td bgcolor='red'><xsl:attribute name='width'><xsl:value-of select='200 - round((@translated + @fuzzy) div ../@strings * 200)'/>px;</xsl:attribute></td> -->
-									<td bgcolor='red'></td>
+									<td class="translated"><xsl:attribute name='style'>width:<xsl:value-of select='round(@translated div ../@strings * 200)'/>px;</xsl:attribute></td>
+									<td class="fuzzy"><xsl:attribute name='style'>width:<xsl:value-of select='round(@fuzzy div ../@strings * 200)'/>px;</xsl:attribute></td>
+									<td class="untranslated"><xsl:attribute name='style'>width:<xsl:value-of select='round((../@strings - @translated - @fuzzy) div ../@strings * 200)'/>px;</xsl:attribute></td>
 							</tr></table>
 						</td>
 						</tr>
 					</xsl:for-each>
 				</table>
-				<a><xsl:attribute name='href'><xsl:value-of select='@pofile'/></xsl:attribute><xsl:value-of select='@pofile'/></a> generated on <xsl:value-of select='@generated'/>
+				<p><a><xsl:attribute name='href'><xsl:value-of select='@pofile'/></xsl:attribute><xsl:value-of select='@pofile'/></a> generated on <xsl:value-of select='@generated'/></p>
 				<!-- </div> -->
 			</body>
 		</html>