changeset 31350:0462bec07414

merged from im.pidgin.pidgin
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Wed, 10 Nov 2010 11:41:51 +0900
parents 6d99f7cdc654 (current diff) 63b9cb97d356 (diff)
children ccd6a1da0d59
files configure.ac libpurple/protocols/msn/msg.c libpurple/protocols/msn/msn.c libpurple/protocols/oscar/encoding.c libpurple/protocols/oscar/family_icbm.c libpurple/protocols/oscar/oscar.c libpurple/protocols/oscar/oscar.h pidgin/pixmaps/icons/hicolor/16x16/apps/pidgin.png pidgin/pixmaps/icons/hicolor/16x16/apps/scalable/pidgin.svg pidgin/pixmaps/icons/hicolor/22x22/apps/pidgin.png pidgin/pixmaps/icons/hicolor/24x24/apps/pidgin.png pidgin/pixmaps/icons/hicolor/24x24/apps/scalable/pidgin.svg pidgin/pixmaps/icons/hicolor/32x32/apps/pidgin.png pidgin/pixmaps/icons/hicolor/32x32/apps/scalable/pidgin.svg pidgin/pixmaps/icons/hicolor/48x48/apps/pidgin.png
diffstat 42 files changed, 1131 insertions(+), 145 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgtags	Wed Nov 10 11:41:51 2010 +0900
@@ -0,0 +1,3 @@
+dfd8d82313be100ef3a9cbb792ee683e5dda34b8 2.6.0_jp
+493f48f8d17fc16475c2fb60f094d1cfae54d862 2.6.2_jp
+7c33fccedea8f0f43fb894a19453db389e16a3c6 2.6.2_jp1
--- a/autogen.sh	Sat Nov 06 03:46:35 2010 +0000
+++ b/autogen.sh	Wed Nov 10 11:41:51 2010 +0900
@@ -161,4 +161,4 @@
 # Run configure
 ###############################################################################
 echo "running ./configure ${CONFIGURE_FLAGS} $@"
-./configure ${CONFIGURE_FLAGS} $@
+#./configure ${CONFIGURE_FLAGS} $@
--- a/configure.ac	Sat Nov 06 03:46:35 2010 +0000
+++ b/configure.ac	Wed Nov 10 11:41:51 2010 +0900
@@ -2070,7 +2070,7 @@
 					esac
 				fi
 			else
-				nsslibs="-lssl3 -lsmime3 -lnss3 -lsoftokn3"
+				nsslibs="-lssl3 -lsmime3 -lnss3 -lsoftokn3 -lsqlite3"
 			fi
 
 			AC_CACHE_CHECK([for Mozilla nss libraries], ac_cv_moz_nss_libs,
@@ -2084,7 +2084,7 @@
 					[ac_cv_moz_nss_libs="no"])
 
 				if test "x$ac_cv_moz_nss_libs" = "xno"; then
-					nsslibs="-lssl3 -lsmime3 -lnss3 -lsoftokn3"
+					nsslibs="-lssl3 -lsmime3 -lnss3 -lsoftokn3 -lsqlite3"
 					LDFLAGS="$LDFLAGS -L$with_nspr_libs -L$with_nss_libs"
 					LIBS="$LIBS $nsslibs"
 					AC_TRY_LINK_FUNC(NSS_Init,
--- a/libpurple/conversation.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/conversation.c	Wed Nov 10 11:41:51 2010 +0900
@@ -713,6 +713,8 @@
 	PurpleBuddy *b;
 	PurpleChat *chat;
 	const char *text = NULL, *name;
+	gchar *utf8;
+	gsize dummy;
 
 	g_return_if_fail(conv != NULL);
 
@@ -731,7 +733,9 @@
 	if(text == NULL)
 		text = name;
 
-	purple_conversation_set_title(conv, text);
+	utf8 = sanitize_utf(text, strlen(text), &dummy);
+	purple_conversation_set_title(conv, utf8);
+	g_free(utf8);
 }
 
 void
@@ -1218,17 +1222,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	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/notify.c	Wed Nov 10 11:41:51 2010 +0900
@@ -417,6 +417,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
+
 		ui_handle = ops->notify_userinfo(gc, who, user_info);
 
 		if (ui_handle != NULL) {
--- a/libpurple/protocols/gg/lib/pubdir50.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/gg/lib/pubdir50.c	Wed Nov 10 11:41:51 2010 +0900
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <glib.h>
 
 #include "libgadu.h"
 #include "libgadu-internal.h"
--- a/libpurple/protocols/irc/irc.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/irc/irc.c	Wed Nov 10 11:41:51 2010 +0900
@@ -1016,6 +1016,12 @@
 	option = purple_account_option_bool_new(_("Auto-detect incoming UTF-8"), "autodetect_utf8", IRC_DEFAULT_AUTODETECT);
 	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	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/irc/parse.c	Wed Nov 10 11:41:51 2010 +0900
@@ -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);
 
@@ -160,6 +160,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)
 {
@@ -227,34 +241,111 @@
 	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;
+	gsize 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 NULL;
 	}
 
-	utf8 = g_convert(string, strlen(string), encodings[0], "UTF-8", NULL, NULL, &err);
+	strtmp  = botch_utf(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;
 	gboolean autodetect;
 	int i;
+	GError *err;
+	gboolean retry;
+	gsize in_len, out_len;
+	int conv_len;
+	char *strtmp;
+	gsize strtmp_len;
 
 	enclist = purple_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET);
 	encodings = g_strsplit(enclist, ",", -1);
@@ -278,13 +369,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 = sanitize_utf(utf8, strlen(utf8), &strtmp_len);
+ 			g_strfreev(encodings);
+			g_free(utf8);
+			return strtmp;
 		}
 	}
 	g_strfreev(encodings);
--- a/libpurple/protocols/jabber/jabber.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Wed Nov 10 11:41:51 2010 +0900
@@ -586,8 +586,9 @@
                            gpointer unused)
 {
 	JabberStream *js;
-	char *txt;
+	char *txt, *utf;
 	int len;
+	gsize utflen;
 
 	if (NULL == packet)
 		return;
@@ -605,8 +606,9 @@
 				g_str_equal((*packet)->name, "presence"))
 			xmlnode_set_namespace(*packet, NS_XMPP_CLIENT);
 	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);
 }
 
 void jabber_send(JabberStream *js, xmlnode *packet)
@@ -2320,6 +2322,7 @@
 				const char *title = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE);
 				const char *artist = purple_status_get_attr_string(tune, PURPLE_TUNE_ARTIST);
 				const char *album = purple_status_get_attr_string(tune, PURPLE_TUNE_ALBUM);
+
 				char *playing = purple_util_format_song_info(title, artist, album, NULL);
 				if (playing) {
 					purple_notify_user_info_add_pair(user_info, _("Now Listening"), playing);
--- a/libpurple/protocols/jabber/message.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/jabber/message.c	Wed Nov 10 11:41:51 2010 +0900
@@ -586,15 +586,20 @@
 				jm->thread_id = xmlnode_get_data(child);
 		} else if(!strcmp(child->name, "body") && !strcmp(xmlns, NS_XMPP_CLIENT)) {
 			if(!jm->body) {
-				char *msg = xmlnode_get_data(child);
-				char *escaped = purple_markup_escape_text(msg, -1);
-				jm->body = purple_strdup_withhtml(escaped);
+				char *tmp, *msg, *escaped;
+				gsize len;
+				tmp = xmlnode_get_data(child);
+				escaped = purple_markup_escape_text(tmp, -1);
+				msg = sanitize_utf(escaped, strlen(escaped), &len);
+				jm->body = purple_strdup_withhtml(msg);
+				g_free(tmp);
 				g_free(escaped);
 				g_free(msg);
 			}
 		} else if(!strcmp(child->name, "html") && !strcmp(xmlns, NS_XHTML_IM)) {
 			if(!jm->xhtml && xmlnode_get_child(child, "body")) {
 				char *c;
+				gsize len;
 
 				const PurpleConnection *gc = js->gc;
 				PurpleAccount *account = purple_connection_get_account(gc);
@@ -645,7 +650,9 @@
 				reformatted_xhtml =
 					jabber_message_xml_to_string_strip_img_smileys(child);
 
-				jm->xhtml = reformatted_xhtml;
+				jm->xhtml =
+					sanitize_utf(reformatted_xhtml,
+								 strlen(reformatted_xhtml), &len);
 
 				/* add known custom emoticons to the conversation */
 				/* note: if there were no smileys in the incoming message, or
--- a/libpurple/protocols/jabber/si.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/jabber/si.c	Wed Nov 10 11:41:51 2010 +0900
@@ -42,6 +42,8 @@
 #define STREAMHOST_CONNECT_TIMEOUT 15
 #define ENABLE_FT_THUMBNAILS 0
 
+#include "util.h"
+
 typedef struct _JabberSIXfer {
 	JabberStream *js;
 
@@ -858,7 +860,7 @@
 			purple_network_get_all_local_system_ips();
 		const char *public_ip;
 		gboolean has_public_ip = FALSE;
-		
+
 		jsx->local_streamhost_fd = sock;
 
 		jid = g_strdup_printf("%s@%s/%s", jsx->js->user->node,
@@ -1248,14 +1250,23 @@
 	JabberIq *iq;
 	xmlnode *si, *file, *feature, *x, *field, *option, *value;
 	char buf[32];
+	gchar *f1 = NULL, *f2 = NULL;
+	gsize dummy;
 #if ENABLE_FT_THUMBNAILS
 	gconstpointer thumb;
 	gsize thumb_size;
 
 	purple_xfer_prepare_thumbnail(xfer, "jpeg,png");
 #endif
-	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);
 	si = xmlnode_new_child(iq->node, "si");
@@ -1280,14 +1291,14 @@
 				mimetype, TRUE, jsx->js);
 		xmlnode *thumbnail = xmlnode_new_child(file, "thumbnail");
 		xmlnode_set_namespace(thumbnail, NS_THUMBS);
-		xmlnode_set_attrib(thumbnail, "cid", 
+		xmlnode_set_attrib(thumbnail, "cid",
 			jabber_data_get_cid(thumbnail_data));
 		xmlnode_set_attrib(thumbnail, "mime-type", mimetype);
 		/* cache data */
 		jabber_data_associate_local(thumbnail_data, NULL);
 	}
 #endif
-						  
+
 	feature = xmlnode_new_child(si, "feature");
 	xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg");
 	x = xmlnode_new_child(feature, "x");
@@ -1780,7 +1791,7 @@
 	purple_xfer_set_request_denied_fnc(xfer, jabber_si_xfer_request_denied);
 	purple_xfer_set_cancel_recv_fnc(xfer, jabber_si_xfer_cancel_recv);
 	purple_xfer_set_end_fnc(xfer, jabber_si_xfer_end);
-				   
+
 	js->file_transfers = g_list_append(js->file_transfers, xfer);
 
 #if ENABLE_FT_THUMBNAILS
--- a/libpurple/protocols/msn/msg.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/msn/msg.c	Wed Nov 10 11:41:51 2010 +0900
@@ -115,7 +115,8 @@
 msn_message_new_plain(const char *message)
 {
 	MsnMessage *msg;
-	char *message_cr;
+	char *message_cr, *message_cr2;
+	gsize len;
 
 	msg = msn_message_new(MSN_MSG_TEXT);
 	msg->retries = 1;
@@ -127,8 +128,10 @@
 						 "FN=Segoe%20UI; EF=; CO=0; CS=1;PF=0");
 
 	message_cr = purple_str_add_cr(message);
-	msn_message_set_bin_data(msg, message_cr, strlen(message_cr));
+	message_cr2 = botch_utf((gchar *)message_cr, -1, &len);
+	msn_message_set_bin_data(msg, message_cr2, len);
 	g_free(message_cr);
+	g_free(message_cr2);
 
 	return msg;
 }
@@ -696,16 +699,20 @@
 {
 	PurpleConnection *gc;
 	const char *body;
+	char *body_str;
 	char *body_enc;
 	char *body_final;
-	size_t body_len;
+	char *yaz_body_final;
+	size_t body_len, new_len;
 	const char *passport;
 	const char *value;
 
 	gc = cmdproc->session->account->gc;
 
 	body = msn_message_get_bin_data(msg, &body_len);
-	body_enc = g_markup_escape_text(body, body_len);
+	body_str = sanitize_utf(body, body_len, &new_len);
+	body_enc = g_markup_escape_text(body_str, -1);
+	g_free(body_str);
 
 	passport = msg->remote_user;
 
@@ -740,23 +747,30 @@
 		body_final = body_enc;
 	}
 
+	/* yaz */
+	/* replace 0D 0A with <br> */
+	yaz_body_final = purple_strreplace(body_final, "\r\n", "<br>");
+//	purple_debug_info("yaz msn", "yaz_body_final=%s\n", yaz_body_final);
+	g_free(body_final);
+	body_final = yaz_body_final;
+
 	if (cmdproc->servconn->type == MSN_SERVCONN_SB) {
 		MsnSwitchBoard *swboard = cmdproc->data;
 
 		swboard->flag |= MSN_SB_FLAG_IM;
 
 		if (swboard->current_users > 1 ||
-			((swboard->conv != NULL) &&
-			 purple_conversation_get_type(swboard->conv) == PURPLE_CONV_TYPE_CHAT))
+		    ((swboard->conv != NULL) &&
+		     purple_conversation_get_type(swboard->conv) == PURPLE_CONV_TYPE_CHAT))
 		{
 			/* If current_users is always ok as it should then there is no need to
 			 * check if this is a chat. */
 			if (swboard->current_users <= 1)
 				purple_debug_misc("msn", "plain_msg: current_users(%d)\n",
-								swboard->current_users);
+						  swboard->current_users);
 
 			serv_got_chat_in(gc, swboard->chat_id, passport, 0, body_final,
-							 time(NULL));
+					 time(NULL));
 			if (swboard->conv == NULL)
 			{
 				swboard->conv = purple_find_chat(gc, swboard->chat_id);
@@ -770,7 +784,7 @@
 			if (swboard->conv == NULL)
 			{
 				swboard->conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
-										passport, purple_connection_get_account(gc));
+										      passport, purple_connection_get_account(gc));
 				swboard->flag |= MSN_SB_FLAG_IM;
 			}
 		}
--- a/libpurple/protocols/msn/msn.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/msn/msn.c	Wed Nov 10 11:41:51 2010 +0900
@@ -252,6 +252,8 @@
 	PurpleAccount *account;
 	const char *real_alias;
 	struct public_alias_closure *closure;
+	gchar *tmp;
+	gsize dummy;
 
 	session = purple_connection_get_protocol_data(pc);
 	cmdproc = session->notification->cmdproc;
@@ -259,7 +261,7 @@
 
 	if (alias && *alias)
 	{
-		char *tmp = g_strdup(alias);
+		char *tmp = botch_utf(alias, strlen(alias), &dummy);
 		real_alias = purple_url_encode(g_strstrip(tmp));
 		g_free(tmp);
 	}
@@ -578,6 +580,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;
@@ -1365,13 +1384,18 @@
 msn_send_emoticons(MsnSwitchBoard *swboard, GString *body)
 {
 	MsnMessage *msg;
+	gchar *tmp;
+	gsize len;
 
 	g_return_if_fail(body != NULL);
 
 	msg = msn_message_new(MSN_MSG_SLP);
 	msn_message_set_content_type(msg, "text/x-mms-emoticon");
 	msn_message_set_flag(msg, 'N');
-	msn_message_set_bin_data(msg, body->str, body->len);
+
+	tmp = botch_utf(body->str, -1, &len);
+	msn_message_set_bin_data(msg, tmp, len);
+	g_free(tmp);
 
 	msn_switchboard_send_msg(swboard, msg, TRUE);
 	msn_message_destroy(msg);
@@ -2817,6 +2841,9 @@
 	msn_notification_init();
 	msn_switchboard_init();
 
+	// yaz
+	msn_ipc_init(plugin);
+
 	return TRUE;
 }
 
@@ -2825,6 +2852,9 @@
 	msn_notification_end();
 	msn_switchboard_end();
 
+	// yaz
+	msn_ipc_end(plugin);
+
 	return TRUE;
 }
 
--- a/libpurple/protocols/oscar/encoding.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/oscar/encoding.c	Wed Nov 10 11:41:51 2010 +0900
@@ -51,15 +51,34 @@
 	gchar *utf8 = NULL;
 	const gchar *glib_encoding = NULL;
 	gchar *extracted_encoding = encoding_extract(encoding);
-	
+
 	if (extracted_encoding == NULL || *extracted_encoding == '\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)){
+			gsize newlen;
+			utf8 = sanitize_utf(text, textlen, &newlen);
+			goto done;
+		}
+		// not UTF-8
+		purple_debug_info("yaz oscar", "Empty encoding, assuming UTF-16BE\n");
+		sanitize_ucs((gchar *)text, textlen);
+		utf8 = g_convert(text, textlen, "UTF-8", "UTF-16BE", 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(extracted_encoding, "iso-8859-1")) {
 		glib_encoding = "iso-8859-1";
 	} else if (!g_ascii_strcasecmp(extracted_encoding, "ISO-8859-1-Windows-3.1-Latin-1") || !g_ascii_strcasecmp(extracted_encoding, "us-ascii")) {
 		glib_encoding = "Windows-1252";
 	} else if (!g_ascii_strcasecmp(extracted_encoding, "unicode-2-0")) {
 		glib_encoding = "UTF-16BE";
+		sanitize_ucs((gchar *)text, textlen);
 	} else if (g_ascii_strcasecmp(extracted_encoding, "utf-8")) {
 		glib_encoding = extracted_encoding;
 	}
@@ -81,6 +100,7 @@
 			utf8 = g_strndup(text, textlen);
 	}
 
+done:
 	g_free(extracted_encoding);
 	return utf8;
 }
@@ -112,7 +132,7 @@
 static gchar *
 oscar_convert_to_utf8(const gchar *data, gsize datalen, const char *charsetstr, gboolean fallback)
 {
-	gchar *ret = NULL;
+	gchar *ret = NULL, *ret2 = NULL;
 	GError *err = NULL;
 
 	if ((charsetstr == NULL) || (*charsetstr == '\0'))
@@ -135,7 +155,9 @@
 			purple_debug_warning("oscar", "String is not valid UTF-8.\n");
 	}
 
-	return ret;
+	ret2 = sanitize_utf(ret, -1, NULL);
+	g_free(ret);
+	return ret2;
 }
 
 gchar *
@@ -160,13 +182,14 @@
 	} else if (charset == AIM_CHARSET_ASCII) {
 		/* Should just be "ASCII" */
 		charsetstr1 = "ASCII";
-		charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
-	} else if (charset == 0x000d) {
+		charsetstr2 = "UTF-8";
+        charsetstr3 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
+	} else if (charset == AIM_CHARSET_QUIRKUTF8) {
 		/* iChat sending unicode over a Direct IM connection = UTF-8 */
-		/* Mobile AIM client on multiple devices (including Blackberry Tour, Nokia 3100, and LG VX6000) = ISO-8859-1 */
-		charsetstr1 = "UTF-8";
-		charsetstr2 = "ISO-8859-1";
-		charsetstr3 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
+        /* Mobile AIM client on a Nokia 3100 and an LG VX6000 */
+        charsetstr1 = "UTF-8";
+        charsetstr2 = "ISO-8859-1";
+        charsetstr3 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
 	} else {
 		/* Unknown, hope for valid UTF-8... */
 		charsetstr1 = "UTF-8";
--- a/libpurple/protocols/oscar/family_icbm.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/oscar/family_icbm.c	Wed Nov 10 11:41:51 2010 +0900
@@ -53,6 +53,7 @@
 #endif
 
 #include "util.h"
+#include "debug.h" /* yaz */
 
 static const char * const errcodereason[] = {
 	N_("Invalid error"),
@@ -413,6 +414,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, SNAC_FAMILY_ICBM)))
 		return -EINVAL;
@@ -451,15 +455,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 UTF-16BE, 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), (guint8 *)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, (guint8 *)"unicode-2-0");
+		aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
+		//yaz
+		ucs = g_convert(msg, strlen(msg), "UTF-16BE", "UTF-8", NULL, &bytes, NULL);
+		if(ucs){
+			botch_ucs(ucs, bytes);
+			aim_tlvlist_add_raw(&inner_tlvlist, 0x000c, bytes, (guint8 *)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/odc.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/oscar/odc.c	Wed Nov 10 11:41:51 2010 +0900
@@ -102,18 +102,23 @@
 	byte_stream_new(&bs, length + frame->payload.len);
 	byte_stream_putraw(&bs, conn->magic, 4);
 	byte_stream_put16(&bs, length);
+
 	byte_stream_put16(&bs, frame->type);
 	byte_stream_put16(&bs, frame->subtype);
 	byte_stream_put16(&bs, 0x0000);
+
 	byte_stream_putraw(&bs, frame->cookie, 8);
 	byte_stream_put16(&bs, 0x0000);
 	byte_stream_put16(&bs, 0x0000);
 	byte_stream_put16(&bs, 0x0000);
 	byte_stream_put16(&bs, 0x0000);
+
 	byte_stream_put32(&bs, frame->payload.len);
 	byte_stream_put16(&bs, frame->encoding);
 	byte_stream_put16(&bs, 0x0000);	
 	byte_stream_put16(&bs, 0x0000);
+	byte_stream_put16(&bs, 0x0000);
+
 	byte_stream_put16(&bs, frame->flags);
 	byte_stream_put16(&bs, 0x0000);
 	byte_stream_put16(&bs, 0x0000);
@@ -495,11 +500,14 @@
 	frame->type = byte_stream_get16(bs);
 	frame->subtype = byte_stream_get16(bs);
 	byte_stream_advance(bs, 2);
+
 	byte_stream_getrawbuf(bs, frame->cookie, 8);
 	byte_stream_advance(bs, 8);
+
 	frame->payload.len = byte_stream_get32(bs);
 	frame->encoding = byte_stream_get16(bs);
 	byte_stream_advance(bs, 4);
+
 	frame->flags = byte_stream_get16(bs);
 	byte_stream_advance(bs, 4);
 	byte_stream_getrawbuf(bs, frame->bn, 32);
--- a/libpurple/protocols/oscar/oft.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/oscar/oft.c	Wed Nov 10 11:41:51 2010 +0900
@@ -652,6 +652,8 @@
 {
 	PeerConnection *conn;
 	size_t size;
+	gchar *f1 = NULL, *f2 = NULL;
+	gsize dummy;
 
 	conn = xfer->data;
 	conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
@@ -689,7 +691,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	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Wed Nov 10 11:41:51 2010 +0900
@@ -1855,7 +1855,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++) {
@@ -3115,8 +3115,6 @@
 {
 	GString *msg;
 	GString *data;
-	gchar *tmp;
-	gsize tmplen;
 	guint16 charset;
 	GData *attribs;
 	const char *start, *end, *last;
@@ -3177,11 +3175,9 @@
 
 	g_string_append(msg, "</BODY></HTML>");
 
-	/* Convert the message to a good encoding */
-	tmp = oscar_encode_im(msg->str, &tmplen, &charset, NULL);
-	g_string_free(msg, TRUE);
-	msg = g_string_new_len(tmp, tmplen);
-	g_free(tmp);
+	/* iChat and AIM6 use 0x000d to send UTF8.
+       moreover, AIM6 persists only to UTF8! --yaz */
+    charset = AIM_CHARSET_QUIRKUTF8;
 
 	/* Append any binary data that we may have */
 	if (oscar_id) {
@@ -3319,10 +3315,14 @@
 			/* Messaging an SMS (mobile) user--strip HTML */
 			tmp2 = purple_markup_strip_html(tmp1);
 			is_html = FALSE;
-		} else {
+		} else if (od->icq) {
 			/* ICQ 6 wants its HTML wrapped in these tags. Oblige it. */
 			tmp2 = g_strdup_printf("<HTML><BODY>%s</BODY></HTML>", tmp1);
 			is_html = TRUE;
+		} else {
+			/* otherwise */
+			tmp2 = g_strdup(tmp1);
+			is_html = FALSE;
 		}
 		g_free(tmp1);
 		tmp1 = tmp2;
@@ -4495,7 +4495,7 @@
 				message, buf2);
 	}
 
-	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/oscar/oscar.h	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/oscar/oscar.h	Wed Nov 10 11:41:51 2010 +0900
@@ -616,6 +616,7 @@
 #define AIM_CHARSET_ASCII   0x0000 /* ISO 646 */
 #define AIM_CHARSET_UNICODE 0x0002 /* ISO 10646 (UTF-16/UCS-2BE) */
 #define AIM_CHARSET_LATIN_1 0x0003 /* ISO 8859-1 */
+#define AIM_CHARSET_QUIRKUTF8	0x000d /* iChat and AIM6 use this in the meaning of UTF-8 in ODC. --yaz */
 
 /*
  * Arguments to aim_send_im_ext().
--- a/libpurple/protocols/yahoo/libyahoo.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/yahoo/libyahoo.c	Wed Nov 10 11:41:51 2010 +0900
@@ -32,6 +32,7 @@
 #include "yahoo_doodle.h"
 #include "yahoo_filexfer.h"
 #include "yahoo_picture.h"
+#include "ycht.h"
 
 static PurplePlugin *my_protocol = NULL;
 
@@ -330,9 +331,15 @@
 	option = purple_account_option_bool_new(_("Use account proxy for HTTP and HTTPS connections"), "proxy_ssl", FALSE);
 	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);
+
+	option = purple_account_option_string_new(_("Yahoo Chat server"), "ycht-server", YAHOO_YCHT_HOST);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_int_new(_("Yahoo Chat port"), "ycht-port", YAHOO_YCHT_PORT);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 #endif
 
 	my_protocol = plugin;
--- a/libpurple/protocols/yahoo/libyahoojp.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/yahoo/libyahoojp.c	Wed Nov 10 11:41:51 2010 +0900
@@ -31,6 +31,7 @@
 #include "yahoo_doodle.h"
 #include "yahoo_filexfer.h"
 #include "yahoo_picture.h"
+#include "ycht.h"
 
 static void yahoojp_register_commands(void)
 {
@@ -226,8 +227,14 @@
 	option = purple_account_option_bool_new(_("Use account proxy for HTTP and HTTPS connections"), "proxy_ssl", FALSE);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
-#if 0
-	option = purple_account_option_string_new(_("Chat room list URL"), "room_list", YAHOO_ROOMLIST_URL);
+#if 1
+	option = purple_account_option_string_new(_("Chat room list URL"), "room_list", YAHOOJP_ROOMLIST_URL);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_string_new(_("Yahoo Chat server"), "ycht-server", YAHOOJP_YCHT_HOST);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_int_new(_("Yahoo Chat port"), "ycht-port", YAHOOJP_YCHT_PORT);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 #endif
 
--- a/libpurple/protocols/yahoo/libymsg.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/yahoo/libymsg.c	Wed Nov 10 11:41:51 2010 +0900
@@ -1566,8 +1566,9 @@
 
 #define OUT_CHARSET "utf-8"
 
-static char *yahoo_decode(const char *text)
+static char *yahoo_decode(PurpleConnection *gc, const char *text)
 {
+	YahooData *yd = gc->proto_data;
 	char *converted = NULL;
 	char *n, *new;
 	const char *end, *p;
@@ -1608,11 +1609,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, "UTF-8", 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;
 }
@@ -1645,8 +1651,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),
@@ -4798,6 +4804,7 @@
 	char *msg = NULL, *msg2 = NULL;
 	PurpleStatus *status = NULL;
 	gboolean invisible = FALSE;
+	gboolean utf8 = TRUE;
 
 	if (idle && yd->current_status != YAHOO_STATUS_CUSTOM)
 		yd->current_status = YAHOO_STATUS_IDLE;
@@ -4821,7 +4828,6 @@
 			status = purple_presence_get_active_status(purple_account_get_presence(purple_connection_get_account(gc)));
 		tmp = purple_status_get_attr_string(status, "message");
 		if (tmp != NULL) {
-			gboolean utf8 = TRUE;
 			msg = yahoo_string_encode(gc, tmp, &utf8);
 			msg2 = purple_markup_strip_html(msg);
 			yahoo_packet_hash_str(pkt, 97, utf8 ? "1" : 0);
@@ -4829,6 +4835,7 @@
 		} else {
 			/* get_yahoo_status_from_purple_status() returns YAHOO_STATUS_CUSTOM for
 			 * the generic away state (YAHOO_STATUS_TYPE_AWAY) with no message */
+			yahoo_packet_hash_str(pkt, 97, utf8 ? "1" : 0);
 			yahoo_packet_hash_str(pkt, 19, _("Away"));
 		}
 	} else {
--- a/libpurple/protocols/yahoo/util.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/yahoo/util.c	Wed Nov 10 11:41:51 2010 +0900
@@ -29,6 +29,7 @@
 #include "prpl.h"
 
 #include "libymsg.h"
+#include "util.h"
 
 #include <string.h>
 
@@ -130,14 +131,13 @@
 char *yahoo_string_encode(PurpleConnection *gc, const char *str, gboolean *utf8)
 {
 	YahooData *yd = gc->proto_data;
-	char *ret;
+	char *ret = NULL;
+	gsize newlen;
 	const char *to_codeset;
 
-	if (yd->jp)
-		return g_strdup(str);
-
-	if (utf8 && *utf8) /* FIXME: maybe don't use utf8 if it'll fit in latin1 */
-		return g_strdup(str);
+	if (utf8 && *utf8) {
+		return botch_utf((gchar *)str, strlen((gchar *)str), &newlen);
+	}
 
 	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);
@@ -159,23 +159,29 @@
 char *yahoo_string_decode(PurpleConnection *gc, const char *str, gboolean utf8)
 {
 	YahooData *yd = gc->proto_data;
-	char *ret;
+	char *ret, *tmp;
 	const char *from_codeset;
+	gsize newlen;
 
 	if (utf8) {
-		if (g_utf8_validate(str, -1, NULL))
-			return g_strdup(str);
+		ret = sanitize_utf((gchar *)str, strlen((gchar *)str), &newlen);
+		if (g_utf8_validate(ret, -1, NULL))
+			return ret;
 	}
 
 	if (yd->jp)
-		from_codeset = "SHIFT_JIS";
+		from_codeset = "UTF-8";
 	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);
 
-	if (ret)
+	if (ret) {
+		tmp = ret;
+		ret = sanitize_utf((gchar *)tmp, strlen((gchar *)tmp), &newlen);
+		g_free(tmp);
 		return ret;
+	}
 	else
 		return g_strdup("");
 }
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c	Wed Nov 10 11:41:51 2010 +0900
@@ -226,7 +226,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;
@@ -234,6 +234,7 @@
 	PurpleConnection *gc;
 	PurpleAccount *account;
 	YahooData *yd;
+	gsize dummy;
 
 	purple_debug_info("yahoo", "in yahoo_sendfile_connected\n");
 
@@ -260,8 +261,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);
@@ -984,7 +989,7 @@
 	struct sockaddr_in *addr;
 	struct yahoo_packet *pkt;
 	unsigned long actaddr;
-	unsigned char a,b,c,d;
+	unsigned long a,b,c,d;
 	PurpleConnection *gc;
 	PurpleAccount *account;
 	YahooData *yd;
--- a/libpurple/protocols/yahoo/yahoo_packet.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/yahoo/yahoo_packet.c	Wed Nov 10 11:41:51 2010 +0900
@@ -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,8 @@
 {
 	struct yahoo_pair *pair;
 
+	g_return_if_fail(pkt != NULL);
+
 	pair = g_new0(struct yahoo_pair, 1);
 	pair->key = key;
 	pair->value = g_strdup_printf("%d", value);
@@ -386,6 +389,9 @@
 {
 	int ret;
 
+	g_return_val_if_fail(pkt != NULL, 0);
+	g_return_val_if_fail(yd != NULL, 0);
+
 	ret = yahoo_packet_send(pkt, yd);
 	yahoo_packet_free(pkt);
 	return ret;
--- a/libpurple/protocols/yahoo/yahoo_profile.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/yahoo/yahoo_profile.c	Wed Nov 10 11:41:51 2010 +0900
@@ -22,6 +22,7 @@
  */
 
 #define PHOTO_SUPPORT 1
+//original is 1 --yaz
 
 #include "internal.h"
 #include "debug.h"
@@ -670,6 +671,7 @@
 	},
 };
 
+#if 0
 static char *yahoo_info_date_reformat(const char *field, size_t len)
 {
 	char *tmp = g_strndup(field, len);
@@ -678,6 +680,7 @@
 	g_free(tmp);
 	return g_strdup(purple_date_format_short(localtime(&t)));
 }
+#endif
 
 static char *yahoo_remove_nonbreaking_spaces(char *str)
 {
@@ -763,6 +766,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 +1015,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 +1029,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) {
@@ -1055,16 +1062,17 @@
 		}
 	}
 #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, _("Email"), 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,
@@ -1095,7 +1103,7 @@
 	found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
 			strings->occupation_string, 2, "\n", '\n',
 			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
@@ -1104,7 +1112,7 @@
 	 * 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))
@@ -1190,6 +1198,7 @@
 				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));
 	}
+#endif
 	} /* if (profile_state == PROFILE_STATE_DEFAULT) */
 
 	if(!found)
--- a/libpurple/protocols/yahoo/yahoochat.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/yahoo/yahoochat.c	Wed Nov 10 11:41:51 2010 +0900
@@ -945,7 +945,7 @@
 	g_free(msg1);
 	msg1 = yahoo_string_encode(gc, msg2, &utf8);
 	g_free(msg2);
-	room2 = yahoo_string_encode(gc, room, NULL);
+	room2 = yahoo_string_encode(gc, room, &utf8);
 
 	pkt = yahoo_packet_new(YAHOO_SERVICE_COMMENT, YAHOO_STATUS_AVAILABLE, yd->session_id);
 
@@ -1584,6 +1584,7 @@
 	char *url;
 	char *id;
 	const char *rll;
+	gboolean jp = purple_account_get_bool(list->account, "yahoojp", FALSE);
 
 	if (category->type != PURPLE_ROOMLIST_ROOMTYPE_CATEGORY)
 		return;
@@ -1593,17 +1594,12 @@
 		return;
 	}
 
-	rll = purple_account_get_string(list->account, "room_list_locale",
-								  YAHOO_ROOMLIST_LOCALE);
+	rll = jp ? YAHOOJP_ROOMLIST_LOCALE : purple_account_get_string(list->account, "room_list_locale", YAHOO_ROOMLIST_LOCALE);
 
 	if (rll != NULL && *rll != '\0') {
-		url = g_strdup_printf("%s?chatroom_%s=0&intl=%s",
-	       purple_account_get_string(list->account,"room_list",
-	       YAHOO_ROOMLIST_URL), id, rll);
+		url = g_strdup_printf("%s?chatroom_%s=0&intl=%s", jp ? YAHOOJP_ROOMLIST_URL : purple_account_get_string(list->account,"room_list", YAHOO_ROOMLIST_URL), id, rll);
 	} else {
-		url = g_strdup_printf("%s?chatroom_%s=0",
-	       purple_account_get_string(list->account,"room_list",
-	       YAHOO_ROOMLIST_URL), id);
+		url = g_strdup_printf("%s?chatroom_%s=0", jp ? YAHOOJP_ROOMLIST_URL : purple_account_get_string(list->account,"room_list", YAHOO_ROOMLIST_URL), id);
 	}
 
 	yrl = g_new0(struct yahoo_roomlist, 1);
--- a/libpurple/protocols/yahoo/ycht.h	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/protocols/yahoo/ycht.h	Wed Nov 10 11:41:51 2010 +0900
@@ -32,6 +32,10 @@
 #define YAHOO_YCHT_HOST "jcs3.chat.dcn.yahoo.com"
 #define YAHOO_YCHT_PORT 8002
 
+/* fix these --yaz */
+#define YAHOOJP_YCHT_HOST "chat.yahoo.co.jp"
+#define YAHOOJP_YCHT_PORT 8000
+
 #define YCHT_VERSION (0xae)
 #define YCHT_HEADER_LEN (0x10)
 
--- a/libpurple/server.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/server.c	Wed Nov 10 11:41:51 2010 +0900
@@ -239,6 +239,8 @@
 	GSList *buddies;
 	PurpleBuddy *b;
 	PurpleConversation *conv;
+	gsize dummy;
+	gchar *alias2 = NULL;
 
 	account = purple_connection_get_account(gc);
 	buddies = purple_find_buddies(account, who);
@@ -255,13 +257,16 @@
 		if (purple_strequal(server_alias, alias))
 			continue;
 
-		purple_blist_server_alias_buddy(b, alias);
+		if(alias)
+			alias2 = sanitize_utf(alias, strlen(alias), &dummy);
+
+		purple_blist_server_alias_buddy(b, alias2);
 
 		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, purple_buddy_get_name(b), account);
-		if (conv != NULL && alias != NULL && !purple_strequal(alias, who))
+		if (conv != NULL && alias2 != NULL && !purple_strequal(alias2, who))
 		{
 			char *escaped = g_markup_escape_text(who, -1);
-			char *escaped2 = g_markup_escape_text(alias, -1);
+			char *escaped2 = g_markup_escape_text(alias2, -1);
 			char *tmp = g_strdup_printf(_("%s is now known as %s.\n"),
 										escaped, escaped2);
 
@@ -273,6 +278,8 @@
 			g_free(escaped2);
 			g_free(escaped);
 		}
+		g_free(alias2);
+		alias2 = NULL;
 	}
 }
 
@@ -282,6 +289,8 @@
 	PurpleAccount *account = NULL;
 	GSList *buddies = NULL;
 	PurpleBuddy *b = NULL;
+	gsize dummy;
+	gchar *alias2 = NULL;
 
 	account = purple_connection_get_account(gc);
 	buddies = purple_find_buddies(account, who);
@@ -296,11 +305,13 @@
 		if (purple_strequal(balias, alias))
 			continue;
 
-		purple_blist_alias_buddy(b, alias);
+		alias2 = sanitize_utf(alias, strlen(alias), &dummy);
+		purple_blist_alias_buddy(b, alias2);
+		g_free(alias2);
+		alias2 = NULL;
 	}
 }
 
-
 PurpleAttentionType *purple_get_attention_type_from_code(PurpleAccount *account, guint type_code)
 {
 	PurplePlugin *prpl;
--- a/libpurple/util.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/util.c	Wed Nov 10 11:41:51 2010 +0900
@@ -1230,6 +1230,8 @@
 		return FALSE;
 
 	q = strstr(p, end_token);
+	if(q == NULL) //yaz
+		return FALSE;
 
 	/* Trim leading blanks */
 	while (*p != '\n' && g_ascii_isspace(*p)) {
@@ -1242,7 +1244,7 @@
 	}
 
 	/* Don't bother with null strings */
-	if (p == q)
+	if (p >= q)
 		return FALSE;
 
 	if (q != NULL && (!no_value_token ||
@@ -2027,6 +2029,20 @@
 }
 
 static gboolean
+is_zenkaku_space(const char *c)
+{
+    gboolean rv = FALSE;
+    const guchar *u = (guchar *)c;
+
+    if(!c || !strcmp(c, "") || strlen(c) < 3)
+        rv = FALSE;
+    else if(*u == 0xe3 && *(u+1) == 0x80 && *(u+2) == 0x80)
+        rv = TRUE;
+
+    return rv;
+}
+
+static gboolean
 badchar(char c)
 {
 	switch (c) {
@@ -2066,7 +2082,7 @@
 	const char *t;
 
 	for (t = c;; t++) {
-		if (!badchar(*t) && !badentity(t))
+		if (!badchar(*t) && !badentity(t) && !is_zenkaku_space(t))
 			continue;
 
 		if (t - c == matchlen)
@@ -2102,6 +2118,7 @@
 	gunichar g;
 	gboolean inside_html = FALSE;
 	int inside_paren = 0;
+	int inside_bracket = 0;
 	GString *ret;
 
 	if (text == NULL)
@@ -2118,6 +2135,12 @@
 			c++;
 		}
 
+		if(*c == '[' && !inside_html) {
+			inside_bracket++;
+			ret = g_string_append_c(ret, *c);
+			c++;
+		}
+
 		if(inside_html) {
 			if(*c == '>') {
 				inside_html = FALSE;
@@ -2160,7 +2183,7 @@
 		} else if (!g_ascii_strncasecmp(c, "mailto:", 7)) {
 			t = c;
 			while (1) {
-				if (badchar(*t) || badentity(t)) {
+				if (badchar(*t) || badentity(t) || is_zenkaku_space(t)) {
 					char *d;
 					if (t - c == 7) {
 						break;
@@ -2261,6 +2284,11 @@
 			ret = g_string_append_c(ret, *c);
 			c++;
 		}
+		if(*c == ']' && !inside_html) {
+			inside_bracket--;
+			ret = g_string_append_c(ret, *c);
+			c++;
+		}
 
 		if (*c == 0)
 			break;
@@ -5044,3 +5072,296 @@
 			b,
 			(tmp >> 16) & 0xFFFF, g_random_int());
 }
+
+#ifdef _WIN32
+void botch_ucs(gchar *ucs_src, gsize len)
+{
+	/* no operation */
+}
+#else
+void botch_ucs(gchar *ucs_src, gsize len)
+{
+	gint i;
+	guchar *ucs = (guchar *)ucs_src;
+
+	g_return_if_fail(ucs_src != NULL);
+	g_return_if_fail(len > 0);
+
+ 	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;
+ 		}
+ 	}
+
+}
+#endif
+
+#ifdef _WIN32
+void sanitize_ucs(gchar *ucs, gsize len)
+{
+	/* no operation */
+}
+#else
+void sanitize_ucs(gchar *ucs_src, gsize len)
+{
+	gint i;
+	guchar *ucs = (guchar *)ucs_src;
+
+	g_return_if_fail(ucs_src != NULL);
+	g_return_if_fail(len > 0);
+
+	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;
+		}
+	}
+}
+#endif
+
+#ifdef _WIN32
+gchar *sanitize_utf(const gchar *msg, gsize len, gsize *newlen)
+{
+	g_return_val_if_fail(msg != NULL, NULL);
+	if(len == -1)
+		len = strlen(msg);
+	g_return_val_if_fail(len > 0, NULL);
+
+	if(newlen)
+		*newlen = len;
+
+	return g_strndup(msg, len);
+}
+#else
+gchar *sanitize_utf(const gchar *msg, gsize len, gsize *newlen)
+{
+	gint i;
+	size_t bytes;
+	guchar *utf;
+
+	g_return_val_if_fail(msg != NULL, NULL);
+	if(len == -1)
+		len = strlen(msg);
+	g_return_val_if_fail(len > 0, NULL);
+
+	utf = (guchar *)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); //shorten by 1byte
+				       bytes--;
+				       break;
+			       case 0xa1:	// £
+				       *(utf+i) = 0xc2;
+				       *(utf+i+1) = 0xa3;
+				       memmove(utf+i+2, utf+i+3,
+					       len-i-3); //shorten by 1byte
+				       bytes--;
+				       break;
+			       case 0xa2:	// ¬
+				       *(utf+i) = 0xc2;
+				       *(utf+i+1) = 0xac;
+				       memmove(utf+i+2, utf+i+3,
+					       len-i-3); //shorten by 1byte
+				       bytes--;
+				       break;
+			       }
+			       break;
+			}
+			break;
+		}
+	}
+	*(utf+bytes)= 0x00; //terminate
+	if(newlen)
+		*newlen = bytes;
+	return (gchar *)utf;
+}
+#endif
+
+#ifdef _WIN32
+gchar *botch_utf(const gchar *msg, gsize len, gsize *newlen)
+{
+	g_return_val_if_fail(msg != NULL, NULL);
+	if(len == -1)
+		len = strlen(msg);
+	g_return_val_if_fail(len > 0, NULL);
+
+	if(newlen)
+		*newlen = len;
+
+	return g_strndup(msg, len);
+}
+#else
+gchar *botch_utf(const gchar *msg, gsize len, gsize *newlen)
+{
+ 	int i,bytes;
+	unsigned char *utf;
+
+	g_return_val_if_fail(msg != NULL, NULL);
+	if(len == -1)
+		len = strlen(msg);
+	g_return_val_if_fail(len > 0, NULL);
+
+	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
+	if(newlen)
+		*newlen = bytes;
+	return (gchar *)utf;
+}
+#endif
--- a/libpurple/util.h	Sat Nov 06 03:46:35 2010 +0000
+++ b/libpurple/util.h	Wed Nov 10 11:41:51 2010 +0900
@@ -1486,4 +1486,10 @@
 }
 #endif
 
+/* to address incompatibility with cp932. */
+void botch_ucs(gchar *ucs, gsize len);
+void sanitize_ucs(gchar *ucs, gsize len);
+gchar *botch_utf(const gchar *utf, gsize len, gsize *newlen);
+gchar *sanitize_utf(const gchar *msg, gsize len, gsize *newlen);
+
 #endif /* _PURPLE_UTIL_H_ */
--- a/pidgin/gtkblist.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/pidgin/gtkblist.c	Wed Nov 10 11:41:51 2010 +0900
@@ -70,6 +70,11 @@
 #include <gtk/gtk.h>
 #include <gdk/gdk.h>
 
+/* I noticed that some of short cuts are very annoying.
+   If you really want to use them, change this to 1. --yaz
+*/
+#define ENABLE_SHORTCUT 0
+
 typedef struct
 {
 	PurpleAccount *account;
@@ -3696,6 +3701,7 @@
 	{ N_("/Tools/System _Log"), NULL, gtk_blist_show_systemlog_cb, 3, "<Item>", NULL },
 	{ "/Tools/sep3", NULL, NULL, 0, "<Separator>", NULL },
 	{ N_("/Tools/Mute _Sounds"), NULL, pidgin_blist_mute_sounds_cb, 0, "<CheckItem>", NULL },
+
 	/* Help */
 	{ N_("/_Help"), NULL, NULL, 0, "<Branch>", NULL },
 	{ N_("/Help/Online _Help"), "F1", gtk_blist_show_onlinehelp_cb, 0, "<StockItem>", GTK_STOCK_HELP },
--- a/pidgin/gtkconv.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/pidgin/gtkconv.c	Wed Nov 10 11:41:51 2010 +0900
@@ -1,3 +1,4 @@
+/* -*- coding: utf-8 -*- */
 /**
  * @file gtkconv.c GTK+ Conversation API
  * @ingroup pidgin
@@ -120,6 +121,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;
 
@@ -274,6 +279,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)
 {
@@ -453,6 +495,20 @@
 	gtkconv->send_history = g_list_prepend(first, NULL);
 }
 
+#if 0
+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"));
+}
+#endif
+
 static gboolean
 check_for_and_do_command(PurpleConversation *conv)
 {
@@ -3062,13 +3118,21 @@
 
 	{ "/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 },
 
 #ifdef USE_VV
@@ -3086,8 +3150,13 @@
 	{ N_("/Conversation/Get _Attention"), NULL, menu_get_attention_cb, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SEND_ATTENTION },
 	{ 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 },
@@ -3868,7 +3937,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();
@@ -4594,12 +4667,10 @@
 		height += 2 * focus_width;
 
 	diff = height - gtkconv->entry->allocation.height;
-	if (ABS(diff) < oneline.height / 2)
+	if (diff == 0 || (diff < 0 && -diff < oneline.height / 2))
 		return FALSE;
-
 	gtk_widget_set_size_request(gtkconv->lower_hbox, -1,
-		diff + gtkconv->lower_hbox->allocation.height);
-
+				    diff + gtkconv->lower_hbox->allocation.height);
 	return FALSE;
 }
 
@@ -4832,6 +4903,10 @@
 	switch (event->keyval) {
 		case GDK_Return:
 		case GDK_KP_Enter:
+			if (gtk_im_context_filter_keypress (GTK_ENTRY(entry)->im_context, event)) {
+				GTK_ENTRY(entry)->need_im_reset = TRUE;
+				return TRUE;
+			}
 			if (gtk_imhtml_search_find(GTK_IMHTML(gtkconv->imhtml), gtk_entry_get_text(GTK_ENTRY(entry)))) {
 				gtk_widget_modify_base(gtkconv->quickfind.entry, GTK_STATE_NORMAL, NULL);
 			} else {
@@ -4885,7 +4960,7 @@
 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;
@@ -4894,8 +4969,12 @@
 	GtkPolicyType imhtml_sw_hscroll;
 	int buddyicon_size = 0;
 
+	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 */
@@ -5020,20 +5099,32 @@
 	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);
+
 	pidgin_conv_setup_quickfind(gtkconv, 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);
@@ -5043,6 +5134,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));
@@ -5067,7 +5160,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
@@ -6705,6 +6798,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);
@@ -6774,8 +6870,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 ||
@@ -7192,6 +7306,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)
@@ -7262,6 +7394,7 @@
 			pidgin_conv_tab_pack(gtkwin, gtkconvs->data);
 		}
 	}
+	trim_vertical_tabs_pref_cb(name, type, value, data);
 }
 
 static void
@@ -7320,7 +7453,7 @@
 		else
 			gtk_widget_hide(gtkconv->toolbar);
 
-		g_idle_add((GSourceFunc)resize_imhtml_cb,gtkconv);
+//		g_idle_add((GSourceFunc)resize_imhtml_cb,gtkconv);
 	}
 }
 
@@ -7862,6 +7995,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);
@@ -7918,6 +8052,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",
--- a/pidgin/gtkdocklet-gtk.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/pidgin/gtkdocklet-gtk.c	Wed Nov 10 11:41:51 2010 +0900
@@ -79,7 +79,7 @@
 		icon_name = PIDGIN_STOCK_TRAY_CONNECT;
 
 	if (icon_name) {
-		gtk_status_icon_set_from_icon_name(docklet, icon_name);
+		gtk_status_icon_set_from_stock(docklet, icon_name);
 	}
 
 	if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/blink")) {
--- a/pidgin/gtkimhtml.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/pidgin/gtkimhtml.c	Wed Nov 10 11:41:51 2010 +0900
@@ -106,6 +106,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);
@@ -518,10 +522,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;
 
@@ -566,7 +571,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) +
@@ -680,7 +687,6 @@
 		tip = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_tiptext");
 		hand = FALSE;
 	}
-
 	if (tip && *tip) {
 		GTK_IMHTML(imhtml)->tip_timer = g_timeout_add (TOOLTIP_TIMEOUT,
 							       gtk_imhtml_tip, imhtml);
@@ -1030,18 +1036,25 @@
 	if (info == TARGET_HTML) {
 		char *selection;
 #ifndef _WIN32
-		gsize len;
 		if (primary) {
 			text = gtk_imhtml_get_markup_range(imhtml, &start, &end);
 		} else
 			text = html_clipboard;
 
-		/* Mozilla asks that we start our text/html with the Unicode byte order mark */
-		selection = g_convert(text, -1, "UTF-16", "UTF-8", NULL, &len, NULL);
-		gtk_selection_data_set(selection_data, gdk_atom_intern("text/html", FALSE), 16, (const guchar *)selection, len);
-#else
+		selection = NULL;
+		if (primary) {
+			text = gtk_imhtml_get_markup_range(imhtml, &start, &end);
+		} else {
+			text = html_clipboard;
+		}
+		/* xxx should remove following line --yaz */
+		purple_debug_info("imhtml clipboard", "html_clipboard: %s len = %d\n", text, strlen(text));
+		gtk_selection_data_set(selection_data, gdk_atom_intern("text/html", FALSE),
+				       8, (const guchar *)text, strlen(text)+1); // include trailing '\0' --yaz
+#else /*_WIN32 */
 		selection = clipboard_html_to_win32(html_clipboard);
-		gtk_selection_data_set(selection_data, gdk_atom_intern("HTML Format", FALSE), 8, (const guchar *)selection, strlen(selection));
+		gtk_selection_data_set(selection_data, gdk_atom_intern("HTML Format", FALSE),
+				       8, (const guchar *)selection, strlen(selection));
 #endif
 		g_free(selection);
 	} else {
@@ -1206,7 +1219,8 @@
 	if (selection_data->length >= 2 &&
 		(*(guint16 *)text == 0xfeff || *(guint16 *)text == 0xfffe)) {
 		/* This is UTF-16 */
-		char *utf8 = utf16_to_utf8_with_bom_check(text, selection_data->length);
+//		char *utf8 = utf16_to_utf8_with_bom_check(text, selection_data->length);
+		char *utf8 = g_convert(text, selection_data->length, "UTF-8", "UTF-16", NULL, NULL, NULL);
 		g_free(text);
 		text = utf8;
 		if (!text) {
@@ -1960,7 +1974,8 @@
 			 * http://mail.gnome.org/archives/gtk-devel-list/2001-September/msg00114.html
 			 */
 			if (sd->length >= 2 && !g_utf8_validate(text, sd->length - 1, NULL)) {
-				utf8 = utf16_to_utf8_with_bom_check(text, sd->length);
+//				utf8 = utf16_to_utf8_with_bom_check(text, sd->length);
+				utf8 = g_convert(text, sd->length, "UTF-8", "UTF-16", NULL, NULL, NULL);
 
 				if (!utf8) {
 					purple_debug_warning("gtkimhtml", "g_convert from UTF-16 failed in drag_rcv_cb\n");
@@ -3403,6 +3418,7 @@
 			break;
 		}
 	}
+	ws[wpos] = '\0'; // chop ws at wpos. due to bug of gtk_text_buffer_insert() --yaz
 	gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
 	ws[0] = '\0'; wpos = 0;
 
--- a/pidgin/gtkimhtmltoolbar.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/pidgin/gtkimhtmltoolbar.c	Wed Nov 10 11:41:51 2010 +0900
@@ -1468,7 +1468,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(G_OBJECT(smiley_button), "button-press-event", G_CALLBACK(button_activate_on_click), toolbar);
--- a/pidgin/gtkimhtmltoolbar.h	Sat Nov 06 03:46:35 2010 +0000
+++ b/pidgin/gtkimhtmltoolbar.h	Wed Nov 10 11:41:51 2010 +0900
@@ -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)            (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_IMHTMLTOOLBAR, GtkIMHtmlToolbar))
--- a/pidgin/gtknotify.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/pidgin/gtknotify.c	Wed Nov 10 11:41:51 2010 +0900
@@ -1252,12 +1252,15 @@
 pidgin_notify_uri(const char *uri)
 {
 #ifndef _WIN32
-	char *escaped = g_shell_quote(uri);
+	char *tmp = g_shell_quote(uri);
+	char *escaped = g_locale_from_utf8(tmp, -1, NULL, NULL, NULL);
 	char *command = NULL;
 	char *remote_command = NULL;
 	const char *web_browser;
 	int place;
 
+	g_free(tmp);
+
 	web_browser = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/browser");
 	place = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/browsers/place");
 
--- a/pidgin/gtkprefs.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/pidgin/gtkprefs.c	Wed Nov 10 11:41:51 2010 +0900
@@ -1384,6 +1384,9 @@
 	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,
@@ -1476,7 +1479,7 @@
 #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);
 #endif
--- a/pidgin/gtkutils.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/pidgin/gtkutils.c	Wed Nov 10 11:41:51 2010 +0900
@@ -3536,3 +3536,61 @@
 	gtk_imhtml_class_register_protocol("gopher://", NULL, NULL);
 }
 
+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	Sat Nov 06 03:46:35 2010 +0000
+++ b/pidgin/gtkutils.h	Wed Nov 10 11:41:51 2010 +0900
@@ -858,5 +858,7 @@
  */
 void pidgin_utils_uninit(void);
 
+gchar *pidgin_gtk_ellipsis_text(GtkWidget *widget, const char *text, gint min_width, gchar *ellipsis);
+
 #endif /* _PIDGINUTILS_H_ */
 
--- a/pidgin/pidginstock.c	Sat Nov 06 03:46:35 2010 +0000
+++ b/pidgin/pidginstock.c	Wed Nov 10 11:41:51 2010 +0900
@@ -331,7 +331,8 @@
 
 static void
 add_sized_icon(GtkIconSet *iconset, GtkIconSize sizeid, PidginIconTheme *theme,
-		const char *size, SizedStockIcon sized_icon, gboolean translucent)
+		const char *size, SizedStockIcon sized_icon, gboolean translucent,
+		gboolean size_wildcarded)
 {
 	char *filename;
 	GtkIconSource *source;
@@ -348,7 +349,7 @@
 	gtk_icon_source_set_direction(source, GTK_TEXT_DIR_LTR);
 	gtk_icon_source_set_direction_wildcarded(source, !sized_icon.rtl);
 	gtk_icon_source_set_size(source, sizeid);
-	gtk_icon_source_set_size_wildcarded(source, FALSE);
+	gtk_icon_source_set_size_wildcarded(source, size_wildcarded);
 	gtk_icon_source_set_state_wildcarded(source, TRUE);
 	gtk_icon_set_add_source(iconset, source);
 	gtk_icon_source_free(source);
@@ -358,7 +359,7 @@
 		gtk_icon_source_set_pixbuf(source, pixbuf);
 		gtk_icon_source_set_direction_wildcarded(source, TRUE);
 		gtk_icon_source_set_size(source, GTK_ICON_SIZE_MENU);
-		gtk_icon_source_set_size_wildcarded(source, FALSE);
+		gtk_icon_source_set_size_wildcarded(source, size_wildcarded);
 		gtk_icon_source_set_state_wildcarded(source, TRUE);
 		gtk_icon_set_add_source(iconset, source);
 		gtk_icon_source_free(source);
@@ -378,7 +379,7 @@
 		gtk_icon_source_set_filename(source, filename);
 		gtk_icon_source_set_direction(source, GTK_TEXT_DIR_RTL);
 		gtk_icon_source_set_size(source, sizeid);
-		gtk_icon_source_set_size_wildcarded(source, FALSE);
+		gtk_icon_source_set_size_wildcarded(source, size_wildcarded);
 		gtk_icon_source_set_state_wildcarded(source, TRUE);
 		gtk_icon_set_add_source(iconset, source);
 		g_free(filename);
@@ -434,9 +435,9 @@
 
 #define ADD_SIZED_ICON(name, size) \
 		if (sized_status_icons[i].name) { \
-			add_sized_icon(normal, name, PIDGIN_ICON_THEME(theme), size, sized_status_icons[i], FALSE); \
+			add_sized_icon(normal, name, PIDGIN_ICON_THEME(theme), size, sized_status_icons[i], FALSE, FALSE); \
 			if (sized_status_icons[i].translucent_name) \
-				add_sized_icon(translucent, name, PIDGIN_ICON_THEME(theme), size, sized_status_icons[i], TRUE); \
+				add_sized_icon(translucent, name, PIDGIN_ICON_THEME(theme), size, sized_status_icons[i], TRUE, FALSE); \
 		}
 		ADD_SIZED_ICON(microscopic, "11");
 		ADD_SIZED_ICON(extra_small, "16");
@@ -463,9 +464,9 @@
 
 #define ADD_SIZED_ICON(name, size) \
 		if (sized_tray_icons[i].name) { \
-			add_sized_icon(normal, name, PIDGIN_ICON_THEME(theme), size, sized_tray_icons[i], FALSE); \
+			add_sized_icon(normal, name, PIDGIN_ICON_THEME(theme), size, sized_tray_icons[i], FALSE, TRUE); \
 			if (sized_tray_icons[i].translucent_name) \
-				add_sized_icon(translucent, name, PIDGIN_ICON_THEME(theme), size, sized_tray_icons[i], TRUE); \
+				add_sized_icon(translucent, name, PIDGIN_ICON_THEME(theme), size, sized_tray_icons[i], TRUE, TRUE); \
 		}
 		ADD_SIZED_ICON(extra_small, "16x16");
 		ADD_SIZED_ICON(small, "22x22");
@@ -553,7 +554,7 @@
 
 #define ADD_SIZED_ICON(name, size) \
 		if (sized_stock_icons[i].name) \
-			add_sized_icon(iconset, name, PIDGIN_ICON_THEME(theme), size, sized_stock_icons[i], FALSE);
+			add_sized_icon(iconset, name, PIDGIN_ICON_THEME(theme), size, sized_stock_icons[i], FALSE, FALSE);
 		ADD_SIZED_ICON(microscopic, "11");
 		ADD_SIZED_ICON(extra_small, "16");
 		ADD_SIZED_ICON(small, "22");