changeset 27765:ed6de6a3604f

propagate from branch 'im.pidgin.pidgin' (head 3639bb4d5d5a867f6bdb2a82be21e4887179b929) to branch 'im.pidgin.pidgin.yaz' (head 8d569a6f9423673c795c293426cd53ea41e5e716)
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 11 Feb 2008 08:16:15 +0000
parents 5411ca13b878 (current diff) 96934545f5be (diff)
children 056fb36a5770
files libpurple/conversation.c libpurple/protocols/msn/msn.c libpurple/protocols/oscar/oscar.c pidgin/gtkconv.c pidgin/gtkprefs.c
diffstat 33 files changed, 3205 insertions(+), 2357 deletions(-) [+]
line wrap: on
line diff
--- a/autogen.sh	Mon Feb 11 00:50:42 2008 +0000
+++ b/autogen.sh	Mon Feb 11 08:16:15 2008 +0000
@@ -69,5 +69,5 @@
 echo;
 echo "Running ./configure ${CONFIGURE_ARGS} $@"
 echo;
-./configure ${CONFIGURE_ARGS} $@
+#./configure ${CONFIGURE_ARGS} $@
 
--- a/configure.ac	Mon Feb 11 00:50:42 2008 +0000
+++ b/configure.ac	Mon Feb 11 08:16:15 2008 +0000
@@ -136,7 +136,7 @@
 	;;
 esac
 
-ALL_LINGUAS="af am ar az be@latin bg bn bs ca ca@valencia cs da de dz el en_AU en_CA en_GB eo es et eu fa fi fr gl gu he hi hu id it ja ka kn ko ku lo lt mk my_MM nb ne nl nn pa pl pt_BR pt ps ro ru sk sl sq sr sr@latin sv ta te th tr uk ur vi xh zh_CN zh_HK zh_TW"
+ALL_LINGUAS=""
 AM_GLIB_GNU_GETTEXT
 
 dnl If we don't have msgfmt, then po/ is going to fail -- ensure that
@@ -884,8 +884,7 @@
 AC_SUBST(GADU_CFLAGS)
 
 # uncomment the next line to make MSNP14 the available
-# AC_ARG_ENABLE(msnp14,[AC_HELP_STRING([--enable-msnp14], [Disable the newer MSNP14 protocol])],,enable_msnp14=no)
-enable_msnp14=no
+AC_ARG_ENABLE(msnp14,[AC_HELP_STRING([--enable-msnp14], [Enable the newer MSNP14 protocol])],,enable_msnp14=no)
 
 AC_ARG_ENABLE(distrib,,,enable_distrib=no)
 AM_CONDITIONAL(DISTRIB, test "x$enable_distrib" = "xyes")
--- a/libpurple/conversation.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/conversation.c	Mon Feb 11 08:16:15 2008 +0000
@@ -1146,17 +1146,27 @@
 			  PurpleMessageFlags flags, time_t mtime)
 {
 	PurpleConversation *c;
+	char *tmpmessage = NULL;
 
 	g_return_if_fail(im != NULL);
 	g_return_if_fail(message != NULL);
 
 	c = purple_conv_im_get_conversation(im);
 
+	// yaz
+	if (purple_prefs_get_bool("/purple/conversations/msnstyle")) {
+		tmpmessage = g_strdup_printf("<br>%s", message);
+	} else {
+		tmpmessage = g_strdup_printf("%s", message);
+	}
+
 	/* Pass this on to either the ops structure or the default write func. */
 	if (c->ui_ops != NULL && c->ui_ops->write_im != NULL)
-		c->ui_ops->write_im(c, who, message, flags, mtime);
+		c->ui_ops->write_im(c, who, tmpmessage, flags, mtime);
 	else
-		purple_conversation_write(c, who, message, flags, mtime);
+		purple_conversation_write(c, who, tmpmessage, flags, mtime);
+
+	g_free(tmpmessage);
 }
 
 gboolean purple_conv_present_error(const char *who, PurpleAccount *account, const char *what)
--- a/libpurple/notify.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/notify.c	Mon Feb 11 08:16:15 2008 +0000
@@ -458,6 +458,9 @@
 		purple_signal_emit(purple_notify_get_handle(), "displaying-userinfo",
 						 purple_connection_get_account(gc), who, user_info);
 
+		g_return_val_if_fail(g_utf8_validate(who, -1, NULL), NULL); //yaz
+		g_return_val_if_fail(g_utf8_validate(user_info, -1, NULL), NULL); //yaz
+
 		info->ui_handle = ops->notify_userinfo(gc, who, user_info);
 		info->cb = cb;
 		info->cb_user_data = user_data;
--- a/libpurple/protocols/gg/lib/http.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/gg/lib/http.c	Mon Feb 11 08:16:15 2008 +0000
@@ -44,6 +44,7 @@
 
 #include "compat.h"
 #include "libgadu.h"
+#include <glib.h>
 
 /*
  * gg_http_connect() // funkcja pomocnicza
--- a/libpurple/protocols/gg/lib/pubdir50.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/gg/lib/pubdir50.c	Mon Feb 11 08:16:15 2008 +0000
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <glib.h>
 
 #include "libgadu.h"
 
--- a/libpurple/protocols/irc/irc.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/irc/irc.c	Mon Feb 11 08:16:15 2008 +0000
@@ -971,6 +971,12 @@
 	option = purple_account_option_string_new(_("Encodings"), "encoding", IRC_DEFAULT_CHARSET);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
+	option = purple_account_option_bool_new(_("Use SO/SI to send hankaku kana"), "irc_use_sosi", FALSE);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_bool_new(_("Use 8bit to send hankaku kana"), "irc_use_8bit", FALSE);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
 	option = purple_account_option_string_new(_("Username"), "username", "");
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
--- a/libpurple/protocols/irc/parse.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/irc/parse.c	Mon Feb 11 08:16:15 2008 +0000
@@ -35,7 +35,7 @@
 #include <ctype.h>
 
 static char *irc_send_convert(struct irc_conn *irc, const char *string);
-static char *irc_recv_convert(struct irc_conn *irc, const char *string);
+static char *irc_recv_convert(struct irc_conn *irc, char *string);
 
 static void irc_parse_error_cb(struct irc_conn *irc, char *input);
 
@@ -157,6 +157,20 @@
 	{ NULL, NULL, NULL, NULL }
 };
 
+/* yaz */
+#define ASCII	0
+#define KANJI	1
+#define KANA	2
+#define ROMAN	3
+char seq_ascii[] = {0x1B,0x28,0x42,0x00}; /* ESC ( B */
+char seq_kanji[] = {0x1B,0x24,0x42,0x00}; /* ESC $ B */
+char seq_kana[]  = {0x1B,0x28,0x49,0x00}; /* ESC ( I */
+char seq_roman[] = {0x1B,0x28,0x4A,0x00}; /* ESC ( J */
+char *seq[4] = {seq_ascii, seq_kanji, seq_kana, seq_roman};
+char *jisstate[5] = {"ASCII", "KANJI", "KANA", "ROMAN"};
+char SO[] = {0x0E,0x00};
+char SI[] = {0x0F,0x00};
+
 static PurpleCmdRet irc_parse_purple_cmd(PurpleConversation *conv, const gchar *cmd,
                                         gchar **args, gchar **error, void *data)
 {
@@ -224,33 +238,110 @@
 	GError *err = NULL;
 	gchar **encodings;
 	const gchar *enclist;
+	char *escpos = NULL;
+	char *temp = NULL;
+	gboolean iskana = FALSE;
+	char *pos = NULL;
+	gboolean irc_use_sosi, irc_use_8bit;
+	char *strtmp;
+	size_t strtmp_len;
 
 	enclist = purple_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET);
 	encodings = g_strsplit(enclist, ",", 2);
 
+	irc_use_sosi = purple_account_get_bool(irc->account, "irc_use_sosi", FALSE);
+	irc_use_8bit = purple_account_get_bool(irc->account, "irc_use_8bit", FALSE);
+
 	if (encodings[0] == NULL || !g_ascii_strcasecmp("UTF-8", encodings[0])) {
 		g_strfreev(encodings);
 		return g_strdup(string);
 	}
 
-	utf8 = g_convert(string, strlen(string), encodings[0], "UTF-8", NULL, NULL, &err);
+	strtmp  = (char *)sanitize_utf((unsigned char *)string, strlen(string), &strtmp_len);
+	utf8 = g_convert(strtmp, strlen(strtmp), encodings[0], "UTF-8", NULL, NULL, &err);
+
 	if (err) {
 		purple_debug(PURPLE_DEBUG_ERROR, "irc", "Send conversion error: %s\n", err->message);
 		purple_debug(PURPLE_DEBUG_ERROR, "irc", "Sending as UTF-8 instead of %s\n", encodings[0]);
-		utf8 = g_strdup(string);
+		utf8 = g_strdup(strtmp);
 		g_error_free(err);
 	}
+
+	/* yaz */
+	if (!strncasecmp("iso-2022-jp", encodings[0], strlen("iso-2022-jp"))) {
+		escpos = strrchr(utf8, 0x1B);
+		if(escpos && (!strncmp(seq_kanji, escpos, 3) || !strncmp(seq_kana, escpos, 3))){
+			char *oldutf8 = utf8;
+			utf8 = g_realloc(utf8, strlen(utf8)+1+3);
+			if(utf8)
+				strncat(utf8, seq_ascii, 3);
+			else
+				utf8 = oldutf8;
+		}
+
+		if(irc_use_sosi || irc_use_8bit){
+			/* SO/SI */
+			//find kana escape and replace with roman+SO
+			temp = g_malloc0(strlen(utf8) * 7); //XXX should be reasonable size
+			pos = utf8;
+			while(pos < utf8+strlen(utf8)){
+				escpos = strchr(pos, 0x1B);
+				if(escpos){
+					if(!strncmp(seq_kana, escpos, 3)){ /* kana found */
+						iskana = TRUE;
+						strncat(temp, pos, escpos-pos);
+						strcat(temp, seq_roman);
+						if(irc_use_sosi)
+							strcat(temp, SO);
+						pos = escpos+3;
+					} else {
+						if(iskana){
+							char *ptr;
+							ptr = temp + strlen(temp);
+							while(pos<escpos){
+								if(irc_use_8bit)
+									*ptr = *pos + 128; // convert to 8bit
+								else
+									*ptr = *pos;
+								ptr++; pos++;
+							}
+							if(irc_use_sosi)
+								strcat(temp, SI);
+							strncat(temp, escpos, 3);
+							pos = escpos+3;
+							iskana = FALSE;
+						} else {
+							strncat(temp, pos, escpos-pos+3); //include esc
+							pos = escpos+3;
+						}
+					}
+				} else { /* escpos == NULL */
+					strcat(temp, pos);
+					break;
+				}
+			}
+			g_free(utf8);
+			utf8 = temp;
+		}
+	}
+
 	g_strfreev(encodings);
-
+	g_free(strtmp);
 	return utf8;
 }
 
-static char *irc_recv_convert(struct irc_conn *irc, const char *string)
+static char *irc_recv_convert(struct irc_conn *irc, char *string)
 {
 	char *utf8 = NULL;
 	const gchar *charset, *enclist;
 	gchar **encodings;
 	int i;
+	GError *err;
+	gboolean retry;
+	gsize in_len, out_len;
+	int conv_len;
+	char *strtmp;
+	size_t strtmp_len;
 
 	enclist = purple_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET);
 	encodings = g_strsplit(enclist, ",", -1);
@@ -268,13 +359,123 @@
 		if (!g_ascii_strcasecmp("UTF-8", charset)) {
 			if (g_utf8_validate(string, -1, NULL))
 				utf8 = g_strdup(string);
+		} else if (!strncasecmp("iso-2022-jp-2", charset, strlen("iso-2022-jp-2"))){
+			/* pre-process quirky jis */
+			unsigned char *jisstr;
+			unsigned char *ptr, *ptr2;
+			int state = ASCII;
+			int is8bit = FALSE;
+
+			jisstr = (unsigned char *)calloc(1, strlen(string)*7); /* enough? */
+			ptr = (unsigned char *)string; ptr2 = jisstr;
+
+			while(*ptr){
+				if(*ptr == 0x1B){
+					/* escape sequence. */
+					if(*(ptr+1) == 0x28 && *(ptr+2) == 0x42){
+						state = ASCII;
+
+					} else if(*(ptr+1) == 0x24 && *(ptr+2) == 0x42){
+						state = KANJI;
+
+					} else if(*(ptr+1) == 0x28 && *(ptr+2) == 0x49){
+						state = KANA;
+
+					} else if(*(ptr+1) == 0x28 && *(ptr+2) == 0x4a){
+						state = ROMAN;
+
+					}
+					purple_debug(PURPLE_DEBUG_INFO, "irc", "state %s\n", jisstate[state]);
+				}
+				if(*ptr >= 0xA1 && *ptr <= 0xDF){
+					/* raw 8bit */
+					if(!is8bit){
+						strcat((char *)jisstr, seq[KANA]);
+						ptr2 += 3;
+						is8bit = TRUE;
+						purple_debug(PURPLE_DEBUG_INFO, "irc", "8bit = TRUE\n");
+					}
+					*ptr2 = *ptr - 0x80;
+					ptr++ ; ptr2++;
+				} else {
+					/* 7bit */
+					if(*ptr == 0x0E){
+						/* SO */
+						strcat((char *)jisstr, seq[KANA]);
+						ptr++; ptr2 += 3;
+						purple_debug(PURPLE_DEBUG_INFO, "irc", "SO\n");
+						continue;
+					} else if(*ptr == 0x0F){
+						/* SI */
+						strcat((char *)jisstr, seq[state]);
+						purple_debug(PURPLE_DEBUG_INFO, "irc", "SI to %s\n", jisstate[state]);
+						ptr++; ptr2 += 3;
+						purple_debug(PURPLE_DEBUG_INFO, "irc", "SI\n");
+						continue;
+					}
+					if(is8bit){ /* the edge of 8bit -> 7bit */
+						purple_debug(PURPLE_DEBUG_INFO, "irc", "8bit to %s\n", jisstate[state]);
+						strcat((char *)jisstr, seq[state]);
+						ptr2 += 3;
+						is8bit=FALSE;
+						purple_debug(PURPLE_DEBUG_INFO, "irc", "8bit = FALSE\n");
+					}
+					/* copy str */
+					*ptr2 = *ptr;
+					ptr++; ptr2++;
+				}
+			}
+
+			/* convert & error recovery */
+			do {
+				err = NULL;
+				retry = FALSE;
+
+				conv_len = strlen((char *)jisstr);
+				utf8 = g_convert_with_fallback((char *)jisstr, conv_len, "UTF-8", charset,
+							       "?", &in_len, &out_len, &err);
+				if(err != NULL){
+					if(err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE){
+						memmove(jisstr + in_len, jisstr + in_len + 1,
+							conv_len - in_len -1);
+						conv_len--;
+						*(jisstr + conv_len) = '\0';
+						retry = TRUE;
+					}
+					g_error_free(err);
+				}
+			} while(retry);
+
+			if(jisstr)
+				free(jisstr);
+
 		} else {
-			utf8 = g_convert(string, -1, "UTF-8", charset, NULL, NULL, NULL);
+			do {
+				err = NULL;
+				retry = FALSE;
+
+				conv_len = strlen(string);
+				utf8 = g_convert_with_fallback(string, conv_len, "UTF-8", charset,
+							       "?", &in_len, &out_len, &err);
+				if(err != NULL){
+					if(err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE){
+						memmove(string + in_len, string + in_len + 1,
+							 conv_len - in_len -1);
+						conv_len--;
+						*(string + conv_len) = '\0';
+						retry = TRUE;
+					}
+					g_error_free(err);
+				}
+			} while(retry);
 		}
 
-		if (utf8) {
-			g_strfreev(encodings);
-			return utf8;
+
+		if(utf8){
+			strtmp  = (char *)botch_utf((unsigned char *)utf8, strlen(utf8), &strtmp_len);
+ 			g_strfreev(encodings);
+			g_free(utf8);
+			return strtmp;
 		}
 	}
 	g_strfreev(encodings);
--- a/libpurple/protocols/jabber/jabber.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Mon Feb 11 08:16:15 2008 +0000
@@ -374,8 +374,8 @@
 
 void jabber_send(JabberStream *js, xmlnode *packet)
 {
-	char *txt;
-	int len;
+	char *txt, *utf;
+	int len, utflen;
 
 	purple_signal_emit(my_protocol, "jabber-sending-xmlnode", js->gc, &packet);
 
@@ -384,8 +384,9 @@
 		return;
 
 	txt = xmlnode_to_str(packet, &len);
-	jabber_send_raw(js, txt, len);
-	g_free(txt);
+	utf = botch_utf(txt, len, &utflen); //yaz
+	jabber_send_raw(js, utf, utflen);
+	g_free(txt); g_free(utf);
 }
 
 static void jabber_pong_cb(JabberStream *js, xmlnode *packet, gpointer timeout) 
--- a/libpurple/protocols/jabber/message.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/jabber/message.c	Mon Feb 11 08:16:15 2008 +0000
@@ -361,14 +361,19 @@
 				jm->thread_id = xmlnode_get_data(child);
 		} else if(!strcmp(child->name, "body") && !strcmp(xmlns,"jabber:client")) {
 			if(!jm->body) {
-				char *msg = xmlnode_to_str(child, NULL);
+				char *tmp, *msg;
+				int len;
+				tmp = xmlnode_to_str(child, NULL);
+				msg = sanitize_utf(tmp, strlen(tmp), &len);
 				jm->body = purple_strdup_withhtml(msg);
-				g_free(msg);
+				g_free(msg); g_free(tmp);
 			}
 		} else if(!strcmp(child->name, "html") && !strcmp(xmlns,"http://jabber.org/protocol/xhtml-im")) {
-			if(!jm->xhtml && xmlnode_get_child(child, "body")) {
-				char *c;
-				jm->xhtml = xmlnode_to_str(child, NULL);
+			if(!jm->xhtml && xmlnode_get_child(child, "body")){
+				char *tmp, *c;
+				int len;
+				tmp = xmlnode_to_str(child, NULL);
+				jm->xhtml = sanitize_utf(tmp, strlen(tmp), &len);
 			        /* Convert all newlines to whitespace. Technically, even regular, non-XML HTML is supposed to ignore newlines, but Pidgin has, as convention
 			 	 * treated \n as a newline for compatibility with other protocols
 				 */
@@ -376,6 +381,7 @@
 					if (*c == '\n') 
 						*c = ' ';
 				}
+				g_free(tmp);
 			}
 		} else if(!strcmp(child->name, "active") && !strcmp(xmlns,"http://jabber.org/protocol/chatstates")) {
 			jm->chat_state = JM_STATE_ACTIVE;
--- a/libpurple/protocols/jabber/si.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/jabber/si.c	Mon Feb 11 08:16:15 2008 +0000
@@ -38,6 +38,8 @@
 
 #define STREAMHOST_CONNECT_TIMEOUT 15
 
+#include "util.h"
+
 typedef struct _JabberSIXfer {
 	JabberStream *js;
 
@@ -895,8 +897,17 @@
 	JabberIq *iq;
 	xmlnode *si, *file, *feature, *x, *field, *option, *value;
 	char buf[32];
+    gchar *f1 = NULL, *f2 = NULL;
+    size_t dummy;
 
-	xfer->filename = g_path_get_basename(xfer->local_filename);
+    /* yaz */
+    f1 = g_filename_display_basename(xfer->local_filename);
+    f2 = botch_utf(f1, strlen(f1), &dummy);
+    if(f2){
+        purple_xfer_set_filename(xfer, (char *)f2);
+    }
+    g_free(f1); f1 = NULL;
+    g_free(f2); f2 = NULL;
 
 	iq = jabber_iq_new(jsx->js, JABBER_IQ_SET);
 	xmlnode_set_attrib(iq->node, "to", xfer->who);
--- a/libpurple/protocols/msn/msg.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/msn/msg.c	Mon Feb 11 08:16:15 2008 +0000
@@ -522,9 +522,7 @@
 
 	if (data != NULL && len > 0)
 	{
-		msg->body = g_malloc0(len + 1);
-		memcpy(msg->body, data, len);
-		msg->body_len = len;
+		msg->body = botch_utf((void *)data, len, &msg->body_len); /* yaz */
 	}
 	else
 	{
--- a/libpurple/protocols/msn/msn.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/msn/msn.c	Mon Feb 11 08:16:15 2008 +0000
@@ -176,6 +176,8 @@
 	}
 
 	msn_cmdproc_send(cmdproc, "PRP", "MFN %s", alias);
+	// propagate change on server side to local --yaz
+	purple_account_set_alias(account, entry); //oct16 <-- XXX questionable. Sep19.
 
 }
 
@@ -290,6 +292,23 @@
 }
 
 static void
+msn_ipc_init(PurplePlugin *plugin)
+{
+	purple_plugin_ipc_register(plugin, "msn_set_friendly_name",
+				   PURPLE_CALLBACK(msn_act_id),
+				   purple_marshal_VOID__POINTER_POINTER,
+				   purple_value_new(PURPLE_TYPE_UNKNOWN),2,
+				   purple_value_new(PURPLE_TYPE_POINTER),
+				   purple_value_new(PURPLE_TYPE_POINTER));
+}
+
+static void
+msn_ipc_end(PurplePlugin *plugin)
+{
+	purple_plugin_ipc_unregister_all(plugin);
+}
+
+static void
 msn_show_set_home_phone(PurplePluginAction *action)
 {
 	PurpleConnection *gc;
@@ -2148,6 +2167,9 @@
 	msn_switchboard_init();
 	msn_sync_init();
 
+	// yaz
+	msn_ipc_init(plugin);
+
 	return TRUE;
 }
 
@@ -2157,6 +2179,9 @@
 	msn_switchboard_end();
 	msn_sync_end();
 
+	// yaz
+	msn_ipc_end(plugin);
+
 	return TRUE;
 }
 
@@ -2268,7 +2293,7 @@
 	NULL,					/* register_user */
 	NULL,					/* get_cb_info */
 	NULL,					/* get_cb_away */
-	NULL,					/* alias_buddy */
+	NULL,				/* alias_buddy */
 	msn_group_buddy,		/* group_buddy */
 	msn_rename_group,		/* rename_group */
 	NULL,					/* buddy_free */
--- a/libpurple/protocols/msn/switchboard.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/msn/switchboard.c	Mon Feb 11 08:16:15 2008 +0000
@@ -909,13 +909,17 @@
 	}
 	else
 	{
-		serv_got_im(gc, passport, body_final, 0, time(NULL));
+		char *yaz_body_final;
+		yaz_body_final = purple_strreplace(body_final, "\r\n", "<br>"); // replace 0D 0A with <br>
+		purple_debug_info("yaz msn", "yaz_body_final=%s\n", yaz_body_final);
+		serv_got_im(gc, passport, yaz_body_final, 0, time(NULL));
 		if (swboard->conv == NULL)
 		{
 			swboard->conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
 									passport, purple_connection_get_account(gc));
 			swboard->flag |= MSN_SB_FLAG_IM;
 		}
+		g_free(yaz_body_final);
 	}
 
 	g_free(body_final);
--- a/libpurple/protocols/oscar/family_icbm.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/oscar/family_icbm.c	Mon Feb 11 08:16:15 2008 +0000
@@ -52,8 +52,8 @@
 #endif
 
 #include "util.h"
-
-
+/* yaz */
+#include "debug.h"
 /**
  * Add a standard ICBM header to the given bstream with the given
  * information.
@@ -458,6 +458,9 @@
 	guchar cookie[8];
 	GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
 	ByteStream hdrbs;
+	// yaz
+	char *ucs = NULL;
+	gsize bytes;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
 		return -EINVAL;
@@ -497,15 +500,51 @@
 	 * raw data, followed by a series of TLVs.
 	 *
 	 */
+#if 0
 	byte_stream_new(&hdrbs, 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2);
 
 	byte_stream_put16(&hdrbs, 0x0000); /* Unknown! */
 	byte_stream_putraw(&hdrbs, cookie, sizeof(cookie)); /* I think... */
 	byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_CHAT);
-
+#endif
+	//yaz
+	// convert msg to ascii first. if it succeed, send as plain ascii.
+	// if it fails, convert msg into ucs-2be, and send it. 
+	ucs = g_convert(msg, strlen(msg), "ASCII", "UTF-8", NULL, &bytes, NULL);
+	if(ucs){
+		byte_stream_new(&hdrbs, 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2);
+
+		byte_stream_put16(&hdrbs, 0x0000); /* Unknown! */
+		byte_stream_putraw(&hdrbs, cookie, sizeof(cookie)); /* I think... */
+		byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_CHAT);
+
+		aim_tlvlist_add_16(&inner_tlvlist, 0x000a, 0x0001);
+		aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
+		aim_tlvlist_add_raw(&inner_tlvlist, 0x000c, strlen(msg), msg);
+		free(ucs);
+	} else {
+		byte_stream_new(&hdrbs, 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2+4+11);
+
+		byte_stream_put16(&hdrbs, 0x0000); /* Unknown! */
+		byte_stream_putraw(&hdrbs, cookie, sizeof(cookie)); /* I think... */
+		byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_CHAT);
+
+		aim_tlvlist_add_16(&inner_tlvlist, 0x000a, 0x0001);
+		aim_tlvlist_add_raw(&inner_tlvlist, 0x000d, 11, "unicode-2-0");
+		aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
+		//yaz
+		ucs = g_convert(msg, strlen(msg), "UCS-2BE", "UTF-8", NULL, &bytes, NULL);
+		if(ucs){
+			botch_ucs(ucs, bytes);
+			aim_tlvlist_add_raw(&inner_tlvlist, 0x000c, bytes, ucs);
+			free(ucs);
+		}
+	}
+#if 0
 	aim_tlvlist_add_16(&inner_tlvlist, 0x000a, 0x0001);
 	aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
 	aim_tlvlist_add_str(&inner_tlvlist, 0x000c, msg);
+#endif
 	aim_tlvlist_add_chatroom(&inner_tlvlist, 0x2711, exchange, roomname, instance);
 	aim_tlvlist_write(&hdrbs, &inner_tlvlist);
 
--- a/libpurple/protocols/oscar/oft.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/oscar/oft.c	Mon Feb 11 08:16:15 2008 +0000
@@ -642,6 +642,8 @@
 {
 	PeerConnection *conn;
 	size_t size;
+    gchar *f1 = NULL, *f2 = NULL;
+    size_t dummy;
 
 	conn = xfer->data;
 	conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
@@ -679,7 +681,16 @@
 	strncpy((gchar *)conn->xferdata.idstring, "Cool FileXfer", 31);
 	conn->xferdata.modtime = 0;
 	conn->xferdata.cretime = 0;
-	xfer->filename = g_path_get_basename(xfer->local_filename);
+
+    /* yaz */
+    f1 = g_filename_display_basename(xfer->local_filename);
+    f2 = botch_utf(f1, strlen(f1), &dummy);
+    if(f2){
+        purple_xfer_set_filename(xfer, (char *)f2);
+    }
+    g_free(f1); f1 = NULL;
+    g_free(f2); f2 = NULL;
+
 	conn->xferdata.name_length = MAX(64, strlen(xfer->filename) + 1);
 	conn->xferdata.name = (guchar *)g_strndup(xfer->filename, conn->xferdata.name_length - 1);
 
--- a/libpurple/protocols/oscar/oscar.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Mon Feb 11 08:16:15 2008 +0000
@@ -302,7 +302,25 @@
 	gchar *utf8 = NULL;
 
 	if ((encoding == NULL) || encoding[0] == '\0') {
-		purple_debug_info("oscar", "Empty encoding, assuming UTF-8\n");
+		purple_debug_info("yaz oscar", "Empty encoding, validate as UTF-8\n");
+		if(g_utf8_validate(text, textlen, NULL)){
+			size_t newlen;
+			utf8 = sanitize_utf(text, textlen, &newlen);
+			goto done;
+		}
+		// not UTF-8
+		purple_debug_info("yaz oscar", "Empty encoding, assuming UCS-2BE\n");
+		sanitize_ucs(text, textlen);
+		utf8 = g_convert(text, textlen, "UTF-8", "UCS-2BE", NULL, NULL, NULL);
+		if(utf8){
+			if(!g_utf8_validate(utf8, strlen(utf8), NULL)){
+				purple_debug_info("yaz oscar", "Invalid conversion\n");
+				g_free(utf8);
+				utf8 = NULL;
+			}
+		} else {
+			purple_debug_info("yaz oscar", "Conversion failed\n");
+		}
 	} else if (!g_ascii_strcasecmp(encoding, "iso-8859-1")) {
 		utf8 = g_convert(text, textlen, "UTF-8", "iso-8859-1", NULL, NULL, NULL);
 	} else if (!g_ascii_strcasecmp(encoding, "ISO-8859-1-Windows-3.1-Latin-1") ||
@@ -310,6 +328,7 @@
 	{
 		utf8 = g_convert(text, textlen, "UTF-8", "Windows-1252", NULL, NULL, NULL);
 	} else if (!g_ascii_strcasecmp(encoding, "unicode-2-0")) {
+		sanitize_ucs(text, textlen);
 		/* Some official ICQ clients are apparently total crack,
 		 * and have been known to save a UTF-8 string converted
 		 * from the locale character set to UCS-2 (not from UTF-8
@@ -348,7 +367,7 @@
 		else
 			utf8 = g_strndup(text, textlen);
 	}
-
+done:
 	return utf8;
 }
 
@@ -504,7 +523,8 @@
 		b = purple_find_buddy(account, destsn);
 		if ((b != NULL) && (PURPLE_BUDDY_IS_ONLINE(b)))
 		{
-			*msg = g_convert(from, -1, "UCS-2BE", "UTF-8", NULL, &msglen, NULL);
+			*msg = g_convert(from, strlen(from), "UCS-2BE", "UTF-8", NULL, &msglen, NULL);
+			botch_ucs(*msg, msglen);
 			if (*msg != NULL)
 			{
 				*charset = AIM_CHARSET_UNICODE;
@@ -538,7 +558,8 @@
 	/*
 	 * Nothing else worked, so send as UCS-2BE.
 	 */
-	*msg = g_convert(from, -1, "UCS-2BE", "UTF-8", NULL, &msglen, &err);
+	*msg = g_convert(from, strlen(from), "UCS-2BE", "UTF-8", NULL, &msglen, &err);
+	botch_ucs(*msg, msglen);
 	if (*msg != NULL) {
 		*charset = AIM_CHARSET_UNICODE;
 		*charsubset = 0x0000;
@@ -2024,6 +2045,8 @@
 		tmp = purple_plugin_oscar_decode_im_part(account, userinfo->sn, curpart->charset,
 				curpart->charsubset, curpart->data, curpart->datalen);
 		if (tmp != NULL) {
+			purple_str_strip_char(tmp, 0x0d); // yaz: strip CR
+//			purple_debug_info("yaz oscar", "tmp=%s",tmp);
 			g_string_append(message, tmp);
 			g_free(tmp);
 		}
@@ -2125,6 +2148,7 @@
 		char *encoding, *utf8name, *tmp;
 		GHashTable *components;
 
+//		purple_debug_info("yaz oscar", "chat request %s\n", args->msg);
 		if (!args->info.chat.roominfo.name || !args->info.chat.roominfo.exchange) {
 			g_free(message);
 			return 1;
@@ -2147,6 +2171,8 @@
 		g_hash_table_replace(components, g_strdup("room"), utf8name);
 		g_hash_table_replace(components, g_strdup("exchange"),
 				g_strdup_printf("%d", args->info.chat.roominfo.exchange));
+		purple_debug_info("yaz oscar", "about to call serv_got_chat_invite\n");
+//		purple_debug_info("yaz oscar", "name=%s message=%s\n", name ? name : args->info.chat.roominfo.name, message);
 		serv_got_chat_invite(gc,
 				     utf8name,
 				     userinfo->sn,
@@ -2380,7 +2406,7 @@
 	 * for this suck-ass part of the protocol by splitting the string into at
 	 * most 1 baby string.
 	 */
-	msg1 = g_strsplit(args->msg, "\376", (args->type == 0x01 ? 1 : 0));
+	msg1 = g_strsplit(args->msg, "\376", (args->type == 0x01 ? 1 : 0)); // \376 is 0xfe
 	for (numtoks=0; msg1[numtoks]; numtoks++);
 	msg2 = (gchar **)g_malloc((numtoks+1)*sizeof(gchar *));
 	for (i=0; msg1[i]; i++) {
@@ -4424,7 +4450,8 @@
 
 	charset = oscar_charset_check(str);
 	if (charset == AIM_CHARSET_UNICODE) {
-		encoded = g_convert(str, -1, "UCS-2BE", "UTF-8", NULL, ret_len, NULL);
+		encoded = g_convert(str, strlen(str), "UCS-2BE", "UTF-8", NULL, ret_len, NULL);
+		botch_ucs(encoded, *ret_len);
 		*encoding = "unicode-2-0";
 	} else if (charset == AIM_CHARSET_CUSTOM) {
 		encoded = g_convert(str, -1, "ISO-8859-1", "UTF-8", NULL, ret_len, NULL);
@@ -5547,7 +5574,7 @@
 		charsetstr = "unicode-2-0";
 	else if (charset == AIM_CHARSET_CUSTOM)
 		charsetstr = "iso-8859-1";
-	aim_chat_send_im(od, c->conn, 0, buf2, len, charsetstr, "en");
+	aim_chat_send_im(od, c->conn, 0, buf2, len, charsetstr, "JA");
 	g_free(buf2);
 	g_free(buf);
 
--- a/libpurple/protocols/yahoo/util.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/yahoo/util.c	Mon Feb 11 08:16:15 2008 +0000
@@ -29,6 +29,7 @@
 #include "prpl.h"
 
 #include "yahoo.h"
+#include "util.h"
 
 #include <string.h>
 /*
@@ -111,7 +112,8 @@
 char *yahoo_string_encode(PurpleConnection *gc, const char *str, gboolean *utf8)
 {
 	struct yahoo_data *yd = gc->proto_data;
-	char *ret;
+	char *ret, *strtmp;
+	int newlen;
 	const char *to_codeset;
 
 	if (yd->jp && utf8 && *utf8)
@@ -125,7 +127,13 @@
 	else
 		to_codeset = purple_account_get_string(purple_connection_get_account(gc), "local_charset",  "ISO-8859-1");
 
-	ret = g_convert_with_fallback(str, -1, to_codeset, "UTF-8", "?", NULL, NULL, NULL);
+//	strtmp = sanitize_utf((char *)str, strlen((char *)str), &newlen);
+    strtmp = g_strdup(str);
+
+	ret = g_convert_with_fallback(strtmp, strlen(strtmp), to_codeset, "UTF-8", "?", NULL, NULL, NULL);
+
+	g_free(strtmp);
+
 	if (ret)
 		return ret;
 	else
@@ -143,8 +151,9 @@
 char *yahoo_string_decode(PurpleConnection *gc, const char *str, gboolean utf8)
 {
 	struct yahoo_data *yd = gc->proto_data;
-	char *ret;
-	const char *from_codeset;
+	char *ret, *tmp;
+	char *from_codeset;
+	int newlen;
 
 	if (utf8) {
 		if (g_utf8_validate(str, -1, NULL))
@@ -156,10 +165,22 @@
 	else
 		from_codeset = purple_account_get_string(purple_connection_get_account(gc), "local_charset",  "ISO-8859-1");
 
-	ret = g_convert_with_fallback(str, -1, "UTF-8", from_codeset, NULL, NULL, NULL, NULL);
+	/* yaz: it's a kind of voodoo to avoid malconversion of "~". */
+	tmp = g_convert(str, strlen(str), "EUC-JP", from_codeset, NULL, NULL, NULL);
+	if(tmp) { 
+		ret = g_convert(tmp, strlen(tmp), "UTF-8", "EUC-JP", NULL, NULL, NULL);
+		g_free(tmp);
+	} else {
+		ret = g_convert_with_fallback(str, strlen(str), "UTF-8", from_codeset, NULL, NULL, NULL, NULL);
+	}
 
-	if (ret)
+	if (ret){
+		tmp = ret;
+//		ret = botch_utf(tmp, strlen(tmp), &newlen);
+        ret = g_strdup(tmp);
+		g_free(tmp);
 		return ret;
+	}
 	else
 		return g_strdup("");
 }
--- a/libpurple/protocols/yahoo/yahoo.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Mon Feb 11 08:16:15 2008 +0000
@@ -1236,8 +1236,9 @@
 
 #define OUT_CHARSET "utf-8"
 
-static char *yahoo_decode(const char *text)
+static char *yahoo_decode(PurpleConnection *gc, const char *text)
 {
+	struct yahoo_data *yd = gc->proto_data;
 	char *converted = NULL;
 	char *n, *new;
 	const char *end, *p;
@@ -1278,11 +1279,16 @@
 
 	*n = '\0';
 
-	if (strstr(text, "\033$B"))
-		converted = g_convert(new, n - new, OUT_CHARSET, "iso-2022-jp", NULL, NULL, NULL);
-	if (!converted)
-		converted = g_convert(new, n - new, OUT_CHARSET, "iso-8859-1", NULL, NULL, NULL);
-	g_free(new);
+	if (yd->jp) {
+		converted = g_convert(new, n - new, OUT_CHARSET, "SJIS", NULL, NULL, NULL);
+	}
+	if (!yd->jp || !converted) {
+		if (strstr(text, "\033$B"))
+			converted = g_convert(new, n - new, OUT_CHARSET, "iso-2022-jp", NULL, NULL, NULL);
+		if (!converted)
+			converted = g_convert(new, n - new, OUT_CHARSET, "iso-8859-1", NULL, NULL, NULL);
+		g_free(new);
+	}
 
 	return converted;
 }
@@ -1315,8 +1321,8 @@
 	}
 
 	if (who && subj && email && *email) {
-		char *dec_who = yahoo_decode(who);
-		char *dec_subj = yahoo_decode(subj);
+		char *dec_who = yahoo_decode(gc, who);
+		char *dec_subj = yahoo_decode(gc, subj);
 		char *from = g_strdup_printf("%s (%s)", dec_who, email);
 
 		purple_notify_email(gc, dec_subj, from, purple_account_get_username(account),
@@ -3681,6 +3687,10 @@
 	}
 
 	pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, 0);
+    if(!pkt) { // yaz
+        purple_debug_info("yahoo", "yahoo_set_idle: pkt == NULL\n");
+        return;
+    }
 	yahoo_packet_hash_int(pkt, 10, yd->current_status);
 
 	if (yd->current_status == YAHOO_STATUS_CUSTOM) {
@@ -3725,6 +3735,10 @@
 	}
 
 	pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, 0);
+	if(!pkt) {
+		purple_debug_info("yahoo", "yahoo_set_idle: pkt == NULL\n");
+		return;
+	}
 
 	yahoo_packet_hash_int(pkt, 10, yd->current_status);
 	if (yd->current_status == YAHOO_STATUS_CUSTOM) {
@@ -3735,7 +3749,7 @@
 		if (tmp != NULL) {
 			msg = yahoo_string_encode(gc, tmp, NULL);
 			msg2 = purple_markup_strip_html(msg);
-			yahoo_packet_hash_str(pkt, 19, msg2);
+			yahoo_packet_hash_str(pkt, 19, msg2); // yaz: pkt may be NULL.
 		} else {
 			/* get_yahoo_status_from_purple_status() returns YAHOO_STATUS_CUSTOM for
 			 * the generic away state (YAHOO_STATUS_TYPE_AWAY) with no message */
@@ -4406,7 +4420,7 @@
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
 
-#if 0
+#if 1
 	option = purple_account_option_string_new(_("Chat room list URL"), "room_list", YAHOO_ROOMLIST_URL);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c	Mon Feb 11 08:16:15 2008 +0000
@@ -217,7 +217,7 @@
 	PurpleXfer *xfer;
 	struct yahoo_xfer_data *xd;
 	struct yahoo_packet *pkt;
-	gchar *size, *filename, *encoded_filename, *header;
+	gchar *size, *filename, *encoded_filename, *header, *tmp = NULL;
 	guchar *pkt_buf;
 	const char *host;
 	int port;
@@ -225,6 +225,7 @@
 	PurpleConnection *gc;
 	PurpleAccount *account;
 	struct yahoo_data *yd;
+	size_t dummy;
 
 	purple_debug(PURPLE_DEBUG_INFO, "yahoo",
 			   "AAA - in yahoo_sendfile_connected\n");
@@ -251,8 +252,12 @@
 		YAHOO_STATUS_AVAILABLE, yd->session_id);
 
 	size = g_strdup_printf("%" G_GSIZE_FORMAT, purple_xfer_get_size(xfer));
-	filename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
-	encoded_filename = yahoo_string_encode(gc, filename, NULL);
+
+	/* yaz */
+	tmp = g_filename_display_basename(purple_xfer_get_local_filename(xfer));
+	filename = botch_utf(tmp, strlen(tmp), &dummy);
+	g_free(tmp);
+	encoded_filename = yahoo_string_encode(gc, filename, NULL); // this takes utf8 as input. --yaz
 
 	yahoo_packet_hash(pkt, "sssss", 0, purple_connection_get_display_name(gc),
 	  5, xfer->who, 14, "", 27, encoded_filename, 28, size);
--- a/libpurple/protocols/yahoo/yahoo_packet.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_packet.c	Mon Feb 11 08:16:15 2008 +0000
@@ -42,6 +42,7 @@
 {
 	struct yahoo_pair *pair;
 
+	g_return_if_fail(pkt != NULL);
 	g_return_if_fail(value != NULL);
 
 	pair = g_new0(struct yahoo_pair, 1);
@@ -54,6 +55,9 @@
 {
 	struct yahoo_pair *pair;
 
+	g_return_if_fail(pkt != NULL);
+	g_return_if_fail(value != NULL);
+
 	pair = g_new0(struct yahoo_pair, 1);
 	pair->key = key;
 	pair->value = g_strdup_printf("%d", value);
@@ -386,6 +390,9 @@
 {
 	int ret;
 
+	g_return_if_fail(pkt != NULL);
+	g_return_if_fail(yd != NULL);
+
 	ret = yahoo_packet_send(pkt, yd);
 	yahoo_packet_free(pkt);
 	return ret;
--- a/libpurple/protocols/yahoo/yahoo_profile.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_profile.c	Mon Feb 11 08:16:15 2008 +0000
@@ -22,6 +22,7 @@
  */
 
 #define PHOTO_SUPPORT 1
+//original is 1 --yaz
 
 #include "internal.h"
 #include "debug.h"
@@ -761,6 +762,7 @@
 
 #endif /* PHOTO_SUPPORT */
 
+#define PROF_LEN (1024 * 10)
 static void yahoo_got_info(PurpleUtilFetchUrlData *url_data, gpointer user_data,
 		const gchar *url_text, size_t len, const gchar *error_message)
 {
@@ -1011,6 +1013,9 @@
 			g_free(stripped);
 			stripped = purple_utf8_ncr_decode(p);
 			stripped_len = strlen(stripped);
+
+            purple_debug_misc("yahoo", "after utf8 conversion: stripped@1 = (%s)\n",
+                              stripped); //payload --yaz
 			g_free(p);
 		}
 	}
@@ -1022,7 +1027,7 @@
 				strings->charset, NULL, NULL, NULL);
 		yahoo_remove_nonbreaking_spaces(last_updated_utf8_string);
 
-		purple_debug_misc("yahoo", "after utf8 conversion: stripped = (%s)\n", stripped);
+		purple_debug_misc("yahoo", "after utf8 conversion: stripped = (%s)\n", stripped); //payload --yaz
 	}
 
 	if (profile_state == PROFILE_STATE_DEFAULT) {
@@ -1054,47 +1059,48 @@
 		}
 	}
 #endif /* PHOTO_SUPPORT */
+	purple_debug_info("yahoo", "email = %s\n", strings->my_email_string);
 
 	/* extract their Email address and put it in */
 	found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 			strings->my_email_string, (yd->jp ? 4 : 1), " ", 0,
-			strings->private_string, _("E-Mail"), 0, NULL, NULL);
-
+            strings->private_string, _("E-Mail"), 0, NULL, NULL);
+#if 0
 	/* extract the Nickname if it exists */
 	found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 			"Nickname:", 1, "\n", '\n',
-			NULL, _("Nickname"), 0, NULL, NULL);
+            NULL, _("Nickname"), 0, NULL, NULL);
 
 	/* extract their RealName and put it in */
 	found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 			strings->realname_string, (yd->jp ? 3 : 1), "\n", '\n',
-			NULL, _("Real Name"), 0, NULL, NULL);
+            NULL, _("Real Name"), 0, NULL, NULL);
 
 	/* extract their Location and put it in */
 	found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 			strings->location_string, (yd->jp ? 4 : 2), "\n", '\n',
-			NULL, _("Location"), 0, NULL, NULL);
+            NULL, _("Location"), 0, NULL, NULL);
 
 	/* extract their Age and put it in */
 	found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 			strings->age_string, (yd->jp ? 2 : 3), "\n", '\n',
-			NULL, _("Age"), 0, NULL, NULL);
+            NULL, _("Age"), 0, NULL, NULL);
 
 	/* extract their MaritalStatus and put it in */
 	found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 			strings->maritalstatus_string, (yd->jp ? 2 : 3), "\n", '\n',
-			strings->no_answer_string, _("Marital Status"), 0, NULL, NULL);
+            strings->no_answer_string, _("Marital Status"), 0, NULL, NULL);
 
 	/* extract their Gender and put it in */
 	found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 			strings->gender_string, (yd->jp ? 2 : 3), "\n", '\n',
-			strings->no_answer_string, _("Gender"), 0, NULL, NULL);
+            strings->no_answer_string, _("Gender"), 0, NULL, NULL);
 
 	/* extract their Occupation and put it in */
 	found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 			strings->occupation_string, 2, "\n", '\n',
-			NULL, _("Occupation"), 0, NULL, NULL);
-
+            NULL, _("Occupation"), 0, NULL, NULL);
+#endif
 	/* Hobbies, Latest News, and Favorite Quote are a bit different, since
 	 * the values can contain embedded newlines... but any or all of them
 	 * can also not appear.  The way we delimit them is to successively
@@ -1103,18 +1109,18 @@
 	 * next thing to follow this bunch.  (For Yahoo Japan, we check for
 	 * the "Description" ("Self PR") heading instead of "Links".)
 	 */
-
+#if 0
 	if (!purple_markup_extract_info_field(stripped, stripped_len, user_info,
 			strings->hobbies_string, (yd->jp ? 3 : 1), strings->latest_news_string,
-			'\n', "\n", _("Hobbies"), 0, NULL, NULL))
+            '\n', "\n", _("Hobbies"), 0, NULL, NULL))
 	{
 		if (!purple_markup_extract_info_field(stripped, stripped_len, user_info,
 				strings->hobbies_string, 1, strings->favorite_quote_string,
-				'\n', "\n", _("Hobbies"), 0, NULL, NULL))
+                '\n', "\n", _("Hobbies"), 0, NULL, NULL))
 		{
 			found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 					strings->hobbies_string, 1, strings->links_string,
-					'\n', "\n", _("Hobbies"), 0, NULL, NULL);
+                    '\n', "\n", _("Hobbies"), 0, NULL, NULL);
 		}
 		else
 			found = TRUE;
@@ -1124,7 +1130,7 @@
 
 	if (!purple_markup_extract_info_field(stripped, stripped_len, user_info,
 			strings->latest_news_string, 1, strings->favorite_quote_string,
-			'\n', "\n", _("Latest News"), 0, NULL, NULL))
+            '\n', "\n", _("Latest News"), 0, NULL, NULL))
 	{
 		found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 				strings->latest_news_string, (yd->jp ? 2 : 1), strings->links_string,
@@ -1135,7 +1141,7 @@
 
 	found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 			strings->favorite_quote_string, 1, strings->links_string,
-			'\n', "\n", _("Favorite Quote"), 0, NULL, NULL);
+            '\n', "\n", _("Favorite Quote"), 0, NULL, NULL);
 
 	/* Home Page will either be "No home page specified",
 	 * or "Home Page: " and a link.
@@ -1149,7 +1155,7 @@
 		{
 			found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 					strings->home_page_string, 1, "\n", 0, NULL,
-					_("Home Page"), 1, NULL, NULL);
+                    _("Home Page"), 1, NULL, NULL);
 		}
 	}
 
@@ -1164,7 +1170,7 @@
 	{
 		if (purple_markup_extract_info_field(stripped, stripped_len, user_info,
 				strings->cool_link_1_string, 1, "\n", 0, NULL,
-				_("Cool Link 1"), 1, NULL, NULL))
+                _("Cool Link 1"), 1, NULL, NULL))
 		{
 			found = TRUE;
 			if (purple_markup_extract_info_field(stripped, stripped_len, user_info,
@@ -1182,13 +1188,14 @@
 		/* see if Member Since is there, and if so, extract it. */
 		found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 				"Member Since:", 1, last_updated_utf8_string,
-				'\n', NULL, _("Member Since"), 0, NULL, yahoo_info_date_reformat);
+                '\n', NULL, _("Member Since"), 0, NULL, yahoo_info_date_reformat);
 
 		/* extract the Last Updated date and put it in */
 		found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 				last_updated_utf8_string, (yd->jp ? 2 : 1), (yd->jp ? "\n" : " "), (yd->jp ? 0 : '\n'), NULL,
-				_("Last Update"), 0, NULL, (yd->jp ? NULL : yahoo_info_date_reformat));
+                _("Last Update"), 0, NULL, (yd->jp ? NULL : yahoo_info_date_reformat));
 	}
+#endif
 	} /* if (profile_state == PROFILE_STATE_DEFAULT) */
 
 	if(!found)
--- a/libpurple/util.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/util.c	Mon Feb 11 08:16:15 2008 +0000
@@ -1209,6 +1209,8 @@
 		return FALSE;
 
 	q = strstr(p, end_token);
+	if(q == NULL) //yaz
+		return FALSE;
 
 	/* Trim leading blanks */
 	while (*p != '\n' && g_ascii_isspace(*p)) {
@@ -1221,7 +1223,7 @@
 	}
 
 	/* Don't bother with null strings */
-	if (p == q)
+	if (p >= q)
 		return FALSE;
 
 	if (q != NULL && (!no_value_token ||
@@ -4696,3 +4698,232 @@
 	return g_string_free(string, FALSE);
 }
 
+void botch_ucs(gchar *ucs, gssize len)
+{
+	gint i;
+
+ 	for(i=0;i<len;i+=2){
+ 		switch(*(ucs+i)){
+ 		case 0x00:
+ 			switch(*(ucs+i+1)){
+ 			case 0xa2:	// ¢
+ 				*(ucs+i) = 0xff;
+ 				*(ucs+i+1) = 0xe0;
+ 				break;
+ 			case 0xa3:	// £
+ 				*(ucs+i) = 0xff;
+				*(ucs+i+1) = 0xe1;
+ 				break;
+ 			case 0xac:	// ¬
+ 				*(ucs+i) = 0xff;
+ 				*(ucs+i+1) = 0xe2;
+ 				break;
+ 			}
+ 			break;
+ 		case 0x20:	// ‖
+ 			if(*(ucs+i+1) == 0x16){
+ 				*(ucs+i) = 0x22;
+				*(ucs+i+1) = 0x25;
+ 			}
+ 			break;
+ 		case 0x22:	// −
+ 			if(*(ucs+i+1) == 0x12){
+ 				*(ucs+i) = 0xff;
+ 				*(ucs+i+1) = 0x0d;
+ 			}
+ 			break;
+ 		case 0x30:	// 〜
+ 			if(*(ucs+i+1) == 0x1c){
+ 				*(ucs+i) = 0xff;
+ 				*(ucs+i+1) = 0x5e;
+ 			}
+ 			break;
+ 		}
+ 	}
+
+}
+
+void sanitize_ucs(gchar *ucs, gssize len)
+{
+	gint i;
+
+	for(i=0;i<len;i+=2){
+		switch(*(ucs+i)){
+		case 0x22:
+			switch(*(ucs+i+1)){
+			case 0x25:	// ‖
+				*(ucs+i) = 0x20;
+				*(ucs+i+1) = 0x16;
+				break;
+			}
+			break;
+		case 0xff:
+			switch(*(ucs+i+1)){
+			case 0x0d:	// −
+				*(ucs+i) = 0x22;
+				*(ucs+i+1) = 0x12;
+				break;
+			case 0x5e:	// 〜
+				*(ucs+i) = 0x30;
+				*(ucs+i+1) = 0x1c;
+				break;
+			case 0xe0:	// ¢
+				*(ucs+i) = 0x00;
+				*(ucs+i+1) = 0xa2;
+				break;
+			case 0xe1:	// £
+				*(ucs+i) = 0x00;
+				*(ucs+i+1) = 0xa3;
+				break;
+			case 0xe2:	// ¬
+				*(ucs+i) = 0x00;
+				*(ucs+i+1) = 0xac;
+				break;
+			}
+			break;
+		}
+	}
+}
+
+guchar *sanitize_utf(unsigned char *msg, size_t len, size_t *newlen)
+{
+	gint i;
+	size_t bytes;
+	unsigned char *utf;
+
+	utf = g_strndup(msg, len);
+
+	bytes = len;
+
+	for(i=0;i<len;i++){
+		switch(*(utf+i)){
+		case 0xe2:
+			if(*(utf+i+1) == 0x88) {
+				if(*(utf+i+2) == 0xa5) {	// ‖
+					*(utf+i) = 0xe2;
+					*(utf+i+1) = 0x80;
+					*(utf+i+2) = 0x96;
+				}
+			}
+			break;
+		case 0xef:
+			switch(*(utf+i+1)){
+			case 0xbc:
+				if(*(utf+i+2) == 0x8d) {	// −
+					*(utf+i) = 0xe2;
+					*(utf+i+1) = 0x88;
+					*(utf+i+2) = 0x92;
+				}
+				break;
+			case 0xbd:
+				if(*(utf+i+2) == 0x9e) {	// 〜
+					*(utf+i) = 0xe3;
+					*(utf+i+1) = 0x80;
+					*(utf+i+2) = 0x9c;
+				}
+				break;
+			case 0xbf:
+				switch(*(utf+i+2)){
+			       case 0xa0:// ¢
+				       *(utf+i) = 0xc2;
+				       *(utf+i+1) = 0xa2;
+				       memmove(utf+i+2, utf+i+3,
+					       len-i-3); //1byte詰める
+				       bytes--;
+				       break;
+			       case 0xa1:	// £
+				       *(utf+i) = 0xc2;
+				       *(utf+i+1) = 0xa3;
+				       memmove(utf+i+2, utf+i+3,
+					       len-i-3); //1byte詰める
+				       bytes--;
+				       break;
+			       case 0xa2:	// ¬
+				       *(utf+i) = 0xc2;
+				       *(utf+i+1) = 0xac;
+				       memmove(utf+i+2, utf+i+3,
+					       len-i-3); //1byte詰める
+				       bytes--;
+				       break;
+			       }
+			       break;
+			}
+			break;
+		}
+	}
+	*(utf+bytes)= 0x00; //terminate
+	*newlen = bytes;
+	return utf;
+}
+
+
+guchar *botch_utf(const void *msg, size_t len, size_t *newlen)
+{
+ 	int i,bytes;
+	unsigned char *utf;
+
+	bytes = len;
+
+	utf = g_malloc0(bytes*3/2+1); /* new length might be 3/2 in the worst case */
+	memcpy(utf, msg, bytes);
+	
+ 	for(i=0;i<bytes;i++){
+ 		switch(*(utf+i)){
+ 		case 0xc2:
+ 			switch(*(utf+i+1)){
+ 			case 0xa2:	// ¢
+ 				*(utf+i) = 0xef;
+ 				*(utf+i+1) = 0xbf;
+				memmove(utf+i+3, utf+i+2, bytes-i-2);
+				*(utf+i+2) = 0xa0;
+				bytes++;
+ 				break;
+ 			case 0xa3:	// £
+ 				*(utf+i) = 0xef;
+ 				*(utf+i+1) = 0xbf;
+				memmove(utf+i+3, utf+i+2, bytes-i-2);
+				*(utf+i+2) = 0xa1;
+				bytes++;
+ 				break;
+ 			case 0xac:	// ¬
+ 				*(utf+i) = 0xef;
+ 				*(utf+i+1) = 0xbf;
+				memmove(utf+i+3, utf+i+2, bytes-i-2);
+				*(utf+i+2) = 0xa2;
+				bytes++;
+ 				break;
+ 			}
+ 			break;
+ 		case 0xe2:
+			switch(*(utf+i+1)){
+			case 0x80:	// ‖
+				if(*(utf+i+2) == 0x96){
+					*(utf+i) = 0xe2;
+					*(utf+i+1) = 0x88;
+					*(utf+i+2) = 0xa5;
+				}
+				break;
+			case 0x88:	// −
+				if(*(utf+i+1) == 0x92){
+					*(utf+i) = 0xef;
+					*(utf+i+1) = 0xbc;
+					*(utf+i+2) = 0x8d;
+				}
+				break;
+			}
+			break;
+ 		case 0xe3:	// 〜
+ 			if(*(utf+i+1) == 0x80){
+				if(*(utf+i+2) == 0x9c){
+					*(utf+i) = 0xef;
+					*(utf+i+1) = 0xbd;
+					*(utf+i+2) = 0x9e;
+				}
+ 			}
+ 			break;
+ 		} //switch
+ 	}
+	*(utf+bytes) = 0x00; //terminate
+	*newlen = bytes;
+	return utf;
+}
--- a/libpurple/util.h	Mon Feb 11 00:50:42 2008 +0000
+++ b/libpurple/util.h	Mon Feb 11 08:16:15 2008 +0000
@@ -1254,4 +1254,10 @@
 }
 #endif
 
+/* to address incompatibility with cp932. */
+void botch_ucs(gchar *ucs, gssize len);
+void sanitize_ucs(gchar *ucs, gssize len);
+guchar *botch_utf(const void *utf, size_t len, size_t *newlen);
+guchar *sanitize_utf(unsigned char *msg, size_t len, size_t *newlen);
+
 #endif /* _PURPLE_UTIL_H_ */
--- a/pidgin/gtkconv.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/pidgin/gtkconv.c	Mon Feb 11 08:16:15 2008 +0000
@@ -114,6 +114,10 @@
 static GdkColor *nick_colors = NULL;
 static guint nbr_nick_colors;
 
+/* yaz. If you want to use shortcut keys that may conflict with
+   inputmethods, change this to 1. */
+#define ENABLE_SHORTCUT 0
+
 typedef struct {
 	GtkWidget *window;
 
@@ -266,6 +270,43 @@
 	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)
 {
@@ -415,6 +456,18 @@
 	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)
 {
@@ -531,6 +584,7 @@
 
 	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));
@@ -590,6 +644,7 @@
 
 	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);
@@ -2942,20 +2997,33 @@
 
 	{ "/Conversation/sep0", NULL, NULL, 0, "<Separator>", NULL },
 
+#if ENABLE_SHORTCUT
 	{ N_("/Conversation/_Find..."), NULL, menu_find_cb, 0,
 			"<StockItem>", GTK_STOCK_FIND },
+#else
+	{ N_("/Conversation/_Find..."), NULL, menu_find_cb, 0,
+      "<Item>", NULL },
+#endif
 	{ N_("/Conversation/View _Log"), NULL, menu_view_log_cb, 0, "<Item>", NULL },
 	{ N_("/Conversation/_Save As..."), NULL, menu_save_as_cb, 0,
 			"<StockItem>", GTK_STOCK_SAVE_AS },
+#if ENABLE_SHORTCUT
 	{ N_("/Conversation/Clea_r Scrollback"), "<CTL>L", menu_clear_cb, 0, "<StockItem>", GTK_STOCK_CLEAR },
-
+#else
+	{ N_("/Conversation/Clea_r Scrollback"), NULL, menu_clear_cb, 0, "<Item>", NULL },
+#endif
 	{ "/Conversation/sep1", NULL, NULL, 0, "<Separator>", NULL },
 
 	{ N_("/Conversation/Se_nd File..."), NULL, menu_send_file_cb, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SEND_FILE },
 	{ N_("/Conversation/Add Buddy _Pounce..."), NULL, menu_add_pounce_cb,
 			0, "<Item>", NULL },
+#if ENABLE_SHORTCUT
 	{ N_("/Conversation/_Get Info"), "<CTL>O", menu_get_info_cb, 0,
 			"<StockItem>", PIDGIN_STOCK_TOOLBAR_USER_INFO },
+#else
+	{ N_("/Conversation/_Get Info"), NULL, menu_get_info_cb, 0,
+			"<StockItem>", PIDGIN_STOCK_TOOLBAR_USER_INFO },
+#endif
 	{ N_("/Conversation/In_vite..."), NULL, menu_invite_cb, 0,
 			"<Item>", NULL },
 	{ N_("/Conversation/M_ore"), NULL, NULL, 0, "<Branch>", NULL },
@@ -3641,7 +3709,11 @@
 		gtk_widget_destroy(win->menu.send_to);
 
 	/* Build the Send To menu */
+#if ENABLE_SHORTCUT
 	win->menu.send_to = gtk_menu_item_new_with_mnemonic(_("S_end To"));
+#else
+	win->menu.send_to = gtk_menu_item_new_with_mnemonic(_("Send To")); //to free Alt-s. intentional. --yaz
+#endif
 	gtk_widget_show(win->menu.send_to);
 
 	menu = gtk_menu_new();
@@ -4115,6 +4187,7 @@
 	PidginChatPane *gtkchat;
 	char *new_topic;
 	const char *current_topic;
+	char dummy[] = "No Topic";
 
 	gc      = purple_conversation_get_gc(conv);
 
@@ -4134,7 +4207,7 @@
 		return;
 	}
 
-	gtk_entry_set_text(GTK_ENTRY(gtkchat->topic_text), current_topic);
+	gtk_entry_set_text(GTK_ENTRY(gtkchat->topic_text), current_topic ? current_topic : dummy);
 	prpl_info->set_chat_topic(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)),
 			new_topic);
 
@@ -4365,7 +4438,7 @@
 	gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menuitem, 1);
 }
 
-static gboolean resize_imhtml_cb(PidginConversation *gtkconv)
+static void resize_imhtml_cb(PidginConversation *gtkconv)
 {
 	GtkTextBuffer *buffer;
 	GtkTextIter iter;
@@ -4403,12 +4476,18 @@
 
 	diff = height - gtkconv->entry->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;
+	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);
+	}
 }
 
 static void
@@ -4600,15 +4679,19 @@
 static GtkWidget *
 setup_common_pane(PidginConversation *gtkconv)
 {
-	GtkWidget *vbox, *frame, *imhtml_sw, *event_box;
+	GtkWidget *paned, *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 */
@@ -4701,18 +4784,30 @@
 	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, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), gtkconv->lower_hbox, TRUE, TRUE, 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(gtkconv->lower_hbox), frame, TRUE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), 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);
@@ -4722,6 +4817,8 @@
 	                       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));
@@ -4744,7 +4841,7 @@
 	default_formatize(gtkconv);
 	g_signal_connect_after(G_OBJECT(gtkconv->entry), "format_function_clear",
 	                       G_CALLBACK(clear_formatting_cb), gtkconv);
-	return vbox;
+	return paned;
 }
 
 static void
@@ -5016,7 +5113,8 @@
 		gtk_widget_show(gtkconv->toolbar);
 	else
 		gtk_widget_hide(gtkconv->toolbar);
-	g_idle_add((GSourceFunc)resize_imhtml_cb, gtkconv);
+
+//	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);
@@ -6473,6 +6571,9 @@
 		AtkObject *accessibility_obj;
 		/* I think this is a little longer than it needs to be but I'm lazy. */
 		char *style;
+		gboolean ellipsis;
+		int side;
+		char *tab_title = NULL;
 
 		if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
 			im = PURPLE_CONV_IM(conv);
@@ -6560,8 +6661,26 @@
 			style = NULL;
 		}
 
+		// nosuke's tab width patch
+		side = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/tab_side");
+		side &= ~8; 
+		if ( (side == GTK_POS_LEFT || side == GTK_POS_RIGHT) &&
+		     purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/trim_vertical_tabs") )
+			ellipsis = TRUE;
+		else
+			ellipsis = FALSE;
+
+		if (ellipsis) {
+			tab_title = pidgin_gtk_ellipsis_text(gtkconv->tab_label, title, 60, "...");
+		}
+		else {
+			tab_title = g_strdup(title);
+		}
+
 		gtk_widget_set_name(gtkconv->tab_label, style);
-		gtk_label_set_text(GTK_LABEL(gtkconv->tab_label), title);
+		gtk_label_set_text(GTK_LABEL(gtkconv->tab_label), tab_title);
+		g_free(tab_title); tab_title = NULL;
+
 		gtk_widget_set_state(gtkconv->tab_label, GTK_STATE_ACTIVE);
 
 		if (gtkconv->unseen_state == PIDGIN_UNSEEN_TEXT ||
@@ -6967,6 +7086,24 @@
 	return page_num;
 }
 
+//nosuke
+static void
+trim_vertical_tabs_pref_cb(const char *name, PurplePrefType type,
+						   gconstpointer value, gpointer data)
+{
+	GList *l;
+	PurpleConversation *conv;
+
+	for (l = purple_get_conversations(); l != NULL; l = l->next) {
+		conv = (PurpleConversation *)l->data;
+
+		if (!PIDGIN_IS_PIDGIN_CONVERSATION(conv))
+			continue;
+
+		pidgin_conv_update_fields(conv, PIDGIN_CONV_SET_TITLE);
+	}
+}
+
 static void
 close_on_tabs_pref_cb(const char *name, PurplePrefType type,
 					  gconstpointer value, gpointer data)
@@ -7036,6 +7173,7 @@
 			pidgin_conv_tab_pack(gtkwin, gtkconvs->data);
 		}
 	}
+	trim_vertical_tabs_pref_cb(name, type, value, data);
 }
 
 static void
@@ -7094,7 +7232,7 @@
 		else
 			gtk_widget_hide(gtkconv->toolbar);
 
-		g_idle_add((GSourceFunc)resize_imhtml_cb,gtkconv);
+//		g_idle_add((GSourceFunc)resize_imhtml_cb,gtkconv);
 	}
 }
 
@@ -7597,6 +7735,7 @@
 	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/conversations");
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/use_smooth_scrolling", TRUE);
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/close_on_tabs", TRUE);
+	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/trim_vertical_tabs", FALSE);
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/send_bold", FALSE);
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/send_italic", FALSE);
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/send_underline", FALSE);
@@ -7649,6 +7788,8 @@
 	/* Connect callbacks. */
 	purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/conversations/close_on_tabs",
 								close_on_tabs_pref_cb, NULL);
+	purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/conversations/trim_vertical_tabs",
+								  trim_vertical_tabs_pref_cb, NULL);
 	purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/conversations/show_timestamps",
 								show_timestamps_pref_cb, NULL);
 	purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/conversations/show_formatting_toolbar",
@@ -9137,7 +9278,7 @@
 		ptr = gdk_cursor_new(GDK_LEFT_PTR);
 	}
 
-	gtk_label_set_markup(label, "×");
+	gtk_label_set_markup(label, "");
 	gdk_window_set_cursor(event->window, ptr);
 	return FALSE;
 }
@@ -9150,7 +9291,7 @@
 		hand = gdk_cursor_new(GDK_HAND2);
 	}
 
-	gtk_label_set_markup(label, "<u>×</u>");
+	gtk_label_set_markup(label, "<u></u>");
 	gdk_window_set_cursor(event->window, hand);
 	return FALSE;
 }
@@ -9180,7 +9321,7 @@
 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(gtkconv->close), FALSE);
 #endif
 	gtk_widget_set_events(gtkconv->close, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
-	close_image = gtk_label_new("×");
+	close_image = gtk_label_new("");
 	g_signal_connect(G_OBJECT(gtkconv->close), "enter-notify-event", G_CALLBACK(close_button_entered_cb), close_image);
 	g_signal_connect(G_OBJECT(gtkconv->close), "leave-notify-event", G_CALLBACK(close_button_left_cb), close_image);
 	gtk_widget_show(close_image);
--- a/pidgin/gtkimhtml.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/pidgin/gtkimhtml.c	Mon Feb 11 08:16:15 2008 +0000
@@ -90,6 +90,10 @@
                            gint              y,
                            guint             time);
 
+/* yaz. If you want to use shortcut keys that may conflict with
+   inputmethods, change this to 1. */
+#define ENABLE_SHORTCUT 0
+
 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml);
 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml);
 static void delete_cb(GtkTextBuffer *buffer, GtkTextIter *iter, GtkTextIter *end, GtkIMHtml *imhtml);
@@ -416,10 +420,11 @@
 static gint
 gtk_imhtml_tip (gpointer data)
 {
-	GtkIMHtml *imhtml = data;
+	GtkIMHtml *imhtml = (GtkIMHtml *)data;
 	PangoFontMetrics *font_metrics;
 	PangoLayout *layout;
 	PangoFont *font;
+	PangoLanguage *lang;
 
 	gint gap, x, y, h, w, scr_w, baseline_skip;
 
@@ -460,7 +465,9 @@
 		return FALSE;
 	}
 
-	font_metrics = pango_font_get_metrics(font, NULL);
+	lang = pango_context_get_language (pango_layout_get_context(layout));
+	font_metrics = pango_font_get_metrics(font, lang); //it's ok.
+//	font_metrics = pango_font_get_metrics(font, NULL); //crash!
 
 	pango_layout_get_pixel_size(layout, &scr_w, NULL);
 	gap = PANGO_PIXELS((pango_font_metrics_get_ascent(font_metrics) +
@@ -575,14 +582,15 @@
 		tip = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_plaintext");
 		hand = FALSE;
 	}
-
+//yaz here bomb explodes
+#if 1
 	if (tip){
 		if (!GTK_IMHTML(imhtml)->editable && hand)
 			gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->hand_cursor);
 		GTK_IMHTML(imhtml)->tip_timer = g_timeout_add (TOOLTIP_TIMEOUT,
 							       gtk_imhtml_tip, imhtml);
 	}
-
+#endif
 	GTK_IMHTML(imhtml)->tip = tip;
 	g_slist_free(tags);
 	return FALSE;
--- a/pidgin/gtkimhtmltoolbar.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/pidgin/gtkimhtmltoolbar.c	Mon Feb 11 08:16:15 2008 +0000
@@ -1304,7 +1304,7 @@
 	gtk_container_add(GTK_CONTAINER(smiley_button), bbox);
 	image = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_SMILEY, gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL));
 	gtk_box_pack_start(GTK_BOX(bbox), image, FALSE, FALSE, 0);
-	label = gtk_label_new_with_mnemonic(_("_Smile!"));
+	label = gtk_label_new_with_mnemonic(_("Smile!"));
 	gtk_box_pack_start(GTK_BOX(bbox), label, FALSE, FALSE, 0);
 	gtk_box_pack_start(GTK_BOX(box), smiley_button, FALSE, FALSE, 0);
 	g_signal_connect_swapped(G_OBJECT(smiley_button), "clicked", G_CALLBACK(gtk_button_clicked), toolbar->smiley);
--- a/pidgin/gtkimhtmltoolbar.h	Mon Feb 11 00:50:42 2008 +0000
+++ b/pidgin/gtkimhtmltoolbar.h	Mon Feb 11 08:16:15 2008 +0000
@@ -30,7 +30,7 @@
 extern "C" {
 #endif
 
-#define DEFAULT_FONT_FACE "Helvetica 12"
+#define DEFAULT_FONT_FACE "Sans 12"
 
 #define GTK_TYPE_IMHTMLTOOLBAR            (gtk_imhtmltoolbar_get_type ())
 #define GTK_IMHTMLTOOLBAR(obj)            (GTK_CHECK_CAST ((obj), GTK_TYPE_IMHTMLTOOLBAR, GtkIMHtmlToolbar))
--- a/pidgin/gtkmain.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/pidgin/gtkmain.c	Mon Feb 11 08:16:15 2008 +0000
@@ -215,10 +215,12 @@
 		purple_debug_warning("sighandler", "Caught signal %d\n", sig);
 		purple_connections_disconnect_all();
 		break;
+#if 1
 	case SIGSEGV:
 		fprintf(stderr, "%s", segfault_message);
 		abort();
 		break;
+#endif
 	case SIGCHLD:
 		/* Restore signal catching */
 		signal(SIGCHLD, sighandler);
--- a/pidgin/gtkprefs.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/pidgin/gtkprefs.c	Mon Feb 11 08:16:15 2008 +0000
@@ -1,2248 +1,2251 @@
-/**
- * @file gtkprefs.c GTK+ Preferences
- * @ingroup pidgin
- */
-
-/* pidgin
- *
- * Pidgin is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-#include "internal.h"
-#include "pidgin.h"
-
-#include "debug.h"
-#include "notify.h"
-#include "prefs.h"
-#include "proxy.h"
-#include "prpl.h"
-#include "request.h"
-#include "savedstatuses.h"
-#include "sound.h"
-#include "util.h"
-#include "network.h"
-
-#include "gtkblist.h"
-#include "gtkconv.h"
-#include "gtkdebug.h"
-#include "gtkdialogs.h"
-#include "gtkimhtml.h"
-#include "gtkimhtmltoolbar.h"
-#include "gtkprefs.h"
-#include "gtksavedstatuses.h"
-#include "gtksound.h"
-#include "gtkthemes.h"
-#include "gtkutils.h"
-#include "pidginstock.h"
-
-#define PROXYHOST 0
-#define PROXYPORT 1
-#define PROXYUSER 2
-#define PROXYPASS 3
-
-static int sound_row_sel = 0;
-static GtkWidget *prefsnotebook;
-
-static GtkWidget *sound_entry = NULL;
-static GtkListStore *smiley_theme_store = NULL;
-static GtkTreeSelection *smiley_theme_sel = NULL;
-static GtkWidget *prefs_proxy_frame = NULL;
-
-static GtkWidget *prefs = NULL;
-static GtkWidget *debugbutton = NULL;
-static int notebook_page = 0;
-static GtkTreeRowReference *previous_smiley_row = NULL;
-
-/*
- * PROTOTYPES
- */
-static void delete_prefs(GtkWidget *, void *);
-
-static void
-update_spin_value(GtkWidget *w, GtkWidget *spin)
-{
-	const char *key = g_object_get_data(G_OBJECT(spin), "val");
-	int value;
-
-	value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
-
-	purple_prefs_set_int(key, value);
-}
-
-GtkWidget *
-pidgin_prefs_labeled_spin_button(GtkWidget *box, const gchar *title,
-		const char *key, int min, int max, GtkSizeGroup *sg)
-{
-	GtkWidget *spin;
-	GtkObject *adjust;
-	int val;
-
-	val = purple_prefs_get_int(key);
-
-	adjust = gtk_adjustment_new(val, min, max, 1, 1, 1);
-	spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0);
-	g_object_set_data(G_OBJECT(spin), "val", (char *)key);
-	if (max < 10000)
-		gtk_widget_set_size_request(spin, 50, -1);
-	else
-		gtk_widget_set_size_request(spin, 60, -1);
-	g_signal_connect(G_OBJECT(adjust), "value-changed",
-					 G_CALLBACK(update_spin_value), GTK_WIDGET(spin));
-	gtk_widget_show(spin);
-
-	return pidgin_add_widget_to_vbox(GTK_BOX(box), title, sg, spin, FALSE, NULL);
-}
-
-static void
-entry_set(GtkEntry *entry, gpointer data) {
-	const char *key = (const char*)data;
-
-	purple_prefs_set_string(key, gtk_entry_get_text(entry));
-}
-
-GtkWidget *
-pidgin_prefs_labeled_entry(GtkWidget *page, const gchar *title,
-							 const char *key, GtkSizeGroup *sg)
-{
-	GtkWidget *entry;
-	const gchar *value;
-
-	value = purple_prefs_get_string(key);
-
-	entry = gtk_entry_new();
-	gtk_entry_set_text(GTK_ENTRY(entry), value);
-	g_signal_connect(G_OBJECT(entry), "changed",
-					 G_CALLBACK(entry_set), (char*)key);
-	gtk_widget_show(entry);
-
-	return pidgin_add_widget_to_vbox(GTK_BOX(page), title, sg, entry, TRUE, NULL);
-}
-
-static void
-dropdown_set(GObject *w, const char *key)
-{
-	const char *str_value;
-	int int_value;
-	PurplePrefType type;
-
-	type = GPOINTER_TO_INT(g_object_get_data(w, "type"));
-
-	if (type == PURPLE_PREF_INT) {
-		int_value = GPOINTER_TO_INT(g_object_get_data(w, "value"));
-
-		purple_prefs_set_int(key, int_value);
-	}
-	else if (type == PURPLE_PREF_STRING) {
-		str_value = (const char *)g_object_get_data(w, "value");
-
-		purple_prefs_set_string(key, str_value);
-	}
-	else if (type == PURPLE_PREF_BOOLEAN) {
-		purple_prefs_set_bool(key,
-				GPOINTER_TO_INT(g_object_get_data(w, "value")));
-	}
-}
-
-GtkWidget *
-pidgin_prefs_dropdown_from_list(GtkWidget *box, const gchar *title,
-		PurplePrefType type, const char *key, GList *menuitems)
-{
-	GtkWidget  *dropdown, *opt, *menu;
-	GtkWidget  *label = NULL;
-	gchar      *text;
-	const char *stored_str = NULL;
-	int         stored_int = 0;
-	int         int_value  = 0;
-	const char *str_value  = NULL;
-	int         o = 0;
-
-	g_return_val_if_fail(menuitems != NULL, NULL);
-
-#if 0 /* GTK_CHECK_VERSION(2,4,0) */
-	if(type == PURPLE_PREF_INT)
-		model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
-	else if(type == PURPLE_PREF_STRING)
-		model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
-	dropdown = gtk_combo_box_new_with_model(model);
-#else
-	dropdown = gtk_option_menu_new();
-	menu = gtk_menu_new();
-#endif
-
-	if (type == PURPLE_PREF_INT)
-		stored_int = purple_prefs_get_int(key);
-	else if (type == PURPLE_PREF_STRING)
-		stored_str = purple_prefs_get_string(key);
-
-	while (menuitems != NULL && (text = (char *) menuitems->data) != NULL) {
-		menuitems = g_list_next(menuitems);
-		g_return_val_if_fail(menuitems != NULL, NULL);
-
-		opt = gtk_menu_item_new_with_label(text);
-
-		g_object_set_data(G_OBJECT(opt), "type", GINT_TO_POINTER(type));
-
-		if (type == PURPLE_PREF_INT) {
-			int_value = GPOINTER_TO_INT(menuitems->data);
-			g_object_set_data(G_OBJECT(opt), "value",
-							  GINT_TO_POINTER(int_value));
-		}
-		else if (type == PURPLE_PREF_STRING) {
-			str_value = (const char *)menuitems->data;
-
-			g_object_set_data(G_OBJECT(opt), "value", (char *)str_value);
-		}
-		else if (type == PURPLE_PREF_BOOLEAN) {
-			g_object_set_data(G_OBJECT(opt), "value",
-					menuitems->data);
-		}
-
-		g_signal_connect(G_OBJECT(opt), "activate",
-						 G_CALLBACK(dropdown_set), (char *)key);
-
-		gtk_widget_show(opt);
-		gtk_menu_shell_append(GTK_MENU_SHELL(menu), opt);
-
-		if ((type == PURPLE_PREF_INT && stored_int == int_value) ||
-			(type == PURPLE_PREF_STRING && stored_str != NULL &&
-			 !strcmp(stored_str, str_value)) ||
-			(type == PURPLE_PREF_BOOLEAN &&
-			 (purple_prefs_get_bool(key) == GPOINTER_TO_INT(menuitems->data)))) {
-
-			gtk_menu_set_active(GTK_MENU(menu), o);
-		}
-
-		menuitems = g_list_next(menuitems);
-
-		o++;
-	}
-
-	gtk_option_menu_set_menu(GTK_OPTION_MENU(dropdown), menu);
-
-	pidgin_add_widget_to_vbox(GTK_BOX(box), title, NULL, dropdown, FALSE, &label);
-
-	return label;
-}
-
-GtkWidget *
-pidgin_prefs_dropdown(GtkWidget *box, const gchar *title, PurplePrefType type,
-			   const char *key, ...)
-{
-	va_list ap;
-	GList *menuitems = NULL;
-	GtkWidget *dropdown = NULL;
-	char *name;
-	int int_value;
-	const char *str_value;
-
-	g_return_val_if_fail(type == PURPLE_PREF_BOOLEAN || type == PURPLE_PREF_INT ||
-			type == PURPLE_PREF_STRING, NULL);
-
-	va_start(ap, key);
-	while ((name = va_arg(ap, char *)) != NULL) {
-
-		menuitems = g_list_prepend(menuitems, name);
-
-		if (type == PURPLE_PREF_INT || type == PURPLE_PREF_BOOLEAN) {
-			int_value = va_arg(ap, int);
-			menuitems = g_list_prepend(menuitems, GINT_TO_POINTER(int_value));
-		}
-		else {
-			str_value = va_arg(ap, const char *);
-			menuitems = g_list_prepend(menuitems, (char *)str_value);
-		}
-	}
-	va_end(ap);
-
-	g_return_val_if_fail(menuitems != NULL, NULL);
-
-	menuitems = g_list_reverse(menuitems);
-
-	dropdown = pidgin_prefs_dropdown_from_list(box, title, type, key,
-			menuitems);
-
-	g_list_free(menuitems);
-
-	return dropdown;
-}
-
-static void
-delete_prefs(GtkWidget *asdf, void *gdsa)
-{
-	/* Close any "select sound" request dialogs */
-	purple_request_close_with_handle(prefs);
-
-	/* Unregister callbacks. */
-	purple_prefs_disconnect_by_handle(prefs);
-
-	prefs = NULL;
-	sound_entry = NULL;
-	debugbutton = NULL;
-	notebook_page = 0;
-	smiley_theme_store = NULL;
-	if (previous_smiley_row)
-		gtk_tree_row_reference_free(previous_smiley_row);
-	previous_smiley_row = NULL;
-
-}
-
-static void smiley_sel(GtkTreeSelection *sel, GtkTreeModel *model) {
-	GtkTreeIter  iter;
-	const char *themename;
-	char *description;
-	GValue val;
-	GtkTreePath *path, *oldpath;
-	struct smiley_theme *new_theme, *old_theme;
-	GtkWidget *remove_button = g_object_get_data(G_OBJECT(sel), "remove_button");
-
-	if (!gtk_tree_selection_get_selected(sel, &model, &iter)) {
-		gtk_widget_set_sensitive(remove_button, FALSE);
-		return;
-	}
-
-	old_theme = current_smiley_theme;
-	val.g_type = 0;
-	gtk_tree_model_get_value(model, &iter, 3, &val);
-	path = gtk_tree_model_get_path(model, &iter);
-	themename = g_value_get_string(&val);
-	purple_prefs_set_string(PIDGIN_PREFS_ROOT "/smileys/theme", themename);
-
-	gtk_widget_set_sensitive(remove_button, (strcmp(themename, "none") &&
-	                                         strcmp(themename, _("Default"))));
-	g_value_unset (&val);
-
-	/* current_smiley_theme is set in callback for the above pref change */
-	new_theme = current_smiley_theme;
-	description = g_strdup_printf("<span size='larger' weight='bold'>%s</span> - %s\n"
-								"<span size='smaller' foreground='white'>%s</span>",
-								_(new_theme->name), _(new_theme->author), _(new_theme->desc));
-	gtk_list_store_set(smiley_theme_store, &iter, 1, description, -1);
-	g_free(description);
-
-	if (new_theme != old_theme && previous_smiley_row) {
-		oldpath = gtk_tree_row_reference_get_path(previous_smiley_row);
-		if (gtk_tree_model_get_iter(model, &iter, oldpath)) {
-			description = g_strdup_printf("<span size='larger' weight='bold'>%s</span> - %s\n"
-								"<span size='smaller' foreground='dim grey'>%s</span>",
-								_(old_theme->name), _(old_theme->author), _(old_theme->desc));
-			gtk_list_store_set(smiley_theme_store, &iter, 1,
-				description, -1);
-			g_free(description);
-		}
-		gtk_tree_path_free(oldpath);
-	}
-	if (previous_smiley_row)
-		gtk_tree_row_reference_free(previous_smiley_row);
-	previous_smiley_row = gtk_tree_row_reference_new(model, path);
-	gtk_tree_path_free(path);
-}
-
-static GtkTreeRowReference *theme_refresh_theme_list(void)
-{
-	GdkPixbuf *pixbuf;
-	GSList *themes;
-	GtkTreeIter iter;
-	GtkTreeRowReference *row_ref = NULL;
-
-	if (previous_smiley_row)
-		gtk_tree_row_reference_free(previous_smiley_row);
-	previous_smiley_row = NULL;
-
-	pidgin_themes_smiley_theme_probe();
-
-	if (!(themes = smiley_themes))
-		return NULL;
-
-	gtk_list_store_clear(smiley_theme_store);
-
-	while (themes) {
-		struct smiley_theme *theme = themes->data;
-		char *description = g_strdup_printf("<span size='larger' weight='bold'>%s</span> - %s\n"
-						    "<span size='smaller' foreground='dim grey'>%s</span>",
-						    _(theme->name), _(theme->author), _(theme->desc));
-		gtk_list_store_append (smiley_theme_store, &iter);
-
-		/*
-		 * LEAK - Gentoo memprof thinks pixbuf is leaking here... but it
-		 * looks like it should be ok to me.  Anyone know what's up?  --Mark
-		 */
-		pixbuf = (theme->icon ? gdk_pixbuf_new_from_file(theme->icon, NULL) : NULL);
-
-		gtk_list_store_set(smiley_theme_store, &iter,
-				   0, pixbuf,
-				   1, description,
-				   2, theme->path,
-				   3, theme->name,
-				   -1);
-
-		if (pixbuf != NULL)
-			g_object_unref(G_OBJECT(pixbuf));
-
-		g_free(description);
-		themes = themes->next;
-
-		/* If this is the currently selected theme,
-		 * we will need to select it. Grab the row reference. */
-		if (theme == current_smiley_theme) {
-			GtkTreePath *path = gtk_tree_model_get_path(
-				GTK_TREE_MODEL(smiley_theme_store), &iter);
-			row_ref = gtk_tree_row_reference_new(
-				GTK_TREE_MODEL(smiley_theme_store), path);
-			gtk_tree_path_free(path);
-		}
-	}
-
-	return row_ref;
-}
-
-static void theme_install_theme(char *path, char *extn) {
-#ifndef _WIN32
-	gchar *command;
-#endif
-	gchar *destdir;
-	gchar *tail;
-	GtkTreeRowReference *theme_rowref;
-
-	/* Just to be safe */
-	g_strchomp(path);
-
-	/* I dont know what you are, get out of here */
-	if (extn != NULL)
-		tail = extn;
-	else if ((tail = strrchr(path, '.')) == NULL)
-		return;
-
-	destdir = g_strconcat(purple_user_dir(), G_DIR_SEPARATOR_S "smileys", NULL);
-
-	/* We'll check this just to make sure. This also lets us do something different on
-	 * other platforms, if need be */
-	if (!g_ascii_strcasecmp(tail, ".gz") || !g_ascii_strcasecmp(tail, ".tgz")) {
-#ifndef _WIN32
-		gchar *path_escaped = g_shell_quote(path);
-		gchar *destdir_escaped = g_shell_quote(destdir);
-		command = g_strdup_printf("tar > /dev/null xzf %s -C %s", path_escaped, destdir_escaped);
-		g_free(path_escaped);
-		g_free(destdir_escaped);
-#else
-		if(!winpidgin_gz_untar(path, destdir)) {
-			g_free(destdir);
-			return;
-		}
-#endif
-	}
-	else {
-		g_free(destdir);
-		return;
-	}
-
-#ifndef _WIN32
-	/* Fire! */
-	if (system(command))
-	{
-		purple_notify_error(NULL, NULL, _("Smiley theme failed to unpack."), NULL);
-	}
-
-	g_free(command);
-#endif
-	g_free(destdir);
-
-	theme_rowref = theme_refresh_theme_list();
-	if (theme_rowref != NULL) {
-		GtkTreePath *tp = gtk_tree_row_reference_get_path(theme_rowref);
-
-		if (tp)
-			gtk_tree_selection_select_path(smiley_theme_sel, tp);
-		gtk_tree_row_reference_free(theme_rowref);
-	}
-}
-
-static void
-theme_got_url(PurpleUtilFetchUrlData *url_data, gpointer user_data,
-		const gchar *themedata, size_t len, const gchar *error_message)
-{
-	FILE *f;
-	gchar *path;
-	size_t wc;
-
-	if ((error_message != NULL) || (len == 0))
-		return;
-
-	f = purple_mkstemp(&path, TRUE);
-	wc = fwrite(themedata, len, 1, f);
-	if (wc != 1) {
-		purple_debug_warning("theme_got_url", "Unable to write theme data.\n");
-		fclose(f);
-		g_unlink(path);
-		g_free(path);
-		return;
-	}
-	fclose(f);
-
-	theme_install_theme(path, user_data);
-
-	g_unlink(path);
-	g_free(path);
-}
-
-static void
-theme_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y,
-		GtkSelectionData *sd, guint info, guint t, gpointer data)
-{
-	gchar *name = (gchar *)sd->data;
-
-	if ((sd->length >= 0) && (sd->format == 8)) {
-		/* Well, it looks like the drag event was cool.
-		 * Let's do something with it */
-
-		if (!g_ascii_strncasecmp(name, "file://", 7)) {
-			GError *converr = NULL;
-			gchar *tmp;
-			/* It looks like we're dealing with a local file. Let's
-			 * just untar it in the right place */
-			if(!(tmp = g_filename_from_uri(name, NULL, &converr))) {
-				purple_debug(PURPLE_DEBUG_ERROR, "theme dnd", "%s\n",
-						   (converr ? converr->message :
-							"g_filename_from_uri error"));
-				return;
-			}
-			theme_install_theme(tmp, NULL);
-			g_free(tmp);
-		} else if (!g_ascii_strncasecmp(name, "http://", 7)) {
-			/* Oo, a web drag and drop. This is where things
-			 * will start to get interesting */
-			purple_util_fetch_url(name, TRUE, NULL, FALSE, theme_got_url, ".tgz");
-		} else if (!g_ascii_strncasecmp(name, "https://", 8)) {
-			/* purple_util_fetch_url() doesn't support HTTPS, but we want users
-			 * to be able to drag and drop links from the SF trackers, so
-			 * we'll try it as an HTTP URL. */
-			char *tmp = g_strdup(name + 1);
-			tmp[0] = 'h';
-			tmp[1] = 't';
-			tmp[2] = 't';
-			tmp[3] = 'p';
-			purple_util_fetch_url(tmp, TRUE, NULL, FALSE, theme_got_url, ".tgz");
-			g_free(tmp);
-		}
-
-		gtk_drag_finish(dc, TRUE, FALSE, t);
-	}
-
-	gtk_drag_finish(dc, FALSE, FALSE, t);
-}
-
-/* Does same as normal sort, except "none" is sorted first */
-static gint pidgin_sort_smileys (GtkTreeModel	*model,
-						GtkTreeIter		*a,
-						GtkTreeIter		*b,
-						gpointer		userdata)
-{
-	gint ret = 0;
-	gchar *name1 = NULL, *name2 = NULL;
-
-	gtk_tree_model_get(model, a, 3, &name1, -1);
-	gtk_tree_model_get(model, b, 3, &name2, -1);
-
-	if (name1 == NULL || name2 == NULL) {
-		if (!(name1 == NULL && name2 == NULL))
-			ret = (name1 == NULL) ? -1: 1;
-	} else if (!g_ascii_strcasecmp(name1, "none")) {
-		if (!g_utf8_collate(name1, name2))
-			ret = 0;
-		else
-			/* Sort name1 first */
-			ret = -1;
-	} else if (!g_ascii_strcasecmp(name2, "none")) {
-		/* Sort name2 first */
-		ret = 1;
-	} else {
-		/* Neither string is "none", default to normal sort */
-		ret = purple_utf8_strcasecmp(name1,name2);
-	}
-
-	g_free(name1);
-	g_free(name2);
-
-	return ret;
-}
-
-static void
-request_theme_file_name_cb(gpointer data, char *theme_file_name)
-{
-	theme_install_theme(theme_file_name, NULL) ;
-}
-
-static void
-add_theme_button_clicked_cb(GtkWidget *widget, gpointer null)
-{
-	purple_request_file(NULL, _("Install Theme"), NULL, FALSE, (GCallback)request_theme_file_name_cb, NULL, NULL, NULL, NULL, NULL) ;
-}
-
-static void
-remove_theme_button_clicked_cb(GtkWidget *button, GtkTreeView *tv)
-{
-	char *theme_name = NULL, *theme_file = NULL;
-	GtkTreeModel *tm;
-	GtkTreeIter itr;
-	GtkTreeRowReference *trr = NULL;
-
-	if ((tm = gtk_tree_view_get_model(tv)) == NULL)
-		return;
-	if (!gtk_tree_selection_get_selected(smiley_theme_sel, NULL, &itr))
-		return;
-	gtk_tree_model_get(tm, &itr, 2, &theme_file, 3, &theme_name, -1);
-
-	if (theme_file && theme_name && strcmp(theme_name, "none"))
-		pidgin_themes_remove_smiley_theme(theme_file);
-
-	if ((trr = theme_refresh_theme_list()) != NULL) {
-		GtkTreePath *tp = gtk_tree_row_reference_get_path(trr);
-
-		if (tp) {
-			gtk_tree_selection_select_path(smiley_theme_sel, tp);
-			gtk_tree_path_free(tp);
-		}
-		gtk_tree_row_reference_free(trr);
-	}
-
-	g_free(theme_file);
-	g_free(theme_name);
-}
-
-static GtkWidget *
-theme_page(void)
-{
-	GtkWidget *add_button, *remove_button;
-	GtkWidget *hbox_buttons;
-	GtkWidget *alignment;
-	GtkWidget *ret;
-	GtkWidget *sw;
-	GtkWidget *view;
-	GtkCellRenderer *rend;
-	GtkTreeViewColumn *col;
-	GtkTreeSelection *sel;
-	GtkTreeRowReference *rowref;
-	GtkWidget *label;
-	GtkTargetEntry te[3] = {{"text/plain", 0, 0},{"text/uri-list", 0, 1},{"STRING", 0, 2}};
-
-	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
-	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
-
-	label = gtk_label_new(_("Select a smiley theme that you would like to use from the list below. New themes can be installed by dragging and dropping them onto the theme list."));
-
-	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
-
-	gtk_box_pack_start(GTK_BOX(ret), label, FALSE, TRUE, 0);
-	gtk_widget_show(label);
-
-	sw = gtk_scrolled_window_new(NULL,NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
-
-	gtk_box_pack_start(GTK_BOX(ret), sw, TRUE, TRUE, 0);
-	smiley_theme_store = gtk_list_store_new (4, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
-
-	rowref = theme_refresh_theme_list();
-
-	view = gtk_tree_view_new_with_model (GTK_TREE_MODEL(smiley_theme_store));
-
-	gtk_drag_dest_set(view, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te,
-					sizeof(te) / sizeof(GtkTargetEntry) , GDK_ACTION_COPY | GDK_ACTION_MOVE);
-
-	g_signal_connect(G_OBJECT(view), "drag_data_received", G_CALLBACK(theme_dnd_recv), smiley_theme_store);
-
-	rend = gtk_cell_renderer_pixbuf_new();
-	smiley_theme_sel = sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
-
-	/* Custom sort so "none" theme is at top of list */
-	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(smiley_theme_store),
-									3, pidgin_sort_smileys, NULL, NULL);
-
-	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(smiley_theme_store),
-										 3, GTK_SORT_ASCENDING);
-
-	col = gtk_tree_view_column_new_with_attributes (_("Icon"),
-							rend,
-							"pixbuf", 0,
-							NULL);
-	gtk_tree_view_append_column (GTK_TREE_VIEW(view), col);
-
-	rend = gtk_cell_renderer_text_new();
-	col = gtk_tree_view_column_new_with_attributes (_("Description"),
-							rend,
-							"markup", 1,
-							NULL);
-	gtk_tree_view_append_column (GTK_TREE_VIEW(view), col);
-	g_object_unref(G_OBJECT(smiley_theme_store));
-	gtk_container_add(GTK_CONTAINER(sw), view);
-
-	g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(smiley_sel), NULL);
-
-	alignment = gtk_alignment_new(1.0, 0.5, 0.0, 1.0);
-	gtk_widget_show(alignment);
-	gtk_box_pack_start(GTK_BOX(ret), alignment, FALSE, TRUE, 0);
-
-	hbox_buttons = gtk_hbox_new(TRUE, PIDGIN_HIG_CAT_SPACE);
-	gtk_widget_show(hbox_buttons);
-	gtk_container_add(GTK_CONTAINER(alignment), hbox_buttons);
-
-	add_button = gtk_button_new_from_stock(GTK_STOCK_ADD);
-	gtk_widget_show(add_button);
-	gtk_box_pack_start(GTK_BOX(hbox_buttons), add_button, FALSE, TRUE, 0);
-	g_signal_connect(G_OBJECT(add_button), "clicked", (GCallback)add_theme_button_clicked_cb, view);
-
-	remove_button = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
-	gtk_widget_show(remove_button);
-	gtk_box_pack_start(GTK_BOX(hbox_buttons), remove_button, FALSE, TRUE, 0);
-	g_signal_connect(G_OBJECT(remove_button), "clicked", (GCallback)remove_theme_button_clicked_cb, view);
-	g_object_set_data(G_OBJECT(sel), "remove_button", remove_button);
-
-	if (rowref) {
-		GtkTreePath *path = gtk_tree_row_reference_get_path(rowref);
-		gtk_tree_row_reference_free(rowref);
-		gtk_tree_selection_select_path(sel, path);
-		gtk_tree_path_free(path);
-	}
-
-	gtk_widget_show_all(ret);
-
-	pidgin_set_accessible_label (view, label);
-
-	return ret;
-}
-
-static void
-formatting_toggle_cb(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons, void *toolbar)
-{
-	gboolean bold, italic, uline;
-
-	gtk_imhtml_get_current_format(GTK_IMHTML(imhtml),
-								  &bold, &italic, &uline);
-
-	if (buttons & GTK_IMHTML_BOLD)
-		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/send_bold", bold);
-	if (buttons & GTK_IMHTML_ITALIC)
-		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/send_italic", italic);
-	if (buttons & GTK_IMHTML_UNDERLINE)
-		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/send_underline", uline);
-
-	if (buttons & GTK_IMHTML_GROW || buttons & GTK_IMHTML_SHRINK)
-		purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/font_size",
-						   gtk_imhtml_get_current_fontsize(GTK_IMHTML(imhtml)));
-	if (buttons & GTK_IMHTML_FACE) {
-		char *face = gtk_imhtml_get_current_fontface(GTK_IMHTML(imhtml));
-		if (!face)
-			face = g_strdup("");
-
-		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/font_face", face);
-		g_free(face);
-	}
-
-	if (buttons & GTK_IMHTML_FORECOLOR) {
-		char *color = gtk_imhtml_get_current_forecolor(GTK_IMHTML(imhtml));
-		if (!color)
-			color = g_strdup("");
-
-		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/fgcolor", color);
-		g_free(color);
-	}
-
-	if (buttons & GTK_IMHTML_BACKCOLOR) {
-		char *color;
-		GObject *object;
-
-		color = gtk_imhtml_get_current_backcolor(GTK_IMHTML(imhtml));
-		if (!color)
-			color = g_strdup("");
-
-		/* Block the signal to prevent a loop. */
-		object = g_object_ref(G_OBJECT(imhtml));
-		g_signal_handlers_block_matched(object, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
-										NULL, toolbar);
-		/* Clear the backcolor. */
-		gtk_imhtml_toggle_backcolor(GTK_IMHTML(imhtml), "");
-		/* Unblock the signal. */
-		g_signal_handlers_unblock_matched(object, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
-										  NULL, toolbar);
-		g_object_unref(object);
-
-		/* This will fire a toggle signal and get saved below. */
-		gtk_imhtml_toggle_background(GTK_IMHTML(imhtml), color);
-
-		g_free(color);
-	}
-
-	if (buttons & GTK_IMHTML_BACKGROUND) {
-		char *color = gtk_imhtml_get_current_background(GTK_IMHTML(imhtml));
-		if (!color)
-			color = g_strdup("");
-
-		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/bgcolor", color);
-		g_free(color);
-	}
-}
-
-static void
-formatting_clear_cb(GtkIMHtml *imhtml, void *data)
-{
-	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/send_bold", FALSE);
-	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/send_italic", FALSE);
-	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/send_underline", FALSE);
-
-	purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/font_size", 3);
-
-	purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/font_face", "");
-	purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/fgcolor", "");
-	purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/bgcolor", "");
-}
-
-static void
-conversation_usetabs_cb(const char *name, PurplePrefType type,
-						gconstpointer value, gpointer data)
-{
-	gboolean usetabs = GPOINTER_TO_INT(value);
-
-	if (usetabs)
-		gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
-	else
-		gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
-}
-
-static GtkWidget *
-interface_page(void)
-{
-	GtkWidget *ret;
-	GtkWidget *vbox;
-	GtkWidget *vbox2;
-	GtkWidget *label;
-	GtkSizeGroup *sg;
-	GList *names = NULL;
-
-	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
-	gtk_container_set_border_width(GTK_CONTAINER(ret), PIDGIN_HIG_BORDER);
-
-	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
-
-	vbox = pidgin_make_frame(ret, _("System Tray Icon"));
-	label = pidgin_prefs_dropdown(vbox, _("_Show system tray icon:"), PURPLE_PREF_STRING,
-					PIDGIN_PREFS_ROOT "/docklet/show",
-					_("Always"), "always",
-					_("On unread messages"), "pending",
-					_("Never"), "never",
-					NULL);
-	gtk_size_group_add_widget(sg, label);
-        gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-
-	vbox = pidgin_make_frame(ret, _("Conversation Window Hiding"));
-	label = pidgin_prefs_dropdown(vbox, _("_Hide new IM conversations:"),
-					PURPLE_PREF_STRING, PIDGIN_PREFS_ROOT "/conversations/im/hide_new",
-					_("Never"), "never",
-					_("When away"), "away",
-					_("Always"), "always",
-					NULL);
-	gtk_size_group_add_widget(sg, label);
-        gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-
-
-	/* All the tab options! */
-	vbox = pidgin_make_frame(ret, _("Tabs"));
-
-	pidgin_prefs_checkbox(_("Show IMs and chats in _tabbed windows"),
-							PIDGIN_PREFS_ROOT "/conversations/tabs", vbox);
-
-	/*
-	 * Connect a signal to the above preference.  When conversations are not
-	 * shown in a tabbed window then all tabbing options should be disabled.
-	 */
-	vbox2 = gtk_vbox_new(FALSE, 9);
-	gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 0);
-	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/conversations/tabs",
-	                            conversation_usetabs_cb, vbox2);
-	if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/tabs"))
-	  gtk_widget_set_sensitive(vbox2, FALSE);
-
-	pidgin_prefs_checkbox(_("Show close b_utton on tabs"),
-				PIDGIN_PREFS_ROOT "/conversations/close_on_tabs", vbox2);
-
-	label = pidgin_prefs_dropdown(vbox2, _("_Placement:"), PURPLE_PREF_INT,
-					PIDGIN_PREFS_ROOT "/conversations/tab_side",
-					_("Top"), GTK_POS_TOP,
-					_("Bottom"), GTK_POS_BOTTOM,
-					_("Left"), GTK_POS_LEFT,
-					_("Right"), GTK_POS_RIGHT,
-#if GTK_CHECK_VERSION(2,6,0)
-					_("Left Vertical"), GTK_POS_LEFT|8,
-					_("Right Vertical"), GTK_POS_RIGHT|8,
-#endif
-					NULL);
-	gtk_size_group_add_widget(sg, label);
-        gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-
-	names = pidgin_conv_placement_get_options();
-	label = pidgin_prefs_dropdown_from_list(vbox2, _("N_ew conversations:"),
-				PURPLE_PREF_STRING, PIDGIN_PREFS_ROOT "/conversations/placement", names);
-	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-
-	gtk_size_group_add_widget(sg, label);
-
-	g_list_free(names);
-
-	gtk_widget_show_all(ret);
-	g_object_unref(sg);
-	return ret;
-}
-
-#if GTK_CHECK_VERSION(2,4,0)
-static void
-pidgin_custom_font_set(GtkFontButton *font_button, gpointer nul)
-{
-	purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/custom_font",
-				gtk_font_button_get_font_name(font_button));
-}
-#endif
-
-static GtkWidget *
-conv_page(void)
-{
-	GtkWidget *ret;
-	GtkWidget *vbox;
-	GtkWidget *toolbar;
-	GtkWidget *iconpref1;
-	GtkWidget *iconpref2;
-	GtkWidget *fontpref;
-	GtkWidget *imhtml;
-	GtkWidget *frame;
-
-#if GTK_CHECK_VERSION(2,4,0)
-	GtkWidget *hbox;
-	GtkWidget *font_button;
-	const char *font_name;
-#endif
-
-	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
-	gtk_container_set_border_width(GTK_CONTAINER(ret), PIDGIN_HIG_BORDER);
-
-	vbox = pidgin_make_frame(ret, _("Conversations"));
-
-	pidgin_prefs_checkbox(_("Show _formatting on incoming messages"),
-				PIDGIN_PREFS_ROOT "/conversations/show_incoming_formatting", vbox);
-
-	iconpref1 = pidgin_prefs_checkbox(_("Show _detailed information"),
-			PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", vbox);
-	iconpref2 = pidgin_prefs_checkbox(_("Enable buddy ic_on animation"),
-			PIDGIN_PREFS_ROOT "/conversations/im/animate_buddy_icons", vbox);
-	if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons"))
-		gtk_widget_set_sensitive(iconpref2, FALSE);
-	g_signal_connect(G_OBJECT(iconpref1), "clicked",
-					 G_CALLBACK(pidgin_toggle_sensitive), iconpref2);
-
-	pidgin_prefs_checkbox(_("_Notify buddies that you are typing to them"),
-			"/purple/conversations/im/send_typing", vbox);
-#ifdef USE_GTKSPELL
-	pidgin_prefs_checkbox(_("Highlight _misspelled words"),
-			PIDGIN_PREFS_ROOT "/conversations/spellcheck", vbox);
-#endif
-
-	pidgin_prefs_checkbox(_("Use smooth-scrolling"), PIDGIN_PREFS_ROOT "/conversations/use_smooth_scrolling", vbox);
-
-#ifdef _WIN32
-	pidgin_prefs_checkbox(_("F_lash window when IMs are received"), PIDGIN_PREFS_ROOT "/win32/blink_im", vbox);
-
-	pidgin_prefs_checkbox(_("Minimi_ze new conversation windows"), PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", vbox);
-#endif
-
-#if GTK_CHECK_VERSION(2,4,0)
-	vbox = pidgin_make_frame(ret, _("Font"));
-	if (purple_running_gnome())
-		fontpref = pidgin_prefs_checkbox(_("Use document font from _theme"), PIDGIN_PREFS_ROOT "/conversations/use_theme_font", vbox);
-	else
-		fontpref = pidgin_prefs_checkbox(_("Use font from _theme"), PIDGIN_PREFS_ROOT "/conversations/use_theme_font", vbox);
-
-	font_name = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/custom_font");
-	font_button = gtk_font_button_new_with_font(font_name ? font_name : NULL);
-
-	gtk_font_button_set_show_style(GTK_FONT_BUTTON(font_button), TRUE);
-	hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Conversation _font:"), NULL, font_button, FALSE, NULL);
-	if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_theme_font"))
-		gtk_widget_set_sensitive(hbox, FALSE);
-	g_signal_connect(G_OBJECT(fontpref), "clicked", G_CALLBACK(pidgin_toggle_sensitive), hbox);
-	g_signal_connect(G_OBJECT(font_button), "font-set", G_CALLBACK(pidgin_custom_font_set), NULL);
-#endif
-
-	vbox = pidgin_make_frame(ret, _("Default Formatting"));
-	gtk_box_set_child_packing(GTK_BOX(vbox->parent), vbox, TRUE, TRUE, 0, GTK_PACK_START);
-
-	frame = pidgin_create_imhtml(TRUE, &imhtml, &toolbar, NULL);
-	gtk_widget_show(frame);
-	gtk_widget_set_name(imhtml, "pidgin_prefs_font_imhtml");
-	gtk_widget_set_size_request(frame, 300, -1);
-	gtk_imhtml_set_whole_buffer_formatting_only(GTK_IMHTML(imhtml), TRUE);
-	gtk_imhtml_set_format_functions(GTK_IMHTML(imhtml),
-									GTK_IMHTML_BOLD |
-									GTK_IMHTML_ITALIC |
-									GTK_IMHTML_UNDERLINE |
-									GTK_IMHTML_GROW |
-									GTK_IMHTML_SHRINK |
-									GTK_IMHTML_FACE |
-									GTK_IMHTML_FORECOLOR |
-									GTK_IMHTML_BACKCOLOR |
-									GTK_IMHTML_BACKGROUND);
-
-	gtk_imhtml_append_text(GTK_IMHTML(imhtml), _("This is how your outgoing message text will appear when you use protocols that support formatting."), 0);
-
-	gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
-
-	gtk_imhtml_setup_entry(GTK_IMHTML(imhtml), PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_FORMATTING_WBFO);
-
-	g_signal_connect_after(G_OBJECT(imhtml), "format_function_toggle",
-					 G_CALLBACK(formatting_toggle_cb), toolbar);
-	g_signal_connect_after(G_OBJECT(imhtml), "format_function_clear",
-					 G_CALLBACK(formatting_clear_cb), NULL);
-
-
-	gtk_widget_show(ret);
-
-	return ret;
-}
-
-static void network_ip_changed(GtkEntry *entry, gpointer data)
-{
-	/*
-	 * TODO: It would be nice if we could validate this and show a
-	 *       red background in the box when the IP address is invalid
-	 *       and a green background when the IP address is valid.
-	 */
-	purple_network_set_public_ip(gtk_entry_get_text(entry));
-}
-
-static void
-proxy_changed_cb(const char *name, PurplePrefType type,
-				 gconstpointer value, gpointer data)
-{
-	GtkWidget *frame = data;
-	const char *proxy = value;
-
-	if (strcmp(proxy, "none") && strcmp(proxy, "envvar"))
-		gtk_widget_show_all(frame);
-	else
-		gtk_widget_hide(frame);
-}
-
-static void proxy_print_option(GtkEntry *entry, int entrynum)
-{
-	if (entrynum == PROXYHOST)
-		purple_prefs_set_string("/purple/proxy/host", gtk_entry_get_text(entry));
-	else if (entrynum == PROXYPORT)
-		purple_prefs_set_int("/purple/proxy/port", atoi(gtk_entry_get_text(entry)));
-	else if (entrynum == PROXYUSER)
-		purple_prefs_set_string("/purple/proxy/username", gtk_entry_get_text(entry));
-	else if (entrynum == PROXYPASS)
-		purple_prefs_set_string("/purple/proxy/password", gtk_entry_get_text(entry));
-}
-
-static void
-proxy_button_clicked_cb(GtkWidget *button, gpointer null)
-{
-	GError *err = NULL;
-
-	if (g_spawn_command_line_async ("gnome-network-preferences", &err))
-		return;
-
-	purple_notify_error(NULL, NULL, _("Cannot start proxy configuration program."), err->message);
-	g_error_free(err);
-}
-
-static void
-browser_button_clicked_cb(GtkWidget *button, gpointer null)
-{
-	GError *err = NULL;
-
-	if (g_spawn_command_line_async ("gnome-default-applications-properties", &err))
-		return;
-
-	purple_notify_error(NULL, NULL, _("Cannot start browser configuration program."), err->message);
-	g_error_free(err);
-}
-
-static GtkWidget *
-network_page(void)
-{
-	GtkWidget *ret;
-	GtkWidget *vbox, *hbox, *entry;
-	GtkWidget *table, *label, *auto_ip_checkbox, *ports_checkbox, *spin_button;
-	GtkWidget *proxy_warning = NULL, *browser_warning = NULL;
-	GtkWidget *proxy_button = NULL, *browser_button = NULL;
-	GtkSizeGroup *sg;
-	PurpleProxyInfo *proxy_info = NULL;
-
-	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
-	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
-
-	vbox = pidgin_make_frame (ret, _("IP Address"));
-	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
-	pidgin_prefs_labeled_entry(vbox,_("ST_UN server:"),
-			"/purple/network/stun_server", sg);
-
-	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-	gtk_container_add(GTK_CONTAINER(vbox), hbox);
-
-	label = gtk_label_new(NULL);
-	gtk_container_add(GTK_CONTAINER(hbox), label);
-	gtk_size_group_add_widget(sg, label);
-
-	label = gtk_label_new(NULL);
-	gtk_label_set_markup(GTK_LABEL(label),
-			_("<span style=\"italic\">Example: stunserver.org</span>"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-	gtk_container_add(GTK_CONTAINER(hbox), label);
-
-	auto_ip_checkbox = pidgin_prefs_checkbox(_("_Autodetect IP address"),
-			"/purple/network/auto_ip", vbox);
-
-	table = gtk_table_new(2, 2, FALSE);
-	gtk_container_set_border_width(GTK_CONTAINER(table), 0);
-	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
-	gtk_table_set_row_spacings(GTK_TABLE(table), 10);
-	gtk_container_add(GTK_CONTAINER(vbox), table);
-
-	label = gtk_label_new_with_mnemonic(_("Public _IP:"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
-	gtk_size_group_add_widget(sg, label);
-
-	entry = gtk_entry_new();
-	gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
-	g_signal_connect(G_OBJECT(entry), "changed",
-					 G_CALLBACK(network_ip_changed), NULL);
-
-	/*
-	 * TODO: This could be better by showing the autodeteced
-	 * IP separately from the user-specified IP.
-	 */
-	if (purple_network_get_my_ip(-1) != NULL)
-		gtk_entry_set_text(GTK_ENTRY(entry),
-		                   purple_network_get_my_ip(-1));
-
-	pidgin_set_accessible_label (entry, label);
-
-
-	if (purple_prefs_get_bool("/purple/network/auto_ip")) {
-		gtk_widget_set_sensitive(GTK_WIDGET(table), FALSE);
-	}
-
-	g_signal_connect(G_OBJECT(auto_ip_checkbox), "clicked",
-					 G_CALLBACK(pidgin_toggle_sensitive), table);
-
-	g_object_unref(sg);
-
-	vbox = pidgin_make_frame (ret, _("Ports"));
-	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
-
-	pidgin_prefs_checkbox(_("_Enable automatic router port forwarding"),
-			"/purple/network/map_ports", vbox);
-
-	ports_checkbox = pidgin_prefs_checkbox(_("_Manually specify range of ports to listen on"),
-			"/purple/network/ports_range_use", vbox);
-
-	spin_button = pidgin_prefs_labeled_spin_button(vbox, _("_Start port:"),
-			"/purple/network/ports_range_start", 0, 65535, sg);
-	if (!purple_prefs_get_bool("/purple/network/ports_range_use"))
-		gtk_widget_set_sensitive(GTK_WIDGET(spin_button), FALSE);
-	g_signal_connect(G_OBJECT(ports_checkbox), "clicked",
-					 G_CALLBACK(pidgin_toggle_sensitive), spin_button);
-
-	spin_button = pidgin_prefs_labeled_spin_button(vbox, _("_End port:"),
-			"/purple/network/ports_range_end", 0, 65535, sg);
-	if (!purple_prefs_get_bool("/purple/network/ports_range_use"))
-		gtk_widget_set_sensitive(GTK_WIDGET(spin_button), FALSE);
-	g_signal_connect(G_OBJECT(ports_checkbox), "clicked",
-					 G_CALLBACK(pidgin_toggle_sensitive), spin_button);
-
-	if (purple_running_gnome()) {
-		vbox = pidgin_make_frame(ret, _("Proxy Server &amp; Browser"));
-		prefs_proxy_frame = gtk_vbox_new(FALSE, 0);
-
-		proxy_warning = hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-		gtk_container_add(GTK_CONTAINER(vbox), hbox);
-
-		label = gtk_label_new(NULL);
-		gtk_label_set_markup(GTK_LABEL(label),
-		                     _("<b>Proxy configuration program was not found.</b>"));
-		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-
-		browser_warning = hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-		gtk_container_add(GTK_CONTAINER(vbox), hbox);
-
-		label = gtk_label_new(NULL);
-		gtk_label_set_markup(GTK_LABEL(label),
-		                     _("<b>Browser configuration program was not found.</b>"));
-		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-
-		hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-		gtk_container_add(GTK_CONTAINER(vbox), hbox);
-		label = gtk_label_new(_("Proxy & Browser preferences are configured\n"
-		                        "in GNOME Preferences"));
-		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-		gtk_widget_show(label);
-
-		hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-		gtk_container_add(GTK_CONTAINER(vbox), hbox);
-		proxy_button = gtk_button_new_with_mnemonic(_("Configure _Proxy"));
-		g_signal_connect(G_OBJECT(proxy_button), "clicked",
-		                 G_CALLBACK(proxy_button_clicked_cb), NULL);
-		gtk_box_pack_start(GTK_BOX(hbox), proxy_button, FALSE, FALSE, 0);
-		gtk_widget_show(proxy_button);
-		browser_button = gtk_button_new_with_mnemonic(_("Configure _Browser"));
-		g_signal_connect(G_OBJECT(browser_button), "clicked",
-		                 G_CALLBACK(browser_button_clicked_cb), NULL);
-		gtk_box_pack_start(GTK_BOX(hbox), browser_button, FALSE, FALSE, 0);
-		gtk_widget_show(browser_button);
-	} else {
-		vbox = pidgin_make_frame(ret, _("Proxy Server"));
-		prefs_proxy_frame = gtk_vbox_new(FALSE, 0);
-
-		pidgin_prefs_dropdown(vbox, _("Proxy _type:"), PURPLE_PREF_STRING,
-					"/purple/proxy/type",
-					_("No proxy"), "none",
-					"SOCKS 4", "socks4",
-					"SOCKS 5", "socks5",
-					"HTTP", "http",
-					_("Use Environmental Settings"), "envvar",
-					NULL);
-		gtk_box_pack_start(GTK_BOX(vbox), prefs_proxy_frame, 0, 0, 0);
-		proxy_info = purple_global_proxy_get_info();
-
-		purple_prefs_connect_callback(prefs, "/purple/proxy/type",
-					    proxy_changed_cb, prefs_proxy_frame);
-
-		table = gtk_table_new(4, 2, FALSE);
-		gtk_container_set_border_width(GTK_CONTAINER(table), 0);
-		gtk_table_set_col_spacings(GTK_TABLE(table), 5);
-		gtk_table_set_row_spacings(GTK_TABLE(table), 10);
-		gtk_container_add(GTK_CONTAINER(prefs_proxy_frame), table);
-
-
-		label = gtk_label_new_with_mnemonic(_("_Host:"));
-		gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
-		gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
-
-		entry = gtk_entry_new();
-		gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
-		gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
-		g_signal_connect(G_OBJECT(entry), "changed",
-				 G_CALLBACK(proxy_print_option), (void *)PROXYHOST);
-
-		if (proxy_info != NULL && purple_proxy_info_get_host(proxy_info))
-			gtk_entry_set_text(GTK_ENTRY(entry),
-					   purple_proxy_info_get_host(proxy_info));
-
-		hbox = gtk_hbox_new(TRUE, 5);
-		gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-		pidgin_set_accessible_label (entry, label);
-
-		label = gtk_label_new_with_mnemonic(_("_Port:"));
-		gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
-		gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, 0, 0, 0);
-
-		entry = gtk_entry_new();
-		gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
-		gtk_table_attach(GTK_TABLE(table), entry, 3, 4, 0, 1, GTK_FILL, 0, 0, 0);
-		g_signal_connect(G_OBJECT(entry), "changed",
-				 G_CALLBACK(proxy_print_option), (void *)PROXYPORT);
-
-		if (proxy_info != NULL && purple_proxy_info_get_port(proxy_info) != 0) {
-			char buf[128];
-			g_snprintf(buf, sizeof(buf), "%d",
-				   purple_proxy_info_get_port(proxy_info));
-
-			gtk_entry_set_text(GTK_ENTRY(entry), buf);
-		}
-		pidgin_set_accessible_label (entry, label);
-
-		label = gtk_label_new_with_mnemonic(_("_User:"));
-		gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
-		gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
-
-		entry = gtk_entry_new();
-		gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
-		gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
-		g_signal_connect(G_OBJECT(entry), "changed",
-				 G_CALLBACK(proxy_print_option), (void *)PROXYUSER);
-
-		if (proxy_info != NULL && purple_proxy_info_get_username(proxy_info) != NULL)
-			gtk_entry_set_text(GTK_ENTRY(entry),
-						   purple_proxy_info_get_username(proxy_info));
-
-		hbox = gtk_hbox_new(TRUE, 5);
-		gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-		pidgin_set_accessible_label (entry, label);
-
-		label = gtk_label_new_with_mnemonic(_("Pa_ssword:"));
-		gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
-		gtk_table_attach(GTK_TABLE(table), label, 2, 3, 1, 2, GTK_FILL, 0, 0, 0);
-
-		entry = gtk_entry_new();
-		gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
-		gtk_table_attach(GTK_TABLE(table), entry, 3, 4, 1, 2, GTK_FILL , 0, 0, 0);
-		gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
-		if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*')
-			gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR);
-		g_signal_connect(G_OBJECT(entry), "changed",
-				 G_CALLBACK(proxy_print_option), (void *)PROXYPASS);
-
-		if (proxy_info != NULL && purple_proxy_info_get_password(proxy_info) != NULL)
-			gtk_entry_set_text(GTK_ENTRY(entry),
-					   purple_proxy_info_get_password(proxy_info));
-		pidgin_set_accessible_label (entry, label);
-	}
-
-	gtk_widget_show_all(ret);
-	g_object_unref(sg);
-	/* Only hide table if not running gnome otherwise we hide the IP address table! */
-	if (!purple_running_gnome() && (proxy_info == NULL ||
-	    purple_proxy_info_get_type(proxy_info) == PURPLE_PROXY_NONE ||
-	    purple_proxy_info_get_type(proxy_info) == PURPLE_PROXY_USE_ENVVAR)) {
-		gtk_widget_hide(table);
-	} else if (purple_running_gnome()) {
-		gchar *path;
-		path = g_find_program_in_path("gnome-network-preferences");
-		if (path != NULL) {
-			gtk_widget_set_sensitive(proxy_button, TRUE);
-			gtk_widget_hide(proxy_warning);
-			g_free(path);
-		} else {
-			gtk_widget_set_sensitive(proxy_button, FALSE);
-			gtk_widget_show(proxy_warning);
-		}
-		path = g_find_program_in_path("gnome-default-applications-properties");
-		if (path != NULL) {
-			gtk_widget_set_sensitive(browser_button, TRUE);
-			gtk_widget_hide(browser_warning);
-			g_free(path);
-		} else {
-			gtk_widget_set_sensitive(browser_button, FALSE);
-			gtk_widget_show(browser_warning);
-		}
-	}
-
-	return ret;
-}
-
-#ifndef _WIN32
-static gboolean manual_browser_set(GtkWidget *entry, GdkEventFocus *event, gpointer data) {
-	const char *program = gtk_entry_get_text(GTK_ENTRY(entry));
-
-	purple_prefs_set_path(PIDGIN_PREFS_ROOT "/browsers/command", program);
-
-	/* carry on normally */
-	return FALSE;
-}
-
-static GList *get_available_browsers(void)
-{
-	struct browser {
-		char *name;
-		char *command;
-	};
-
-	/* Sorted reverse alphabetically */
-	static const struct browser possible_browsers[] = {
-		{N_("Seamonkey"), "seamonkey"},
-		{N_("Opera"), "opera"},
-		{N_("Netscape"), "netscape"},
-		{N_("Mozilla"), "mozilla"},
-		{N_("Konqueror"), "kfmclient"},
-		{N_("Desktop Default"), "xdg-open"},
-		{N_("GNOME Default"), "gnome-open"},
-		{N_("Galeon"), "galeon"},
-		{N_("Firefox"), "firefox"},
-		{N_("Firebird"), "mozilla-firebird"},
-		{N_("Epiphany"), "epiphany"}
-	};
-	static const int num_possible_browsers = G_N_ELEMENTS(possible_browsers);
-
-	GList *browsers = NULL;
-	int i = 0;
-	char *browser_setting = (char *)purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/browser");
-
-	browsers = g_list_prepend(browsers, (gpointer)"custom");
-	browsers = g_list_prepend(browsers, (gpointer)_("Manual"));
-
-	for (i = 0; i < num_possible_browsers; i++) {
-		if (purple_program_is_valid(possible_browsers[i].command)) {
-			browsers = g_list_prepend(browsers,
-									  possible_browsers[i].command);
-			browsers = g_list_prepend(browsers, (gpointer)_(possible_browsers[i].name));
-			if(browser_setting && !strcmp(possible_browsers[i].command, browser_setting))
-				browser_setting = NULL;
-			/* If xdg-open is valid, prefer it over gnome-open and skip forward */
-			if(!strcmp(possible_browsers[i].command, "xdg-open")) {
-				if (browser_setting && !strcmp("gnome-open", browser_setting)) {
-					purple_prefs_set_string(PIDGIN_PREFS_ROOT "/browsers/browser", possible_browsers[i].command);
-					browser_setting = NULL;
-				}
-				i++;
-			}
-		}
-	}
-
-	if(browser_setting)
-		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/browsers/browser", "custom");
-
-	return browsers;
-}
-
-static void
-browser_changed1_cb(const char *name, PurplePrefType type,
-					gconstpointer value, gpointer data)
-{
-	GtkWidget *hbox = data;
-	const char *browser = value;
-
-	gtk_widget_set_sensitive(hbox, strcmp(browser, "custom"));
-}
-
-static void
-browser_changed2_cb(const char *name, PurplePrefType type,
-					gconstpointer value, gpointer data)
-{
-	GtkWidget *hbox = data;
-	const char *browser = value;
-
-	gtk_widget_set_sensitive(hbox, !strcmp(browser, "custom"));
-}
-
-static GtkWidget *
-browser_page(void)
-{
-	GtkWidget *ret;
-	GtkWidget *vbox;
-	GtkWidget *hbox;
-	GtkWidget *label;
-	GtkWidget *entry;
-	GtkSizeGroup *sg;
-	GList *browsers = NULL;
-
-	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
-	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
-
-	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
-	vbox = pidgin_make_frame (ret, _("Browser Selection"));
-
-	browsers = get_available_browsers();
-	if (browsers != NULL) {
-		label = pidgin_prefs_dropdown_from_list(vbox,_("_Browser:"), PURPLE_PREF_STRING,
-										 PIDGIN_PREFS_ROOT "/browsers/browser",
-										 browsers);
-		g_list_free(browsers);
-		gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-		gtk_size_group_add_widget(sg, label);
-
-		hbox = gtk_hbox_new(FALSE, 0);
-		label = pidgin_prefs_dropdown(hbox, _("_Open link in:"), PURPLE_PREF_INT,
-			PIDGIN_PREFS_ROOT "/browsers/place",
-			_("Browser default"), PIDGIN_BROWSER_DEFAULT,
-			_("Existing window"), PIDGIN_BROWSER_CURRENT,
-			_("New window"), PIDGIN_BROWSER_NEW_WINDOW,
-			_("New tab"), PIDGIN_BROWSER_NEW_TAB,
-			NULL);
-		gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-		gtk_size_group_add_widget(sg, label);
-		gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-
-		if (!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/browser"), "custom"))
-			gtk_widget_set_sensitive(hbox, FALSE);
-		purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/browsers/browser",
-									browser_changed1_cb, hbox);
-	}
-
-	entry = gtk_entry_new();
-	gtk_entry_set_text(GTK_ENTRY(entry),
-					   purple_prefs_get_path(PIDGIN_PREFS_ROOT "/browsers/command"));
-	g_signal_connect(G_OBJECT(entry), "focus-out-event",
-					 G_CALLBACK(manual_browser_set), NULL);
-	hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Manual:\n(%s for URL)"), sg, entry, TRUE, NULL);
-	if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/browser"), "custom"))
-		gtk_widget_set_sensitive(hbox, FALSE);
-	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/browsers/browser",
-			browser_changed2_cb, hbox);
-
-	gtk_widget_show_all(ret);
-	g_object_unref(sg);
-	return ret;
-}
-#endif /*_WIN32*/
-
-static GtkWidget *
-logging_page(void)
-{
-	GtkWidget *ret;
-	GtkWidget *vbox;
-	GList *names;
-
-	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
-	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
-
-
-	vbox = pidgin_make_frame (ret, _("Logging"));
-	names = purple_log_logger_get_options();
-
-	pidgin_prefs_dropdown_from_list(vbox, _("Log _format:"), PURPLE_PREF_STRING,
-				 "/purple/logging/format", names);
-
-	g_list_free(names);
-
-	pidgin_prefs_checkbox(_("Log all _instant messages"),
-				  "/purple/logging/log_ims", vbox);
-	pidgin_prefs_checkbox(_("Log all c_hats"),
-				  "/purple/logging/log_chats", vbox);
-	pidgin_prefs_checkbox(_("Log all _status changes to system log"),
-				  "/purple/logging/log_system", vbox);
-
-	gtk_widget_show_all(ret);
-
-	return ret;
-}
-
-#ifndef _WIN32
-static gint sound_cmd_yeah(GtkEntry *entry, gpointer d)
-{
-	purple_prefs_set_path(PIDGIN_PREFS_ROOT "/sound/command",
-			gtk_entry_get_text(GTK_ENTRY(entry)));
-	return TRUE;
-}
-
-static void
-sound_changed1_cb(const char *name, PurplePrefType type,
-				  gconstpointer value, gpointer data)
-{
-	GtkWidget *hbox = data;
-	const char *method = value;
-
-	gtk_widget_set_sensitive(hbox, !strcmp(method, "custom"));
-}
-
-static void
-sound_changed2_cb(const char *name, PurplePrefType type,
-				  gconstpointer value, gpointer data)
-{
-	GtkWidget *vbox = data;
-	const char *method = value;
-
-	gtk_widget_set_sensitive(vbox, strcmp(method, "none"));
-}
-#endif /* !_WIN32 */
-
-#ifdef USE_GSTREAMER
-static void
-sound_changed3_cb(const char *name, PurplePrefType type,
-				  gconstpointer value, gpointer data)
-{
-	GtkWidget *hbox = data;
-	const char *method = value;
-
-	gtk_widget_set_sensitive(hbox,
-			!strcmp(method, "automatic") ||
-			!strcmp(method, "esd"));
-}
-#endif /* USE_GSTREAMER */
-
-
-static void
-event_toggled(GtkCellRendererToggle *cell, gchar *pth, gpointer data)
-{
-	GtkTreeModel *model = (GtkTreeModel *)data;
-	GtkTreeIter iter;
-	GtkTreePath *path = gtk_tree_path_new_from_string(pth);
-	char *pref;
-
-	gtk_tree_model_get_iter (model, &iter, path);
-	gtk_tree_model_get (model, &iter,
-						2, &pref,
-						-1);
-
-	purple_prefs_set_bool(pref, !gtk_cell_renderer_toggle_get_active(cell));
-	g_free(pref);
-
-	gtk_list_store_set(GTK_LIST_STORE (model), &iter,
-					   0, !gtk_cell_renderer_toggle_get_active(cell),
-					   -1);
-
-	gtk_tree_path_free(path);
-}
-
-static void
-test_sound(GtkWidget *button, gpointer i_am_NULL)
-{
-	char *pref;
-	gboolean temp_enabled;
-	gboolean temp_mute;
-
-	pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/enabled/%s",
-			pidgin_sound_get_event_option(sound_row_sel));
-
-	temp_enabled = purple_prefs_get_bool(pref);
-	temp_mute = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/sound/mute");
-
-	if (!temp_enabled) purple_prefs_set_bool(pref, TRUE);
-	if (temp_mute) purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute", FALSE);
-
-	purple_sound_play_event(sound_row_sel, NULL);
-
-	if (!temp_enabled) purple_prefs_set_bool(pref, FALSE);
-	if (temp_mute) purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute", TRUE);
-
-	g_free(pref);
-}
-
-/*
- * Resets a sound file back to default.
- */
-static void
-reset_sound(GtkWidget *button, gpointer i_am_also_NULL)
-{
-	gchar *pref;
-
-	pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
-						   pidgin_sound_get_event_option(sound_row_sel));
-	purple_prefs_set_path(pref, "");
-	g_free(pref);
-
-	gtk_entry_set_text(GTK_ENTRY(sound_entry), _("(default)"));
-}
-
-static void
-sound_chosen_cb(void *user_data, const char *filename)
-{
-	gchar *pref;
-	int sound;
-
-	sound = GPOINTER_TO_INT(user_data);
-
-	/* Set it -- and forget it */
-	pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
-						   pidgin_sound_get_event_option(sound));
-	purple_prefs_set_path(pref, filename);
-	g_free(pref);
-
-	/*
-	 * If the sound we just changed is still the currently selected
-	 * sound, then update the box showing the file name.
-	 */
-	if (sound == sound_row_sel)
-		gtk_entry_set_text(GTK_ENTRY(sound_entry), filename);
-}
-
-static void select_sound(GtkWidget *button, gpointer being_NULL_is_fun)
-{
-	gchar *pref;
-	const char *filename;
-
-	pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
-						   pidgin_sound_get_event_option(sound_row_sel));
-	filename = purple_prefs_get_path(pref);
-	g_free(pref);
-
-	if (*filename == '\0')
-		filename = NULL;
-
-	purple_request_file(prefs, _("Sound Selection"), filename, FALSE,
-					  G_CALLBACK(sound_chosen_cb), NULL,
-					  NULL, NULL, NULL,
-					  GINT_TO_POINTER(sound_row_sel));
-}
-
-#ifdef USE_GSTREAMER
-static gchar* prefs_sound_volume_format(GtkScale *scale, gdouble val)
-{
-	if(val < 15) {
-		return g_strdup_printf(_("Quietest"));
-	} else if(val < 30) {
-		return g_strdup_printf(_("Quieter"));
-	} else if(val < 45) {
-		return g_strdup_printf(_("Quiet"));
-	} else if(val < 55) {
-		return g_strdup_printf(_("Normal"));
-	} else if(val < 70) {
-		return g_strdup_printf(_("Loud"));
-	} else if(val < 85) {
-		return g_strdup_printf(_("Louder"));
-	} else {
-		return g_strdup_printf(_("Loudest"));
-	}
-}
-
-static void prefs_sound_volume_changed(GtkRange *range)
-{
-	int val = (int)gtk_range_get_value(GTK_RANGE(range));
-	purple_prefs_set_int(PIDGIN_PREFS_ROOT "/sound/volume", val);
-}
-#endif
-
-static void prefs_sound_sel(GtkTreeSelection *sel, GtkTreeModel *model) {
-	GtkTreeIter  iter;
-	GValue val;
-	const char *file;
-	char *pref;
-
-	if (! gtk_tree_selection_get_selected (sel, &model, &iter))
-		return;
-
-	val.g_type = 0;
-	gtk_tree_model_get_value (model, &iter, 3, &val);
-	sound_row_sel = g_value_get_uint(&val);
-
-	pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
-			pidgin_sound_get_event_option(sound_row_sel));
-	file = purple_prefs_get_path(pref);
-	g_free(pref);
-	if (sound_entry)
-		gtk_entry_set_text(GTK_ENTRY(sound_entry), (file && *file != '\0') ? file : _("(default)"));
-	g_value_unset (&val);
-}
-
-static GtkWidget *
-sound_page(void)
-{
-	GtkWidget *ret;
-	GtkWidget *vbox, *sw, *button;
-	GtkSizeGroup *sg;
-	GtkTreeIter iter;
-	GtkWidget *event_view;
-	GtkListStore *event_store;
-	GtkCellRenderer *rend;
-	GtkTreeViewColumn *col;
-	GtkTreeSelection *sel;
-	GtkTreePath *path;
-	GtkWidget *hbox;
-	int j;
-	const char *file;
-	char *pref;
-#ifndef _WIN32
-	GtkWidget *dd;
-	GtkWidget *entry;
-	const char *cmd;
-#endif
-
-	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
-	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
-
-	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
-
-#ifndef _WIN32
-	vbox = pidgin_make_frame (ret, _("Sound Method"));
-	dd = pidgin_prefs_dropdown(vbox, _("_Method:"), PURPLE_PREF_STRING,
-			PIDGIN_PREFS_ROOT "/sound/method",
-			_("Console beep"), "beep",
-#ifdef USE_GSTREAMER
-			_("Automatic"), "automatic",
-			"ESD", "esd",
-			"ALSA", "alsa",
-#endif
-			_("Command"), "custom",
-			_("No sounds"), "none",
-			NULL);
-	gtk_size_group_add_widget(sg, dd);
-	gtk_misc_set_alignment(GTK_MISC(dd), 0, 0.5);
-
-	entry = gtk_entry_new();
-	gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE);
-	cmd = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/sound/command");
-	if(cmd)
-		gtk_entry_set_text(GTK_ENTRY(entry), cmd);
-	g_signal_connect(G_OBJECT(entry), "changed",
-					 G_CALLBACK(sound_cmd_yeah), NULL);
-
-	hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Sound c_ommand:\n(%s for filename)"), sg, entry, TRUE, NULL);
-	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/sound/method",
-								sound_changed1_cb, hbox);
-	gtk_widget_set_sensitive(hbox,
-			!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method"),
-					"custom"));
-#endif /* _WIN32 */
-
-	vbox = pidgin_make_frame (ret, _("Sound Options"));
-	pidgin_prefs_checkbox(_("Sounds when conversation has _focus"),
-				   PIDGIN_PREFS_ROOT "/sound/conv_focus", vbox);
-	pidgin_prefs_dropdown(vbox, _("Enable sounds:"),
-				 PURPLE_PREF_INT, "/purple/sound/while_status",
-				_("Only when available"), 1,
-				_("Only when not available"), 2,
-				_("Always"), 3,
-				NULL);
-
-#ifdef USE_GSTREAMER
-	sw = gtk_hscale_new_with_range(0.0, 100.0, 5.0);
-	gtk_range_set_increments(GTK_RANGE(sw), 5.0, 25.0);
-	gtk_range_set_value(GTK_RANGE(sw), purple_prefs_get_int(PIDGIN_PREFS_ROOT "/sound/volume"));
-	g_signal_connect (G_OBJECT (sw), "format-value",
-			  G_CALLBACK (prefs_sound_volume_format),
-			  NULL);
-	g_signal_connect (G_OBJECT (sw), "value-changed",
-			  G_CALLBACK (prefs_sound_volume_changed),
-			  NULL);
-	hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Volume:"), NULL, sw, TRUE, NULL);
-
-	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/sound/method",
-								sound_changed3_cb, hbox);
-	sound_changed3_cb(PIDGIN_PREFS_ROOT "/sound/method", PURPLE_PREF_STRING,
-			  purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method"), hbox);
-#endif
-
-#ifndef _WIN32
-	gtk_widget_set_sensitive(vbox,
-			strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method"), "none"));
-	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/sound/method",
-								sound_changed2_cb, vbox);
-#endif
-
-	vbox = pidgin_make_frame(ret, _("Sound Events"));
-
-	/* The following is an ugly hack to make the frame expand so the
-	 * sound events list is big enough to be usable */
-	gtk_box_set_child_packing(GTK_BOX(vbox->parent), vbox, TRUE, TRUE, 0,
-			GTK_PACK_START);
-	gtk_box_set_child_packing(GTK_BOX(vbox->parent->parent), vbox->parent, TRUE,
-			TRUE, 0, GTK_PACK_START);
-	gtk_box_set_child_packing(GTK_BOX(vbox->parent->parent->parent),
-			vbox->parent->parent, TRUE, TRUE, 0, GTK_PACK_START);
-
-	sw = gtk_scrolled_window_new(NULL,NULL);
-	gtk_widget_set_size_request(sw, -1, 100);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
-
-	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
-	event_store = gtk_list_store_new (4, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT);
-
-	for (j=0; j < PURPLE_NUM_SOUNDS; j++) {
-		char *pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/enabled/%s",
-					     pidgin_sound_get_event_option(j));
-		const char *label = pidgin_sound_get_event_label(j);
-
-		if (label == NULL) {
-			g_free(pref);
-			continue;
-		}
-
-		gtk_list_store_append (event_store, &iter);
-		gtk_list_store_set(event_store, &iter,
-				   0, purple_prefs_get_bool(pref),
-				   1, _(label),
-				   2, pref,
-				   3, j,
-				   -1);
-		g_free(pref);
-	}
-
-	event_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL(event_store));
-
-	rend = gtk_cell_renderer_toggle_new();
-	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_view));
-	g_signal_connect (G_OBJECT (sel), "changed",
-			  G_CALLBACK (prefs_sound_sel),
-			  NULL);
-	g_signal_connect (G_OBJECT(rend), "toggled",
-			  G_CALLBACK(event_toggled), event_store);
-	path = gtk_tree_path_new_first();
-	gtk_tree_selection_select_path(sel, path);
-	gtk_tree_path_free(path);
-
-	col = gtk_tree_view_column_new_with_attributes (_("Play"),
-							rend,
-							"active", 0,
-							NULL);
-	gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col);
-
-	rend = gtk_cell_renderer_text_new();
-	col = gtk_tree_view_column_new_with_attributes (_("Event"),
-							rend,
-							"text", 1,
-							NULL);
-	gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col);
-	g_object_unref(G_OBJECT(event_store));
-	gtk_container_add(GTK_CONTAINER(sw), event_view);
-
-	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-	sound_entry = gtk_entry_new();
-	pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
-			       pidgin_sound_get_event_option(0));
-	file = purple_prefs_get_path(pref);
-	g_free(pref);
-	gtk_entry_set_text(GTK_ENTRY(sound_entry), (file && *file != '\0') ? file : _("(default)"));
-	gtk_editable_set_editable(GTK_EDITABLE(sound_entry), FALSE);
-	gtk_box_pack_start(GTK_BOX(hbox), sound_entry, FALSE, FALSE, PIDGIN_HIG_BOX_SPACE);
-
-	button = gtk_button_new_with_label(_("Test"));
-	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(test_sound), NULL);
-	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1);
-
-	button = gtk_button_new_with_label(_("Reset"));
-	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(reset_sound), NULL);
-	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1);
-
-	button = gtk_button_new_with_label(_("Choose..."));
-	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(select_sound), NULL);
-	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1);
-
-	gtk_widget_show_all(ret);
-	g_object_unref(sg);
-
-	return ret;
-}
-
-
-static void
-set_idle_away(PurpleSavedStatus *status)
-{
-	purple_prefs_set_int("/purple/savedstatus/idleaway", purple_savedstatus_get_creation_time(status));
-}
-
-static void
-set_startupstatus(PurpleSavedStatus *status)
-{
-	purple_prefs_set_int("/purple/savedstatus/startup", purple_savedstatus_get_creation_time(status));
-}
-
-static GtkWidget *
-away_page(void)
-{
-	GtkWidget *ret;
-	GtkWidget *vbox;
-	GtkWidget *dd;
-	GtkWidget *label;
-	GtkWidget *button;
-	GtkWidget *select;
-	GtkWidget *menu;
-	GtkSizeGroup *sg;
-
-	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
-	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
-
-	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
-
-	/* Idle stuff */
-	vbox = pidgin_make_frame(ret, _("Idle"));
-
-	dd = pidgin_prefs_dropdown(vbox, _("_Report idle time:"),
-		PURPLE_PREF_STRING, "/purple/away/idle_reporting",
-		_("Never"), "none",
-		_("From last sent message"), "purple",
-#if defined(USE_SCREENSAVER) || defined(HAVE_IOKIT)
-		_("Based on keyboard or mouse use"), "system",
-#endif
-		NULL);
-	gtk_size_group_add_widget(sg, dd);
-	gtk_misc_set_alignment(GTK_MISC(dd), 0, 0.5);
-
-	/* Away stuff */
-	vbox = pidgin_make_frame(ret, _("Away"));
-
-	dd = pidgin_prefs_dropdown(vbox, _("_Auto-reply:"),
-		PURPLE_PREF_STRING, "/purple/away/auto_reply",
-		_("Never"), "never",
-		_("When away"), "away",
-		_("When both away and idle"), "awayidle",
-		NULL);
-	gtk_size_group_add_widget(sg, dd);
-	gtk_misc_set_alignment(GTK_MISC(dd), 0, 0.5);
-
-	/* Auto-away stuff */
-	vbox = pidgin_make_frame(ret, _("Auto-away"));
-
-	button = pidgin_prefs_checkbox(_("Change status when _idle"),
-						   "/purple/away/away_when_idle", vbox);
-
-	select = pidgin_prefs_labeled_spin_button(vbox,
-			_("_Minutes before becoming idle:"), "/purple/away/mins_before_away",
-			1, 24 * 60, sg);
-	g_signal_connect(G_OBJECT(button), "clicked",
-					 G_CALLBACK(pidgin_toggle_sensitive), select);
-
-	/* TODO: Show something useful if we don't have any saved statuses. */
-	menu = pidgin_status_menu(purple_savedstatus_get_idleaway(), G_CALLBACK(set_idle_away));
-	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Change _status to:"), sg, menu, TRUE, &label);
-	g_signal_connect(G_OBJECT(button), "clicked",
-			 G_CALLBACK(pidgin_toggle_sensitive), menu);
-	g_signal_connect(G_OBJECT(button), "clicked",
-					 G_CALLBACK(pidgin_toggle_sensitive), label);
-
-	if (!purple_prefs_get_bool("/purple/away/away_when_idle")) {
-		gtk_widget_set_sensitive(GTK_WIDGET(menu), FALSE);
-		gtk_widget_set_sensitive(GTK_WIDGET(select), FALSE);
-		gtk_widget_set_sensitive(GTK_WIDGET(label), FALSE);
-	}
-
-	/* Signon status stuff */
-	vbox = pidgin_make_frame(ret, _("Status at Startup"));
-
-	button = pidgin_prefs_checkbox(_("Use status from last _exit at startup"),
-		"/purple/savedstatus/startup_current_status", vbox);
-
-	/* TODO: Show something useful if we don't have any saved statuses. */
-	menu = pidgin_status_menu(purple_savedstatus_get_startup(), G_CALLBACK(set_startupstatus));
-	g_signal_connect(G_OBJECT(button), "clicked",
-			 G_CALLBACK(pidgin_toggle_sensitive), menu);
-	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Status to a_pply at startup:"), sg, menu, TRUE, &label);
-	g_signal_connect(G_OBJECT(button), "clicked",
-					 G_CALLBACK(pidgin_toggle_sensitive), label);
-
-	if (purple_prefs_get_bool("/purple/savedstatus/startup_current_status")) {
-		gtk_widget_set_sensitive(GTK_WIDGET(menu), FALSE);
-		gtk_widget_set_sensitive(GTK_WIDGET(label), FALSE);
-	}
-
-	gtk_widget_show_all(ret);
-	g_object_unref(sg);
-
-	return ret;
-}
-
-static int
-prefs_notebook_add_page(const char *text,
-  		        GtkWidget *page,
-			int ind) {
-
-#if GTK_CHECK_VERSION(2,4,0)
-	return gtk_notebook_append_page(GTK_NOTEBOOK(prefsnotebook), page, gtk_label_new(text));
-#else
-	gtk_notebook_append_page(GTK_NOTEBOOK(prefsnotebook), page, gtk_label_new(text));
-	return gtk_notebook_page_num(GTK_NOTEBOOK(prefsnotebook), page);
-#endif
-}
-
-static void prefs_notebook_init(void) {
-	prefs_notebook_add_page(_("Interface"), interface_page(), notebook_page++);
-	prefs_notebook_add_page(_("Conversations"), conv_page(), notebook_page++);
-	prefs_notebook_add_page(_("Smiley Themes"), theme_page(), notebook_page++);
-	prefs_notebook_add_page(_("Sounds"), sound_page(), notebook_page++);
-	prefs_notebook_add_page(_("Network"), network_page(), notebook_page++);
-#ifndef _WIN32
-	/* We use the registered default browser in windows */
-	/* if the user is running gnome 2.x or Mac OS X, hide the browsers tab */
-	if ((purple_running_gnome() == FALSE) && (purple_running_osx() == FALSE)) {
-		prefs_notebook_add_page(_("Browser"), browser_page(), notebook_page++);
-	}
-#endif
-	prefs_notebook_add_page(_("Logging"), logging_page(), notebook_page++);
-	prefs_notebook_add_page(_("Status / Idle"), away_page(), notebook_page++);
-}
-
-void pidgin_prefs_show(void)
-{
-	GtkWidget *vbox;
-	GtkWidget *notebook;
-	GtkWidget *button;
-
-	if (prefs) {
-		gtk_window_present(GTK_WINDOW(prefs));
-		return;
-	}
-
-	/* copy the preferences to tmp values...
-	 * I liked "take affect immediately" Oh well :-( */
-	/* (that should have been "effect," right?) */
-
-	/* Back to instant-apply! I win!  BU-HAHAHA! */
-
-	/* Create the window */
-	prefs = pidgin_create_dialog(_("Preferences"), PIDGIN_HIG_BORDER, "preferences", FALSE);
-	g_signal_connect(G_OBJECT(prefs), "destroy",
-					 G_CALLBACK(delete_prefs), NULL);
-
-	vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(prefs), FALSE, PIDGIN_HIG_BORDER);
-
-	/* The notebook */
-	prefsnotebook = notebook = gtk_notebook_new ();
-	gtk_box_pack_start (GTK_BOX (vbox), notebook, FALSE, FALSE, 0);
-	gtk_widget_show(prefsnotebook);
-
-	button = pidgin_dialog_add_button(GTK_DIALOG(prefs), GTK_STOCK_CLOSE, NULL, NULL);
-	g_signal_connect_swapped(G_OBJECT(button), "clicked",
-							 G_CALLBACK(gtk_widget_destroy), prefs);
-
-	prefs_notebook_init();
-
-	/* Show everything. */
-	gtk_widget_show(prefs);
-}
-
-static void
-set_bool_pref(GtkWidget *w, const char *key)
-{
-	purple_prefs_set_bool(key,
-		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
-}
-
-GtkWidget *
-pidgin_prefs_checkbox(const char *text, const char *key, GtkWidget *page)
-{
-	GtkWidget *button;
-
-	button = gtk_check_button_new_with_mnemonic(text);
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
-								 purple_prefs_get_bool(key));
-
-	gtk_box_pack_start(GTK_BOX(page), button, FALSE, FALSE, 0);
-
-	g_signal_connect(G_OBJECT(button), "clicked",
-					 G_CALLBACK(set_bool_pref), (char *)key);
-
-	gtk_widget_show(button);
-
-	return button;
-}
-
-static void
-smiley_theme_pref_cb(const char *name, PurplePrefType type,
-					 gconstpointer value, gpointer data)
-{
-	const char *themename = value;
-	GSList *themes;
-
-	for (themes = smiley_themes; themes; themes = themes->next) {
-		struct smiley_theme *smile = themes->data;
-		if (smile->name && strcmp(themename, smile->name) == 0) {
-			pidgin_themes_load_smiley_theme(smile->path, TRUE);
-			break;
-		}
-	}
-}
-
-void
-pidgin_prefs_init(void)
-{
-	purple_prefs_add_none(PIDGIN_PREFS_ROOT "");
-	purple_prefs_add_none("/plugins/gtk");
-
-#ifndef _WIN32
-	/* Browsers */
-	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/browsers");
-	purple_prefs_add_int(PIDGIN_PREFS_ROOT "/browsers/place", PIDGIN_BROWSER_DEFAULT);
-	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/browsers/command", "");
-	purple_prefs_add_string(PIDGIN_PREFS_ROOT "/browsers/browser", "mozilla");
-#endif
-
-	/* Plugins */
-	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/plugins");
-	purple_prefs_add_path_list(PIDGIN_PREFS_ROOT "/plugins/loaded", NULL);
-
-	/* File locations */
-	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/filelocations");
-	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_save_folder", "");
-	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_open_folder", "");
-	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder", "");
-
-	/* Smiley Themes */
-	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/smileys");
-	purple_prefs_add_string(PIDGIN_PREFS_ROOT "/smileys/theme", "Default");
-
-	/* Smiley Callbacks */
-	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/smileys/theme",
-								smiley_theme_pref_cb, NULL);
-
-	pidgin_prefs_update_old();
-}
-
-void pidgin_prefs_update_old()
-{
-	const char *str;
-
-	purple_prefs_rename("/gaim/gtk", PIDGIN_PREFS_ROOT);
-
-	/* Rename some old prefs */
-	purple_prefs_rename(PIDGIN_PREFS_ROOT "/logging/log_ims", "/purple/logging/log_ims");
-	purple_prefs_rename(PIDGIN_PREFS_ROOT "/logging/log_chats", "/purple/logging/log_chats");
-	purple_prefs_rename("/purple/conversations/placement",
-					  PIDGIN_PREFS_ROOT "/conversations/placement");
-
-	purple_prefs_rename(PIDGIN_PREFS_ROOT "/debug/timestamps", "/purple/debug/timestamps");
-	purple_prefs_rename(PIDGIN_PREFS_ROOT "/conversations/im/raise_on_events", "/plugins/gtk/X11/notify/method_raise");
-
-	purple_prefs_rename_boolean_toggle(PIDGIN_PREFS_ROOT "/conversations/ignore_colors",
-									 PIDGIN_PREFS_ROOT "/conversations/show_incoming_formatting");
-
-	/* this string pref moved into the core, try to be friendly */
-	purple_prefs_rename(PIDGIN_PREFS_ROOT "/idle/reporting_method", "/purple/away/idle_reporting");
-	if ((str = purple_prefs_get_string("/purple/away/idle_reporting")) &&
-			strcmp(str, "gaim") == 0)
-		purple_prefs_set_string("/purple/away/idle_reporting", "purple");
-
-	/* Remove some no-longer-used prefs */
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/auto_expand_contacts");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/button_style");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/grey_idle_buddies");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/raise_on_events");
-	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");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/html_shortcuts");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/icons_on_tabs");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/send_formatting");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/show_smileys");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/show_urls_as_links");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/smiley_shortcuts");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/use_custom_bgcolor");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/use_custom_fgcolor");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/use_custom_font");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/use_custom_size");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/chat/old_tab_complete");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/chat/tab_completion");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/im/hide_on_send");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/chat/color_nicks");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/chat/raise_on_events");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/ignore_fonts");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/ignore_font_sizes");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/passthrough_unknown_commands");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/idle");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/logging/individual_logs");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/sound/signon");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/sound/silent_signon");
-
-	/* Convert old queuing prefs to hide_new 3-way pref. */
-	if (purple_prefs_exists("/plugins/gtk/docklet/queue_messages") &&
-	    purple_prefs_get_bool("/plugins/gtk/docklet/queue_messages"))
-	{
-		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "always");
-	}
-	else if (purple_prefs_exists(PIDGIN_PREFS_ROOT "/away/queue_messages") &&
-	         purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/away/queue_messages"))
-	{
-		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "away");
-	}
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/away/queue_messages");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/away");
-	purple_prefs_remove("/plugins/gtk/docklet/queue_messages");
-
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/chat/default_width");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/chat/default_height");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/im/default_width");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/im/default_height");
-	purple_prefs_rename(PIDGIN_PREFS_ROOT "/conversations/x",
-			PIDGIN_PREFS_ROOT "/conversations/im/x");
-	purple_prefs_rename(PIDGIN_PREFS_ROOT "/conversations/y",
-			PIDGIN_PREFS_ROOT "/conversations/im/y");
-}
+/**
+ * @file gtkprefs.c GTK+ Preferences
+ * @ingroup pidgin
+ */
+
+/* pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+#include "internal.h"
+#include "pidgin.h"
+
+#include "debug.h"
+#include "notify.h"
+#include "prefs.h"
+#include "proxy.h"
+#include "prpl.h"
+#include "request.h"
+#include "savedstatuses.h"
+#include "sound.h"
+#include "util.h"
+#include "network.h"
+
+#include "gtkblist.h"
+#include "gtkconv.h"
+#include "gtkdebug.h"
+#include "gtkdialogs.h"
+#include "gtkimhtml.h"
+#include "gtkimhtmltoolbar.h"
+#include "gtkprefs.h"
+#include "gtksavedstatuses.h"
+#include "gtksound.h"
+#include "gtkthemes.h"
+#include "gtkutils.h"
+#include "pidginstock.h"
+
+#define PROXYHOST 0
+#define PROXYPORT 1
+#define PROXYUSER 2
+#define PROXYPASS 3
+
+static int sound_row_sel = 0;
+static GtkWidget *prefsnotebook;
+
+static GtkWidget *sound_entry = NULL;
+static GtkListStore *smiley_theme_store = NULL;
+static GtkTreeSelection *smiley_theme_sel = NULL;
+static GtkWidget *prefs_proxy_frame = NULL;
+
+static GtkWidget *prefs = NULL;
+static GtkWidget *debugbutton = NULL;
+static int notebook_page = 0;
+static GtkTreeRowReference *previous_smiley_row = NULL;
+
+/*
+ * PROTOTYPES
+ */
+static void delete_prefs(GtkWidget *, void *);
+
+static void
+update_spin_value(GtkWidget *w, GtkWidget *spin)
+{
+	const char *key = g_object_get_data(G_OBJECT(spin), "val");
+	int value;
+
+	value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
+
+	purple_prefs_set_int(key, value);
+}
+
+GtkWidget *
+pidgin_prefs_labeled_spin_button(GtkWidget *box, const gchar *title,
+		const char *key, int min, int max, GtkSizeGroup *sg)
+{
+	GtkWidget *spin;
+	GtkObject *adjust;
+	int val;
+
+	val = purple_prefs_get_int(key);
+
+	adjust = gtk_adjustment_new(val, min, max, 1, 1, 1);
+	spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0);
+	g_object_set_data(G_OBJECT(spin), "val", (char *)key);
+	if (max < 10000)
+		gtk_widget_set_size_request(spin, 50, -1);
+	else
+		gtk_widget_set_size_request(spin, 60, -1);
+	g_signal_connect(G_OBJECT(adjust), "value-changed",
+					 G_CALLBACK(update_spin_value), GTK_WIDGET(spin));
+	gtk_widget_show(spin);
+
+	return pidgin_add_widget_to_vbox(GTK_BOX(box), title, sg, spin, FALSE, NULL);
+}
+
+static void
+entry_set(GtkEntry *entry, gpointer data) {
+	const char *key = (const char*)data;
+
+	purple_prefs_set_string(key, gtk_entry_get_text(entry));
+}
+
+GtkWidget *
+pidgin_prefs_labeled_entry(GtkWidget *page, const gchar *title,
+							 const char *key, GtkSizeGroup *sg)
+{
+	GtkWidget *entry;
+	const gchar *value;
+
+	value = purple_prefs_get_string(key);
+
+	entry = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(entry), value);
+	g_signal_connect(G_OBJECT(entry), "changed",
+					 G_CALLBACK(entry_set), (char*)key);
+	gtk_widget_show(entry);
+
+	return pidgin_add_widget_to_vbox(GTK_BOX(page), title, sg, entry, TRUE, NULL);
+}
+
+static void
+dropdown_set(GObject *w, const char *key)
+{
+	const char *str_value;
+	int int_value;
+	PurplePrefType type;
+
+	type = GPOINTER_TO_INT(g_object_get_data(w, "type"));
+
+	if (type == PURPLE_PREF_INT) {
+		int_value = GPOINTER_TO_INT(g_object_get_data(w, "value"));
+
+		purple_prefs_set_int(key, int_value);
+	}
+	else if (type == PURPLE_PREF_STRING) {
+		str_value = (const char *)g_object_get_data(w, "value");
+
+		purple_prefs_set_string(key, str_value);
+	}
+	else if (type == PURPLE_PREF_BOOLEAN) {
+		purple_prefs_set_bool(key,
+				GPOINTER_TO_INT(g_object_get_data(w, "value")));
+	}
+}
+
+GtkWidget *
+pidgin_prefs_dropdown_from_list(GtkWidget *box, const gchar *title,
+		PurplePrefType type, const char *key, GList *menuitems)
+{
+	GtkWidget  *dropdown, *opt, *menu;
+	GtkWidget  *label = NULL;
+	gchar      *text;
+	const char *stored_str = NULL;
+	int         stored_int = 0;
+	int         int_value  = 0;
+	const char *str_value  = NULL;
+	int         o = 0;
+
+	g_return_val_if_fail(menuitems != NULL, NULL);
+
+#if 0 /* GTK_CHECK_VERSION(2,4,0) */
+	if(type == PURPLE_PREF_INT)
+		model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
+	else if(type == PURPLE_PREF_STRING)
+		model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
+	dropdown = gtk_combo_box_new_with_model(model);
+#else
+	dropdown = gtk_option_menu_new();
+	menu = gtk_menu_new();
+#endif
+
+	if (type == PURPLE_PREF_INT)
+		stored_int = purple_prefs_get_int(key);
+	else if (type == PURPLE_PREF_STRING)
+		stored_str = purple_prefs_get_string(key);
+
+	while (menuitems != NULL && (text = (char *) menuitems->data) != NULL) {
+		menuitems = g_list_next(menuitems);
+		g_return_val_if_fail(menuitems != NULL, NULL);
+
+		opt = gtk_menu_item_new_with_label(text);
+
+		g_object_set_data(G_OBJECT(opt), "type", GINT_TO_POINTER(type));
+
+		if (type == PURPLE_PREF_INT) {
+			int_value = GPOINTER_TO_INT(menuitems->data);
+			g_object_set_data(G_OBJECT(opt), "value",
+							  GINT_TO_POINTER(int_value));
+		}
+		else if (type == PURPLE_PREF_STRING) {
+			str_value = (const char *)menuitems->data;
+
+			g_object_set_data(G_OBJECT(opt), "value", (char *)str_value);
+		}
+		else if (type == PURPLE_PREF_BOOLEAN) {
+			g_object_set_data(G_OBJECT(opt), "value",
+					menuitems->data);
+		}
+
+		g_signal_connect(G_OBJECT(opt), "activate",
+						 G_CALLBACK(dropdown_set), (char *)key);
+
+		gtk_widget_show(opt);
+		gtk_menu_shell_append(GTK_MENU_SHELL(menu), opt);
+
+		if ((type == PURPLE_PREF_INT && stored_int == int_value) ||
+			(type == PURPLE_PREF_STRING && stored_str != NULL &&
+			 !strcmp(stored_str, str_value)) ||
+			(type == PURPLE_PREF_BOOLEAN &&
+			 (purple_prefs_get_bool(key) == GPOINTER_TO_INT(menuitems->data)))) {
+
+			gtk_menu_set_active(GTK_MENU(menu), o);
+		}
+
+		menuitems = g_list_next(menuitems);
+
+		o++;
+	}
+
+	gtk_option_menu_set_menu(GTK_OPTION_MENU(dropdown), menu);
+
+	pidgin_add_widget_to_vbox(GTK_BOX(box), title, NULL, dropdown, FALSE, &label);
+
+	return label;
+}
+
+GtkWidget *
+pidgin_prefs_dropdown(GtkWidget *box, const gchar *title, PurplePrefType type,
+			   const char *key, ...)
+{
+	va_list ap;
+	GList *menuitems = NULL;
+	GtkWidget *dropdown = NULL;
+	char *name;
+	int int_value;
+	const char *str_value;
+
+	g_return_val_if_fail(type == PURPLE_PREF_BOOLEAN || type == PURPLE_PREF_INT ||
+			type == PURPLE_PREF_STRING, NULL);
+
+	va_start(ap, key);
+	while ((name = va_arg(ap, char *)) != NULL) {
+
+		menuitems = g_list_prepend(menuitems, name);
+
+		if (type == PURPLE_PREF_INT || type == PURPLE_PREF_BOOLEAN) {
+			int_value = va_arg(ap, int);
+			menuitems = g_list_prepend(menuitems, GINT_TO_POINTER(int_value));
+		}
+		else {
+			str_value = va_arg(ap, const char *);
+			menuitems = g_list_prepend(menuitems, (char *)str_value);
+		}
+	}
+	va_end(ap);
+
+	g_return_val_if_fail(menuitems != NULL, NULL);
+
+	menuitems = g_list_reverse(menuitems);
+
+	dropdown = pidgin_prefs_dropdown_from_list(box, title, type, key,
+			menuitems);
+
+	g_list_free(menuitems);
+
+	return dropdown;
+}
+
+static void
+delete_prefs(GtkWidget *asdf, void *gdsa)
+{
+	/* Close any "select sound" request dialogs */
+	purple_request_close_with_handle(prefs);
+
+	/* Unregister callbacks. */
+	purple_prefs_disconnect_by_handle(prefs);
+
+	prefs = NULL;
+	sound_entry = NULL;
+	debugbutton = NULL;
+	notebook_page = 0;
+	smiley_theme_store = NULL;
+	if (previous_smiley_row)
+		gtk_tree_row_reference_free(previous_smiley_row);
+	previous_smiley_row = NULL;
+
+}
+
+static void smiley_sel(GtkTreeSelection *sel, GtkTreeModel *model) {
+	GtkTreeIter  iter;
+	const char *themename;
+	char *description;
+	GValue val;
+	GtkTreePath *path, *oldpath;
+	struct smiley_theme *new_theme, *old_theme;
+	GtkWidget *remove_button = g_object_get_data(G_OBJECT(sel), "remove_button");
+
+	if (!gtk_tree_selection_get_selected(sel, &model, &iter)) {
+		gtk_widget_set_sensitive(remove_button, FALSE);
+		return;
+	}
+
+	old_theme = current_smiley_theme;
+	val.g_type = 0;
+	gtk_tree_model_get_value(model, &iter, 3, &val);
+	path = gtk_tree_model_get_path(model, &iter);
+	themename = g_value_get_string(&val);
+	purple_prefs_set_string(PIDGIN_PREFS_ROOT "/smileys/theme", themename);
+
+	gtk_widget_set_sensitive(remove_button, (strcmp(themename, "none") &&
+	                                         strcmp(themename, _("Default"))));
+	g_value_unset (&val);
+
+	/* current_smiley_theme is set in callback for the above pref change */
+	new_theme = current_smiley_theme;
+	description = g_strdup_printf("<span size='larger' weight='bold'>%s</span> - %s\n"
+								"<span size='smaller' foreground='white'>%s</span>",
+								_(new_theme->name), _(new_theme->author), _(new_theme->desc));
+	gtk_list_store_set(smiley_theme_store, &iter, 1, description, -1);
+	g_free(description);
+
+	if (new_theme != old_theme && previous_smiley_row) {
+		oldpath = gtk_tree_row_reference_get_path(previous_smiley_row);
+		if (gtk_tree_model_get_iter(model, &iter, oldpath)) {
+			description = g_strdup_printf("<span size='larger' weight='bold'>%s</span> - %s\n"
+								"<span size='smaller' foreground='dim grey'>%s</span>",
+								_(old_theme->name), _(old_theme->author), _(old_theme->desc));
+			gtk_list_store_set(smiley_theme_store, &iter, 1,
+				description, -1);
+			g_free(description);
+		}
+		gtk_tree_path_free(oldpath);
+	}
+	if (previous_smiley_row)
+		gtk_tree_row_reference_free(previous_smiley_row);
+	previous_smiley_row = gtk_tree_row_reference_new(model, path);
+	gtk_tree_path_free(path);
+}
+
+static GtkTreeRowReference *theme_refresh_theme_list(void)
+{
+	GdkPixbuf *pixbuf;
+	GSList *themes;
+	GtkTreeIter iter;
+	GtkTreeRowReference *row_ref = NULL;
+
+	if (previous_smiley_row)
+		gtk_tree_row_reference_free(previous_smiley_row);
+	previous_smiley_row = NULL;
+
+	pidgin_themes_smiley_theme_probe();
+
+	if (!(themes = smiley_themes))
+		return NULL;
+
+	gtk_list_store_clear(smiley_theme_store);
+
+	while (themes) {
+		struct smiley_theme *theme = themes->data;
+		char *description = g_strdup_printf("<span size='larger' weight='bold'>%s</span> - %s\n"
+						    "<span size='smaller' foreground='dim grey'>%s</span>",
+						    _(theme->name), _(theme->author), _(theme->desc));
+		gtk_list_store_append (smiley_theme_store, &iter);
+
+		/*
+		 * LEAK - Gentoo memprof thinks pixbuf is leaking here... but it
+		 * looks like it should be ok to me.  Anyone know what's up?  --Mark
+		 */
+		pixbuf = (theme->icon ? gdk_pixbuf_new_from_file(theme->icon, NULL) : NULL);
+
+		gtk_list_store_set(smiley_theme_store, &iter,
+				   0, pixbuf,
+				   1, description,
+				   2, theme->path,
+				   3, theme->name,
+				   -1);
+
+		if (pixbuf != NULL)
+			g_object_unref(G_OBJECT(pixbuf));
+
+		g_free(description);
+		themes = themes->next;
+
+		/* If this is the currently selected theme,
+		 * we will need to select it. Grab the row reference. */
+		if (theme == current_smiley_theme) {
+			GtkTreePath *path = gtk_tree_model_get_path(
+				GTK_TREE_MODEL(smiley_theme_store), &iter);
+			row_ref = gtk_tree_row_reference_new(
+				GTK_TREE_MODEL(smiley_theme_store), path);
+			gtk_tree_path_free(path);
+		}
+	}
+
+	return row_ref;
+}
+
+static void theme_install_theme(char *path, char *extn) {
+#ifndef _WIN32
+	gchar *command;
+#endif
+	gchar *destdir;
+	gchar *tail;
+	GtkTreeRowReference *theme_rowref;
+
+	/* Just to be safe */
+	g_strchomp(path);
+
+	/* I dont know what you are, get out of here */
+	if (extn != NULL)
+		tail = extn;
+	else if ((tail = strrchr(path, '.')) == NULL)
+		return;
+
+	destdir = g_strconcat(purple_user_dir(), G_DIR_SEPARATOR_S "smileys", NULL);
+
+	/* We'll check this just to make sure. This also lets us do something different on
+	 * other platforms, if need be */
+	if (!g_ascii_strcasecmp(tail, ".gz") || !g_ascii_strcasecmp(tail, ".tgz")) {
+#ifndef _WIN32
+		gchar *path_escaped = g_shell_quote(path);
+		gchar *destdir_escaped = g_shell_quote(destdir);
+		command = g_strdup_printf("tar > /dev/null xzf %s -C %s", path_escaped, destdir_escaped);
+		g_free(path_escaped);
+		g_free(destdir_escaped);
+#else
+		if(!winpidgin_gz_untar(path, destdir)) {
+			g_free(destdir);
+			return;
+		}
+#endif
+	}
+	else {
+		g_free(destdir);
+		return;
+	}
+
+#ifndef _WIN32
+	/* Fire! */
+	if (system(command))
+	{
+		purple_notify_error(NULL, NULL, _("Smiley theme failed to unpack."), NULL);
+	}
+
+	g_free(command);
+#endif
+	g_free(destdir);
+
+	theme_rowref = theme_refresh_theme_list();
+	if (theme_rowref != NULL) {
+		GtkTreePath *tp = gtk_tree_row_reference_get_path(theme_rowref);
+
+		if (tp)
+			gtk_tree_selection_select_path(smiley_theme_sel, tp);
+		gtk_tree_row_reference_free(theme_rowref);
+	}
+}
+
+static void
+theme_got_url(PurpleUtilFetchUrlData *url_data, gpointer user_data,
+		const gchar *themedata, size_t len, const gchar *error_message)
+{
+	FILE *f;
+	gchar *path;
+	size_t wc;
+
+	if ((error_message != NULL) || (len == 0))
+		return;
+
+	f = purple_mkstemp(&path, TRUE);
+	wc = fwrite(themedata, len, 1, f);
+	if (wc != 1) {
+		purple_debug_warning("theme_got_url", "Unable to write theme data.\n");
+		fclose(f);
+		g_unlink(path);
+		g_free(path);
+		return;
+	}
+	fclose(f);
+
+	theme_install_theme(path, user_data);
+
+	g_unlink(path);
+	g_free(path);
+}
+
+static void
+theme_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y,
+		GtkSelectionData *sd, guint info, guint t, gpointer data)
+{
+	gchar *name = (gchar *)sd->data;
+
+	if ((sd->length >= 0) && (sd->format == 8)) {
+		/* Well, it looks like the drag event was cool.
+		 * Let's do something with it */
+
+		if (!g_ascii_strncasecmp(name, "file://", 7)) {
+			GError *converr = NULL;
+			gchar *tmp;
+			/* It looks like we're dealing with a local file. Let's
+			 * just untar it in the right place */
+			if(!(tmp = g_filename_from_uri(name, NULL, &converr))) {
+				purple_debug(PURPLE_DEBUG_ERROR, "theme dnd", "%s\n",
+						   (converr ? converr->message :
+							"g_filename_from_uri error"));
+				return;
+			}
+			theme_install_theme(tmp, NULL);
+			g_free(tmp);
+		} else if (!g_ascii_strncasecmp(name, "http://", 7)) {
+			/* Oo, a web drag and drop. This is where things
+			 * will start to get interesting */
+			purple_util_fetch_url(name, TRUE, NULL, FALSE, theme_got_url, ".tgz");
+		} else if (!g_ascii_strncasecmp(name, "https://", 8)) {
+			/* purple_util_fetch_url() doesn't support HTTPS, but we want users
+			 * to be able to drag and drop links from the SF trackers, so
+			 * we'll try it as an HTTP URL. */
+			char *tmp = g_strdup(name + 1);
+			tmp[0] = 'h';
+			tmp[1] = 't';
+			tmp[2] = 't';
+			tmp[3] = 'p';
+			purple_util_fetch_url(tmp, TRUE, NULL, FALSE, theme_got_url, ".tgz");
+			g_free(tmp);
+		}
+
+		gtk_drag_finish(dc, TRUE, FALSE, t);
+	}
+
+	gtk_drag_finish(dc, FALSE, FALSE, t);
+}
+
+/* Does same as normal sort, except "none" is sorted first */
+static gint pidgin_sort_smileys (GtkTreeModel	*model,
+						GtkTreeIter		*a,
+						GtkTreeIter		*b,
+						gpointer		userdata)
+{
+	gint ret = 0;
+	gchar *name1 = NULL, *name2 = NULL;
+
+	gtk_tree_model_get(model, a, 3, &name1, -1);
+	gtk_tree_model_get(model, b, 3, &name2, -1);
+
+	if (name1 == NULL || name2 == NULL) {
+		if (!(name1 == NULL && name2 == NULL))
+			ret = (name1 == NULL) ? -1: 1;
+	} else if (!g_ascii_strcasecmp(name1, "none")) {
+		if (!g_utf8_collate(name1, name2))
+			ret = 0;
+		else
+			/* Sort name1 first */
+			ret = -1;
+	} else if (!g_ascii_strcasecmp(name2, "none")) {
+		/* Sort name2 first */
+		ret = 1;
+	} else {
+		/* Neither string is "none", default to normal sort */
+		ret = purple_utf8_strcasecmp(name1,name2);
+	}
+
+	g_free(name1);
+	g_free(name2);
+
+	return ret;
+}
+
+static void
+request_theme_file_name_cb(gpointer data, char *theme_file_name)
+{
+	theme_install_theme(theme_file_name, NULL) ;
+}
+
+static void
+add_theme_button_clicked_cb(GtkWidget *widget, gpointer null)
+{
+	purple_request_file(NULL, _("Install Theme"), NULL, FALSE, (GCallback)request_theme_file_name_cb, NULL, NULL, NULL, NULL, NULL) ;
+}
+
+static void
+remove_theme_button_clicked_cb(GtkWidget *button, GtkTreeView *tv)
+{
+	char *theme_name = NULL, *theme_file = NULL;
+	GtkTreeModel *tm;
+	GtkTreeIter itr;
+	GtkTreeRowReference *trr = NULL;
+
+	if ((tm = gtk_tree_view_get_model(tv)) == NULL)
+		return;
+	if (!gtk_tree_selection_get_selected(smiley_theme_sel, NULL, &itr))
+		return;
+	gtk_tree_model_get(tm, &itr, 2, &theme_file, 3, &theme_name, -1);
+
+	if (theme_file && theme_name && strcmp(theme_name, "none"))
+		pidgin_themes_remove_smiley_theme(theme_file);
+
+	if ((trr = theme_refresh_theme_list()) != NULL) {
+		GtkTreePath *tp = gtk_tree_row_reference_get_path(trr);
+
+		if (tp) {
+			gtk_tree_selection_select_path(smiley_theme_sel, tp);
+			gtk_tree_path_free(tp);
+		}
+		gtk_tree_row_reference_free(trr);
+	}
+
+	g_free(theme_file);
+	g_free(theme_name);
+}
+
+static GtkWidget *
+theme_page(void)
+{
+	GtkWidget *add_button, *remove_button;
+	GtkWidget *hbox_buttons;
+	GtkWidget *alignment;
+	GtkWidget *ret;
+	GtkWidget *sw;
+	GtkWidget *view;
+	GtkCellRenderer *rend;
+	GtkTreeViewColumn *col;
+	GtkTreeSelection *sel;
+	GtkTreeRowReference *rowref;
+	GtkWidget *label;
+	GtkTargetEntry te[3] = {{"text/plain", 0, 0},{"text/uri-list", 0, 1},{"STRING", 0, 2}};
+
+	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
+	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
+
+	label = gtk_label_new(_("Select a smiley theme that you would like to use from the list below. New themes can be installed by dragging and dropping them onto the theme list."));
+
+	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+
+	gtk_box_pack_start(GTK_BOX(ret), label, FALSE, TRUE, 0);
+	gtk_widget_show(label);
+
+	sw = gtk_scrolled_window_new(NULL,NULL);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
+
+	gtk_box_pack_start(GTK_BOX(ret), sw, TRUE, TRUE, 0);
+	smiley_theme_store = gtk_list_store_new (4, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+	rowref = theme_refresh_theme_list();
+
+	view = gtk_tree_view_new_with_model (GTK_TREE_MODEL(smiley_theme_store));
+
+	gtk_drag_dest_set(view, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te,
+					sizeof(te) / sizeof(GtkTargetEntry) , GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
+	g_signal_connect(G_OBJECT(view), "drag_data_received", G_CALLBACK(theme_dnd_recv), smiley_theme_store);
+
+	rend = gtk_cell_renderer_pixbuf_new();
+	smiley_theme_sel = sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
+
+	/* Custom sort so "none" theme is at top of list */
+	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(smiley_theme_store),
+									3, pidgin_sort_smileys, NULL, NULL);
+
+	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(smiley_theme_store),
+										 3, GTK_SORT_ASCENDING);
+
+	col = gtk_tree_view_column_new_with_attributes (_("Icon"),
+							rend,
+							"pixbuf", 0,
+							NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW(view), col);
+
+	rend = gtk_cell_renderer_text_new();
+	col = gtk_tree_view_column_new_with_attributes (_("Description"),
+							rend,
+							"markup", 1,
+							NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW(view), col);
+	g_object_unref(G_OBJECT(smiley_theme_store));
+	gtk_container_add(GTK_CONTAINER(sw), view);
+
+	g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(smiley_sel), NULL);
+
+	alignment = gtk_alignment_new(1.0, 0.5, 0.0, 1.0);
+	gtk_widget_show(alignment);
+	gtk_box_pack_start(GTK_BOX(ret), alignment, FALSE, TRUE, 0);
+
+	hbox_buttons = gtk_hbox_new(TRUE, PIDGIN_HIG_CAT_SPACE);
+	gtk_widget_show(hbox_buttons);
+	gtk_container_add(GTK_CONTAINER(alignment), hbox_buttons);
+
+	add_button = gtk_button_new_from_stock(GTK_STOCK_ADD);
+	gtk_widget_show(add_button);
+	gtk_box_pack_start(GTK_BOX(hbox_buttons), add_button, FALSE, TRUE, 0);
+	g_signal_connect(G_OBJECT(add_button), "clicked", (GCallback)add_theme_button_clicked_cb, view);
+
+	remove_button = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
+	gtk_widget_show(remove_button);
+	gtk_box_pack_start(GTK_BOX(hbox_buttons), remove_button, FALSE, TRUE, 0);
+	g_signal_connect(G_OBJECT(remove_button), "clicked", (GCallback)remove_theme_button_clicked_cb, view);
+	g_object_set_data(G_OBJECT(sel), "remove_button", remove_button);
+
+	if (rowref) {
+		GtkTreePath *path = gtk_tree_row_reference_get_path(rowref);
+		gtk_tree_row_reference_free(rowref);
+		gtk_tree_selection_select_path(sel, path);
+		gtk_tree_path_free(path);
+	}
+
+	gtk_widget_show_all(ret);
+
+	pidgin_set_accessible_label (view, label);
+
+	return ret;
+}
+
+static void
+formatting_toggle_cb(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons, void *toolbar)
+{
+	gboolean bold, italic, uline;
+
+	gtk_imhtml_get_current_format(GTK_IMHTML(imhtml),
+								  &bold, &italic, &uline);
+
+	if (buttons & GTK_IMHTML_BOLD)
+		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/send_bold", bold);
+	if (buttons & GTK_IMHTML_ITALIC)
+		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/send_italic", italic);
+	if (buttons & GTK_IMHTML_UNDERLINE)
+		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/send_underline", uline);
+
+	if (buttons & GTK_IMHTML_GROW || buttons & GTK_IMHTML_SHRINK)
+		purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/font_size",
+						   gtk_imhtml_get_current_fontsize(GTK_IMHTML(imhtml)));
+	if (buttons & GTK_IMHTML_FACE) {
+		char *face = gtk_imhtml_get_current_fontface(GTK_IMHTML(imhtml));
+		if (!face)
+			face = g_strdup("");
+
+		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/font_face", face);
+		g_free(face);
+	}
+
+	if (buttons & GTK_IMHTML_FORECOLOR) {
+		char *color = gtk_imhtml_get_current_forecolor(GTK_IMHTML(imhtml));
+		if (!color)
+			color = g_strdup("");
+
+		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/fgcolor", color);
+		g_free(color);
+	}
+
+	if (buttons & GTK_IMHTML_BACKCOLOR) {
+		char *color;
+		GObject *object;
+
+		color = gtk_imhtml_get_current_backcolor(GTK_IMHTML(imhtml));
+		if (!color)
+			color = g_strdup("");
+
+		/* Block the signal to prevent a loop. */
+		object = g_object_ref(G_OBJECT(imhtml));
+		g_signal_handlers_block_matched(object, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
+										NULL, toolbar);
+		/* Clear the backcolor. */
+		gtk_imhtml_toggle_backcolor(GTK_IMHTML(imhtml), "");
+		/* Unblock the signal. */
+		g_signal_handlers_unblock_matched(object, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
+										  NULL, toolbar);
+		g_object_unref(object);
+
+		/* This will fire a toggle signal and get saved below. */
+		gtk_imhtml_toggle_background(GTK_IMHTML(imhtml), color);
+
+		g_free(color);
+	}
+
+	if (buttons & GTK_IMHTML_BACKGROUND) {
+		char *color = gtk_imhtml_get_current_background(GTK_IMHTML(imhtml));
+		if (!color)
+			color = g_strdup("");
+
+		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/bgcolor", color);
+		g_free(color);
+	}
+}
+
+static void
+formatting_clear_cb(GtkIMHtml *imhtml, void *data)
+{
+	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/send_bold", FALSE);
+	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/send_italic", FALSE);
+	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/send_underline", FALSE);
+
+	purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/font_size", 3);
+
+	purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/font_face", "");
+	purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/fgcolor", "");
+	purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/bgcolor", "");
+}
+
+static void
+conversation_usetabs_cb(const char *name, PurplePrefType type,
+						gconstpointer value, gpointer data)
+{
+	gboolean usetabs = GPOINTER_TO_INT(value);
+
+	if (usetabs)
+		gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
+	else
+		gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
+}
+
+static GtkWidget *
+interface_page(void)
+{
+	GtkWidget *ret;
+	GtkWidget *vbox;
+	GtkWidget *vbox2;
+	GtkWidget *label;
+	GtkSizeGroup *sg;
+	GList *names = NULL;
+
+	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
+	gtk_container_set_border_width(GTK_CONTAINER(ret), PIDGIN_HIG_BORDER);
+
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+
+	vbox = pidgin_make_frame(ret, _("System Tray Icon"));
+	label = pidgin_prefs_dropdown(vbox, _("_Show system tray icon:"), PURPLE_PREF_STRING,
+					PIDGIN_PREFS_ROOT "/docklet/show",
+					_("Always"), "always",
+					_("On unread messages"), "pending",
+					_("Never"), "never",
+					NULL);
+	gtk_size_group_add_widget(sg, label);
+        gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+
+	vbox = pidgin_make_frame(ret, _("Conversation Window Hiding"));
+	label = pidgin_prefs_dropdown(vbox, _("_Hide new IM conversations:"),
+					PURPLE_PREF_STRING, PIDGIN_PREFS_ROOT "/conversations/im/hide_new",
+					_("Never"), "never",
+					_("When away"), "away",
+					_("Always"), "always",
+					NULL);
+	gtk_size_group_add_widget(sg, label);
+        gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+
+
+	/* All the tab options! */
+	vbox = pidgin_make_frame(ret, _("Tabs"));
+
+	pidgin_prefs_checkbox(_("Show IMs and chats in _tabbed windows"),
+							PIDGIN_PREFS_ROOT "/conversations/tabs", vbox);
+
+	/*
+	 * Connect a signal to the above preference.  When conversations are not
+	 * shown in a tabbed window then all tabbing options should be disabled.
+	 */
+	vbox2 = gtk_vbox_new(FALSE, 9);
+	gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 0);
+	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/conversations/tabs",
+	                            conversation_usetabs_cb, vbox2);
+	if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/tabs"))
+	  gtk_widget_set_sensitive(vbox2, FALSE);
+
+	pidgin_prefs_checkbox(_("Show close b_utton on tabs"),
+				PIDGIN_PREFS_ROOT "/conversations/close_on_tabs", vbox2);
+
+	pidgin_prefs_checkbox(_("Trim names on vertical tabs"),
+				PIDGIN_PREFS_ROOT "/conversations/trim_vertical_tabs", vbox2);
+
+	label = pidgin_prefs_dropdown(vbox2, _("_Placement:"), PURPLE_PREF_INT,
+					PIDGIN_PREFS_ROOT "/conversations/tab_side",
+					_("Top"), GTK_POS_TOP,
+					_("Bottom"), GTK_POS_BOTTOM,
+					_("Left"), GTK_POS_LEFT,
+					_("Right"), GTK_POS_RIGHT,
+#if GTK_CHECK_VERSION(2,6,0)
+					_("Left Vertical"), GTK_POS_LEFT|8,
+					_("Right Vertical"), GTK_POS_RIGHT|8,
+#endif
+					NULL);
+	gtk_size_group_add_widget(sg, label);
+        gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+
+	names = pidgin_conv_placement_get_options();
+	label = pidgin_prefs_dropdown_from_list(vbox2, _("N_ew conversations:"),
+				PURPLE_PREF_STRING, PIDGIN_PREFS_ROOT "/conversations/placement", names);
+	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+
+	gtk_size_group_add_widget(sg, label);
+
+	g_list_free(names);
+
+	gtk_widget_show_all(ret);
+	g_object_unref(sg);
+	return ret;
+}
+
+#if GTK_CHECK_VERSION(2,4,0)
+static void
+pidgin_custom_font_set(GtkFontButton *font_button, gpointer nul)
+{
+	purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/custom_font",
+				gtk_font_button_get_font_name(font_button));
+}
+#endif
+
+static GtkWidget *
+conv_page(void)
+{
+	GtkWidget *ret;
+	GtkWidget *vbox;
+	GtkWidget *toolbar;
+	GtkWidget *iconpref1;
+	GtkWidget *iconpref2;
+	GtkWidget *fontpref;
+	GtkWidget *imhtml;
+	GtkWidget *frame;
+
+#if GTK_CHECK_VERSION(2,4,0)
+	GtkWidget *hbox;
+	GtkWidget *font_button;
+	const char *font_name;
+#endif
+
+	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
+	gtk_container_set_border_width(GTK_CONTAINER(ret), PIDGIN_HIG_BORDER);
+
+	vbox = pidgin_make_frame(ret, _("Conversations"));
+
+	pidgin_prefs_checkbox(_("Show _formatting on incoming messages"),
+				PIDGIN_PREFS_ROOT "/conversations/show_incoming_formatting", vbox);
+
+	iconpref1 = pidgin_prefs_checkbox(_("Show _detailed information"),
+			PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", vbox);
+	iconpref2 = pidgin_prefs_checkbox(_("Enable buddy ic_on animation"),
+			PIDGIN_PREFS_ROOT "/conversations/im/animate_buddy_icons", vbox);
+	if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons"))
+		gtk_widget_set_sensitive(iconpref2, FALSE);
+	g_signal_connect(G_OBJECT(iconpref1), "clicked",
+					 G_CALLBACK(pidgin_toggle_sensitive), iconpref2);
+
+	pidgin_prefs_checkbox(_("_Notify buddies that you are typing to them"),
+			"/purple/conversations/im/send_typing", vbox);
+#ifdef USE_GTKSPELL
+	pidgin_prefs_checkbox(_("Highlight _misspelled words"),
+			PIDGIN_PREFS_ROOT "/conversations/spellcheck", vbox);
+#endif
+
+	pidgin_prefs_checkbox(_("Use smooth-scrolling"), PIDGIN_PREFS_ROOT "/conversations/use_smooth_scrolling", vbox);
+	pidgin_prefs_checkbox(_("Use msn messenger style"), "/purple/conversations/msnstyle", vbox);//yaz
+#ifdef _WIN32
+	pidgin_prefs_checkbox(_("F_lash window when IMs are received"), PIDGIN_PREFS_ROOT "/win32/blink_im", vbox);
+
+	pidgin_prefs_checkbox(_("Minimi_ze new conversation windows"), PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", vbox);
+#endif
+
+#if GTK_CHECK_VERSION(2,4,0)
+	vbox = pidgin_make_frame(ret, _("Font"));
+	if (purple_running_gnome())
+		fontpref = pidgin_prefs_checkbox(_("Use document font from _theme"), PIDGIN_PREFS_ROOT "/conversations/use_theme_font", vbox);
+	else
+		fontpref = pidgin_prefs_checkbox(_("Use font from _theme"), PIDGIN_PREFS_ROOT "/conversations/use_theme_font", vbox);
+
+	font_name = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/custom_font");
+	font_button = gtk_font_button_new_with_font(font_name ? font_name : NULL);
+
+	gtk_font_button_set_show_style(GTK_FONT_BUTTON(font_button), TRUE);
+	hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Conversation _font:"), NULL, font_button, FALSE, NULL);
+	if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_theme_font"))
+		gtk_widget_set_sensitive(hbox, FALSE);
+	g_signal_connect(G_OBJECT(fontpref), "clicked", G_CALLBACK(pidgin_toggle_sensitive), hbox);
+	g_signal_connect(G_OBJECT(font_button), "font-set", G_CALLBACK(pidgin_custom_font_set), NULL);
+#endif
+
+	vbox = pidgin_make_frame(ret, _("Default Formatting"));
+	gtk_box_set_child_packing(GTK_BOX(vbox->parent), vbox, TRUE, TRUE, 0, GTK_PACK_START);
+
+	frame = pidgin_create_imhtml(TRUE, &imhtml, &toolbar, NULL);
+	gtk_widget_show(frame);
+	gtk_widget_set_name(imhtml, "pidgin_prefs_font_imhtml");
+	gtk_widget_set_size_request(frame, 300, -1);
+	gtk_imhtml_set_whole_buffer_formatting_only(GTK_IMHTML(imhtml), TRUE);
+	gtk_imhtml_set_format_functions(GTK_IMHTML(imhtml),
+									GTK_IMHTML_BOLD |
+									GTK_IMHTML_ITALIC |
+									GTK_IMHTML_UNDERLINE |
+									GTK_IMHTML_GROW |
+									GTK_IMHTML_SHRINK |
+									GTK_IMHTML_FACE |
+									GTK_IMHTML_FORECOLOR |
+									GTK_IMHTML_BACKCOLOR |
+									GTK_IMHTML_BACKGROUND);
+
+	gtk_imhtml_append_text(GTK_IMHTML(imhtml), _("This is how your outgoing message text will appear when you use protocols that support formatting."), 0);
+
+	gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
+
+	gtk_imhtml_setup_entry(GTK_IMHTML(imhtml), PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_FORMATTING_WBFO);
+
+	g_signal_connect_after(G_OBJECT(imhtml), "format_function_toggle",
+					 G_CALLBACK(formatting_toggle_cb), toolbar);
+	g_signal_connect_after(G_OBJECT(imhtml), "format_function_clear",
+					 G_CALLBACK(formatting_clear_cb), NULL);
+
+
+	gtk_widget_show(ret);
+
+	return ret;
+}
+
+static void network_ip_changed(GtkEntry *entry, gpointer data)
+{
+	/*
+	 * TODO: It would be nice if we could validate this and show a
+	 *       red background in the box when the IP address is invalid
+	 *       and a green background when the IP address is valid.
+	 */
+	purple_network_set_public_ip(gtk_entry_get_text(entry));
+}
+
+static void
+proxy_changed_cb(const char *name, PurplePrefType type,
+				 gconstpointer value, gpointer data)
+{
+	GtkWidget *frame = data;
+	const char *proxy = value;
+
+	if (strcmp(proxy, "none") && strcmp(proxy, "envvar"))
+		gtk_widget_show_all(frame);
+	else
+		gtk_widget_hide(frame);
+}
+
+static void proxy_print_option(GtkEntry *entry, int entrynum)
+{
+	if (entrynum == PROXYHOST)
+		purple_prefs_set_string("/purple/proxy/host", gtk_entry_get_text(entry));
+	else if (entrynum == PROXYPORT)
+		purple_prefs_set_int("/purple/proxy/port", atoi(gtk_entry_get_text(entry)));
+	else if (entrynum == PROXYUSER)
+		purple_prefs_set_string("/purple/proxy/username", gtk_entry_get_text(entry));
+	else if (entrynum == PROXYPASS)
+		purple_prefs_set_string("/purple/proxy/password", gtk_entry_get_text(entry));
+}
+
+static void
+proxy_button_clicked_cb(GtkWidget *button, gpointer null)
+{
+	GError *err = NULL;
+
+	if (g_spawn_command_line_async ("gnome-network-preferences", &err))
+		return;
+
+	purple_notify_error(NULL, NULL, _("Cannot start proxy configuration program."), err->message);
+	g_error_free(err);
+}
+
+static void
+browser_button_clicked_cb(GtkWidget *button, gpointer null)
+{
+	GError *err = NULL;
+
+	if (g_spawn_command_line_async ("gnome-default-applications-properties", &err))
+		return;
+
+	purple_notify_error(NULL, NULL, _("Cannot start browser configuration program."), err->message);
+	g_error_free(err);
+}
+
+static GtkWidget *
+network_page(void)
+{
+	GtkWidget *ret;
+	GtkWidget *vbox, *hbox, *entry;
+	GtkWidget *table, *label, *auto_ip_checkbox, *ports_checkbox, *spin_button;
+	GtkWidget *proxy_warning = NULL, *browser_warning = NULL;
+	GtkWidget *proxy_button = NULL, *browser_button = NULL;
+	GtkSizeGroup *sg;
+	PurpleProxyInfo *proxy_info = NULL;
+
+	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
+	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
+
+	vbox = pidgin_make_frame (ret, _("IP Address"));
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+	pidgin_prefs_labeled_entry(vbox,_("ST_UN server:"),
+			"/purple/network/stun_server", sg);
+
+	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+	gtk_container_add(GTK_CONTAINER(vbox), hbox);
+
+	label = gtk_label_new(NULL);
+	gtk_container_add(GTK_CONTAINER(hbox), label);
+	gtk_size_group_add_widget(sg, label);
+
+	label = gtk_label_new(NULL);
+	gtk_label_set_markup(GTK_LABEL(label),
+			_("<span style=\"italic\">Example: stunserver.org</span>"));
+	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+	gtk_container_add(GTK_CONTAINER(hbox), label);
+
+	auto_ip_checkbox = pidgin_prefs_checkbox(_("_Autodetect IP address"),
+			"/purple/network/auto_ip", vbox);
+
+	table = gtk_table_new(2, 2, FALSE);
+	gtk_container_set_border_width(GTK_CONTAINER(table), 0);
+	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
+	gtk_table_set_row_spacings(GTK_TABLE(table), 10);
+	gtk_container_add(GTK_CONTAINER(vbox), table);
+
+	label = gtk_label_new_with_mnemonic(_("Public _IP:"));
+	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+	gtk_size_group_add_widget(sg, label);
+
+	entry = gtk_entry_new();
+	gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
+	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
+	g_signal_connect(G_OBJECT(entry), "changed",
+					 G_CALLBACK(network_ip_changed), NULL);
+
+	/*
+	 * TODO: This could be better by showing the autodeteced
+	 * IP separately from the user-specified IP.
+	 */
+	if (purple_network_get_my_ip(-1) != NULL)
+		gtk_entry_set_text(GTK_ENTRY(entry),
+		                   purple_network_get_my_ip(-1));
+
+	pidgin_set_accessible_label (entry, label);
+
+
+	if (purple_prefs_get_bool("/purple/network/auto_ip")) {
+		gtk_widget_set_sensitive(GTK_WIDGET(table), FALSE);
+	}
+
+	g_signal_connect(G_OBJECT(auto_ip_checkbox), "clicked",
+					 G_CALLBACK(pidgin_toggle_sensitive), table);
+
+	g_object_unref(sg);
+
+	vbox = pidgin_make_frame (ret, _("Ports"));
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+
+	pidgin_prefs_checkbox(_("_Enable automatic router port forwarding"),
+			"/purple/network/map_ports", vbox);
+
+	ports_checkbox = pidgin_prefs_checkbox(_("_Manually specify range of ports to listen on"),
+			"/purple/network/ports_range_use", vbox);
+
+	spin_button = pidgin_prefs_labeled_spin_button(vbox, _("_Start port:"),
+			"/purple/network/ports_range_start", 0, 65535, sg);
+	if (!purple_prefs_get_bool("/purple/network/ports_range_use"))
+		gtk_widget_set_sensitive(GTK_WIDGET(spin_button), FALSE);
+	g_signal_connect(G_OBJECT(ports_checkbox), "clicked",
+					 G_CALLBACK(pidgin_toggle_sensitive), spin_button);
+
+	spin_button = pidgin_prefs_labeled_spin_button(vbox, _("_End port:"),
+			"/purple/network/ports_range_end", 0, 65535, sg);
+	if (!purple_prefs_get_bool("/purple/network/ports_range_use"))
+		gtk_widget_set_sensitive(GTK_WIDGET(spin_button), FALSE);
+	g_signal_connect(G_OBJECT(ports_checkbox), "clicked",
+					 G_CALLBACK(pidgin_toggle_sensitive), spin_button);
+
+	if (purple_running_gnome()) {
+		vbox = pidgin_make_frame(ret, _("Proxy Server &amp; Browser"));
+		prefs_proxy_frame = gtk_vbox_new(FALSE, 0);
+
+		proxy_warning = hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+		gtk_container_add(GTK_CONTAINER(vbox), hbox);
+
+		label = gtk_label_new(NULL);
+		gtk_label_set_markup(GTK_LABEL(label),
+		                     _("<b>Proxy configuration program was not found.</b>"));
+		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+		browser_warning = hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+		gtk_container_add(GTK_CONTAINER(vbox), hbox);
+
+		label = gtk_label_new(NULL);
+		gtk_label_set_markup(GTK_LABEL(label),
+		                     _("<b>Browser configuration program was not found.</b>"));
+		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+		hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+		gtk_container_add(GTK_CONTAINER(vbox), hbox);
+		label = gtk_label_new(_("Proxy & Browser preferences are configured\n"
+		                        "in GNOME Preferences"));
+		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+		gtk_widget_show(label);
+
+		hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+		gtk_container_add(GTK_CONTAINER(vbox), hbox);
+		proxy_button = gtk_button_new_with_mnemonic(_("Configure _Proxy"));
+		g_signal_connect(G_OBJECT(proxy_button), "clicked",
+		                 G_CALLBACK(proxy_button_clicked_cb), NULL);
+		gtk_box_pack_start(GTK_BOX(hbox), proxy_button, FALSE, FALSE, 0);
+		gtk_widget_show(proxy_button);
+		browser_button = gtk_button_new_with_mnemonic(_("Configure _Browser"));
+		g_signal_connect(G_OBJECT(browser_button), "clicked",
+		                 G_CALLBACK(browser_button_clicked_cb), NULL);
+		gtk_box_pack_start(GTK_BOX(hbox), browser_button, FALSE, FALSE, 0);
+		gtk_widget_show(browser_button);
+	} else {
+		vbox = pidgin_make_frame(ret, _("Proxy Server"));
+		prefs_proxy_frame = gtk_vbox_new(FALSE, 0);
+
+		pidgin_prefs_dropdown(vbox, _("Proxy _type:"), PURPLE_PREF_STRING,
+					"/purple/proxy/type",
+					_("No proxy"), "none",
+					"SOCKS 4", "socks4",
+					"SOCKS 5", "socks5",
+					"HTTP", "http",
+					_("Use Environmental Settings"), "envvar",
+					NULL);
+		gtk_box_pack_start(GTK_BOX(vbox), prefs_proxy_frame, 0, 0, 0);
+		proxy_info = purple_global_proxy_get_info();
+
+		purple_prefs_connect_callback(prefs, "/purple/proxy/type",
+					    proxy_changed_cb, prefs_proxy_frame);
+
+		table = gtk_table_new(4, 2, FALSE);
+		gtk_container_set_border_width(GTK_CONTAINER(table), 0);
+		gtk_table_set_col_spacings(GTK_TABLE(table), 5);
+		gtk_table_set_row_spacings(GTK_TABLE(table), 10);
+		gtk_container_add(GTK_CONTAINER(prefs_proxy_frame), table);
+
+
+		label = gtk_label_new_with_mnemonic(_("_Host:"));
+		gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+		gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+
+		entry = gtk_entry_new();
+		gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
+		gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
+		g_signal_connect(G_OBJECT(entry), "changed",
+				 G_CALLBACK(proxy_print_option), (void *)PROXYHOST);
+
+		if (proxy_info != NULL && purple_proxy_info_get_host(proxy_info))
+			gtk_entry_set_text(GTK_ENTRY(entry),
+					   purple_proxy_info_get_host(proxy_info));
+
+		hbox = gtk_hbox_new(TRUE, 5);
+		gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+		pidgin_set_accessible_label (entry, label);
+
+		label = gtk_label_new_with_mnemonic(_("_Port:"));
+		gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+		gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, 0, 0, 0);
+
+		entry = gtk_entry_new();
+		gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
+		gtk_table_attach(GTK_TABLE(table), entry, 3, 4, 0, 1, GTK_FILL, 0, 0, 0);
+		g_signal_connect(G_OBJECT(entry), "changed",
+				 G_CALLBACK(proxy_print_option), (void *)PROXYPORT);
+
+		if (proxy_info != NULL && purple_proxy_info_get_port(proxy_info) != 0) {
+			char buf[128];
+			g_snprintf(buf, sizeof(buf), "%d",
+				   purple_proxy_info_get_port(proxy_info));
+
+			gtk_entry_set_text(GTK_ENTRY(entry), buf);
+		}
+		pidgin_set_accessible_label (entry, label);
+
+		label = gtk_label_new_with_mnemonic(_("_User:"));
+		gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+		gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+
+		entry = gtk_entry_new();
+		gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
+		gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
+		g_signal_connect(G_OBJECT(entry), "changed",
+				 G_CALLBACK(proxy_print_option), (void *)PROXYUSER);
+
+		if (proxy_info != NULL && purple_proxy_info_get_username(proxy_info) != NULL)
+			gtk_entry_set_text(GTK_ENTRY(entry),
+						   purple_proxy_info_get_username(proxy_info));
+
+		hbox = gtk_hbox_new(TRUE, 5);
+		gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+		pidgin_set_accessible_label (entry, label);
+
+		label = gtk_label_new_with_mnemonic(_("Pa_ssword:"));
+		gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+		gtk_table_attach(GTK_TABLE(table), label, 2, 3, 1, 2, GTK_FILL, 0, 0, 0);
+
+		entry = gtk_entry_new();
+		gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
+		gtk_table_attach(GTK_TABLE(table), entry, 3, 4, 1, 2, GTK_FILL , 0, 0, 0);
+		gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+		if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*')
+			gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR);
+		g_signal_connect(G_OBJECT(entry), "changed",
+				 G_CALLBACK(proxy_print_option), (void *)PROXYPASS);
+
+		if (proxy_info != NULL && purple_proxy_info_get_password(proxy_info) != NULL)
+			gtk_entry_set_text(GTK_ENTRY(entry),
+					   purple_proxy_info_get_password(proxy_info));
+		pidgin_set_accessible_label (entry, label);
+	}
+
+	gtk_widget_show_all(ret);
+	g_object_unref(sg);
+	/* Only hide table if not running gnome otherwise we hide the IP address table! */
+	if (!purple_running_gnome() && (proxy_info == NULL ||
+	    purple_proxy_info_get_type(proxy_info) == PURPLE_PROXY_NONE ||
+	    purple_proxy_info_get_type(proxy_info) == PURPLE_PROXY_USE_ENVVAR)) {
+		gtk_widget_hide(table);
+	} else if (purple_running_gnome()) {
+		gchar *path;
+		path = g_find_program_in_path("gnome-network-preferences");
+		if (path != NULL) {
+			gtk_widget_set_sensitive(proxy_button, TRUE);
+			gtk_widget_hide(proxy_warning);
+			g_free(path);
+		} else {
+			gtk_widget_set_sensitive(proxy_button, FALSE);
+			gtk_widget_show(proxy_warning);
+		}
+		path = g_find_program_in_path("gnome-default-applications-properties");
+		if (path != NULL) {
+			gtk_widget_set_sensitive(browser_button, TRUE);
+			gtk_widget_hide(browser_warning);
+			g_free(path);
+		} else {
+			gtk_widget_set_sensitive(browser_button, FALSE);
+			gtk_widget_show(browser_warning);
+		}
+	}
+
+	return ret;
+}
+
+#ifndef _WIN32
+static gboolean manual_browser_set(GtkWidget *entry, GdkEventFocus *event, gpointer data) {
+	const char *program = gtk_entry_get_text(GTK_ENTRY(entry));
+
+	purple_prefs_set_path(PIDGIN_PREFS_ROOT "/browsers/command", program);
+
+	/* carry on normally */
+	return FALSE;
+}
+
+static GList *get_available_browsers(void)
+{
+	struct browser {
+		char *name;
+		char *command;
+	};
+
+	/* Sorted reverse alphabetically */
+	static const struct browser possible_browsers[] = {
+		{N_("Seamonkey"), "seamonkey"},
+		{N_("Opera"), "opera"},
+		{N_("Netscape"), "netscape"},
+		{N_("Mozilla"), "mozilla"},
+		{N_("Konqueror"), "kfmclient"},
+		{N_("Desktop Default"), "xdg-open"},
+		{N_("GNOME Default"), "gnome-open"},
+		{N_("Galeon"), "galeon"},
+		{N_("Firefox"), "firefox"},
+		{N_("Firebird"), "mozilla-firebird"},
+		{N_("Epiphany"), "epiphany"}
+	};
+	static const int num_possible_browsers = G_N_ELEMENTS(possible_browsers);
+
+	GList *browsers = NULL;
+	int i = 0;
+	char *browser_setting = (char *)purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/browser");
+
+	browsers = g_list_prepend(browsers, (gpointer)"custom");
+	browsers = g_list_prepend(browsers, (gpointer)_("Manual"));
+
+	for (i = 0; i < num_possible_browsers; i++) {
+		if (purple_program_is_valid(possible_browsers[i].command)) {
+			browsers = g_list_prepend(browsers,
+									  possible_browsers[i].command);
+			browsers = g_list_prepend(browsers, (gpointer)_(possible_browsers[i].name));
+			if(browser_setting && !strcmp(possible_browsers[i].command, browser_setting))
+				browser_setting = NULL;
+			/* If xdg-open is valid, prefer it over gnome-open and skip forward */
+			if(!strcmp(possible_browsers[i].command, "xdg-open")) {
+				if (browser_setting && !strcmp("gnome-open", browser_setting)) {
+					purple_prefs_set_string(PIDGIN_PREFS_ROOT "/browsers/browser", possible_browsers[i].command);
+					browser_setting = NULL;
+				}
+				i++;
+			}
+		}
+	}
+
+	if(browser_setting)
+		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/browsers/browser", "custom");
+
+	return browsers;
+}
+
+static void
+browser_changed1_cb(const char *name, PurplePrefType type,
+					gconstpointer value, gpointer data)
+{
+	GtkWidget *hbox = data;
+	const char *browser = value;
+
+	gtk_widget_set_sensitive(hbox, strcmp(browser, "custom"));
+}
+
+static void
+browser_changed2_cb(const char *name, PurplePrefType type,
+					gconstpointer value, gpointer data)
+{
+	GtkWidget *hbox = data;
+	const char *browser = value;
+
+	gtk_widget_set_sensitive(hbox, !strcmp(browser, "custom"));
+}
+
+static GtkWidget *
+browser_page(void)
+{
+	GtkWidget *ret;
+	GtkWidget *vbox;
+	GtkWidget *hbox;
+	GtkWidget *label;
+	GtkWidget *entry;
+	GtkSizeGroup *sg;
+	GList *browsers = NULL;
+
+	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
+	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
+
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+	vbox = pidgin_make_frame (ret, _("Browser Selection"));
+
+	browsers = get_available_browsers();
+	if (browsers != NULL) {
+		label = pidgin_prefs_dropdown_from_list(vbox,_("_Browser:"), PURPLE_PREF_STRING,
+										 PIDGIN_PREFS_ROOT "/browsers/browser",
+										 browsers);
+		g_list_free(browsers);
+		gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+		gtk_size_group_add_widget(sg, label);
+
+		hbox = gtk_hbox_new(FALSE, 0);
+		label = pidgin_prefs_dropdown(hbox, _("_Open link in:"), PURPLE_PREF_INT,
+			PIDGIN_PREFS_ROOT "/browsers/place",
+			_("Browser default"), PIDGIN_BROWSER_DEFAULT,
+			_("Existing window"), PIDGIN_BROWSER_CURRENT,
+			_("New window"), PIDGIN_BROWSER_NEW_WINDOW,
+			_("New tab"), PIDGIN_BROWSER_NEW_TAB,
+			NULL);
+		gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+		gtk_size_group_add_widget(sg, label);
+		gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+		if (!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/browser"), "custom"))
+			gtk_widget_set_sensitive(hbox, FALSE);
+		purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/browsers/browser",
+									browser_changed1_cb, hbox);
+	}
+
+	entry = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(entry),
+					   purple_prefs_get_path(PIDGIN_PREFS_ROOT "/browsers/command"));
+	g_signal_connect(G_OBJECT(entry), "focus-out-event",
+					 G_CALLBACK(manual_browser_set), NULL);
+	hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Manual:\n(%s for URL)"), sg, entry, TRUE, NULL);
+	if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/browser"), "custom"))
+		gtk_widget_set_sensitive(hbox, FALSE);
+	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/browsers/browser",
+			browser_changed2_cb, hbox);
+
+	gtk_widget_show_all(ret);
+	g_object_unref(sg);
+	return ret;
+}
+#endif /*_WIN32*/
+
+static GtkWidget *
+logging_page(void)
+{
+	GtkWidget *ret;
+	GtkWidget *vbox;
+	GList *names;
+
+	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
+	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
+
+
+	vbox = pidgin_make_frame (ret, _("Logging"));
+	names = purple_log_logger_get_options();
+
+	pidgin_prefs_dropdown_from_list(vbox, _("Log _format:"), PURPLE_PREF_STRING,
+				 "/purple/logging/format", names);
+
+	g_list_free(names);
+
+	pidgin_prefs_checkbox(_("Log all _instant messages"),
+				  "/purple/logging/log_ims", vbox);
+	pidgin_prefs_checkbox(_("Log all c_hats"),
+				  "/purple/logging/log_chats", vbox);
+	pidgin_prefs_checkbox(_("Log all _status changes to system log"),
+				  "/purple/logging/log_system", vbox);
+
+	gtk_widget_show_all(ret);
+
+	return ret;
+}
+
+#ifndef _WIN32
+static gint sound_cmd_yeah(GtkEntry *entry, gpointer d)
+{
+	purple_prefs_set_path(PIDGIN_PREFS_ROOT "/sound/command",
+			gtk_entry_get_text(GTK_ENTRY(entry)));
+	return TRUE;
+}
+
+static void
+sound_changed1_cb(const char *name, PurplePrefType type,
+				  gconstpointer value, gpointer data)
+{
+	GtkWidget *hbox = data;
+	const char *method = value;
+
+	gtk_widget_set_sensitive(hbox, !strcmp(method, "custom"));
+}
+
+static void
+sound_changed2_cb(const char *name, PurplePrefType type,
+				  gconstpointer value, gpointer data)
+{
+	GtkWidget *vbox = data;
+	const char *method = value;
+
+	gtk_widget_set_sensitive(vbox, strcmp(method, "none"));
+}
+#endif /* !_WIN32 */
+
+#ifdef USE_GSTREAMER
+static void
+sound_changed3_cb(const char *name, PurplePrefType type,
+				  gconstpointer value, gpointer data)
+{
+	GtkWidget *hbox = data;
+	const char *method = value;
+
+	gtk_widget_set_sensitive(hbox,
+			!strcmp(method, "automatic") ||
+			!strcmp(method, "esd"));
+}
+#endif /* USE_GSTREAMER */
+
+
+static void
+event_toggled(GtkCellRendererToggle *cell, gchar *pth, gpointer data)
+{
+	GtkTreeModel *model = (GtkTreeModel *)data;
+	GtkTreeIter iter;
+	GtkTreePath *path = gtk_tree_path_new_from_string(pth);
+	char *pref;
+
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_model_get (model, &iter,
+						2, &pref,
+						-1);
+
+	purple_prefs_set_bool(pref, !gtk_cell_renderer_toggle_get_active(cell));
+	g_free(pref);
+
+	gtk_list_store_set(GTK_LIST_STORE (model), &iter,
+					   0, !gtk_cell_renderer_toggle_get_active(cell),
+					   -1);
+
+	gtk_tree_path_free(path);
+}
+
+static void
+test_sound(GtkWidget *button, gpointer i_am_NULL)
+{
+	char *pref;
+	gboolean temp_enabled;
+	gboolean temp_mute;
+
+	pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/enabled/%s",
+			pidgin_sound_get_event_option(sound_row_sel));
+
+	temp_enabled = purple_prefs_get_bool(pref);
+	temp_mute = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/sound/mute");
+
+	if (!temp_enabled) purple_prefs_set_bool(pref, TRUE);
+	if (temp_mute) purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute", FALSE);
+
+	purple_sound_play_event(sound_row_sel, NULL);
+
+	if (!temp_enabled) purple_prefs_set_bool(pref, FALSE);
+	if (temp_mute) purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute", TRUE);
+
+	g_free(pref);
+}
+
+/*
+ * Resets a sound file back to default.
+ */
+static void
+reset_sound(GtkWidget *button, gpointer i_am_also_NULL)
+{
+	gchar *pref;
+
+	pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
+						   pidgin_sound_get_event_option(sound_row_sel));
+	purple_prefs_set_path(pref, "");
+	g_free(pref);
+
+	gtk_entry_set_text(GTK_ENTRY(sound_entry), _("(default)"));
+}
+
+static void
+sound_chosen_cb(void *user_data, const char *filename)
+{
+	gchar *pref;
+	int sound;
+
+	sound = GPOINTER_TO_INT(user_data);
+
+	/* Set it -- and forget it */
+	pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
+						   pidgin_sound_get_event_option(sound));
+	purple_prefs_set_path(pref, filename);
+	g_free(pref);
+
+	/*
+	 * If the sound we just changed is still the currently selected
+	 * sound, then update the box showing the file name.
+	 */
+	if (sound == sound_row_sel)
+		gtk_entry_set_text(GTK_ENTRY(sound_entry), filename);
+}
+
+static void select_sound(GtkWidget *button, gpointer being_NULL_is_fun)
+{
+	gchar *pref;
+	const char *filename;
+
+	pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
+						   pidgin_sound_get_event_option(sound_row_sel));
+	filename = purple_prefs_get_path(pref);
+	g_free(pref);
+
+	if (*filename == '\0')
+		filename = NULL;
+
+	purple_request_file(prefs, _("Sound Selection"), filename, FALSE,
+					  G_CALLBACK(sound_chosen_cb), NULL,
+					  NULL, NULL, NULL,
+					  GINT_TO_POINTER(sound_row_sel));
+}
+
+#ifdef USE_GSTREAMER
+static gchar* prefs_sound_volume_format(GtkScale *scale, gdouble val)
+{
+	if(val < 15) {
+		return g_strdup_printf(_("Quietest"));
+	} else if(val < 30) {
+		return g_strdup_printf(_("Quieter"));
+	} else if(val < 45) {
+		return g_strdup_printf(_("Quiet"));
+	} else if(val < 55) {
+		return g_strdup_printf(_("Normal"));
+	} else if(val < 70) {
+		return g_strdup_printf(_("Loud"));
+	} else if(val < 85) {
+		return g_strdup_printf(_("Louder"));
+	} else {
+		return g_strdup_printf(_("Loudest"));
+	}
+}
+
+static void prefs_sound_volume_changed(GtkRange *range)
+{
+	int val = (int)gtk_range_get_value(GTK_RANGE(range));
+	purple_prefs_set_int(PIDGIN_PREFS_ROOT "/sound/volume", val);
+}
+#endif
+
+static void prefs_sound_sel(GtkTreeSelection *sel, GtkTreeModel *model) {
+	GtkTreeIter  iter;
+	GValue val;
+	const char *file;
+	char *pref;
+
+	if (! gtk_tree_selection_get_selected (sel, &model, &iter))
+		return;
+
+	val.g_type = 0;
+	gtk_tree_model_get_value (model, &iter, 3, &val);
+	sound_row_sel = g_value_get_uint(&val);
+
+	pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
+			pidgin_sound_get_event_option(sound_row_sel));
+	file = purple_prefs_get_path(pref);
+	g_free(pref);
+	if (sound_entry)
+		gtk_entry_set_text(GTK_ENTRY(sound_entry), (file && *file != '\0') ? file : _("(default)"));
+	g_value_unset (&val);
+}
+
+static GtkWidget *
+sound_page(void)
+{
+	GtkWidget *ret;
+	GtkWidget *vbox, *sw, *button;
+	GtkSizeGroup *sg;
+	GtkTreeIter iter;
+	GtkWidget *event_view;
+	GtkListStore *event_store;
+	GtkCellRenderer *rend;
+	GtkTreeViewColumn *col;
+	GtkTreeSelection *sel;
+	GtkTreePath *path;
+	GtkWidget *hbox;
+	int j;
+	const char *file;
+	char *pref;
+#ifndef _WIN32
+	GtkWidget *dd;
+	GtkWidget *entry;
+	const char *cmd;
+#endif
+
+	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
+	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
+
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+
+#ifndef _WIN32
+	vbox = pidgin_make_frame (ret, _("Sound Method"));
+	dd = pidgin_prefs_dropdown(vbox, _("_Method:"), PURPLE_PREF_STRING,
+			PIDGIN_PREFS_ROOT "/sound/method",
+			_("Console beep"), "beep",
+#ifdef USE_GSTREAMER
+			_("Automatic"), "automatic",
+			"ESD", "esd",
+			"ALSA", "alsa",
+#endif
+			_("Command"), "custom",
+			_("No sounds"), "none",
+			NULL);
+	gtk_size_group_add_widget(sg, dd);
+	gtk_misc_set_alignment(GTK_MISC(dd), 0, 0.5);
+
+	entry = gtk_entry_new();
+	gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE);
+	cmd = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/sound/command");
+	if(cmd)
+		gtk_entry_set_text(GTK_ENTRY(entry), cmd);
+	g_signal_connect(G_OBJECT(entry), "changed",
+					 G_CALLBACK(sound_cmd_yeah), NULL);
+
+	hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Sound c_ommand:\n(%s for filename)"), sg, entry, TRUE, NULL);
+	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/sound/method",
+								sound_changed1_cb, hbox);
+	gtk_widget_set_sensitive(hbox,
+			!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method"),
+					"custom"));
+#endif /* _WIN32 */
+
+	vbox = pidgin_make_frame (ret, _("Sound Options"));
+	pidgin_prefs_checkbox(_("Sounds when conversation has _focus"),
+				   PIDGIN_PREFS_ROOT "/sound/conv_focus", vbox);
+	pidgin_prefs_dropdown(vbox, _("Enable sounds:"),
+				 PURPLE_PREF_INT, "/purple/sound/while_status",
+				_("Only when available"), 1,
+				_("Only when not available"), 2,
+				_("Always"), 3,
+				NULL);
+
+#ifdef USE_GSTREAMER
+	sw = gtk_hscale_new_with_range(0.0, 100.0, 5.0);
+	gtk_range_set_increments(GTK_RANGE(sw), 5.0, 25.0);
+	gtk_range_set_value(GTK_RANGE(sw), purple_prefs_get_int(PIDGIN_PREFS_ROOT "/sound/volume"));
+	g_signal_connect (G_OBJECT (sw), "format-value",
+			  G_CALLBACK (prefs_sound_volume_format),
+			  NULL);
+	g_signal_connect (G_OBJECT (sw), "value-changed",
+			  G_CALLBACK (prefs_sound_volume_changed),
+			  NULL);
+	hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Volume:"), NULL, sw, TRUE, NULL);
+
+	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/sound/method",
+								sound_changed3_cb, hbox);
+	sound_changed3_cb(PIDGIN_PREFS_ROOT "/sound/method", PURPLE_PREF_STRING,
+			  purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method"), hbox);
+#endif
+
+#ifndef _WIN32
+	gtk_widget_set_sensitive(vbox,
+			strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method"), "none"));
+	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/sound/method",
+								sound_changed2_cb, vbox);
+#endif
+
+	vbox = pidgin_make_frame(ret, _("Sound Events"));
+
+	/* The following is an ugly hack to make the frame expand so the
+	 * sound events list is big enough to be usable */
+	gtk_box_set_child_packing(GTK_BOX(vbox->parent), vbox, TRUE, TRUE, 0,
+			GTK_PACK_START);
+	gtk_box_set_child_packing(GTK_BOX(vbox->parent->parent), vbox->parent, TRUE,
+			TRUE, 0, GTK_PACK_START);
+	gtk_box_set_child_packing(GTK_BOX(vbox->parent->parent->parent),
+			vbox->parent->parent, TRUE, TRUE, 0, GTK_PACK_START);
+
+	sw = gtk_scrolled_window_new(NULL,NULL);
+	gtk_widget_set_size_request(sw, -1, 100);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
+
+	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
+	event_store = gtk_list_store_new (4, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT);
+
+	for (j=0; j < PURPLE_NUM_SOUNDS; j++) {
+		char *pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/enabled/%s",
+					     pidgin_sound_get_event_option(j));
+		const char *label = pidgin_sound_get_event_label(j);
+
+		if (label == NULL) {
+			g_free(pref);
+			continue;
+		}
+
+		gtk_list_store_append (event_store, &iter);
+		gtk_list_store_set(event_store, &iter,
+				   0, purple_prefs_get_bool(pref),
+				   1, _(label),
+				   2, pref,
+				   3, j,
+				   -1);
+		g_free(pref);
+	}
+
+	event_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL(event_store));
+
+	rend = gtk_cell_renderer_toggle_new();
+	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_view));
+	g_signal_connect (G_OBJECT (sel), "changed",
+			  G_CALLBACK (prefs_sound_sel),
+			  NULL);
+	g_signal_connect (G_OBJECT(rend), "toggled",
+			  G_CALLBACK(event_toggled), event_store);
+	path = gtk_tree_path_new_first();
+	gtk_tree_selection_select_path(sel, path);
+	gtk_tree_path_free(path);
+
+	col = gtk_tree_view_column_new_with_attributes (_("Play"),
+							rend,
+							"active", 0,
+							NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col);
+
+	rend = gtk_cell_renderer_text_new();
+	col = gtk_tree_view_column_new_with_attributes (_("Event"),
+							rend,
+							"text", 1,
+							NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col);
+	g_object_unref(G_OBJECT(event_store));
+	gtk_container_add(GTK_CONTAINER(sw), event_view);
+
+	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+	sound_entry = gtk_entry_new();
+	pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
+			       pidgin_sound_get_event_option(0));
+	file = purple_prefs_get_path(pref);
+	g_free(pref);
+	gtk_entry_set_text(GTK_ENTRY(sound_entry), (file && *file != '\0') ? file : _("(default)"));
+	gtk_editable_set_editable(GTK_EDITABLE(sound_entry), FALSE);
+	gtk_box_pack_start(GTK_BOX(hbox), sound_entry, FALSE, FALSE, PIDGIN_HIG_BOX_SPACE);
+
+	button = gtk_button_new_with_label(_("Test"));
+	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(test_sound), NULL);
+	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1);
+
+	button = gtk_button_new_with_label(_("Reset"));
+	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(reset_sound), NULL);
+	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1);
+
+	button = gtk_button_new_with_label(_("Choose..."));
+	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(select_sound), NULL);
+	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1);
+
+	gtk_widget_show_all(ret);
+	g_object_unref(sg);
+
+	return ret;
+}
+
+
+static void
+set_idle_away(PurpleSavedStatus *status)
+{
+	purple_prefs_set_int("/purple/savedstatus/idleaway", purple_savedstatus_get_creation_time(status));
+}
+
+static void
+set_startupstatus(PurpleSavedStatus *status)
+{
+	purple_prefs_set_int("/purple/savedstatus/startup", purple_savedstatus_get_creation_time(status));
+}
+
+static GtkWidget *
+away_page(void)
+{
+	GtkWidget *ret;
+	GtkWidget *vbox;
+	GtkWidget *dd;
+	GtkWidget *label;
+	GtkWidget *button;
+	GtkWidget *select;
+	GtkWidget *menu;
+	GtkSizeGroup *sg;
+
+	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
+	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
+
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+
+	/* Idle stuff */
+	vbox = pidgin_make_frame(ret, _("Idle"));
+
+	dd = pidgin_prefs_dropdown(vbox, _("_Report idle time:"),
+		PURPLE_PREF_STRING, "/purple/away/idle_reporting",
+		_("Never"), "none",
+		_("From last sent message"), "purple",
+#if defined(USE_SCREENSAVER) || defined(HAVE_IOKIT)
+		_("Based on keyboard or mouse use"), "system",
+#endif
+		NULL);
+	gtk_size_group_add_widget(sg, dd);
+	gtk_misc_set_alignment(GTK_MISC(dd), 0, 0.5);
+
+	/* Away stuff */
+	vbox = pidgin_make_frame(ret, _("Away"));
+
+	dd = pidgin_prefs_dropdown(vbox, _("_Auto-reply:"),
+		PURPLE_PREF_STRING, "/purple/away/auto_reply",
+		_("Never"), "never",
+		_("When away"), "away",
+		_("When both away and idle"), "awayidle",
+		NULL);
+	gtk_size_group_add_widget(sg, dd);
+	gtk_misc_set_alignment(GTK_MISC(dd), 0, 0.5);
+
+	/* Auto-away stuff */
+	vbox = pidgin_make_frame(ret, _("Auto-away"));
+
+	button = pidgin_prefs_checkbox(_("Change status when _idle"),
+						   "/purple/away/away_when_idle", vbox);
+
+	select = pidgin_prefs_labeled_spin_button(vbox,
+			_("_Minutes before becoming idle:"), "/purple/away/mins_before_away",
+			1, 24 * 60, sg);
+	g_signal_connect(G_OBJECT(button), "clicked",
+					 G_CALLBACK(pidgin_toggle_sensitive), select);
+
+	/* TODO: Show something useful if we don't have any saved statuses. */
+	menu = pidgin_status_menu(purple_savedstatus_get_idleaway(), G_CALLBACK(set_idle_away));
+	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Change _status to:"), sg, menu, TRUE, &label);
+	g_signal_connect(G_OBJECT(button), "clicked",
+			 G_CALLBACK(pidgin_toggle_sensitive), menu);
+	g_signal_connect(G_OBJECT(button), "clicked",
+					 G_CALLBACK(pidgin_toggle_sensitive), label);
+
+	if (!purple_prefs_get_bool("/purple/away/away_when_idle")) {
+		gtk_widget_set_sensitive(GTK_WIDGET(menu), FALSE);
+		gtk_widget_set_sensitive(GTK_WIDGET(select), FALSE);
+		gtk_widget_set_sensitive(GTK_WIDGET(label), FALSE);
+	}
+
+	/* Signon status stuff */
+	vbox = pidgin_make_frame(ret, _("Status at Startup"));
+
+	button = pidgin_prefs_checkbox(_("Use status from last _exit at startup"),
+		"/purple/savedstatus/startup_current_status", vbox);
+
+	/* TODO: Show something useful if we don't have any saved statuses. */
+	menu = pidgin_status_menu(purple_savedstatus_get_startup(), G_CALLBACK(set_startupstatus));
+	g_signal_connect(G_OBJECT(button), "clicked",
+			 G_CALLBACK(pidgin_toggle_sensitive), menu);
+	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Status to a_pply at startup:"), sg, menu, TRUE, &label);
+	g_signal_connect(G_OBJECT(button), "clicked",
+					 G_CALLBACK(pidgin_toggle_sensitive), label);
+
+	if (purple_prefs_get_bool("/purple/savedstatus/startup_current_status")) {
+		gtk_widget_set_sensitive(GTK_WIDGET(menu), FALSE);
+		gtk_widget_set_sensitive(GTK_WIDGET(label), FALSE);
+	}
+
+	gtk_widget_show_all(ret);
+	g_object_unref(sg);
+
+	return ret;
+}
+
+static int
+prefs_notebook_add_page(const char *text,
+  		        GtkWidget *page,
+			int ind) {
+
+#if GTK_CHECK_VERSION(2,4,0)
+	return gtk_notebook_append_page(GTK_NOTEBOOK(prefsnotebook), page, gtk_label_new(text));
+#else
+	gtk_notebook_append_page(GTK_NOTEBOOK(prefsnotebook), page, gtk_label_new(text));
+	return gtk_notebook_page_num(GTK_NOTEBOOK(prefsnotebook), page);
+#endif
+}
+
+static void prefs_notebook_init(void) {
+	prefs_notebook_add_page(_("Interface"), interface_page(), notebook_page++);
+	prefs_notebook_add_page(_("Conversations"), conv_page(), notebook_page++);
+	prefs_notebook_add_page(_("Smiley Themes"), theme_page(), notebook_page++);
+	prefs_notebook_add_page(_("Sounds"), sound_page(), notebook_page++);
+	prefs_notebook_add_page(_("Network"), network_page(), notebook_page++);
+#ifndef _WIN32
+	/* We use the registered default browser in windows */
+	/* if the user is running gnome 2.x or Mac OS X, hide the browsers tab */
+	if ((purple_running_gnome() == FALSE) && (purple_running_osx() == FALSE)) {
+		prefs_notebook_add_page(_("Browser"), browser_page(), notebook_page++);
+	}
+#endif
+	prefs_notebook_add_page(_("Logging"), logging_page(), notebook_page++);
+	prefs_notebook_add_page(_("Status / Idle"), away_page(), notebook_page++);
+}
+
+void pidgin_prefs_show(void)
+{
+	GtkWidget *vbox;
+	GtkWidget *notebook;
+	GtkWidget *button;
+
+	if (prefs) {
+		gtk_window_present(GTK_WINDOW(prefs));
+		return;
+	}
+
+	/* copy the preferences to tmp values...
+	 * I liked "take affect immediately" Oh well :-( */
+	/* (that should have been "effect," right?) */
+
+	/* Back to instant-apply! I win!  BU-HAHAHA! */
+
+	/* Create the window */
+	prefs = pidgin_create_dialog(_("Preferences"), PIDGIN_HIG_BORDER, "preferences", FALSE);
+	g_signal_connect(G_OBJECT(prefs), "destroy",
+					 G_CALLBACK(delete_prefs), NULL);
+
+	vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(prefs), FALSE, PIDGIN_HIG_BORDER);
+
+	/* The notebook */
+	prefsnotebook = notebook = gtk_notebook_new ();
+	gtk_box_pack_start (GTK_BOX (vbox), notebook, FALSE, FALSE, 0);
+	gtk_widget_show(prefsnotebook);
+
+	button = pidgin_dialog_add_button(GTK_DIALOG(prefs), GTK_STOCK_CLOSE, NULL, NULL);
+	g_signal_connect_swapped(G_OBJECT(button), "clicked",
+							 G_CALLBACK(gtk_widget_destroy), prefs);
+
+	prefs_notebook_init();
+
+	/* Show everything. */
+	gtk_widget_show(prefs);
+}
+
+static void
+set_bool_pref(GtkWidget *w, const char *key)
+{
+	purple_prefs_set_bool(key,
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
+}
+
+GtkWidget *
+pidgin_prefs_checkbox(const char *text, const char *key, GtkWidget *page)
+{
+	GtkWidget *button;
+
+	button = gtk_check_button_new_with_mnemonic(text);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
+								 purple_prefs_get_bool(key));
+
+	gtk_box_pack_start(GTK_BOX(page), button, FALSE, FALSE, 0);
+
+	g_signal_connect(G_OBJECT(button), "clicked",
+					 G_CALLBACK(set_bool_pref), (char *)key);
+
+	gtk_widget_show(button);
+
+	return button;
+}
+
+static void
+smiley_theme_pref_cb(const char *name, PurplePrefType type,
+					 gconstpointer value, gpointer data)
+{
+	const char *themename = value;
+	GSList *themes;
+
+	for (themes = smiley_themes; themes; themes = themes->next) {
+		struct smiley_theme *smile = themes->data;
+		if (smile->name && strcmp(themename, smile->name) == 0) {
+			pidgin_themes_load_smiley_theme(smile->path, TRUE);
+			break;
+		}
+	}
+}
+
+void
+pidgin_prefs_init(void)
+{
+	purple_prefs_add_none(PIDGIN_PREFS_ROOT "");
+	purple_prefs_add_none("/plugins/gtk");
+
+#ifndef _WIN32
+	/* Browsers */
+	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/browsers");
+	purple_prefs_add_int(PIDGIN_PREFS_ROOT "/browsers/place", PIDGIN_BROWSER_DEFAULT);
+	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/browsers/command", "");
+	purple_prefs_add_string(PIDGIN_PREFS_ROOT "/browsers/browser", "mozilla");
+#endif
+
+	/* Plugins */
+	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/plugins");
+	purple_prefs_add_path_list(PIDGIN_PREFS_ROOT "/plugins/loaded", NULL);
+
+	/* File locations */
+	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/filelocations");
+	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_save_folder", "");
+	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_open_folder", "");
+	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder", "");
+
+	/* Smiley Themes */
+	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/smileys");
+	purple_prefs_add_string(PIDGIN_PREFS_ROOT "/smileys/theme", "Default");
+
+	/* Smiley Callbacks */
+	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/smileys/theme",
+								smiley_theme_pref_cb, NULL);
+
+	pidgin_prefs_update_old();
+}
+
+void pidgin_prefs_update_old()
+{
+	const char *str;
+
+	purple_prefs_rename("/gaim/gtk", PIDGIN_PREFS_ROOT);
+
+	/* Rename some old prefs */
+	purple_prefs_rename(PIDGIN_PREFS_ROOT "/logging/log_ims", "/purple/logging/log_ims");
+	purple_prefs_rename(PIDGIN_PREFS_ROOT "/logging/log_chats", "/purple/logging/log_chats");
+	purple_prefs_rename("/purple/conversations/placement",
+					  PIDGIN_PREFS_ROOT "/conversations/placement");
+
+	purple_prefs_rename(PIDGIN_PREFS_ROOT "/debug/timestamps", "/purple/debug/timestamps");
+	purple_prefs_rename(PIDGIN_PREFS_ROOT "/conversations/im/raise_on_events", "/plugins/gtk/X11/notify/method_raise");
+
+	purple_prefs_rename_boolean_toggle(PIDGIN_PREFS_ROOT "/conversations/ignore_colors",
+									 PIDGIN_PREFS_ROOT "/conversations/show_incoming_formatting");
+
+	/* this string pref moved into the core, try to be friendly */
+	purple_prefs_rename(PIDGIN_PREFS_ROOT "/idle/reporting_method", "/purple/away/idle_reporting");
+	if ((str = purple_prefs_get_string("/purple/away/idle_reporting")) &&
+			strcmp(str, "gaim") == 0)
+		purple_prefs_set_string("/purple/away/idle_reporting", "purple");
+
+	/* Remove some no-longer-used prefs */
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/auto_expand_contacts");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/button_style");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/grey_idle_buddies");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/raise_on_events");
+	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");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/html_shortcuts");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/icons_on_tabs");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/send_formatting");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/show_smileys");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/show_urls_as_links");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/smiley_shortcuts");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/use_custom_bgcolor");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/use_custom_fgcolor");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/use_custom_font");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/use_custom_size");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/chat/old_tab_complete");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/chat/tab_completion");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/im/hide_on_send");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/chat/color_nicks");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/chat/raise_on_events");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/ignore_fonts");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/ignore_font_sizes");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/passthrough_unknown_commands");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/idle");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/logging/individual_logs");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/sound/signon");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/sound/silent_signon");
+
+	/* Convert old queuing prefs to hide_new 3-way pref. */
+	if (purple_prefs_exists("/plugins/gtk/docklet/queue_messages") &&
+	    purple_prefs_get_bool("/plugins/gtk/docklet/queue_messages"))
+	{
+		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "always");
+	}
+	else if (purple_prefs_exists(PIDGIN_PREFS_ROOT "/away/queue_messages") &&
+	         purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/away/queue_messages"))
+	{
+		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "away");
+	}
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/away/queue_messages");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/away");
+	purple_prefs_remove("/plugins/gtk/docklet/queue_messages");
+
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/chat/default_width");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/chat/default_height");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/im/default_width");
+	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/im/default_height");
+	purple_prefs_rename(PIDGIN_PREFS_ROOT "/conversations/x",
+			PIDGIN_PREFS_ROOT "/conversations/im/x");
+	purple_prefs_rename(PIDGIN_PREFS_ROOT "/conversations/y",
+			PIDGIN_PREFS_ROOT "/conversations/im/y");
+}
--- a/pidgin/gtkutils.c	Mon Feb 11 00:50:42 2008 +0000
+++ b/pidgin/gtkutils.c	Mon Feb 11 08:16:15 2008 +0000
@@ -3459,3 +3459,61 @@
 #endif
 }
 
+gchar *
+pidgin_gtk_ellipsis_text(GtkWidget *widget, const char *text, gint min_width, gchar *ellipsis)
+{
+	PangoLayout *layout;
+	gint width, height;
+	gint ewidth;
+	glong len0, len1, len2;
+	gchar *buf, *buf_tmp;
+	gboolean with_ellipsis = FALSE;
+	const gchar default_ellipsis[] = "...";
+
+	if(!ellipsis)
+		ellipsis = default_ellipsis;
+
+	/* allocate buf */
+	buf = g_malloc0(strlen(text) * 2);
+
+	/* create layout */
+	layout = gtk_widget_create_pango_layout(widget, ellipsis);
+	pango_layout_get_pixel_size(layout, &width, &height);
+	ewidth = width; /* length of ellipsis text. */
+
+	len0 = 0;
+	len1 = g_utf8_strlen(text, -1);
+	len2 = len1;
+
+	while (1) {
+
+		if (len2 == len0)
+			break;
+
+		g_utf8_strncpy(buf, text, len2);
+		pango_layout_set_text(layout, buf, -1);
+		pango_layout_get_pixel_size(layout, &width, &height);
+
+		if(!with_ellipsis && width <= min_width)
+			break;
+		else
+			with_ellipsis = TRUE;
+
+		if (width + ewidth > min_width)
+			len1 = len2;
+		else
+			len0 = len2;
+
+		len2 = (len0 + len1) / 2;
+	}
+
+	g_object_unref(layout);
+
+	if (with_ellipsis) {
+		buf_tmp = buf;
+		buf = g_strdup_printf("%s%s", buf_tmp, ellipsis);
+		g_free(buf_tmp);
+	}
+
+	return buf;
+}
--- a/pidgin/gtkutils.h	Mon Feb 11 00:50:42 2008 +0000
+++ b/pidgin/gtkutils.h	Mon Feb 11 08:16:15 2008 +0000
@@ -809,5 +809,7 @@
  */
 GtkWidget *pidgin_add_widget_to_vbox(GtkBox *vbox, const char *widget_label, GtkSizeGroup *sg, GtkWidget *widget, gboolean expand, GtkWidget **p_label);
 
+gchar *pidgin_gtk_ellipsis_text(GtkWidget *widget, const char *text, gint min_width, gchar *ellipsis);
+
 #endif /* _PIDGINUTILS_H_ */
 
--- a/po/ja.po	Mon Feb 11 00:50:42 2008 +0000
+++ b/po/ja.po	Mon Feb 11 08:16:15 2008 +0000
@@ -14498,8 +14498,8 @@
 
 #. Build the Send To menu
 #: ../pidgin/gtkconv.c:3574 ../pidgin/gtkconv.c:8022
-msgid "_Send To"
-msgstr "送信先(_S)"
+msgid "Send To"
+msgstr "送信先"
 
 #: ../pidgin/gtkconv.c:4286
 msgid "_Send"