# HG changeset patch # User Yoshiki Yazawa # Date 1287035506 -32400 # Node ID 7d19aaddba91089756c9375acdfd32f31063cc07 # Parent c5ba7dd399fa1c3a4f57cb423d4acde960251280 revert changes in oscar.c for now. diff -r c5ba7dd399fa -r 7d19aaddba91 libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Wed Sep 22 14:17:09 2010 +0900 +++ b/libpurple/protocols/oscar/oscar.c Thu Oct 14 14:51:46 2010 +0900 @@ -152,564 +152,6 @@ } #endif -/** - * Determine how we can send this message. Per the warnings elsewhere - * in this file, these little checks determine the simplest encoding - * we can use for a given message send using it. - */ -static guint32 -oscar_charset_check(const char *utf8) -{ - int i = 0; - int charset = AIM_CHARSET_ASCII; - - /* - * Can we get away with using our custom encoding? - */ - while (utf8[i]) - { - if ((unsigned char)utf8[i] > 0x7f) { - /* not ASCII! */ - charset = AIM_CHARSET_LATIN_1; - break; - } - i++; - } - - /* - * Must we send this message as UNICODE (in the UTF-16BE encoding)? - */ - while (utf8[i]) - { - /* ISO-8859-1 is 0x00-0xbf in the first byte - * followed by 0xc0-0xc3 in the second */ - if ((unsigned char)utf8[i] < 0x80) { - i++; - continue; - } else if (((unsigned char)utf8[i] & 0xfc) == 0xc0 && - ((unsigned char)utf8[i + 1] & 0xc0) == 0x80) { - i += 2; - continue; - } - charset = AIM_CHARSET_UNICODE; - break; - } - - return charset; -} - -/** - * Take a string of the form charset="bleh" where bleh is - * one of us-ascii, utf-8, iso-8859-1, or unicode-2-0, and - * return a newly allocated string containing bleh. - */ -gchar * -oscar_encoding_extract(const char *encoding) -{ - gchar *ret = NULL; - char *begin, *end; - - g_return_val_if_fail(encoding != NULL, NULL); - - /* Make sure encoding begins with charset= */ - if (strncmp(encoding, "text/aolrtf; charset=", 21) && - strncmp(encoding, "text/x-aolrtf; charset=", 23) && - strncmp(encoding, "text/plain; charset=", 20)) - { - return NULL; - } - - begin = strchr(encoding, '"'); - end = strrchr(encoding, '"'); - - if ((begin == NULL) || (end == NULL) || (begin >= end)) - return NULL; - - ret = g_strndup(begin+1, (end-1) - begin); - - return ret; -} - -gchar * -oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen) -{ - gchar *utf8 = NULL; - - if ((encoding == NULL) || encoding[0] == '\0') { - 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(encoding, "iso-8859-1")) { - utf8 = g_convert(text, textlen, "UTF-8", "iso-8859-1", NULL, NULL, NULL); - } else if (!g_ascii_strcasecmp(encoding, "ISO-8859-1-Windows-3.1-Latin-1") || - !g_ascii_strcasecmp(encoding, "us-ascii")) - { - utf8 = g_convert(text, textlen, "UTF-8", "Windows-1252", NULL, NULL, NULL); - } else if (!g_ascii_strcasecmp(encoding, "unicode-2-0")) { - /* 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 UTF-16 (not from UTF-8 - * to UTF-16!) 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); - sanitize_ucs((gchar *)text, textlen); - if (charset) { - gsize len; - utf8 = g_convert(text, textlen, charset, "UTF-16BE", &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", "UTF-16BE", 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); - utf8 = g_convert(text, textlen, "UTF-8", encoding, NULL, NULL, NULL); - } - - /* - * If utf8 is still NULL then either the encoding is utf-8 or - * we have been unable to convert the text to utf-8 from the encoding - * that was specified. So we check if the text is valid utf-8 then - * just copy it. - */ - if (utf8 == NULL) { - if (textlen != 0 && *text != '\0' - && !g_utf8_validate(text, textlen, NULL)) - utf8 = g_strdup(_("(There was an error receiving this message. The buddy you are speaking with is probably using a different encoding than expected. If you know what encoding he is using, you can specify it in the advanced account options for your AIM/ICQ account.)")); - else - utf8 = g_strndup(text, textlen); - } -done: - return utf8; -} - -static gchar * -oscar_utf8_try_convert(PurpleAccount *account, OscarData *od, const gchar *msg) -{ - const char *charset = NULL; - char *ret = NULL; - - if (od->icq) - charset = purple_account_get_string(account, "encoding", NULL); - - if(charset && *charset) - ret = g_convert(msg, -1, "UTF-8", charset, NULL, NULL, NULL); - - if(!ret) - ret = purple_utf8_try_convert(msg); - - return ret; -} - -static gchar * -purple_plugin_oscar_convert_to_utf8(const gchar *data, gsize datalen, const char *charsetstr, gboolean fallback) -{ - gchar *ret = NULL, *ret2 = NULL; - GError *err = NULL; - - if ((charsetstr == NULL) || (*charsetstr == '\0')) - return NULL; - - if (g_ascii_strcasecmp("UTF-8", charsetstr)) { - if (fallback) - ret = g_convert_with_fallback(data, datalen, "UTF-8", charsetstr, "?", NULL, NULL, &err); - else - ret = g_convert(data, datalen, "UTF-8", charsetstr, NULL, NULL, &err); - if (err != NULL) { - purple_debug_warning("oscar", "Conversion from %s failed: %s.\n", - charsetstr, err->message); - g_error_free(err); - } - } else { - if (g_utf8_validate(data, datalen, NULL)) - ret = g_strndup(data, datalen); - else - purple_debug_warning("oscar", "String is not valid UTF-8.\n"); - } - - ret2 = sanitize_utf(ret, -1, NULL); - g_free(ret); - return ret2; -} - -/** - * This attemps to decode an incoming IM into a UTF8 string. - * - * We try decoding using two different character sets. The charset - * specified in the IM determines the order in which we attempt to - * decode. We do this because there are lots of broken ICQ clients - * that don't correctly send non-ASCII messages. And if Purple isn't - * able to deal with that crap, then people complain like banshees. - * charsetstr1 is always set to what the correct encoding should be. - */ -gchar * -purple_plugin_oscar_decode_im_part(PurpleAccount *account, const char *sourcebn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen) -{ - gchar *ret = NULL; - const gchar *charsetstr1, *charsetstr2, *charsetstr3 = NULL; - - if ((datalen == 0) || (data == NULL)) - return NULL; - - if (charset == AIM_CHARSET_UNICODE) { - charsetstr1 = "UTF-16BE"; - charsetstr2 = "UTF-8"; - } else if (charset == AIM_CHARSET_LATIN_1) { - if ((sourcebn != NULL) && oscar_util_valid_name_icq(sourcebn)) - charsetstr1 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); - else - charsetstr1 = "ISO-8859-1"; - charsetstr2 = "UTF-8"; - } else if (charset == AIM_CHARSET_ASCII) { - /* Should just be "ASCII" */ - charsetstr1 = "ASCII"; - charsetstr2 = "UTF-8"; - charsetstr3 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); - } else if (charset == AIM_CHARSET_QUIRKUTF8) { - /* Mobile AIM client on a Nokia 3100 and an LG VX6000 */ - charsetstr1 = "UTF-8"; //iChat use 0x000d when it sends UTF-8. --yaz - 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"; - charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); - } - - purple_debug_info("oscar", "Parsing IM part, charset=0x%04hx, charsubset=0x%04hx, datalen=%" G_GSIZE_FORMAT ", choice1=%s, choice2=%s, choice3=%s\n", - charset, charsubset, datalen, charsetstr1, charsetstr2, (charsetstr3 ? charsetstr3 : "")); - - ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr1, FALSE); - if (ret == NULL) { - if (charsetstr3 != NULL) { - /* Try charsetstr2 without allowing substitutions, then fall through to charsetstr3 if needed */ - ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr2, FALSE); - if (ret == NULL) - ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr3, TRUE); - } else { - /* Try charsetstr2, allowing substitutions */ - ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr2, TRUE); - } - } - if (ret == NULL) { - char *str, *salvage, *tmp; - - str = g_malloc(datalen + 1); - strncpy(str, data, datalen); - str[datalen] = '\0'; - salvage = purple_utf8_salvage(str); - tmp = g_strdup_printf(_("(There was an error receiving this message. Either you and %s have different encodings selected, or %s has a buggy client.)"), - sourcebn, sourcebn); - ret = g_strdup_printf("%s %s", salvage, tmp); - g_free(tmp); - g_free(str); - g_free(salvage); - } - - return ret; -} - -/** - * Figure out what encoding to use when sending a given outgoing message. - */ -static void -purple_plugin_oscar_convert_to_best_encoding(PurpleConnection *gc, - const char *destbn, const gchar *from, - gchar **msg, int *msglen_int, - guint16 *charset, guint16 *charsubset) -{ - OscarData *od = purple_connection_get_protocol_data(gc); - PurpleAccount *account = purple_connection_get_account(gc); - GError *err = NULL; - aim_userinfo_t *userinfo = NULL; - const gchar *charsetstr; - gsize msglen; - - /* Attempt to send as ASCII */ - if (oscar_charset_check(from) == AIM_CHARSET_ASCII) { - *msg = g_convert(from, -1, "ASCII", "UTF-8", NULL, &msglen, NULL); - *charset = AIM_CHARSET_ASCII; - *charsubset = 0x0000; - *msglen_int = msglen; - return; - } - - /* - * If we're sending to an ICQ user, and they are in our - * buddy list, and they are advertising the Unicode - * capability, and they are online, then attempt to send - * as UTF-16BE. - */ - if ((destbn != NULL) && oscar_util_valid_name_icq(destbn)) - userinfo = aim_locate_finduserinfo(od, destbn); - - if ((userinfo != NULL) && (userinfo->capabilities & OSCAR_CAPABILITY_UNICODE)) - { - PurpleBuddy *b; - b = purple_find_buddy(account, destbn); - if ((b != NULL) && (PURPLE_BUDDY_IS_ONLINE(b))) - { - *msg = g_convert(from, -1, "UTF-16BE", "UTF-8", NULL, &msglen, &err); - botch_ucs(*msg, msglen); - if (*msg != NULL) - { - *charset = AIM_CHARSET_UNICODE; - *charsubset = 0x0000; - *msglen_int = msglen; - return; - } - - purple_debug_error("oscar", "Conversion from UTF-8 to UTF-16BE failed: %s.\n", - err->message); - g_error_free(err); - err = NULL; - } - } - - /* - * If this is AIM then attempt to send as ISO-8859-1. If this is - * ICQ then attempt to send as the user specified character encoding. - */ - charsetstr = "ISO-8859-1"; - if ((destbn != NULL) && oscar_util_valid_name_icq(destbn)) - charsetstr = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); - - /* - * XXX - We need a way to only attempt to convert if we KNOW "from" - * can be converted to "charsetstr" - */ -#ifndef _WIN32 - /* nosuke reported that this portion caused unexpected - * conversion from utf-8 fullwidth tilde/numbers/alphabets to - * halfwidth ones on windows environment. --yaz */ - *msg = g_convert(from, -1, charsetstr, "UTF-8", NULL, &msglen, &err); - if (*msg != NULL) { - *charset = AIM_CHARSET_LATIN_1; - *charsubset = 0x0000; - *msglen_int = msglen; - return; - } - - purple_debug_info("oscar", "Conversion from UTF-8 to %s failed (%s). Falling back to unicode.\n", - charsetstr, err->message); - g_error_free(err); - err = NULL; -#endif - - /* - * Nothing else worked, so send as UTF-16BE. - */ - *msg = g_convert(from, strlen(from), "UTF-16BE", "UTF-8", NULL, &msglen, &err); - botch_ucs(*msg, msglen); - if (*msg != NULL) { - *charset = AIM_CHARSET_UNICODE; - *charsubset = 0x0000; - *msglen_int = msglen; - return; - } - - purple_debug_error("oscar", "Error converting a Unicode message: %s\n", err->message); - g_error_free(err); - err = NULL; - - purple_debug_error("oscar", "This should NEVER happen! Sending UTF-8 text flagged as ASCII.\n"); - *msg = g_strdup(from); - *msglen_int = strlen(*msg); - *charset = AIM_CHARSET_ASCII; - *charsubset = 0x0000; - return; -} - -/** - * Looks for %n, %d, or %t in a string, and replaces them with the - * specified name, date, and time, respectively. - * - * @param str The string that may contain the special variables. - * @param name The sender name. - * - * @return A newly allocated string where the special variables are - * expanded. This should be g_free'd by the caller. - */ -static gchar * -purple_str_sub_away_formatters(const char *str, const char *name) -{ - char *c; - GString *cpy; - time_t t; - struct tm *tme; - - g_return_val_if_fail(str != NULL, NULL); - g_return_val_if_fail(name != NULL, NULL); - - /* Create an empty GString that is hopefully big enough for most messages */ - cpy = g_string_sized_new(1024); - - t = time(NULL); - tme = localtime(&t); - - c = (char *)str; - while (*c) { - switch (*c) { - case '%': - if (*(c + 1)) { - switch (*(c + 1)) { - case 'n': - /* append name */ - g_string_append(cpy, name); - c++; - break; - case 'd': - /* append date */ - g_string_append(cpy, purple_date_format_short(tme)); - c++; - break; - case 't': - /* append time */ - g_string_append(cpy, purple_time_format(tme)); - c++; - break; - default: - g_string_append_c(cpy, *c); - } - } else { - g_string_append_c(cpy, *c); - } - break; - default: - g_string_append_c(cpy, *c); - } - c++; - } - - return g_string_free(cpy, FALSE); -} - -static gchar *oscar_caps_to_string(guint64 caps) -{ - GString *str; - const gchar *tmp; - guint64 bit = 1; - - str = g_string_new(""); - - if (!caps) { - return NULL; - } else while (bit <= OSCAR_CAPABILITY_LAST) { - if (bit & caps) { - switch (bit) { - case OSCAR_CAPABILITY_BUDDYICON: - tmp = _("Buddy Icon"); - break; - case OSCAR_CAPABILITY_TALK: - tmp = _("Voice"); - break; - case OSCAR_CAPABILITY_DIRECTIM: - tmp = _("AIM Direct IM"); - break; - case OSCAR_CAPABILITY_CHAT: - tmp = _("Chat"); - break; - case OSCAR_CAPABILITY_GETFILE: - tmp = _("Get File"); - break; - case OSCAR_CAPABILITY_SENDFILE: - tmp = _("Send File"); - break; - case OSCAR_CAPABILITY_GAMES: - case OSCAR_CAPABILITY_GAMES2: - tmp = _("Games"); - break; - case OSCAR_CAPABILITY_XTRAZ: - case OSCAR_CAPABILITY_NEWCAPS: - tmp = _("ICQ Xtraz"); - break; - case OSCAR_CAPABILITY_ADDINS: - tmp = _("Add-Ins"); - break; - case OSCAR_CAPABILITY_SENDBUDDYLIST: - tmp = _("Send Buddy List"); - break; - case OSCAR_CAPABILITY_ICQ_DIRECT: - tmp = _("ICQ Direct Connect"); - break; - case OSCAR_CAPABILITY_APINFO: - tmp = _("AP User"); - break; - case OSCAR_CAPABILITY_ICQRTF: - tmp = _("ICQ RTF"); - break; - case OSCAR_CAPABILITY_EMPTY: - tmp = _("Nihilist"); - break; - case OSCAR_CAPABILITY_ICQSERVERRELAY: - tmp = _("ICQ Server Relay"); - break; - case OSCAR_CAPABILITY_UNICODEOLD: - tmp = _("Old ICQ UTF8"); - break; - case OSCAR_CAPABILITY_TRILLIANCRYPT: - tmp = _("Trillian Encryption"); - break; - case OSCAR_CAPABILITY_UNICODE: - tmp = _("ICQ UTF8"); - break; - case OSCAR_CAPABILITY_HIPTOP: - tmp = _("Hiptop"); - break; - case OSCAR_CAPABILITY_SECUREIM: - tmp = _("Security Enabled"); - break; - case OSCAR_CAPABILITY_VIDEO: - tmp = _("Video Chat"); - break; - /* Not actually sure about this one... WinAIM doesn't show anything */ - case OSCAR_CAPABILITY_ICHATAV: - tmp = _("iChat AV"); - break; - case OSCAR_CAPABILITY_LIVEVIDEO: - tmp = _("Live Video"); - break; - case OSCAR_CAPABILITY_CAMERA: - tmp = _("Camera"); - break; - case OSCAR_CAPABILITY_ICHAT_SCREENSHARE: - tmp = _("Screen Sharing"); - break; - default: - tmp = NULL; - break; - } - if (tmp) - g_string_append_printf(str, "%s%s", (*(str->str) == '\0' ? "" : ", "), tmp); - } - bit <<= 1; - } - - return g_string_free(str, FALSE); -} - static char *oscar_icqstatus(int state) { /* Make a cute little string that shows the status of the dude or dudet */ if (state & AIM_ICQ_STATE_CHAT) @@ -2103,21 +1545,7 @@ } purple_imgstore_unref(img); - message = g_string_new(""); - curpart = args->mpmsg.parts; - while (curpart != NULL) { - tmp = purple_plugin_oscar_decode_im_part(account, userinfo->bn, curpart->charset, - curpart->charsubset, curpart->data, curpart->datalen); - if (tmp != NULL) { - purple_str_strip_char(tmp, 0x0d); // yaz: strip CR -// purple_debug_info("yaz oscar", "tmp=%s",tmp); - g_string_append(message, tmp); - g_free(tmp); - } - - curpart = curpart->next; - } - tmp = g_string_free(message, FALSE); + tmp = g_strdup(args->msg); /* * Convert iChat color tags to normal font tags. @@ -2238,7 +1666,6 @@ char *utf8name, *tmp; GHashTable *components; -// purple_debug_info("yaz oscar", "chat request %s\n", args->msg); if (!args->info.chat.roominfo.name || !args->info.chat.roominfo.exchange) { g_free(message); return 1; @@ -2257,8 +1684,6 @@ g_hash_table_replace(components, g_strdup("room"), utf8name); g_hash_table_replace(components, g_strdup("exchange"), g_strdup_printf("%d", args->info.chat.roominfo.exchange)); - purple_debug_info("yaz oscar", "about to call serv_got_chat_invite\n"); -// purple_debug_info("yaz oscar", "name=%s message=%s\n", name ? name : args->info.chat.roominfo.name, message); serv_got_chat_invite(gc, utf8name, userinfo->bn, @@ -2387,7 +1812,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)); // \376 is 0xfe + msg1 = g_strsplit(args->msg, "\376", (args->type == 0x01 ? 1 : 0)); for (numtoks=0; msg1[numtoks]; numtoks++); msg2 = (gchar **)g_malloc((numtoks+1)*sizeof(gchar *)); for (i=0; msg1[i]; i++) { @@ -3706,11 +3131,6 @@ g_string_append(msg, ""); -#if 0 - /* iChat and AIM6 use 0x000d to send UTF8. - moreover, AIM6 persists only to UTF8! --yaz */ - charset = AIM_CHARSET_QUIRKUTF8; -#endif /* Convert the message to a good encoding */ tmp = oscar_encode_im(msg->str, &tmplen, &charset, NULL); g_string_free(msg, TRUE); @@ -3853,14 +3273,10 @@ /* Messaging an SMS (mobile) user--strip HTML */ tmp2 = purple_markup_strip_html(tmp1); is_html = FALSE; - } else if (od->icq) { + } else { /* ICQ 6 wants its HTML wrapped in these tags. Oblige it. */ tmp2 = g_strdup_printf("%s", tmp1); is_html = TRUE; - } else { - /* otherwise */ - tmp2 = g_strdup(tmp1); - is_html = FALSE; } g_free(tmp1); tmp1 = tmp2; @@ -3919,29 +3335,6 @@ aim_srv_setidle(od, time); } -static -gchar *purple_prpl_oscar_convert_to_infotext(const gchar *str, gsize *ret_len, char **encoding) -{ - int charset = 0; - char *encoded = NULL; - - charset = oscar_charset_check(str); - if (charset == AIM_CHARSET_UNICODE) { - encoded = g_convert(str, strlen(str), "UTF-16BE", "UTF-8", NULL, ret_len, NULL); - botch_ucs(encoded, *ret_len); - *encoding = "unicode-2-0"; - } else if (charset == AIM_CHARSET_LATIN_1) { - encoded = g_convert(str, -1, "ISO-8859-1", "UTF-8", NULL, ret_len, NULL); - *encoding = "iso-8859-1"; - } else { - encoded = g_strdup(str); - *ret_len = strlen(str); - *encoding = "us-ascii"; - } - - return encoded; -} - void oscar_set_info(PurpleConnection *gc, const char *rawinfo) { @@ -5064,15 +4457,7 @@ message, buf2); } -#if 0 - if (charset == AIM_CHARSET_ASCII) - charsetstr = "us-ascii"; - else if (charset == AIM_CHARSET_UNICODE) - charsetstr = "unicode-2-0"; - else if (charset == AIM_CHARSET_LATIN_1) - charsetstr = "iso-8859-1"; -#endif - aim_chat_send_im(od, c->conn, 0, buf2, len, charsetstr, "JA"); + aim_chat_send_im(od, c->conn, 0, buf2, len, charsetstr, "en"); g_free(buf2); g_free(buf);