changeset 7827:ee32e030c9be

[gaim-migrate @ 8479] marv asserts that these character set conversions are more correct than the previous yahoo conversions, which assumed that pretty much everything was UTF-8. I believe him. committer: Tailor Script <tailor@pidgin.im>
author Ethan Blanton <elb@pidgin.im>
date Wed, 10 Dec 2003 16:48:23 +0000
parents 5ba07997ade3
children 0408e93c8a72
files src/protocols/yahoo/util.c src/protocols/yahoo/yahoo.c src/protocols/yahoo/yahoo.h src/protocols/yahoo/yahoo_filexfer.c src/protocols/yahoo/yahoochat.c
diffstat 5 files changed, 348 insertions(+), 109 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/yahoo/util.c	Wed Dec 10 07:37:13 2003 +0000
+++ b/src/protocols/yahoo/util.c	Wed Dec 10 16:48:23 2003 +0000
@@ -26,9 +26,68 @@
 
 #include "prpl.h"
 #include "debug.h"
+#include "yahoo.h"
 
 #include <string.h>
 
+/**
+ * Encode some text to send to the yahoo server.
+ *
+ * @param gc The connection handle.
+ * @param str The null terminated utf8 string to encode.
+ * @param utf8 If not @c NULL, whether utf8 is okay or not.
+ *             Even if it is okay, we may not use it. If we
+ *             used it, we set this to @c TRUE, else to
+ *             @c FALSE. If @c NULL, false is assumed, and
+ *             it is not dereferenced.
+ * @return The g_malloced string in the appropriate encoding.
+ */
+char *yahoo_string_encode(GaimConnection *gc, const char *str, gboolean *utf8)
+{
+	char *ret;
+	char *to_codeset;
+
+	if (utf8 && *utf8) /* FIXME: maybe don't use utf8 if it'll fit in latin1 */
+		return g_strdup(str);
+
+	to_codeset = "ISO-8859-1";
+
+	ret = g_convert_with_fallback(str, strlen(str), to_codeset, "UTF-8", NULL, NULL, NULL, NULL);
+	if (ret)
+		return ret;
+	else
+		return g_strdup("");
+}
+
+/**
+ * Decode some text received from the server.
+ *
+ * @param gc The gc handle.
+ * @param str The null terminated string to decode.
+ * @param utf8 Did the server tell us it was supposed to be utf8?
+ * @return The decoded, utf-8 string, which must be g_free()'d.
+ */
+char *yahoo_string_decode(GaimConnection *gc, const char *str, gboolean utf8)
+{
+	char *ret;
+	char *from_codeset;
+
+	if (utf8) {
+		if (g_utf8_validate(str, -1, NULL))
+			return g_strdup(str);
+	}
+
+	from_codeset = "ISO-8859-1";
+
+	ret = g_convert_with_fallback(str, strlen(str), "UTF-8", from_codeset, NULL, NULL, NULL, NULL);
+
+	if (ret)
+		return ret;
+	else
+		return g_strdup("");
+}
+
+
 
 /*
  * I found these on some website but i don't know that they actually
--- a/src/protocols/yahoo/yahoo.c	Wed Dec 10 07:37:13 2003 +0000
+++ b/src/protocols/yahoo/yahoo.c	Wed Dec 10 16:48:23 2003 +0000
@@ -51,13 +51,6 @@
 
 /* #define YAHOO_DEBUG */
 
-#define USEROPT_MAIL 0
-
-#define YAHOO_PAGER_HOST "scs.yahoo.com"
-#define YAHOO_PAGER_PORT 5050
-#define YAHOO_PROFILE_URL "http://profiles.yahoo.com/"
-
-
 static void yahoo_add_buddy(GaimConnection *gc, const char *who, GaimGroup *);
 
 static struct yahoo_friend *yahoo_friend_new(void)
@@ -361,7 +354,7 @@
 			if (f) {
 				if (f->msg)
 					g_free(f->msg);
-				f->msg = g_strdup(pair->value);
+				f->msg = yahoo_string_decode(gc, pair->value, FALSE);
 			}
 			break;
 		case 11: /* this is the buddy's session id */
@@ -407,7 +400,11 @@
 			}
 			break;
 		case 16: /* Custom error message */
-			gaim_notify_error(gc, NULL, pair->value, NULL);
+			{
+				char *tmp = yahoo_string_decode(gc, pair->value, TRUE);
+				gaim_notify_error(gc, NULL, tmp, NULL);
+				g_free(tmp);
+			}
 			break;
 		default:
 			gaim_debug(GAIM_DEBUG_ERROR, "yahoo",
@@ -533,6 +530,7 @@
 	char **split;
 	char **buddies;
 	char **tmp, **bud, *norm_bud;
+	char *grp = NULL;
 
 	if (pkt->id)
 		yd->session_id = pkt->id;
@@ -575,6 +573,7 @@
 				g_strfreev(split);
 				continue;
 			}
+			grp = yahoo_string_decode(gc, split[0], FALSE);
 			buddies = g_strsplit(split[1], ",", -1);
 			for (bud = buddies; bud && *bud; bud++) {
 				norm_bud = g_strdup(gaim_normalize(account, *bud));
@@ -582,9 +581,9 @@
 					f = yahoo_friend_new();
 					g_hash_table_insert(yd->friends, g_strdup(norm_bud), f);
 				}
-				if (!(b = gaim_find_buddy(account,  norm_bud))) {
-					if (!(g = gaim_find_group(split[0]))) {
-						g = gaim_group_new(split[0]);
+				if (!(b = gaim_find_buddy(account, norm_bud))) {
+					if (!(g = gaim_find_group(grp))) {
+						g = gaim_group_new(grp);
 						gaim_blist_add_group(g, NULL);
 					}
 					b = gaim_buddy_new(account, norm_bud, NULL);
@@ -592,11 +591,12 @@
 					export = TRUE;
 				}
 
-				yahoo_do_group_check(account, ht, norm_bud, split[0], &export);
+				yahoo_do_group_check(account, ht, norm_bud, grp, &export);
 				g_free(norm_bud);
 			}
 			g_strfreev(buddies);
 			g_strfreev(split);
+			g_free(grp);
 		}
 		g_strfreev(lines);
 
@@ -686,31 +686,38 @@
 	}
 }
 
+
+struct _yahoo_im {
+	char *from;
+	int time;
+	int utf8;
+	char *msg;
+};
+
 static void yahoo_process_message(GaimConnection *gc, struct yahoo_packet *pkt)
 {
-	char *msg = NULL;
-	char *from = NULL;
-	time_t tm = time(NULL);
 	GSList *l = pkt->hash;
+	GSList *list = NULL;
+	struct _yahoo_im *im = NULL;
 
 	if (pkt->status <= 1 || pkt->status == 5) {
 		while (l) {
 			struct yahoo_pair *pair = l->data;
-			if (pair->key == 4)
-				from = pair->value;
+			if (pair->key == 4) {
+				im = g_new0(struct _yahoo_im, 1);
+				list = g_slist_append(list, im);
+				im->from = pair->value;
+				im->time = time(NULL);
+			}
+			if (pair->key == 97)
+				if (im)
+					im->utf8 = strtol(pair->value, NULL, 10);
 			if (pair->key == 15)
-				tm = strtol(pair->value, NULL, 10);
+				if (im)
+					im->time = strtol(pair->value, NULL, 10);
 			if (pair->key == 14) {
-				char *m;
-
-				msg = pair->value;
-
-				gaim_str_strip_cr(msg);
-				m = yahoo_codes_to_html(msg);
-				serv_got_im(gc, from, m, 0, tm);
-				g_free(m);
-
-				tm = time(NULL);
+				if (im)
+					im->msg = pair->value;
 			}
 			l = l->next;
 		}
@@ -718,12 +725,31 @@
 		gaim_notify_error(gc, NULL,
 						  _("Your Yahoo! message did not get sent."), NULL);
 	}
+
+	for (l = list; l; l = l->next) {
+		char *m, *m2;
+		im = l->data;
+
+		if (!im->from || !im->msg) {
+			g_free(im);
+			continue;
+		}
+
+		m = yahoo_string_decode(gc, im->msg, im->utf8);
+		gaim_str_strip_cr(m);
+		m2 = yahoo_codes_to_html(m);
+		g_free(m);
+		serv_got_im(gc, im->from, m2, 0, im->time);
+		g_free(m2);
+		g_free(im);
+	}
+	g_slist_free(list);
 }
 
 static void yahoo_buddy_added_us(GaimConnection *gc, struct yahoo_packet *pkt) {
 	char *id = NULL;
 	char *who = NULL;
-	char *msg = NULL;
+	char *msg = NULL, *tmpmsg = NULL;
 	GSList *l = pkt->hash;
 
 	while (l) {
@@ -745,8 +771,13 @@
 		l = l->next;
 	}
 
-	if (id)
-		gaim_account_notify_added(gc->account, id, who, NULL, msg);
+	if (id) {
+		if (msg)
+			tmpmsg = yahoo_string_decode(gc, msg, FALSE);
+		gaim_account_notify_added(gc->account, id, who, NULL, tmpmsg);
+		if (tmpmsg)
+			g_free(tmpmsg);
+	}
 }
 
 static void yahoo_buddy_denied_our_add(GaimConnection *gc, struct yahoo_packet *pkt)
@@ -772,11 +803,15 @@
 	}
 
 	if (who) {
+		char *msg2;
 		buf = g_string_sized_new(0);
-		if (!msg)
+		if (!msg) {
 			g_string_printf(buf, _("%s has (retroactively) denied your request to add them to your list."), who);
-		else
-			g_string_printf(buf, _("%s has (retroactively) denied your request to add them to your list for the following reason: %s."), who, msg);
+		} else {
+			msg2 = yahoo_string_decode(gc, msg, FALSE);
+			g_string_printf(buf, _("%s has (retroactively) denied your request to add them to your list for the following reason: %s."), who, msg2);
+			g_free(msg2);
+		}
 		gaim_notify_info(gc, NULL, _("Add buddy rejected"), buf->str);
 		g_string_free(buf, TRUE);
 		g_hash_table_remove(yd->friends, who);
@@ -1551,6 +1586,7 @@
 	int err = 0;
 	char *who = NULL;
 	char *group = NULL;
+	char *decoded_group;
 	char *buf;
 	struct yahoo_friend *f;
 	struct yahoo_data *yd = gc->proto_data;
@@ -1588,10 +1624,12 @@
 		return;
 	}
 
+	decoded_group = yahoo_string_decode(gc, group, FALSE);
 	buf = g_strdup_printf(_("Could not add buddy %s to group %s to the server list on account %s."),
-				who, group, gaim_connection_get_display_name(gc));
+				who, decoded_group, gaim_connection_get_display_name(gc));
 	gaim_notify_error(gc, NULL, _("Could not add buddy to server list"), buf);
 	g_free(buf);
+	g_free(decoded_group);
 }
 
 static void yahoo_packet_process(GaimConnection *gc, struct yahoo_packet *pkt)
@@ -1981,12 +2019,16 @@
 	yd->conf_id = 2;
 
 #ifndef YAHOO_WEBMESSENGER
-	if (gaim_proxy_connect(account, gaim_account_get_string(account, "server",  YAHOO_PAGER_HOST),
-			  gaim_account_get_int(account, "port", YAHOO_PAGER_PORT),
-			  yahoo_got_connected, gc) != 0) {
+
+	if (gaim_proxy_connect(account,
+	                       gaim_account_get_string(account, "server",  YAHOO_PAGER_HOST),
+	                       gaim_account_get_int(account, "port", YAHOO_PAGER_PORT),
+	                       yahoo_got_connected, gc) != 0)
+	{
 		gaim_connection_error(gc, _("Connection problem"));
 		return;
 	}
+
 #else
 	gaim_url_fetch(WEBMESSENGER_URL, TRUE, "Gaim/" VERSION, FALSE,
 	               yahoo_login_page_cb, gc);
@@ -2314,17 +2356,24 @@
 	struct yahoo_data *yd = gc->proto_data;
 	struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, 0);
 	char *msg = yahoo_html_to_codes(what);
+	char *msg2;
+	gboolean utf8 = TRUE;
+
+	msg2 = yahoo_string_encode(gc, msg, &utf8);
 
 	yahoo_packet_hash(pkt, 1, gaim_connection_get_display_name(gc));
 	yahoo_packet_hash(pkt, 5, who);
-	yahoo_packet_hash(pkt, 14, msg);
-	yahoo_packet_hash(pkt, 97, "1");
+	if (utf8)
+		yahoo_packet_hash(pkt, 97, "1");
+	yahoo_packet_hash(pkt, 14, msg2);
+
 
 	yahoo_send_packet(yd, pkt);
 
 	yahoo_packet_free(pkt);
 
 	g_free(msg);
+	g_free(msg2);
 
 	return 1;
 }
@@ -2353,6 +2402,7 @@
 	struct yahoo_packet *pkt;
 	int service;
 	char s[4];
+	char *conv_msg = NULL;
 
 	if (gc->away) {
 		g_free(gc->away);
@@ -2408,8 +2458,10 @@
 	g_snprintf(s, sizeof(s), "%d", yd->current_status);
 	yahoo_packet_hash(pkt, 10, s);
 
-	if ((yd->current_status == YAHOO_STATUS_CUSTOM) && gc->away)
-		yahoo_packet_hash(pkt, 19, gc->away);
+	if ((yd->current_status == YAHOO_STATUS_CUSTOM) && gc->away) {
+		conv_msg = yahoo_string_encode(gc, gc->away, NULL);
+		yahoo_packet_hash(pkt, 19, conv_msg);
+	}
 
 	if ((yd->current_status != YAHOO_STATUS_AVAILABLE) &&
 	    (yd->current_status != YAHOO_STATUS_IDLE)) {
@@ -2421,12 +2473,15 @@
 
 	yahoo_send_packet(yd, pkt);
 	yahoo_packet_free(pkt);
+	if (conv_msg)
+		g_free(conv_msg);
 }
 
 static void yahoo_set_idle(GaimConnection *gc, int idle)
 {
 	struct yahoo_data *yd = gc->proto_data;
 	struct yahoo_packet *pkt = NULL;
+	char *msg = NULL;
 
 	if (idle && yd->current_status == YAHOO_STATUS_AVAILABLE) {
 		pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, YAHOO_STATUS_AVAILABLE, 0);
@@ -2443,7 +2498,8 @@
 		g_snprintf(buf, sizeof(buf), "%d", yd->current_status);
 		yahoo_packet_hash(pkt, 10, buf);
 		if (gc->away && yd->current_status == YAHOO_STATUS_CUSTOM) {
-			yahoo_packet_hash(pkt, 19, gc->away);
+			msg = yahoo_string_encode(gc, gc->away, NULL);
+			yahoo_packet_hash(pkt, 19, msg);
 			if (idle)
 				yahoo_packet_hash(pkt, 47, "2");
 			else
@@ -2459,6 +2515,8 @@
 		yahoo_send_packet(yd, pkt);
 		yahoo_packet_free(pkt);
 	}
+	if (msg)
+		g_free(msg);
 }
 
 static GList *yahoo_away_states(GaimConnection *gc)
@@ -2503,6 +2561,7 @@
 	struct yahoo_packet *pkt;
 	GaimGroup *g;
 	char *group = NULL;
+	char *grp2 = NULL;
 
 	if (!yd->logged_in)
 		return;
@@ -2517,13 +2576,15 @@
 			group = "Buddies";
 	}
 
+	grp2 = yahoo_string_encode(gc, group, NULL);
 	pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0);
 	yahoo_packet_hash(pkt, 1, gaim_connection_get_display_name(gc));
 	yahoo_packet_hash(pkt, 7, who);
-	yahoo_packet_hash(pkt, 65, group);
+	yahoo_packet_hash(pkt, 65, grp2);
 	yahoo_packet_hash(pkt, 14, "");
 	yahoo_send_packet(yd, pkt);
 	yahoo_packet_free(pkt);
+	g_free(grp2);
 }
 
 static void yahoo_remove_buddy(GaimConnection *gc, const char *who, const char *group)
@@ -2534,6 +2595,7 @@
 	GSList *buddies, *l;
 	GaimGroup *g;
 	gboolean remove = TRUE;
+	char *cg;
 
 	if (!(f = g_hash_table_lookup(yd->friends, who)))
 		return;
@@ -2552,12 +2614,14 @@
 	if (remove)
 		g_hash_table_remove(yd->friends, who);
 
+	cg = yahoo_string_encode(gc, group, NULL);
 	pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0);
 	yahoo_packet_hash(pkt, 1, gaim_connection_get_display_name(gc));
 	yahoo_packet_hash(pkt, 7, who);
-	yahoo_packet_hash(pkt, 65, group);
+	yahoo_packet_hash(pkt, 65, cg);
 	yahoo_send_packet(yd, pkt);
 	yahoo_packet_free(pkt);
+	g_free(cg);
 }
 
 static void yahoo_add_deny(GaimConnection *gc, const char *who) {
@@ -2884,6 +2948,7 @@
 {
 	struct yahoo_data *yd = gc->proto_data;
 	struct yahoo_packet *pkt;
+	char *gpn, *gpo;
 
 	/* Step 0:  If they aren't on the server list anyway,
 	 *          don't bother letting the server know.
@@ -2891,11 +2956,23 @@
 	if (!g_hash_table_lookup(yd->friends, who))
 		return;
 
+	/* If old and new are the same, we would probably
+	 * end up deleting the buddy, which would be bad.
+	 * This might happen because of the charset conversation.
+	 */
+	gpn = yahoo_string_encode(gc, new_group, NULL);
+	gpo = yahoo_string_encode(gc, old_group, NULL);
+	if (!strcmp(gpn, gpo)) {
+		g_free(gpn);
+		g_free(gpo);
+		return;
+	}
+
 	/* Step 1:  Add buddy to new group. */
 	pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0);
 	yahoo_packet_hash(pkt, 1, gaim_connection_get_display_name(gc));
 	yahoo_packet_hash(pkt, 7, who);
-	yahoo_packet_hash(pkt, 65, new_group);
+	yahoo_packet_hash(pkt, 65, gpn);
 	yahoo_packet_hash(pkt, 14, "");
 	yahoo_send_packet(yd, pkt);
 	yahoo_packet_free(pkt);
@@ -2904,9 +2981,11 @@
 	pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0);
 	yahoo_packet_hash(pkt, 1, gaim_connection_get_display_name(gc));
 	yahoo_packet_hash(pkt, 7, who);
-	yahoo_packet_hash(pkt, 65, old_group);
+	yahoo_packet_hash(pkt, 65, gpo);
 	yahoo_send_packet(yd, pkt);
 	yahoo_packet_free(pkt);
+	g_free(gpn);
+	g_free(gpo);
 }
 
 static void yahoo_rename_group(GaimConnection *gc, const char *old_group,
@@ -2914,13 +2993,24 @@
 {
 	struct yahoo_data *yd = gc->proto_data;
 	struct yahoo_packet *pkt;
+	char *gpn, *gpo;
+
+	gpn = yahoo_string_encode(gc, new_group, NULL);
+	gpo = yahoo_string_encode(gc, old_group, NULL);
+	if (!strcmp(gpn, gpo)) {
+		g_free(gpn);
+		g_free(gpo);
+		return;
+	}
 
 	pkt = yahoo_packet_new(YAHOO_SERVICE_GROUPRENAME, YAHOO_STATUS_AVAILABLE, 0);
 	yahoo_packet_hash(pkt, 1, gaim_connection_get_display_name(gc));
-	yahoo_packet_hash(pkt, 65, old_group);
-	yahoo_packet_hash(pkt, 67, new_group);
+	yahoo_packet_hash(pkt, 65, gpo);
+	yahoo_packet_hash(pkt, 67, gpn);
 	yahoo_send_packet(yd, pkt);
 	yahoo_packet_free(pkt);
+	g_free(gpn);
+	g_free(gpo);
 }
 
 #if 0
@@ -3026,15 +3116,11 @@
 {
 	GaimAccountOption *option;
 
-	option = gaim_account_option_string_new(_("Pager host"), "server",
-											YAHOO_PAGER_HOST);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
-											   option);
-
-	option = gaim_account_option_int_new(_("Pager port"), "port",
-										 YAHOO_PAGER_PORT);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
-											   option);
+	option = gaim_account_option_string_new(_("Pager host"), "server", YAHOO_PAGER_HOST);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = gaim_account_option_int_new(_("Pager port"), "port", YAHOO_PAGER_PORT);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
 	option = gaim_account_option_string_new(_("File transfer host"), "xfer_host", YAHOO_XFER_HOST);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
--- a/src/protocols/yahoo/yahoo.h	Wed Dec 10 07:37:13 2003 +0000
+++ b/src/protocols/yahoo/yahoo.h	Wed Dec 10 16:48:23 2003 +0000
@@ -25,6 +25,9 @@
 
 #include "prpl.h"
 
+#define YAHOO_PAGER_HOST "scs.yahoo.com"
+#define YAHOO_PAGER_PORT 5050
+#define YAHOO_PROFILE_URL "http://profiles.yahoo.com/"
 #define YAHOO_XFER_HOST "filetransfer.msg.yahoo.com"
 #define YAHOO_XFER_PORT 80
 
@@ -193,4 +196,28 @@
 char *yahoo_codes_to_html(const char *x);
 char *yahoo_html_to_codes(const char *src);
 
+/**
+ * Encode some text to send to the yahoo server.
+ *
+ * @param gc The connection handle.
+ * @param str The null terminated utf8 string to encode.
+ * @param utf8 If not @c NULL, whether utf8 is okay or not.
+ *             Even if it is okay, we may not use it. If we
+ *             used it, we set this to @c TRUE, else to
+ *             @c FALSE. If @c NULL, false is assumed, and
+ *             it is not dereferenced.
+ * @return The g_malloced string in the appropriate encoding.
+ */
+char *yahoo_string_encode(GaimConnection *gc, const char *str, gboolean *utf8);
+
+/**
+ * Decode some text received from the server.
+ *
+ * @param gc The gc handle.
+ * @param str The null terminated string to decode.
+ * @param utf8 Did the server tell us it was supposed to be utf8?
+ * @return The decoded, utf-8 string, which must be g_free()'d.
+ */
+char *yahoo_string_decode(GaimConnection *gc, const char *str, gboolean utf8);
+
 #endif /* _YAHOO_H_ */
--- a/src/protocols/yahoo/yahoo_filexfer.c	Wed Dec 10 07:37:13 2003 +0000
+++ b/src/protocols/yahoo/yahoo_filexfer.c	Wed Dec 10 16:48:23 2003 +0000
@@ -189,9 +189,11 @@
 	struct yahoo_xfer_data *xfer_data;
 	GaimConnection *gc;
 	GaimAccount *account;
+	struct yahoo_data *yd;
 
 	xfer_data = xfer->data;
 	gc = xfer_data->gc;
+	yd = gc->proto_data;
 	account = gaim_connection_get_account(gc);
 
 	if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) {
@@ -200,10 +202,9 @@
 		                       yahoo_sendfile_connected, xfer) == -1)
 		{
 			gaim_notify_error(gc, NULL, _("File Transfer Aborted"),
-			             _("Unable to establish file descriptor."));
+			                 _("Unable to establish file descriptor."));
 			gaim_xfer_cancel_remote(xfer);
 		}
-
 	} else {
 		xfer->fd = gaim_proxy_connect(account, xfer_data->host, xfer_data->port,
 		                              yahoo_receivefile_connected, xfer);
--- a/src/protocols/yahoo/yahoochat.c	Wed Dec 10 07:37:13 2003 +0000
+++ b/src/protocols/yahoo/yahoochat.c	Wed Dec 10 16:48:23 2003 +0000
@@ -130,7 +130,7 @@
 		case 1: /* us, but we already know who we are */
 			break;
 		case 57:
-			room = pair->value;
+			room = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 50: /* inviter */
 			who = pair->value;
@@ -140,7 +140,7 @@
 			g_string_append_printf(members, "%s\n", pair->value);
 			break;
 		case 58:
-			msg = pair->value;
+			msg = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 13: /* ? */
 			break;
@@ -153,9 +153,9 @@
 	}
 
 	components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-	g_hash_table_replace(components, g_strdup("room"), g_strdup(room));
+	g_hash_table_replace(components, g_strdup("room"), room);
 	if (msg)
-		g_hash_table_replace(components, g_strdup("topic"), g_strdup(msg));
+		g_hash_table_replace(components, g_strdup("topic"), msg);
 	g_hash_table_replace(components, g_strdup("type"), g_strdup("Conference"));
 	if (members) {
 		g_hash_table_replace(components, g_strdup("members"), g_strdup(members->str));
@@ -177,13 +177,13 @@
 
 		switch (pair->key) {
 		case 57:
-			room = pair->value;
+			room = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 54:
 			who = pair->value;
 			break;
 		case 14:
-			msg = pair->value;
+			msg = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		}
 	}
@@ -195,6 +195,9 @@
 						who, room, msg?msg:"");
 		gaim_notify_info(gc, NULL, _("Invitation Rejected"), tmp);
 		g_free(tmp);
+		g_free(room);
+		if (msg)
+			g_free(msg);
 	}
 }
 
@@ -210,7 +213,7 @@
 
 		switch (pair->key) {
 		case 57:
-			room = pair->value;
+			room = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 53:
 			who = pair->value;
@@ -222,6 +225,7 @@
 		c = yahoo_find_conference(gc, room);
 		if (c)
 			yahoo_chat_add_user(GAIM_CONV_CHAT(c), who, NULL);
+		g_free(room);
 	}
 }
 
@@ -237,7 +241,7 @@
 
 		switch (pair->key) {
 		case 57:
-			room = pair->value;
+			room = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 56:
 			who = pair->value;
@@ -249,6 +253,7 @@
 		c = yahoo_find_conference(gc, room);
 		if (c)
 			gaim_conv_chat_remove_user(GAIM_CONV_CHAT(c), who, NULL);
+		g_free(room);
 	}
 }
 
@@ -258,6 +263,8 @@
 	char *room = NULL;
 	char *who = NULL;
 	char *msg = NULL;
+	char *msg2;
+	int utf8 = 0;
 	GaimConversation *c;
 
 	for (l = pkt->hash; l; l = l->next) {
@@ -265,7 +272,7 @@
 
 		switch (pair->key) {
 		case 57:
-			room = pair->value;
+			room = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 3:
 			who = pair->value;
@@ -273,18 +280,24 @@
 		case 14:
 			msg = pair->value;
 			break;
+		case 97:
+			utf8 = strtol(pair->value, NULL, 10);
+			break;
 		}
 	}
 
 		if (room && who && msg) {
+			msg2 = yahoo_string_decode(gc, msg, utf8);
 			c = yahoo_find_conference(gc, room);
 			if (!c)
 				return;
-			msg = yahoo_codes_to_html(msg);
+			msg = yahoo_codes_to_html(msg2);
 			serv_got_chat_in(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(c)), who, 0, msg, time(NULL));
 			g_free(msg);
+			g_free(msg2);
 		}
-
+		if (room)
+			g_free(room);
 }
 
 
@@ -302,7 +315,7 @@
 {
 	struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data;
 	GSList *l;
-	
+
 	for (l = pkt->hash; l; l = l->next) {
 		struct yahoo_pair *pair = l->data;
 
@@ -311,7 +324,7 @@
 					gaim_connection_get_display_name(gc)))
 				return;
 	}
-	
+
 	if (pkt->status == 1) {
 		yd->chat_online = 0;
 		if (yd->in_chat)
@@ -340,10 +353,10 @@
 		switch (pair->key) {
 
 		case 104:
-			room = pair->value;
+			room = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 105:
-			topic = pair->value;
+			topic = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 128:
 			someid = pair->value;
@@ -404,6 +417,9 @@
 	}
 
 	g_list_free(members);
+	g_free(room);
+	if (topic)
+		g_free(topic);
 }
 
 void yahoo_process_chat_exit(GaimConnection *gc, struct yahoo_packet *pkt)
@@ -419,7 +435,7 @@
 		struct yahoo_pair *pair = l->data;
 
 		if (pair->key == 104)
-			room = pair->value;
+			room = yahoo_string_decode(gc, pair->value, FALSE);
 		if (pair->key == 109)
 			who = pair->value;
 	}
@@ -431,12 +447,14 @@
 			gaim_conv_chat_remove_user(GAIM_CONV_CHAT(c), who, NULL);
 
 	}
+	if (room)
+		g_free(room);
 }
 
 void yahoo_process_chat_message(GaimConnection *gc, struct yahoo_packet *pkt)
 {
-	char *room = NULL, *who = NULL, *msg = NULL;
-	int msgtype = 1;
+	char *room = NULL, *who = NULL, *msg = NULL, *msg2;
+	int msgtype = 1, utf8 = 0;
 	GaimConversation *c = NULL;
 	GSList *l;
 
@@ -445,8 +463,11 @@
 
 		switch (pair->key) {
 
+		case 97:
+			utf8 = strtol(pair->value, NULL, 10);
+			break;
 		case 104:
-			room = pair->value;
+			room = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 109:
 			who = pair->value;
@@ -460,11 +481,11 @@
 		}
 	}
 
-	if (!who)
-		return;
 
 	c = gaim_find_chat(gc, YAHOO_CHAT_ID);
-	if (!c) {
+	if (!who || !c) {
+		if (room)
+			g_free(room);
 		/* we still get messages after we part, funny that */
 		return;
 	}
@@ -473,7 +494,9 @@
 		gaim_debug(GAIM_DEBUG_MISC, "yahoo", "Got a message packet with no message.\nThis probably means something important, but we're ignoring it.\n");
 		return;
 	}
-	msg = yahoo_codes_to_html(msg);
+	msg2 = yahoo_string_decode(gc, msg, utf8);
+	msg = yahoo_codes_to_html(msg2);
+	g_free(msg2);
 
 	if (msgtype == 2 || msgtype == 3) {
 		char *tmp;
@@ -499,14 +522,14 @@
 
 		switch (pair->key) {
 		case 104:
-			room = pair->value;
+			room = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 129: /* room id? */
 			break;
 		case 126: /* ??? */
 			break;
 		case 117:
-			msg = pair->value;
+			msg = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 119:
 			who = pair->value;
@@ -523,6 +546,10 @@
 		g_hash_table_replace(components, g_strdup("room"), g_strdup(room));
 		serv_got_chat_invite(gc, room, who, msg, components);
 	}
+	if (room)
+		g_free(room);
+	if (msg)
+		g_free(msg);
 }
 
 void yahoo_process_chat_goto(GaimConnection *gc, struct yahoo_packet *pkt)
@@ -535,6 +562,7 @@
 
 /*
  * Functions dealing with conferences
+ * I think conference names are always ascii.
  */
 
 static void yahoo_conf_leave(struct yahoo_data *yd, const char *room, const char *dn, GList *who)
@@ -557,14 +585,18 @@
 	yahoo_packet_free(pkt);
 }
 
-static int yahoo_conf_send(struct yahoo_data *yd, const char *dn, const char *room,
+static int yahoo_conf_send(GaimConnection *gc, const char *dn, const char *room,
 							GList *members, const char *what)
 {
+	struct yahoo_data *yd = gc->proto_data;
 	struct yahoo_packet *pkt;
 	GList *who;
-	char *msg;
+	char *msg, *msg2;
+	int utf8 = 1;
 
 	msg = yahoo_html_to_codes(what);
+	msg2 = yahoo_string_encode(gc, msg, &utf8);
+
 
 	pkt = yahoo_packet_new(YAHOO_SERVICE_CONFMSG, YAHOO_STATUS_AVAILABLE, 0);
 
@@ -572,13 +604,15 @@
 	for (who = members; who; who = who->next)
 		yahoo_packet_hash(pkt, 53, (char *)who->data);
 	yahoo_packet_hash(pkt, 57, room);
-	yahoo_packet_hash(pkt, 14, msg);
-	yahoo_packet_hash(pkt, 97, "1"); /* utf-8 */
+	yahoo_packet_hash(pkt, 14, msg2);
+	if (utf8)
+		yahoo_packet_hash(pkt, 97, "1"); /* utf-8 */
 
 	yahoo_send_packet(yd, pkt);
 
 	yahoo_packet_free(pkt);
 	g_free(msg);
+	g_free(msg2);
 
 	return 0;
 }
@@ -615,11 +649,16 @@
 		g_strfreev(memarr);
 }
 
-static void yahoo_conf_invite(struct yahoo_data *yd, GaimConversation *c,
+static void yahoo_conf_invite(GaimConnection *gc, GaimConversation *c,
 		const char *dn, const char *buddy, const char *room, const char *msg)
 {
+	struct yahoo_data *yd = gc->proto_data;
 	struct yahoo_packet *pkt;
 	GList *members;
+	char *msg2 = NULL;
+
+	if (msg)
+		msg2 = yahoo_string_encode(gc, msg, NULL);
 
 	members = gaim_conv_chat_get_users(GAIM_CONV_CHAT(c));
 
@@ -628,7 +667,7 @@
 	yahoo_packet_hash(pkt, 1, dn);
 	yahoo_packet_hash(pkt, 51, buddy);
 	yahoo_packet_hash(pkt, 57, room);
-	yahoo_packet_hash(pkt, 58, msg?msg:"");
+	yahoo_packet_hash(pkt, 58, msg?msg2:"");
 	yahoo_packet_hash(pkt, 13, "0");
 	for(; members; members = members->next) {
 		if (!strcmp(members->data, dn))
@@ -639,6 +678,8 @@
 	yahoo_send_packet(yd, pkt);
 
 	yahoo_packet_free(pkt);
+	if (msg)
+		g_free(msg2);
 }
 
 /*
@@ -650,10 +691,13 @@
 	struct yahoo_data *yd = gc->proto_data;
 	struct yahoo_packet *pkt;
 	GaimConversation *c;
+	char *eroom;
+
+	eroom = yahoo_string_encode(gc, room, NULL);
 
 	pkt = yahoo_packet_new(YAHOO_SERVICE_CHATEXIT, YAHOO_STATUS_AVAILABLE, 0);
 
-	yahoo_packet_hash(pkt, 104, room);
+	yahoo_packet_hash(pkt, 104, eroom);
 	yahoo_packet_hash(pkt, 109, dn);
 	yahoo_packet_hash(pkt, 108, "1");
 	yahoo_packet_hash(pkt, 112, "0"); /* what does this one mean? */
@@ -681,6 +725,7 @@
 	yahoo_packet_free(pkt);
 
 	yd->chat_online = 0;
+	g_free(eroom);
 }
 
 /* borrowed from gtkconv.c */
@@ -722,11 +767,13 @@
 	return FALSE;
 }
 
-static int yahoo_chat_send(struct yahoo_data *yd, const char *dn, const char *room, const char *what)
+static int yahoo_chat_send(GaimConnection *gc, const char *dn, const char *room, const char *what)
 {
+	struct yahoo_data *yd = gc->proto_data;
 	struct yahoo_packet *pkt;
 	int me = 0;
-	char *msg1, *msg2;
+	char *msg1, *msg2, *room2;
+	gboolean utf8 = TRUE;
 
 	msg1 = g_strdup(what);
 
@@ -735,55 +782,75 @@
 
 	msg2 = yahoo_html_to_codes(msg1);
 	g_free(msg1);
+	msg1 = yahoo_string_encode(gc, msg2, &utf8);
+	g_free(msg2);
+	room2 = yahoo_string_encode(gc, room, NULL);
 
 	pkt = yahoo_packet_new(YAHOO_SERVICE_COMMENT, YAHOO_STATUS_AVAILABLE, 0);
 
 	yahoo_packet_hash(pkt, 1, dn);
-	yahoo_packet_hash(pkt, 104, room);
-	yahoo_packet_hash(pkt, 117, msg2);
+	yahoo_packet_hash(pkt, 104, room2);
+	yahoo_packet_hash(pkt, 117, msg1);
 	if (me)
 		yahoo_packet_hash(pkt, 124, "2");
 	else
 		yahoo_packet_hash(pkt, 124, "1");
 	/* fixme: what about /think? (124=3) */
+	if (utf8)
+		yahoo_packet_hash(pkt, 97, "1");
 
 	yahoo_send_packet(yd, pkt);
 	yahoo_packet_free(pkt);
-	g_free(msg2);
+	g_free(msg1);
+	g_free(room2);
 
 	return 0;
 }
 
-static void yahoo_chat_join(struct yahoo_data *yd, const char *dn, const char *room, const char *topic)
+static void yahoo_chat_join(GaimConnection *gc, const char *dn, const char *room, const char *topic)
 {
+	struct yahoo_data *yd = gc->proto_data;
 	struct yahoo_packet *pkt;
+	char *room2;
+
+	room2 = yahoo_string_encode(gc, room, NULL);
 
 	pkt = yahoo_packet_new(YAHOO_SERVICE_CHATJOIN, YAHOO_STATUS_AVAILABLE, 0);
 
 	yahoo_packet_hash(pkt, 62, "2");
-	yahoo_packet_hash(pkt, 104, room);
+	yahoo_packet_hash(pkt, 104, room2);
 	yahoo_packet_hash(pkt, 129, "0");
 
 	yahoo_send_packet(yd, pkt);
 
 	yahoo_packet_free(pkt);
+	g_free(room2);
 }
 
-static void yahoo_chat_invite(struct yahoo_data *yd, const char *dn, const char *buddy,
+static void yahoo_chat_invite(GaimConnection *gc, const char *dn, const char *buddy,
 							const char *room, const char *msg)
 {
+	struct yahoo_data *yd = gc->proto_data;
 	struct yahoo_packet *pkt;
+	char *room2, *msg2 = NULL;
 
+	room2 = yahoo_string_encode(gc, room, NULL);
+	if (msg)
+		msg2 = yahoo_string_encode(gc, msg, NULL);
 	pkt = yahoo_packet_new(YAHOO_SERVICE_CHATADDINVITE, YAHOO_STATUS_AVAILABLE, 0);
 
 	yahoo_packet_hash(pkt, 1, dn);
 	yahoo_packet_hash(pkt, 118, buddy);
-	yahoo_packet_hash(pkt, 104, room);
-	yahoo_packet_hash(pkt, 117, (msg?msg:""));
+	yahoo_packet_hash(pkt, 104, room2);
+	yahoo_packet_hash(pkt, 117, (msg2?msg2:""));
 	yahoo_packet_hash(pkt, 129, "0");
 
 	yahoo_send_packet(yd, pkt);
 	yahoo_packet_free(pkt);
+
+	g_free(room2);
+	if (msg2)
+		g_free(msg2);
 }
 
 void yahoo_chat_goto(GaimConnection *gc, const char *name)
@@ -849,10 +916,10 @@
 		return -1;
 
 	if (id != YAHOO_CHAT_ID) {
-		ret = yahoo_conf_send(yd, gaim_connection_get_display_name(gc),
+		ret = yahoo_conf_send(gc, gaim_connection_get_display_name(gc),
 				gaim_conversation_get_name(c), gaim_conv_chat_get_users(GAIM_CONV_CHAT(c)), what);
 	} else {
-		ret = yahoo_chat_send(yd, gaim_connection_get_display_name(gc),
+		ret = yahoo_chat_send(gc, gaim_connection_get_display_name(gc),
 						gaim_conversation_get_name(c), what);
 		if (!ret)
 			serv_got_chat_in(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(c)),
@@ -910,14 +977,13 @@
 					FALSE);
 		if (!yd->chat_online)
 			yahoo_chat_online(gc);
-		yahoo_chat_join(yd, gaim_connection_get_display_name(gc), room, topic);
+		yahoo_chat_join(gc, gaim_connection_get_display_name(gc), room, topic);
 		return;
 	}
 }
 
 void yahoo_c_invite(GaimConnection *gc, int id, const char *msg, const char *name)
 {
-	struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data;
 	GaimConversation *c;
 
 	c = gaim_find_chat(gc, id);
@@ -925,10 +991,10 @@
 		return;
 
 	if (id != YAHOO_CHAT_ID) {
-		yahoo_conf_invite(yd, c, gaim_connection_get_display_name(gc), name,
+		yahoo_conf_invite(gc, c, gaim_connection_get_display_name(gc), name,
 							gaim_conversation_get_name(c), msg);
 	} else {
-		yahoo_chat_invite(yd, gaim_connection_get_display_name(gc), name,
+		yahoo_chat_invite(gc, gaim_connection_get_display_name(gc), name,
 							gaim_conversation_get_name(c), msg);
 	}
 }