# HG changeset patch # User Ethan Blanton # Date 1181845253 0 # Node ID 36ebcb33e2ebb703e1fbae9080a0459a90079cff # Parent 91e92cb0d8750b60d9d87cdf373194597e6effd9 This fixes a bustination of the official ICQ client in at least some locales. For away (and possibly other) messages, apparently the official ICQ (5.1?) client of some locales converts messages which are stored in UTF-8 from a locale-native character set to UCS-2BE; this results in something which, when decoded "correctly", is gibberish. Instead, we first try decoding from UCS-2BE to the locale-specific character set, and if that validates as UTF-8, we display it, instead. Since UTF-8 is relatively picky, hopefully this won't break too many sane clients. diff -r 91e92cb0d875 -r 36ebcb33e2eb libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Thu Jun 14 16:17:07 2007 +0000 +++ b/libpurple/protocols/oscar/oscar.c Thu Jun 14 18:20:53 2007 +0000 @@ -298,7 +298,7 @@ } gchar * -oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen) +oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen) { gchar *utf8 = NULL; @@ -311,7 +311,25 @@ { utf8 = g_convert(text, textlen, "UTF-8", "Windows-1252", NULL, NULL, NULL); } else if (!g_ascii_strcasecmp(encoding, "unicode-2-0")) { - utf8 = g_convert(text, textlen, "UTF-8", "UCS-2BE", NULL, NULL, NULL); + /* Some official ICQ clients are apparently total crack, + * and have been known to save a UTF-8 string converted + * from the locale character set to UCS-2 (not from UTF-8 + * to UCS-2!) in the away message. This hack should find + * and do something (un)reasonable with that, and not + * mess up too much else. */ + const gchar *charset = purple_account_get_string(account, "encoding", NULL); + if (charset) { + gsize len; + utf8 = g_convert(text, textlen, charset, "UCS-2BE", &len, NULL, NULL); + if (!utf8 || len != textlen || !g_utf8_validate(utf8, -1, NULL)) { + g_free(utf8); + utf8 = NULL; + } else { + purple_debug_info("oscar", "Used broken ICQ fallback encoding\n"); + } + } + if (!utf8) + utf8 = g_convert(text, textlen, "UTF-8", "UCS-2BE", NULL, NULL, NULL); } else if (g_ascii_strcasecmp(encoding, "utf-8")) { purple_debug_warning("oscar", "Unrecognized character encoding \"%s\", " "attempting to convert to UTF-8 anyway\n", encoding); @@ -1774,7 +1792,7 @@ { have_status_message = TRUE; if (info->status[0] != '\0') - message = oscar_encoding_to_utf8(info->status_encoding, + message = oscar_encoding_to_utf8(account, info->status_encoding, info->status, info->status_len); } @@ -1790,7 +1808,7 @@ if ((status_id == OSCAR_STATUS_ID_AVAILABLE) && (info->itmsurl != NULL)) { char *itmsurl; - itmsurl = oscar_encoding_to_utf8(info->itmsurl_encoding, + itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding, info->itmsurl, info->itmsurl_len); purple_prpl_got_user_status(account, info->sn, status_id, "message", message, "itmsurl", itmsurl, NULL); @@ -2047,7 +2065,8 @@ { char *encoding = NULL; encoding = oscar_encoding_extract(args->encoding); - message = oscar_encoding_to_utf8(encoding, args->msg, args->msglen); + message = oscar_encoding_to_utf8(account, encoding, args->msg, + args->msglen); g_free(encoding); } else { if (g_utf8_validate(args->msg, args->msglen, NULL)) @@ -2065,7 +2084,7 @@ return 1; } encoding = args->encoding ? oscar_encoding_extract(args->encoding) : NULL; - utf8name = oscar_encoding_to_utf8(encoding, + utf8name = oscar_encoding_to_utf8(account, encoding, args->info.chat.roominfo.name, args->info.chat.roominfo.namelen); g_free(encoding); @@ -2875,12 +2894,12 @@ if ((userinfo->status != NULL) && !(userinfo->flags & AIM_FLAG_AWAY)) { if (userinfo->status[0] != '\0') - tmp = oscar_encoding_to_utf8(userinfo->status_encoding, + tmp = oscar_encoding_to_utf8(account, userinfo->status_encoding, userinfo->status, userinfo->status_len); #if defined (_WIN32) || defined (__APPLE__) if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0')) { gchar *itmsurl, *tmp2; - itmsurl = oscar_encoding_to_utf8(userinfo->itmsurl_encoding, + itmsurl = oscar_encoding_to_utf8(account, userinfo->itmsurl_encoding, userinfo->itmsurl, userinfo->itmsurl_len); tmp2 = g_strdup_printf("%s", itmsurl, tmp); @@ -2896,7 +2915,8 @@ /* Away message */ if ((userinfo->flags & AIM_FLAG_AWAY) && (userinfo->away_len > 0) && (userinfo->away != NULL) && (userinfo->away_encoding != NULL)) { tmp = oscar_encoding_extract(userinfo->away_encoding); - away_utf8 = oscar_encoding_to_utf8(tmp, userinfo->away, userinfo->away_len); + away_utf8 = oscar_encoding_to_utf8(account, tmp, userinfo->away, + userinfo->away_len); g_free(tmp); if (away_utf8 != NULL) { tmp = purple_str_sub_away_formatters(away_utf8, purple_account_get_username(account)); @@ -2910,7 +2930,8 @@ /* Info */ if ((userinfo->info_len > 0) && (userinfo->info != NULL) && (userinfo->info_encoding != NULL)) { tmp = oscar_encoding_extract(userinfo->info_encoding); - info_utf8 = oscar_encoding_to_utf8(tmp, userinfo->info, userinfo->info_len); + info_utf8 = oscar_encoding_to_utf8(account, tmp, userinfo->info, + userinfo->info_len); g_free(tmp); if (info_utf8 != NULL) { tmp = purple_str_sub_away_formatters(info_utf8, purple_account_get_username(account)); @@ -2930,6 +2951,7 @@ static int purple_got_infoblock(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { PurpleConnection *gc = od->gc; + PurpleAccount *account = purple_connection_get_account(gc); PurpleBuddy *b; PurplePresence *presence; PurpleStatus *status; @@ -2942,7 +2964,7 @@ userinfo = va_arg(ap, aim_userinfo_t *); va_end(ap); - b = purple_find_buddy(purple_connection_get_account(gc), userinfo->sn); + b = purple_find_buddy(account, userinfo->sn); if (b == NULL) return 1; @@ -2962,7 +2984,9 @@ if ((userinfo->flags & AIM_FLAG_AWAY) && (userinfo->away_len > 0) && (userinfo->away != NULL) && (userinfo->away_encoding != NULL)) { gchar *charset = oscar_encoding_extract(userinfo->away_encoding); - message = oscar_encoding_to_utf8(charset, userinfo->away, userinfo->away_len); + message = oscar_encoding_to_utf8(account, charset, + userinfo->away, + userinfo->away_len); g_free(charset); purple_status_set_attr_string(status, "message", message); g_free(message); @@ -3158,6 +3182,7 @@ static int purple_conv_chat_incoming_msg(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { PurpleConnection *gc = od->gc; + PurpleAccount *account = purple_connection_get_account(gc); struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn); gchar *utf8; va_list ap; @@ -3176,7 +3201,7 @@ charset = va_arg(ap, char *); va_end(ap); - utf8 = oscar_encoding_to_utf8(charset, msg, len); + utf8 = oscar_encoding_to_utf8(account, charset, msg, len); if (utf8 == NULL) /* The conversion failed! */ utf8 = g_strdup(_("[Unable to display a message from this user because it contained invalid characters.]")); diff -r 91e92cb0d875 -r 36ebcb33e2eb libpurple/protocols/oscar/oscar.h --- a/libpurple/protocols/oscar/oscar.h Thu Jun 14 16:17:07 2007 +0000 +++ b/libpurple/protocols/oscar/oscar.h Thu Jun 14 18:20:53 2007 +0000 @@ -934,7 +934,7 @@ /* 0x0014 */ int aim_im_sendmtn(OscarData *od, guint16 type1, const char *sn, guint16 type2); void aim_icbm_makecookie(guchar* cookie); gchar *oscar_encoding_extract(const char *encoding); -gchar *oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen); +gchar *oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen); gchar *purple_plugin_oscar_decode_im_part(PurpleAccount *account, const char *sourcesn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen);