changeset 27745:b9197011ddd6

merge of '1ec99cf95363c1e7c839780d51463b0c73d96e25' and '4e52f6d35023c9f4c4b5944f42784a1ac32bb0d8'
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Sat, 15 Dec 2007 05:12:24 +0000
parents 2961a316058c (diff) e81d5493626c (current diff)
children e13759a83714
files pidgin/gtkconv.c
diffstat 27 files changed, 440 insertions(+), 171 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Sat Dec 15 05:02:35 2007 +0000
+++ b/COPYRIGHT	Sat Dec 15 05:12:24 2007 +0000
@@ -95,6 +95,7 @@
 Chris Davies
 Josh Davis
 Martijn Dekker
+Florian Delizy
 Vinicius Depizzol
 Philip Derrin
 Taso N. Devetzis
--- a/doc/finch.1.in	Sat Dec 15 05:02:35 2007 +0000
+++ b/doc/finch.1.in	Sat Dec 15 05:12:24 2007 +0000
@@ -88,9 +88,8 @@
 Start resizing a window. Press the cursor keys to resize the window. When you
 are done, press \fBEnter\fR or \fBEscape\fR.
 .TP
-.B Alt \+ d
-Dump the contents of the screen in HTML format in a file named "dump.html" in
-working directory.
+.B Alt \+ D
+Dump the contents of the screen in HTML format.
 .TP
 .B Alt \+ .
 Move the position of the current window in the window list one place to the
@@ -107,8 +106,7 @@
 Jump to the 1st, 2nd ... 10th window.
 .TP
 .B Ctrl \+ o
-Bring up the menu (if there is one) for a window. Note that currently only the
-buddylist has a menu.
+Bring up the menu (if there is one) for a window.
 .TP
 .B Alt \+ /
 Show a list of available key-bindings for the current widget in focus.
@@ -494,7 +492,7 @@
 .SH BUGS
 Known bugs are listed at
 .br
-\fIhttp://sourceforge.net/tracker/?group_id=235&atid=100235\fR
+\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
--- a/finch/finch.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/finch/finch.c	Sat Dec 15 05:12:24 2007 +0000
@@ -297,7 +297,6 @@
 	if (opt_version) {
 		/* Translators may want to transliterate the name.
 		 It is not to be translated. */
-		gnt_quit();
 		printf("%s %s\n", _("Finch"), DISPLAY_VERSION);
 		return 0;
 	}
@@ -418,8 +417,6 @@
 	g_set_application_name(_("Finch"));
 #endif
 
-	gnt_init();
-
 	if (gnt_start(&argc, &argv)) {
 		gnt_main();
 
--- a/finch/libgnt/gntentry.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/finch/libgnt/gntentry.c	Sat Dec 15 05:12:24 2007 +0000
@@ -575,15 +575,16 @@
 next_begin_word(const char *text, const char *end)
 {
 	gunichar ch = 0;
+
+	while (text && text < end && g_unichar_isspace(g_utf8_get_char(text)))
+		text = g_utf8_find_next_char(text, end);
+
 	ch = g_utf8_get_char(text);
 	while ((text = g_utf8_find_next_char(text, end)) != NULL && text <= end) {
 		gunichar cur = g_utf8_get_char(text);
 		if (!SAME(ch, cur))
 			break;
 	}
-
-	while (text && text < end && g_unichar_isspace(g_utf8_get_char(text)))
-		text = g_utf8_find_next_char(text, end);
 	return (text ? text : end);
 }
 
--- a/finch/libgnt/gntmain.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/finch/libgnt/gntmain.c	Sat Dec 15 05:12:24 2007 +0000
@@ -21,7 +21,7 @@
  */
 
 #define _GNU_SOURCE
-#if defined(__APPLE__) || defined(__unix__)
+#if (defined(__APPLE__) || defined(__unix__)) && !defined(__FreeBSD__)
 #define _XOPEN_SOURCE_EXTENDED
 #endif
 
--- a/finch/libgnt/gntwindow.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/finch/libgnt/gntwindow.c	Sat Dec 15 05:12:24 2007 +0000
@@ -62,7 +62,8 @@
 	if (window->menu)
 		gnt_widget_destroy(GNT_WIDGET(window->menu));
 	if (window->priv) {
-		g_hash_table_destroy(window->priv->accels);
+		if (window->priv->accels)
+			g_hash_table_destroy(window->priv->accels);
 		g_free(window->priv);
 	}
 	org_destroy(widget);
--- a/finch/libgnt/gntwm.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/finch/libgnt/gntwm.c	Sat Dec 15 05:12:24 2007 +0000
@@ -21,13 +21,14 @@
  */
 
 #define _GNU_SOURCE
-#if defined(__APPLE__) || defined(__unix__)
+#if (defined(__APPLE__) || defined(__unix__)) && !defined(__FreeBSD__)
 #define _XOPEN_SOURCE_EXTENDED
 #endif
 
 #include "config.h"
 
 #include <glib.h>
+#include <glib/gstdio.h>
 #include <ctype.h>
 #include <gmodule.h>
 #include <stdlib.h>
@@ -41,6 +42,7 @@
 #include "gntbox.h"
 #include "gntbutton.h"
 #include "gntentry.h"
+#include "gntfilesel.h"
 #include "gntlabel.h"
 #include "gntmenu.h"
 #include "gnttextview.h"
@@ -663,12 +665,12 @@
 	return TRUE;
 }
 
-static gboolean
-dump_screen(GntBindable *bindable, GList *null)
+static void
+dump_file_save(GntFileSel *fs, const char *path, const char *f, gpointer n)
 {
+	FILE *file;
 	int x, y;
 	chtype old = 0, now = 0;
-	FILE *file = fopen("dump.html", "w");
 	struct {
 		char ascii;
 		char *unicode;
@@ -690,6 +692,11 @@
 		{'\0', NULL}
 	};
 
+
+	if ((file = g_fopen(path, "w+")) == NULL) {
+		return;
+	}
+
 	fprintf(file, "<head>\n  <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />\n</head>\n<body>\n");
 	fprintf(file, "<pre>");
 	for (y = 0; y < getmaxy(stdscr); y++) {
@@ -796,6 +803,24 @@
 	}
 	fprintf(file, "</pre>\n</body>");
 	fclose(file);
+	gnt_widget_destroy(GNT_WIDGET(fs));
+}
+
+static void
+dump_file_cancel(GntWidget *w, GntFileSel *fs)
+{
+	gnt_widget_destroy(GNT_WIDGET(fs));
+}
+
+static gboolean
+dump_screen(GntBindable *b, GList *null)
+{
+	GntWidget *window = gnt_file_sel_new();
+	GntFileSel *sel = GNT_FILE_SEL(window);
+	gnt_file_sel_set_suggested_filename(sel, "dump.html");
+	g_signal_connect(G_OBJECT(sel), "file_selected", G_CALLBACK(dump_file_save), NULL);
+	g_signal_connect(G_OBJECT(sel->cancel), "activate", G_CALLBACK(dump_file_cancel), sel);
+	gnt_widget_show(window);
 	return TRUE;
 }
 
@@ -1366,7 +1391,7 @@
 	gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-list", window_list,
 				"\033" "w", NULL);
 	gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "dump-screen", dump_screen,
-				"\033" "d", NULL);
+				"\033" "D", NULL);
 	gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "shift-left", shift_left,
 				"\033" ",", NULL);
 	gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "shift-right", shift_right,
--- a/libpurple/certificate.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/libpurple/certificate.c	Sat Dec 15 05:12:24 2007 +0000
@@ -1758,7 +1758,6 @@
 gboolean
 purple_certificate_register_pool(PurpleCertificatePool *pool)
 {
-	gboolean success = FALSE;
 	g_return_val_if_fail(pool, FALSE);
 	g_return_val_if_fail(pool->scheme_name, FALSE);
 	g_return_val_if_fail(pool->name, FALSE);
@@ -1771,46 +1770,42 @@
 
 	/* Initialize the pool if needed */
 	if (pool->init) {
+		gboolean success;
+
 		success = pool->init();
-	} else {
-		success = TRUE;
+		if (!success)
+			return FALSE;
 	}
-	
-	if (success) {
-		/* Register the Pool */
-		cert_pools = g_list_prepend(cert_pools, pool);
 
-		/* TODO: Emit a signal that the pool got registered */
+	/* Register the Pool */
+	cert_pools = g_list_prepend(cert_pools, pool);
+
+	/* TODO: Emit a signal that the pool got registered */
 
-		PURPLE_DBUS_REGISTER_POINTER(pool, PurpleCertificatePool);
-		purple_signal_register(pool, /* Signals emitted from pool */
-				       "certificate-stored",
-				       purple_marshal_VOID__POINTER_POINTER,
-				       NULL, /* No callback return value */
-				       2,    /* Two non-data arguments */
-				       purple_value_new(PURPLE_TYPE_SUBTYPE,
-							PURPLE_SUBTYPE_CERTIFICATEPOOL),
-				       purple_value_new(PURPLE_TYPE_STRING));
+	PURPLE_DBUS_REGISTER_POINTER(pool, PurpleCertificatePool);
+	purple_signal_register(pool, /* Signals emitted from pool */
+			       "certificate-stored",
+			       purple_marshal_VOID__POINTER_POINTER,
+			       NULL, /* No callback return value */
+			       2,    /* Two non-data arguments */
+			       purple_value_new(PURPLE_TYPE_SUBTYPE,
+						PURPLE_SUBTYPE_CERTIFICATEPOOL),
+			       purple_value_new(PURPLE_TYPE_STRING));
 
-		purple_signal_register(pool, /* Signals emitted from pool */
-				       "certificate-deleted",
-				       purple_marshal_VOID__POINTER_POINTER,
-				       NULL, /* No callback return value */
-				       2,    /* Two non-data arguments */
-				       purple_value_new(PURPLE_TYPE_SUBTYPE,
-							PURPLE_SUBTYPE_CERTIFICATEPOOL),
-				       purple_value_new(PURPLE_TYPE_STRING));
-
+	purple_signal_register(pool, /* Signals emitted from pool */
+			       "certificate-deleted",
+			       purple_marshal_VOID__POINTER_POINTER,
+			       NULL, /* No callback return value */
+			       2,    /* Two non-data arguments */
+			       purple_value_new(PURPLE_TYPE_SUBTYPE,
+						PURPLE_SUBTYPE_CERTIFICATEPOOL),
+			       purple_value_new(PURPLE_TYPE_STRING));
 
-		purple_debug_info("certificate",
-			  "CertificatePool %s registered\n",
-			  pool->name);
-		return TRUE;
-	} else {
-		return FALSE;
-	}
-	
-	/* Control does not reach this point */
+	purple_debug_info("certificate",
+		  "CertificatePool %s registered\n",
+		  pool->name);
+
+	return TRUE;
 }
 
 gboolean
--- a/libpurple/plugins/ssl/ssl-gnutls.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/libpurple/plugins/ssl/ssl-gnutls.c	Sat Dec 15 05:12:24 2007 +0000
@@ -512,9 +512,8 @@
 	dt.data = (unsigned char *) buf;
 	dt.size = buf_sz;
 
-	/* Perform the conversion */
-	crt = x509_import_from_datum(dt,
-				     GNUTLS_X509_FMT_PEM); // files should be in PEM format
+	/* Perform the conversion; files should be in PEM format */
+	crt = x509_import_from_datum(dt, GNUTLS_X509_FMT_PEM);
 
 	/* Cleanup */
 	g_free(buf);
--- a/libpurple/protocols/bonjour/bonjour.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c	Sat Dec 15 05:12:24 2007 +0000
@@ -43,14 +43,6 @@
 #include "buddy.h"
 #include "bonjour_ft.h"
 
-/*
- * TODO: Should implement an add_buddy callback that removes the buddy
- *       from the local list.  Bonjour manages buddies for you, and
- *       adding someone locally by hand is stupid.  Or, maybe even better,
- *       if a PRPL does not have an add_buddy callback then do not allow
- *       users to add buddies.
- */
-
 static char *default_firstname;
 static char *default_lastname;
 static char *default_hostname;
@@ -260,6 +252,25 @@
 	g_free(stripped);
 }
 
+/*
+ * The add_buddy callback removes the buddy from the local list.
+ * Bonjour manages buddies for you, and adding someone locally by
+ * hand is stupid.  Perhaps we should change libpurple not to allow adding
+ * if there is no add_buddy callback.
+ */
+static void
+bonjour_fake_add_buddy(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group) {
+	purple_debug_error("bonjour", "Buddy '%s' manually added; removing.  "
+				      "Bonjour buddies must be discovered and not manually added.\n",
+			   purple_buddy_get_name(buddy));
+
+	/* I suppose we could alert the user here, but it seems unnecessary. */
+
+	/* If this causes problems, it can be moved to an idle callback */
+	purple_blist_remove_buddy(buddy);
+}
+
+
 static void bonjour_remove_buddy(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group) {
 	if (buddy->proto_data) {
 		bonjour_buddy_delete(buddy->proto_data);
@@ -303,7 +314,7 @@
 	PurpleBuddy *buddy = purple_find_buddy(connection->account, who);
 	BonjourBuddy *bb;
 
-	if (buddy == NULL)
+	if (buddy == NULL || buddy->proto_data == NULL)
 	{
 		/*
 		 * This buddy is not in our buddy list, and therefore does not really
@@ -370,6 +381,11 @@
 	if (message != NULL)
 		purple_notify_user_info_add_pair(user_info, _("Message"), message);
 
+	if (bb == NULL) {
+		purple_debug_error("bonjour", "Got tooltip request for a buddy without protocol data.\n");
+		return;
+	}
+
 	/* Only show first/last name if there is a nickname set (to avoid duplication) */
 	if (bb->nick != NULL) {
 		if (bb->first != NULL)
@@ -425,7 +441,7 @@
 	bonjour_set_status,                                      /* set_status */
 	NULL,                                                    /* set_idle */
 	NULL,                                                    /* change_passwd */
-	NULL,                                                    /* add_buddy */
+	bonjour_fake_add_buddy,                                  /* add_buddy */
 	NULL,                                                    /* add_buddies */
 	bonjour_remove_buddy,                                    /* remove_buddy */
 	NULL,                                                    /* remove_buddies */
--- a/libpurple/protocols/bonjour/jabber.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Sat Dec 15 05:12:24 2007 +0000
@@ -19,6 +19,9 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
+
+#include "internal.h"
+
 #ifndef _WIN32
 #include <net/if.h>
 #include <sys/ioctl.h>
@@ -33,7 +36,6 @@
 #include <unistd.h>
 #include <fcntl.h>
 
-#include "internal.h"
 #include "network.h"
 #include "eventloop.h"
 #include "connection.h"
--- a/libpurple/protocols/msn/notification.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/libpurple/protocols/msn/notification.c	Sat Dec 15 05:12:24 2007 +0000
@@ -1181,14 +1181,27 @@
 static void
 rea_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
-	/* TODO: This might be for us too */
-
 	MsnSession *session;
+	PurpleAccount *account;
 	PurpleConnection *gc;
 	const char *friendly;
+	char *username;
 
 	session = cmdproc->session;
-	gc = session->account->gc;
+	account = session->account;
+	username = g_strdup(purple_normalize(account,
+						purple_account_get_username(account)));
+
+	/* Only set display name if our *own* friendly name changed! */
+	if (strcmp(username, purple_normalize(account, cmd->params[2])))
+	{
+		g_free(username);
+		return;
+	}
+
+	g_free(username);
+
+	gc = account->gc;
 	friendly = purple_url_decode(cmd->params[3]);
 
 	purple_connection_set_display_name(gc, friendly);
--- a/libpurple/protocols/msnp9/msn.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/libpurple/protocols/msnp9/msn.c	Sat Dec 15 05:12:24 2007 +0000
@@ -1920,7 +1920,7 @@
 		purple_debug_warning("msn", "invalid connection. ignoring buddy photo info.\n");
 		g_free(stripped);
 		g_free(url_buffer);
-		g_free(user_info);
+		purple_notify_user_info_destroy(user_info);
 		g_free(info_data->name);
 		g_free(info_data);
 		g_free(photo_url_text);
--- a/libpurple/protocols/msnp9/nexus.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/libpurple/protocols/msnp9/nexus.c	Sat Dec 15 05:12:24 2007 +0000
@@ -338,7 +338,7 @@
 		g_strdup(purple_url_encode(purple_account_get_username(session->account)));
 
 	password =
-		g_strndup(purple_url_encode(purple_connection_get_password(session->account->gc)), 16);
+		g_strdup(purple_url_encode(purple_connection_get_password(session->account->gc)));
 
 	ctint = strtoul((char *)g_hash_table_lookup(nexus->challenge_data, "ct"), NULL, 10) + 200;
 
--- a/libpurple/protocols/msnp9/notification.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/libpurple/protocols/msnp9/notification.c	Sat Dec 15 05:12:24 2007 +0000
@@ -780,14 +780,27 @@
 static void
 rea_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
-	/* TODO: This might be for us too */
-
 	MsnSession *session;
+	PurpleAccount *account;
 	PurpleConnection *gc;
 	const char *friendly;
+	char *username;
 
 	session = cmdproc->session;
-	gc = session->account->gc;
+	account = session->account;
+	username = g_strdup(purple_normalize(account,
+						purple_account_get_username(account)));
+
+	/* Only set display name if our *own* friendly name changed! */
+	if (strcmp(username, purple_normalize(account, cmd->params[2])))
+	{
+		g_free(username);
+		return;
+	}
+
+	g_free(username);
+
+	gc = account->gc;
 	friendly = purple_url_decode(cmd->params[3]);
 
 	purple_connection_set_display_name(gc, friendly);
--- a/libpurple/protocols/msnp9/user.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/libpurple/protocols/msnp9/user.c	Sat Dec 15 05:12:24 2007 +0000
@@ -126,16 +126,19 @@
 msn_user_set_friendly_name(MsnUser *user, const char *name)
 {
 	MsnCmdProc *cmdproc;
+	const char *encoded;
 
 	g_return_if_fail(user != NULL);
 
-	if (user->friendly_name && strcmp(user->friendly_name, name)) {
+	encoded = purple_url_encode(name);
+
+	if (user->friendly_name && strcmp(user->friendly_name, name) && (strlen(encoded) < 387)) {
 		/* copy the new name to the server list, but only when new */
 		/* should we check this more thoroughly? */
 		cmdproc = user->userlist->session->notification->cmdproc;
 		msn_cmdproc_send(cmdproc, "REA", "%s %s",
 						 user->passport,
-						 purple_url_encode(name));
+						 encoded);
 	}
 
 	g_free(user->friendly_name);
--- a/libpurple/win32/libc_interface.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/libpurple/win32/libc_interface.c	Sat Dec 15 05:12:24 2007 +0000
@@ -28,6 +28,7 @@
 #include <sys/stat.h>
 #include <time.h>
 #include <glib.h>
+#include "config.h"
 #include "debug.h"
 #include "libc_internal.h"
 #if GLIB_CHECK_VERSION(2,6,0)
@@ -38,6 +39,26 @@
 #define g_stat stat
 #endif
 
+#ifdef ENABLE_NLS
+#  include <locale.h>
+#  include <libintl.h>
+#  define _(String) ((const char *)dgettext(PACKAGE, String))
+#  ifdef gettext_noop
+#    define N_(String) gettext_noop (String)
+#  else
+#    define N_(String) (String)
+#  endif
+#else
+#  include <locale.h>
+#  define N_(String) (String)
+#  ifndef _
+#    define _(String) ((const char *)String)
+#  endif
+#  define ngettext(Singular, Plural, Number) ((Number == 1) ? ((const char *)Singular) : ((const char *)Plural))
+#  define dngettext(Domain, Singular, Plural, Number) ((Number == 1) ? ((const char *)Singular) : ((const char *)Plural))
+#endif
+
+
 static char errbuf[1024];
 
 /* helpers */
@@ -294,15 +315,25 @@
 }
 
 /* string.h */
-char* wpurple_strerror( int errornum ) {
-	if( errornum > WSABASEERR ) {
-		sprintf( errbuf, "Windows socket error #%d", errornum );
-		return errbuf;
+char* wpurple_strerror(int errornum) {
+	if (errornum > WSABASEERR) {
+		switch(errornum) {
+			case WSAECONNABORTED: /* 10053 */
+				snprintf(errbuf, sizeof(errbuf), _("Connection interrupted by other software on your computer."));
+			case WSAECONNRESET: /* 10054 */
+				snprintf(errbuf, sizeof(errbuf), _("Remote host closed connection."));
+			case WSAETIMEDOUT: /* 10060 */
+				snprintf(errbuf, sizeof(errbuf), _("Connection timed out."));
+			case WSAECONNREFUSED: /*10061 */
+				snprintf(errbuf, sizeof(errbuf), _("Connection refused."));
+			default:
+				snprintf(errbuf, sizeof(errbuf), "Windows socket error #%d", errornum);
+		}
+	} else {
+		const char *tmp = g_strerror(errornum);
+		snprintf(errbuf, sizeof(errbuf), tmp);
 	}
-	else
-		/* Nothing is supposed to modify what is returned by strerror,
-		   but it isn't const for some reason */
-		return (char *)g_strerror( errornum );
+	return errbuf;
 }
 
 /* unistd.h */
@@ -409,7 +440,7 @@
 
 	if (p != 0) {
 		_ftime(&timebuffer);
-	   	p->tv_sec = timebuffer.time;			/* seconds since 1-1-1970 */
+		p->tv_sec = timebuffer.time;			/* seconds since 1-1-1970 */
 		p->tv_usec = timebuffer.millitm*1000; 	/* microseconds */
 	}
 
--- a/pidgin/gtkblist.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/pidgin/gtkblist.c	Sat Dec 15 05:12:24 2007 +0000
@@ -753,6 +753,11 @@
 	{
 		case GTK_RESPONSE_OK:
 			do_join_chat(info);
+			break;
+
+		case 1:
+			pidgin_roomlist_dialog_show_with_account(info->account);
+			return;
 
 		break;
 	}
@@ -769,6 +774,8 @@
 static void
 joinchat_set_sensitive_if_input_cb(GtkWidget *entry, gpointer user_data)
 {
+	PurplePluginProtocolInfo *prpl_info;
+	PurpleConnection *gc;
 	PidginJoinChatData *data;
 	GList *tmp;
 	const char *text;
@@ -789,6 +796,12 @@
 	}
 
 	gtk_dialog_set_response_sensitive(GTK_DIALOG(data->window), GTK_RESPONSE_OK, sensitive);
+
+	gc = purple_account_get_connection(data->account);
+	prpl_info = (gc != NULL) ? PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl) : NULL;
+	sensitive = (prpl_info != NULL && prpl_info->roomlist_get_list != NULL);
+
+	gtk_dialog_set_response_sensitive(GTK_DIALOG(data->window), 1, sensitive);
 }
 
 static void
@@ -944,6 +957,7 @@
 
 	data->window = gtk_dialog_new_with_buttons(_("Join a Chat"),
 		NULL, GTK_DIALOG_NO_SEPARATOR,
+		_("Room _List"), 1,
 		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 		PIDGIN_STOCK_CHAT, GTK_RESPONSE_OK, NULL);
 	gtk_dialog_set_default_response(GTK_DIALOG(data->window), GTK_RESPONSE_OK);
@@ -2537,7 +2551,7 @@
  *
  *
  */
-#define STATUS_SIZE 22
+#define STATUS_SIZE 16 
 #define TOOLTIP_BORDER 12
 #define SMALL_SPACE 6
 #define LARGE_SPACE 12
@@ -3451,8 +3465,8 @@
 	struct _pidgin_blist_node *gtkbuddynode = NULL;
 	PurpleBuddy *buddy = NULL;
 	PurpleChat *chat = NULL;
-	GtkIconSize icon_size = gtk_icon_size_from_name((size == PIDGIN_STATUS_ICON_LARGE) ? PIDGIN_ICON_SIZE_TANGO_SMALL :
-											 PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL);
+	GtkIconSize icon_size = gtk_icon_size_from_name((size == PIDGIN_STATUS_ICON_LARGE) ? PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL :
+											 PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC);
 
 	if(PURPLE_BLIST_NODE_IS_CONTACT(node)) {
 		if(!gtknode->contact_expanded) {
@@ -4480,12 +4494,6 @@
 }
 
 static void
-generic_error_ignore_cb(PurpleAccount *account)
-{
-	purple_account_clear_current_error(account);
-}
-
-static void
 generic_error_destroy_cb(GtkObject *dialog,
                          PurpleAccount *account)
 {
@@ -4523,7 +4531,6 @@
 		(enabled ? PURPLE_CALLBACK(purple_account_connect)
 		         : PURPLE_CALLBACK(generic_error_enable_cb)),
 		_("Modify Account"), PURPLE_CALLBACK(generic_error_modify_cb),
-		_("Ignore"), PURPLE_CALLBACK(generic_error_ignore_cb),
 		NULL);
 
 	g_free(primary);
@@ -4608,14 +4615,6 @@
 }
 
 static void
-ignore_elsewhere_accounts(PidginMiniDialog *mini_dialog,
-                          GtkButton *button,
-                          gpointer unused)
-{
-	elsewhere_foreach_account(mini_dialog, purple_account_clear_current_error);
-}
-
-static void
 ensure_signed_on_elsewhere_minidialog(PidginBuddyList *gtkblist)
 {
 	PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
@@ -4625,14 +4624,11 @@
 		return;
 
 	mini_dialog = priv->signed_on_elsewhere =
-		pidgin_mini_dialog_new(NULL, NULL, PIDGIN_STOCK_DISCONNECT);
+		pidgin_mini_dialog_new(_("Welcome back!"), NULL, PIDGIN_STOCK_DISCONNECT);
 
 	pidgin_mini_dialog_add_button(mini_dialog, _("Re-enable"),
 		reconnect_elsewhere_accounts, NULL);
 
-	pidgin_mini_dialog_add_button(mini_dialog, _("Ignore"),
-		ignore_elsewhere_accounts, NULL);
-
 	add_error_dialog(gtkblist, GTK_WIDGET(mini_dialog));
 
 	/* Set priv->signed_on_elsewhere to NULL when the dialog is destroyed */
@@ -4658,11 +4654,11 @@
 	}
 
 	title = g_strdup_printf(
-		ngettext("%d account was disabled because you signed on from another location.",
-			 "%d accounts were disabled because you signed on from another location.",
+		ngettext("%d account was disabled because you signed on from another location:",
+			 "%d accounts were disabled because you signed on from another location:",
 			 accounts),
 		accounts);
-	pidgin_mini_dialog_set_title(mini_dialog, title);
+	pidgin_mini_dialog_set_description(mini_dialog, title);
 	g_free(title);
 }
 
@@ -5744,7 +5740,7 @@
 		return;
 
 	status = pidgin_blist_get_status_icon((PurpleBlistNode*)buddy,
-						PIDGIN_STATUS_ICON_SMALL);
+						biglist ? PIDGIN_STATUS_ICON_LARGE : PIDGIN_STATUS_ICON_SMALL);
 
 	/* Speed it up if we don't want buddy icons. */
 	if(biglist)
@@ -5828,6 +5824,7 @@
 	PurpleBlistNode *cnode;
 	PurpleContact *contact;
 	PurpleBuddy *buddy;
+	gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
 	struct _pidgin_blist_node *gtknode;
 
 	if (editing_blist)
@@ -5863,7 +5860,7 @@
 			char *mark;
 
 			status = pidgin_blist_get_status_icon(cnode,
-					 PIDGIN_STATUS_ICON_SMALL);
+					 biglist? PIDGIN_STATUS_ICON_LARGE : PIDGIN_STATUS_ICON_SMALL);
 
 			mark = g_markup_escape_text(purple_contact_get_alias(contact), -1);
 			gtk_tree_store_set(gtkblist->treemodel, &iter,
@@ -5942,6 +5939,7 @@
 		GdkPixbuf *status, *avatar, *emblem, *prpl_icon;
 		char *mark;
 		gboolean showicons = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
+		gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
 		PidginBlistNode *ui;
 		PurpleConversation *conv;
 		gboolean hidden;
@@ -5954,7 +5952,7 @@
 		hidden = (conv && (ui->conv.flags & PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE));
 
 		status = pidgin_blist_get_status_icon(node,
-				 PIDGIN_STATUS_ICON_SMALL);
+				 biglist ? PIDGIN_STATUS_ICON_LARGE : PIDGIN_STATUS_ICON_SMALL);
 		emblem = pidgin_blist_get_emblem(node);
 
 		/* Speed it up if we don't want buddy icons. */
@@ -6408,6 +6406,10 @@
 	{
 		add_chat_cb(NULL, data);
 	}
+	else if (resp == 1)
+	{
+		pidgin_roomlist_dialog_show_with_account(data->account);
+	}
 	else
 	{
 		gtk_widget_destroy(data->window);
@@ -6424,6 +6426,8 @@
 static void
 addchat_set_sensitive_if_input_cb(GtkWidget *entry, gpointer user_data)
 {
+	PurplePluginProtocolInfo *prpl_info;
+	PurpleConnection *gc;
 	PidginAddChatData *data;
 	GList *tmp;
 	const char *text;
@@ -6444,6 +6448,12 @@
 	}
 
 	gtk_dialog_set_response_sensitive(GTK_DIALOG(data->window), GTK_RESPONSE_OK, sensitive);
+
+	gc = purple_account_get_connection(data->account);
+	prpl_info = (gc != NULL) ? PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl) : NULL;
+	sensitive = (prpl_info != NULL && prpl_info->roomlist_get_list != NULL);
+
+	gtk_dialog_set_response_sensitive(GTK_DIALOG(data->window), 1, sensitive);
 }
 
 static void
@@ -6609,6 +6619,7 @@
 
 	data->window = gtk_dialog_new_with_buttons(_("Add Chat"),
 		gtkblist ? GTK_WINDOW(gtkblist->window) : NULL, GTK_DIALOG_NO_SEPARATOR,
+		_("Room _List"), 1,
 		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 		GTK_STOCK_ADD, GTK_RESPONSE_OK,
 		NULL);
@@ -6692,8 +6703,8 @@
 	pidgin_set_accessible_label (data->group_combo, label);
 	gtk_box_pack_end(GTK_BOX(rowbox), data->group_combo, TRUE, TRUE, 0);
 	
-	data->autojoin = gtk_check_button_new_with_mnemonic(_("Autojoin when account becomes online."));
-	data->persistent = gtk_check_button_new_with_mnemonic(_("Hide chat when the window is closed."));
+	data->autojoin = gtk_check_button_new_with_mnemonic(_("Auto_join when account becomes online."));
+	data->persistent = gtk_check_button_new_with_mnemonic(_("_Hide chat when the window is closed."));
 	gtk_box_pack_start(GTK_BOX(vbox), data->autojoin, FALSE, FALSE, 0);
 	gtk_box_pack_start(GTK_BOX(vbox), data->persistent, FALSE, FALSE, 0);
 
--- a/pidgin/gtkconv.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/pidgin/gtkconv.c	Sat Dec 15 05:12:24 2007 +0000
@@ -239,10 +239,7 @@
 	switch (purple_conversation_get_type(conv)) {
 		case PURPLE_CONV_TYPE_IM:
 		{
-			if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately"))
-				close_this_sucker(gtkconv);
-			else
-				hide_conv(gtkconv, TRUE);
+			hide_conv(gtkconv, TRUE);
 			break;
 		}
 		case PURPLE_CONV_TYPE_CHAT:
@@ -5139,6 +5136,7 @@
 		gtk_widget_show(gtkconv->toolbar);
 	else
 		gtk_widget_hide(gtkconv->toolbar);
+	g_idle_add((GSourceFunc)resize_imhtml_cb, gtkconv);
 
 	if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons"))
 		gtk_widget_show(gtkconv->infopane_hbox);
@@ -7169,6 +7167,8 @@
 			gtk_widget_show(gtkconv->toolbar);
 		else
 			gtk_widget_hide(gtkconv->toolbar);
+
+		g_idle_add((GSourceFunc)resize_imhtml_cb,gtkconv);
 	}
 }
 
@@ -7670,7 +7670,6 @@
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", TRUE);
 
 	purple_prefs_add_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "never");
-	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately", TRUE);
 
 #ifdef _WIN32
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", FALSE);
--- a/pidgin/gtkdialogs.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/pidgin/gtkdialogs.c	Sat Dec 15 05:12:24 2007 +0000
@@ -349,6 +349,7 @@
 	AtkObject *obj;
 	char* filename, *tmp;
 	GdkPixbuf *pixbuf;
+	PidginBuddyList *buddylist;
 
 	if (about != NULL) {
 		gtk_window_present(GTK_WINDOW(about));
@@ -724,6 +725,11 @@
 	gtk_widget_grab_default(button);
 
 	/* Let's give'em something to talk about -- woah woah woah */
+	buddylist = pidgin_blist_get_default_gtk_blist();
+	if (buddylist)
+		gtk_window_set_transient_for(GTK_WINDOW(about),
+				GTK_WINDOW(buddylist->window));
+
 	gtk_widget_show_all(about);
 	gtk_window_present(GTK_WINDOW(about));
 }
--- a/pidgin/gtkimhtml.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/pidgin/gtkimhtml.c	Sat Dec 15 05:12:24 2007 +0000
@@ -31,6 +31,7 @@
 
 #include "internal.h"
 #include "pidgin.h"
+#include "pidginstock.h"
 
 #include "debug.h"
 #include "util.h"
@@ -819,6 +820,7 @@
 static void hijack_menu_cb(GtkIMHtml *imhtml, GtkMenu *menu, gpointer data)
 {
 	GtkWidget *menuitem;
+	GtkWidget *mi, *img;
 
 	menuitem = gtk_menu_item_new_with_mnemonic(_("Paste as Plain _Text"));
 	gtk_widget_show(menuitem);
@@ -844,6 +846,28 @@
 	gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menuitem, 5);
 
 	g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(clear_formatting_cb), imhtml);
+	
+	mi = gtk_menu_item_new();
+	gtk_widget_show(mi);
+	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
+
+	img = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_SMILEY, GTK_ICON_SIZE_MENU);
+	mi = gtk_image_menu_item_new_with_label(_("_Smile!"));
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img);
+	gtk_widget_show(mi);
+	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
+
+	img = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_INSERT, GTK_ICON_SIZE_MENU);
+	mi = gtk_image_menu_item_new_with_label(_("_Insert"));
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img);
+	gtk_widget_show(mi);
+	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
+
+	img = gtk_image_new_from_stock(GTK_STOCK_BOLD, GTK_ICON_SIZE_MENU);
+	mi = gtk_image_menu_item_new_with_label(_("_Font"));
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img);
+	gtk_widget_show(mi);
+	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
 }
 
 static char *
@@ -1105,6 +1129,38 @@
 	g_free(text);
 }
 
+
+static void smart_backspace_cb(GtkIMHtml *imhtml, gpointer blah)
+{
+	GtkTextIter iter;
+	GtkTextChildAnchor* anchor;
+	char * text;
+	gint offset;
+
+	if (!imhtml->editable)
+		return;
+
+	gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, gtk_text_buffer_get_insert(imhtml->text_buffer));
+
+	/* Get the character before the insertion point */
+	offset = gtk_text_iter_get_offset(&iter);
+	if (offset <= 0)
+		return;
+
+	gtk_text_iter_backward_char(&iter);
+	anchor = gtk_text_iter_get_child_anchor(&iter);
+
+	if (!anchor)
+		return; /* No smiley here */
+
+	text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_plaintext");
+	if (!text)
+		return;
+
+	/* ok, then we need to insert the image buffer text before the anchor */
+	gtk_text_buffer_insert(imhtml->text_buffer, &iter, text, -1);
+}
+
 static void paste_clipboard_cb(GtkIMHtml *imhtml, gpointer blah)
 {
 #ifdef _WIN32
@@ -4060,8 +4116,11 @@
 	imhtml->format_functions = GTK_IMHTML_ALL;
 
 	if (editable)
+	{
 		g_signal_connect_after(G_OBJECT(GTK_IMHTML(imhtml)->text_buffer), "mark-set",
-		                       G_CALLBACK(mark_set_cb), imhtml);
+				G_CALLBACK(mark_set_cb), imhtml);
+		g_signal_connect(G_OBJECT(imhtml), "backspace", G_CALLBACK(smart_backspace_cb), NULL);
+	}
 }
 
 void gtk_imhtml_set_whole_buffer_formatting_only(GtkIMHtml *imhtml, gboolean wbfo)
@@ -4230,6 +4289,33 @@
 	g_object_unref(object);
 }
 
+static void populate_popup_cb(GtkTextView *textview, GtkMenu *menu, gpointer nul)
+{
+	GtkWidget *mi, *img;
+	
+	mi = gtk_menu_item_new();
+	gtk_widget_show(mi);
+	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
+
+	img = gtk_image_new_from_stock(GTK_STOCK_BOLD, GTK_ICON_SIZE_MENU);
+	mi = gtk_image_menu_item_new_with_label(_("_Font"));
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img);
+	gtk_widget_show(mi);
+	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
+
+	img = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_INSERT, GTK_ICON_SIZE_MENU);
+	mi = gtk_image_menu_item_new_with_label(_("_Insert"));
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img);
+	gtk_widget_show(mi);
+	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
+
+	img = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_SMILEY, GTK_ICON_SIZE_MENU);
+	mi = gtk_image_menu_item_new_with_label(_("_Smile!"));
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img);
+	gtk_widget_show(mi);
+	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
+}
+
 static void imhtml_toggle_bold(GtkIMHtml *imhtml)
 {
 	GtkTextIter start, end;
--- a/pidgin/gtkimhtmltoolbar.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/pidgin/gtkimhtmltoolbar.c	Sat Dec 15 05:12:24 2007 +0000
@@ -777,6 +777,8 @@
 	/* show everything */
 	gtk_window_set_title(GTK_WINDOW(dialog), _("Smile!"));
 	gtk_widget_show_all(dialog);
+	gtk_window_set_transient_for(GTK_WINDOW(dialog),
+			GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(toolbar))));
 #ifdef _WIN32
 	winpidgin_ensure_onscreen(dialog);
 #endif
--- a/pidgin/gtkprefs.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/pidgin/gtkprefs.c	Sat Dec 15 05:12:24 2007 +0000
@@ -998,8 +998,6 @@
 
 	pidgin_prefs_checkbox(_("Show _formatting on incoming messages"),
 				PIDGIN_PREFS_ROOT "/conversations/show_incoming_formatting", vbox);
-	pidgin_prefs_checkbox(_("Close IMs immediately when the tab is closed"),
-				PIDGIN_PREFS_ROOT "/conversations/im/close_immediately", vbox);
 
 	iconpref1 = pidgin_prefs_checkbox(_("Show _detailed information"),
 			PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", vbox);
@@ -2309,6 +2307,7 @@
 	purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/show_group_count");
 	purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/show_warning_level");
 	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/button_type");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/close_immediately");
 	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/ctrl_enter_sends");
 	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/enter_sends");
 	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/escape_closes");
--- a/pidgin/plugins/convcolors.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/pidgin/plugins/convcolors.c	Sat Dec 15 05:12:24 2007 +0000
@@ -48,22 +48,27 @@
 #define	PREF_SEND	PREF_PREFIX "/send"
 #define	PREF_SEND_C	PREF_SEND "/color"
 #define	PREF_SEND_F	PREF_SEND "/format"
+#define	PREF_SEND_E	PREF_SEND "/enabled"
 
 #define PREF_RECV	PREF_PREFIX "/recv"
 #define	PREF_RECV_C	PREF_RECV "/color"
 #define	PREF_RECV_F	PREF_RECV "/format"
+#define	PREF_RECV_E	PREF_RECV "/enabled"
 
 #define PREF_SYSTEM	PREF_PREFIX "/system"
 #define	PREF_SYSTEM_C	PREF_SYSTEM "/color"
 #define	PREF_SYSTEM_F	PREF_SYSTEM "/format"
+#define	PREF_SYSTEM_E	PREF_SYSTEM "/enabled"
 
 #define PREF_ERROR	PREF_PREFIX "/error"
 #define	PREF_ERROR_C	PREF_ERROR "/color"
 #define	PREF_ERROR_F	PREF_ERROR "/format"
+#define	PREF_ERROR_E	PREF_ERROR "/enabled"
 
 #define PREF_NICK	PREF_PREFIX "/nick"
 #define	PREF_NICK_C	PREF_NICK "/color"
 #define	PREF_NICK_F	PREF_NICK "/format"
+#define	PREF_NICK_E	PREF_NICK "/enabled"
 
 enum
 {
@@ -104,7 +109,10 @@
 	if (!formats[i].prefix)
 		return FALSE;
 
-	if ((purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM &&
+	g_snprintf(tmp, sizeof(tmp), "%s/enabled", formats[i].prefix);
+
+	if (!purple_prefs_get_bool(tmp) ||
+			(purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM &&
 			!purple_prefs_get_bool(PREF_IMS)) ||
 			(purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT &&
 			!purple_prefs_get_bool(PREF_CHATS)))
@@ -223,17 +231,29 @@
 }
 
 static void
+toggle_enabled(GtkWidget *widget, gpointer data)
+{
+	const char *prefix = (char *)data;
+	gboolean e;
+	char tmp[128];
+
+	g_snprintf(tmp, sizeof(tmp), "%s/enabled", prefix);
+	e = purple_prefs_get_bool(tmp);
+	purple_prefs_set_bool(tmp, !e);
+}
+
+static void
 toggle_something(const char *prefix, int format)
 {
 	int f;
 	char tmp[128];
-	
+
 	g_snprintf(tmp, sizeof(tmp), "%s/format", prefix);
 	f = purple_prefs_get_int(tmp);
 	f ^= format;
 	purple_prefs_set_int(tmp, f);
 }
-		
+
 static void
 toggle_bold(GtkWidget *widget, gpointer data)
 {
@@ -252,6 +272,22 @@
 	toggle_something(data, FONT_UNDERLINE);
 }
 
+static void
+enable_toggled(const char *name, PurplePrefType type, gconstpointer val, gpointer data)
+{
+	GtkWidget *widget = (GtkWidget *)data;
+
+	gtk_widget_set_sensitive(widget, GPOINTER_TO_INT(val));
+}
+
+static void
+disconnect_prefs_callbacks(GtkObject *object, gpointer data)
+{
+	PurplePlugin *plugin = (PurplePlugin *)data;
+
+	purple_prefs_disconnect_by_handle(plugin);
+}
+
 static GtkWidget *
 get_config_frame(PurplePlugin *plugin)
 {
@@ -265,9 +301,14 @@
 	for (i = 0; formats[i].prefix; i++)
 	{
 		char tmp[128];
+		char tmp2[128];
 		int f;
+		gboolean e;
 		GtkWidget *vbox, *hbox, *button;
 
+		g_snprintf(tmp2, sizeof(tmp2), "%s/enabled", formats[i].prefix);
+		e = purple_prefs_get_bool(tmp2);
+
 		g_snprintf(tmp, sizeof(tmp), "%s/format", formats[i].prefix);
 		f = purple_prefs_get_int(tmp);
 
@@ -278,11 +319,20 @@
 		hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
 		gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
 
+		button = gtk_check_button_new_with_label(_("Enabled"));
+		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+		if (e)
+			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
+		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(toggle_enabled),
+				formats[i].prefix);
+
 		button = pidgin_pixbuf_button_from_stock(" Color", GTK_STOCK_SELECT_COLOR,
 				PIDGIN_BUTTON_HORIZONTAL);
 		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
 		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(set_color),
 				formats[i].prefix);
+		gtk_widget_set_sensitive(button, e);
+		purple_prefs_connect_callback(plugin, tmp2, enable_toggled, button);
 
 		button = gtk_check_button_new_with_label(_("Bold"));
 		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
@@ -290,22 +340,29 @@
 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
 		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(toggle_bold),
 				formats[i].prefix);
-		
+		gtk_widget_set_sensitive(button, e);
+		purple_prefs_connect_callback(plugin, tmp2, enable_toggled, button);
+
 		button = gtk_check_button_new_with_label(_("Italic"));
 		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
 		if (f & FONT_ITALIC)
 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
 		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(toggle_italic),
 				formats[i].prefix);
-		
+		gtk_widget_set_sensitive(button, e);
+		purple_prefs_connect_callback(plugin, tmp2, enable_toggled, button);
+
 		button = gtk_check_button_new_with_label(_("Underline"));
 		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
 		if (f & FONT_UNDERLINE)
 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
 		g_signal_connect(G_OBJECT(button), "clicked",
 				G_CALLBACK(toggle_underline), formats[i].prefix);
+		gtk_widget_set_sensitive(button, e);
+		purple_prefs_connect_callback(plugin, tmp2, enable_toggled, button);
 	}
 
+	g_signal_connect(GTK_OBJECT(ret), "destroy", G_CALLBACK(disconnect_prefs_callbacks), plugin);
 	frame = pidgin_make_frame(ret, _("General"));
 	pidgin_prefs_checkbox(_("Ignore incoming format"), PREF_IGNORE, frame);
 	pidgin_prefs_checkbox(_("Apply in Chats"), PREF_CHATS, frame);
@@ -388,6 +445,12 @@
 	purple_prefs_add_int(PREF_SYSTEM_F, FONT_ITALIC);
 	purple_prefs_add_int(PREF_ERROR_F, FONT_BOLD | FONT_UNDERLINE);
 	purple_prefs_add_int(PREF_NICK_F, FONT_BOLD);
+
+	purple_prefs_add_bool(PREF_SEND_E, TRUE);
+	purple_prefs_add_bool(PREF_RECV_E, TRUE);
+	purple_prefs_add_bool(PREF_SYSTEM_E, TRUE);
+	purple_prefs_add_bool(PREF_ERROR_E, TRUE);
+	purple_prefs_add_bool(PREF_NICK_E, TRUE);
 }
 
 PURPLE_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info)
--- a/pidgin/plugins/pidginrc.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/pidgin/plugins/pidginrc.c	Sat Dec 15 05:12:24 2007 +0000
@@ -494,7 +494,7 @@
 	gtk_box_pack_start(GTK_BOX(frame), hbox, FALSE, FALSE, 0);
 
 	tmp = g_strdup_printf(_("Write settings to %s%sgtkrc-2.0"),
-	                      homepath, G_DIR_SEPARATOR_S);
+	                      homepath, G_DIR_SEPARATOR_S ".purple" G_DIR_SEPARATOR_S);
 	check = gtk_button_new_with_label(tmp);
 	g_free(tmp);
 	gtk_box_pack_start(GTK_BOX(hbox), check, FALSE, FALSE, 0);
--- a/pidgin/plugins/timestamp.c	Sat Dec 15 05:02:35 2007 +0000
+++ b/pidgin/plugins/timestamp.c	Sat Dec 15 05:12:24 2007 +0000
@@ -49,11 +49,17 @@
 	const char *mdate;
 	int y, height;
 	GdkRectangle rect;
-	
+
 	/* display timestamp */
 	mdate = purple_utf8_strftime(then == 0 ? "%H:%M" : "\n%H:%M",
 		localtime(&now));
 	gtk_text_buffer_get_end_iter(buffer, &iter);
+
+	if (gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), "TIMESTAMP") == NULL)
+		gtk_text_buffer_create_tag(buffer, "TIMESTAMP",
+			"foreground", "#888888", "justification", GTK_JUSTIFY_CENTER,
+			"weight", PANGO_WEIGHT_BOLD, NULL);
+
 	gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, mdate,
 		strlen(mdate), "TIMESTAMP", NULL);
 
@@ -95,17 +101,9 @@
 static void
 timestamp_new_convo(PurpleConversation *conv)
 {
-	PidginConversation *gtk_conv = PIDGIN_CONVERSATION(conv);
-	GtkTextBuffer *buffer;
-
 	if (!g_list_find(purple_get_conversations(), conv))
 		return;
 
-	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_conv->imhtml));
-	gtk_text_buffer_create_tag(buffer, "TIMESTAMP",
-		"foreground", "#888888", "justification", GTK_JUSTIFY_CENTER,
-		"weight", PANGO_WEIGHT_BOLD, NULL);
-
 	purple_conversation_set_data(conv, "timestamp-last", GINT_TO_POINTER(0));
 }
 
--- a/po/de.po	Sat Dec 15 05:02:35 2007 +0000
+++ b/po/de.po	Sat Dec 15 05:12:24 2007 +0000
@@ -11,9 +11,9 @@
 msgstr ""
 "Project-Id-Version: de\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-11-22 21:19+0100\n"
-"PO-Revision-Date: 2007-11-17 16:14+0100\n"
-"Last-Translator: Bjoern Voigt <bjoern@cs.tu-berlin.de>\n"
+"POT-Creation-Date: 2007-11-28 10:03+0100\n"
+"PO-Revision-Date: 2007-11-28 10:03+0100\n"
+"Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n"
 "Language-Team: Deutsch <de@li.org>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -21,6 +21,8 @@
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Generator: KBabel 1.11.4\n"
 
+#. Translators may want to transliterate the name.
+#. It is not to be translated.
 msgid "Finch"
 msgstr "Finch"
 
@@ -493,6 +495,14 @@
 msgid "Re-enable Account"
 msgstr "Konten reaktivieren"
 
+msgid ""
+"The account has disconnected and you are no longer in this chat. You will be "
+"automatically rejoined in the chat when the account reconnects."
+msgstr ""
+"Das Konto wurde getrennt und Sie sind nicht mehr in diesem Chat. Sie werden "
+"automatisch wieder mit dem Chat verbunden, wenn das Konto wieder verbunden "
+"ist."
+
 msgid "No such command."
 msgstr "Es gibt kein solches Kommando."
 
@@ -9785,6 +9795,9 @@
 msgid "_Merge"
 msgstr "_Zusammenführen"
 
+msgid "Room _List"
+msgstr "Ra_umliste"
+
 msgid ""
 "Please enter the appropriate information about the chat you would like to "
 "join.\n"
@@ -10059,19 +10072,19 @@
 msgid "Re-enable"
 msgstr "Reaktivieren"
 
-msgid "Ignore"
-msgstr "Ignorieren"
-
-#, c-format
-msgid "%d account was disabled because you signed on from another location."
+msgid "Welcome back!"
+msgstr "Willkommen zurück!"
+
+#, c-format
+msgid "%d account was disabled because you signed on from another location:"
 msgid_plural ""
-"%d accounts were disabled because you signed on from another location."
+"%d accounts were disabled because you signed on from another location:"
 msgstr[0] ""
 "%d Konto wurde deaktiviert, da Sie sich von einem anderen Ort angemeldet "
-"haben."
+"haben:"
 msgstr[1] ""
 "%d Konten wurden deaktiviert, da Sie sich von einem anderen Ort angemeldet "
-"haben."
+"haben:"
 
 msgid "<b>Username:</b>"
 msgstr "<b>Benutzername:</b>"
@@ -10155,11 +10168,11 @@
 "Bitte geben Sie einen Alias und geeignete Informationen über den Chat ein, "
 "den Sie in Ihre Buddy-Liste aufnehmen wollen.\n"
 
-msgid "Autojoin when account becomes online."
-msgstr "Automatisch beitreten, wenn das Konto online geht."
-
-msgid "Hide chat when the window is closed."
-msgstr "Chat verstecken, wenn das Fenster geschlossen wird."
+msgid "Auto_join when account becomes online."
+msgstr "Automatisch _beitreten, wenn das Konto online geht."
+
+msgid "_Hide chat when the window is closed."
+msgstr "_Chat verstecken, wenn das Fenster geschlossen wird."
 
 msgid "Please enter the name of the group to be added."
 msgstr "Bitte geben Sie den Namen der Gruppe ein, die hinzugefügt werden soll."
@@ -10237,6 +10250,9 @@
 msgid "Un-Ignore"
 msgstr "Nicht Ignorieren"
 
+msgid "Ignore"
+msgstr "Ignorieren"
+
 msgid "Get Away Message"
 msgstr "Neue Abwesenheitsnachricht abholen"
 
@@ -11033,6 +11049,15 @@
 msgid "_Reset formatting"
 msgstr "Formatierung _zurücksetzen"
 
+msgid "_Smile!"
+msgstr "_Lächeln!"
+
+msgid "_Insert"
+msgstr "_Einfügen"
+
+msgid "_Font"
+msgstr "_Schrift"
+
 msgid "Hyperlink color"
 msgstr "Hyperlink-Farbe"
 
@@ -11127,9 +11152,6 @@
 msgid "Insert Link"
 msgstr "Link einfügen"
 
-msgid "_Insert"
-msgstr "_Einfügen"
-
 #, c-format
 msgid "Failed to store image: %s\n"
 msgstr "Speichern des Bildes fehlgeschlagen: %s\n"
@@ -11144,9 +11166,6 @@
 msgid "Smile!"
 msgstr "Lächeln!"
 
-msgid "_Font"
-msgstr "_Schrift"
-
 msgid "Group Items"
 msgstr "Elemente gruppieren"
 
@@ -11231,9 +11250,6 @@
 msgid "_Horizontal rule"
 msgstr "_Horizontale Linie"
 
-msgid "_Smile!"
-msgstr "_Lächeln!"
-
 #, c-format
 msgid ""
 "Are you sure you want to permanently delete the log of the conversation with "
@@ -11613,9 +11629,6 @@
 msgid "Show _formatting on incoming messages"
 msgstr "Zeige _Formatierung bei ankommenden Nachrichten"
 
-msgid "Close IMs immediately when the tab is closed"
-msgstr "Schließe IMs sofort, wenn der Reiter geschlossen wird"
-
 msgid "Show _detailed information"
 msgstr "_Detaillierte Informationen anzeigen"
 
@@ -13119,6 +13132,3 @@
 msgid "This plugin is useful for debbuging XMPP servers or clients."
 msgstr ""
 "Dieses Plugin ist nützlich zur Fehlersuche in XMPP-Servern oder -Clients."
-
-msgid "Buddy"
-msgstr "Buddy"