changeset 27741:6befd211e707

propagate from branch 'im.pidgin.pidgin' (head e07a38238ee8acc8258a095a26e721d95125cb05) to branch 'im.pidgin.pidgin.yaz' (head 6a0bd510aa27104e63a52cca66874f672dc37dfa)
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Wed, 28 Nov 2007 08:44:35 +0000
parents ae8a9f2866bd (current diff) 0bf7b100a75f (diff)
children 2443ea74b0f4
files pidgin/gtkconv.c pidgin/gtkimhtml.c pidgin/gtkprefs.c
diffstat 26 files changed, 431 insertions(+), 239 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Mon Nov 26 07:49:34 2007 +0000
+++ b/COPYRIGHT	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/doc/finch.1.in	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/finch/finch.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/finch/libgnt/gntentry.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/finch/libgnt/gntmain.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/finch/libgnt/gntwindow.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/finch/libgnt/gntwm.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/libpurple/certificate.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/libpurple/plugins/ssl/ssl-gnutls.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/libpurple/protocols/msn/notification.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/libpurple/protocols/msnp9/msn.c	Wed Nov 28 08:44:35 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/notification.c	Mon Nov 26 07:49:34 2007 +0000
+++ b/libpurple/protocols/msnp9/notification.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/libpurple/protocols/msnp9/user.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/libpurple/win32/libc_interface.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/pidgin/gtkblist.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/pidgin/gtkconv.c	Wed Nov 28 08:44:35 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:
@@ -270,43 +267,6 @@
 	return FALSE;
 }
 
-static gboolean
-size_allocate_cb(GtkWidget *w, GtkAllocation *allocation, PidginConversation *gtkconv)
-{
-	PurpleConversation *conv = gtkconv->active_conv;
-
-	if (!GTK_WIDGET_VISIBLE(w))
-		return FALSE;
-
-	if (!PIDGIN_IS_PIDGIN_CONVERSATION(conv))
-		return FALSE;
-	if (gtkconv->auto_resize) {
-		return FALSE;
-	}
-
-	if (gdk_window_get_state(gtkconv->win->window->window) & GDK_WINDOW_STATE_MAXIMIZED) {
-		return FALSE;
-	}
-
-	/* I find that I resize the window when it has a bunch of conversations in it, mostly so that the
-	 * tab bar will fit, but then I don't want new windows taking up the entire screen.  I check to see
-	 * if there is only one conversation in the window.  This way we'll be setting new windows to the
-	 * size of the last resized new window. */
-	/* I think that the above justification is not the majority, and that the new tab resizing should
-	 * negate it anyway.  --luke */
-	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
-	{
-		if (w == gtkconv->lower_hbox)
-			purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/im/entry_height", allocation->height);
-	}
-	else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT)
-	{
-		if (w == gtkconv->lower_hbox)
-			purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/chat/entry_height", allocation->height);
-	}
-	return FALSE;
-}
-
 static void
 default_formatize(PidginConversation *c)
 {
@@ -456,18 +416,6 @@
 	gtkconv->send_history = g_list_prepend(first, NULL);
 }
 
-static void
-reset_default_size(PidginConversation *gtkconv)
-{
-	PurpleConversation *conv = gtkconv->active_conv;
-	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT)
-		gtk_widget_set_size_request(gtkconv->lower_hbox, -1,
-					    purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/entry_height"));
-	else
-		gtk_widget_set_size_request(gtkconv->lower_hbox, -1,
-					    purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/im/entry_height"));
-}
-
 static gboolean
 check_for_and_do_command(PurpleConversation *conv)
 {
@@ -577,7 +525,6 @@
 
 	if (check_for_and_do_command(conv)) {
 		if (gtkconv->entry_growing) {
-			reset_default_size(gtkconv);
 			gtkconv->entry_growing = FALSE;
 		}
 		gtk_imhtml_clear(GTK_IMHTML(gtkconv->entry));
@@ -637,7 +584,6 @@
 
 	gtk_imhtml_clear(GTK_IMHTML(gtkconv->entry));
 	if (gtkconv->entry_growing) {
-		reset_default_size(gtkconv);
 		gtkconv->entry_growing = FALSE;
 	}
 	gtkconv_set_unseen(gtkconv, PIDGIN_UNSEEN_NONE);
@@ -4397,7 +4343,7 @@
 	gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menuitem, 1);
 }
 
-static void resize_imhtml_cb(PidginConversation *gtkconv)
+static gboolean resize_imhtml_cb(PidginConversation *gtkconv)
 {
 	GtkTextBuffer *buffer;
 	GtkTextIter iter;
@@ -4434,18 +4380,12 @@
 
 	diff = height - gtkconv->entry->allocation.height;
 
-	if (diff > 0) {
-		gtk_widget_size_request(gtkconv->lower_hbox, &sr);
-		gtkconv->entry_growing = TRUE;
-
-		/* uncomment this to auto resize even after the user manually
-		   resizes
-		gtk_paned_set_position(GTK_PANED(gtkconv->lower_hbox->parent->parent),
-			-1);
-		*/
-		gtk_widget_set_size_request(gtkconv->lower_hbox, -1,
-			diff + gtkconv->lower_hbox->allocation.height);
-	}
+	gtk_widget_size_request(gtkconv->lower_hbox, &sr);
+	gtkconv->entry_growing = TRUE;
+
+	gtk_widget_set_size_request(gtkconv->lower_hbox, -1,
+		diff + gtkconv->lower_hbox->allocation.height);
+	return FALSE;
 }
 
 static void
@@ -4715,19 +4655,15 @@
 static GtkWidget *
 setup_common_pane(PidginConversation *gtkconv)
 {
-	GtkWidget *paned, *vbox, *frame, *imhtml_sw, *event_box;
+	GtkWidget *vbox, *frame, *imhtml_sw, *event_box;
 	GtkCellRenderer *rend;
 	GtkTreePath *path;
 	PurpleConversation *conv = gtkconv->active_conv;
 	gboolean chat = (conv->type == PURPLE_CONV_TYPE_CHAT);
 	GtkPolicyType imhtml_sw_hscroll;
 
-	paned = gtk_vpaned_new();
-	gtk_widget_show(paned);
-
 	/* Setup the top part of the pane */
 	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-	gtk_paned_pack1(GTK_PANED(paned), vbox, TRUE, TRUE);
 	gtk_widget_show(vbox);
 
 	/* Setup the info pane */
@@ -4822,30 +4758,18 @@
 	g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_release_event",
 	                 G_CALLBACK(refocus_entry_cb), gtkconv);
 
-	/* Setup the bottom half of the conversation window */
-	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-	gtk_paned_pack2(GTK_PANED(paned), vbox, FALSE, TRUE);
-	gtk_widget_show(vbox);
-
 	gtkconv->lower_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-	gtk_box_pack_start(GTK_BOX(vbox), gtkconv->lower_hbox, TRUE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), gtkconv->lower_hbox, FALSE, FALSE, 0);
 	gtk_widget_show(gtkconv->lower_hbox);
 
-	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-	gtk_box_pack_end(GTK_BOX(gtkconv->lower_hbox), vbox, TRUE, TRUE, 0);
-	gtk_widget_show(vbox);
-
 	/* Setup the toolbar, entry widget and all signals */
 	frame = pidgin_create_imhtml(TRUE, &gtkconv->entry, &gtkconv->toolbar, NULL);
-	gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(gtkconv->lower_hbox), frame, TRUE, TRUE, 0);
 	gtk_widget_show(frame);
 
 	gtk_widget_set_name(gtkconv->entry, "pidgin_conv_entry");
 	gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->entry),
 			purple_account_get_protocol_name(conv->account));
-	gtk_widget_set_size_request(gtkconv->lower_hbox, -1,
-			chat ? purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/entry_height") :
-			purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/im/entry_height"));
 
 	g_signal_connect(G_OBJECT(gtkconv->entry), "populate-popup",
 	                 G_CALLBACK(entry_popup_menu_cb), gtkconv);
@@ -4855,8 +4779,6 @@
 	                       G_CALLBACK(send_cb), gtkconv);
 	g_signal_connect_after(G_OBJECT(gtkconv->entry), "button_press_event",
 	                       G_CALLBACK(entry_stop_rclick_cb), NULL);
-	g_signal_connect(G_OBJECT(gtkconv->lower_hbox), "size-allocate",
-	                 G_CALLBACK(size_allocate_cb), gtkconv);
 
 	gtkconv->entry_buffer =
 		gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->entry));
@@ -4879,7 +4801,7 @@
 	default_formatize(gtkconv);
 	g_signal_connect_after(G_OBJECT(gtkconv->entry), "format_function_clear",
 	                       G_CALLBACK(clear_formatting_cb), gtkconv);
-	return paned;
+	return vbox;
 }
 
 static void
@@ -5139,6 +5061,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);
@@ -7181,6 +7104,8 @@
 			gtk_widget_show(gtkconv->toolbar);
 		else
 			gtk_widget_hide(gtkconv->toolbar);
+
+		g_idle_add((GSourceFunc)resize_imhtml_cb,gtkconv);
 	}
 }
 
@@ -7682,7 +7607,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	Mon Nov 26 07:49:34 2007 +0000
+++ b/pidgin/gtkdialogs.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/pidgin/gtkimhtml.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/pidgin/gtkimhtmltoolbar.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/pidgin/gtkprefs.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/pidgin/plugins/convcolors.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/pidgin/plugins/pidginrc.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/pidgin/plugins/timestamp.c	Wed Nov 28 08:44:35 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	Mon Nov 26 07:49:34 2007 +0000
+++ b/po/de.po	Wed Nov 28 08:44:35 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-27 10:57+0100\n"
+"PO-Revision-Date: 2007-11-27 10:57+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"
@@ -493,6 +493,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."
 
@@ -10059,19 +10067,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>"
@@ -10237,6 +10245,9 @@
 msgid "Un-Ignore"
 msgstr "Nicht Ignorieren"
 
+msgid "Ignore"
+msgstr "Ignorieren"
+
 msgid "Get Away Message"
 msgstr "Neue Abwesenheitsnachricht abholen"
 
@@ -13119,6 +13130,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"