changeset 31867:52801bade70e

Currently oscar (ICQ) protocol does not support comma-separated list of encoding, what may cause problems with clients that using single-byte encoding, while we using UTF-8 (for example: QIP2005). This patch adds support for a comma-separated list of encodings. for example: {{{ utf-8,cp1251,us-ascii }}} This patch also fixes invalid encoding of buddy status and buddy info. Fixes #13496. committer: John Bailey <rekkanoryo@rekkanoryo.org>
author loentar@google.com
date Thu, 24 Mar 2011 22:37:29 +0000
parents e2c016bb436f
children a493a43d719b
files libpurple/protocols/oscar/encoding.c
diffstat 1 files changed, 57 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/oscar/encoding.c	Thu Mar 24 21:29:28 2011 +0000
+++ b/libpurple/protocols/oscar/encoding.c	Thu Mar 24 22:37:29 2011 +0000
@@ -21,6 +21,60 @@
 #include "encoding.h"
 
 static gchar *
+encoding_multi_convert_to_utf8(const gchar *text, gssize textlen, const gchar *encodings, GError **error, gboolean fallback)
+{
+	gchar *utf8 = NULL;
+	const gchar *begin = encodings;
+	const gchar *end = NULL;
+	gchar *curr_encoding = NULL; /* allocated buffer for encoding name */
+	const gchar *curr_encoding_ro = NULL; /* read-only encoding name */
+
+	if (!encodings) {
+		purple_debug_error("oscar", "encodings is NULL");
+		return NULL;
+	}
+
+	for (;;)
+	{
+		/* extract next encoding */
+		end = strchr(begin, ',');
+		if (!end) {
+			curr_encoding_ro = begin;
+		}	else { /* allocate buffer for encoding */
+			curr_encoding = g_strndup(begin, end - begin);
+			if (!curr_encoding) {
+				purple_debug_error("oscar", "Error allocating memory for encoding");
+				break;
+			}
+			curr_encoding_ro = curr_encoding;
+		}
+
+		if (!g_ascii_strcasecmp(curr_encoding_ro, "utf-8") && g_utf8_validate(text, textlen, NULL)) {
+			break;
+		}
+
+		utf8 = g_convert(text, textlen, "UTF-8", curr_encoding_ro, NULL, NULL, NULL);
+
+		if (!end) /* last occurence. do not free curr_encoding: buffer was'nt allocated */
+			break;
+
+		g_free(curr_encoding); /* free allocated buffer for encoding here */
+
+		if (utf8) /* text was successfully converted */
+			break;
+
+		begin = end + 1;
+	}
+
+	if (!utf8 && fallback)
+	{ /* "begin" points to last encoding */
+		utf8 = g_convert_with_fallback(text, textlen, "UTF-8", begin, "?", NULL, NULL, error);
+	}
+
+	return utf8;
+}
+
+static gchar *
 encoding_extract(const char *encoding)
 {
 	char *begin, *end;
@@ -65,7 +119,7 @@
 	}
 
 	if (glib_encoding != NULL) {
-		utf8 = g_convert(text, textlen, "UTF-8", glib_encoding, NULL, NULL, NULL);
+		utf8 = encoding_multi_convert_to_utf8(text, textlen, glib_encoding, NULL, FALSE);
 	}
 
 	/*
@@ -101,7 +155,7 @@
 		charset = purple_account_get_string(account, "encoding", NULL);
 
 	if(charset && *charset)
-		ret = g_convert(msg, -1, "UTF-8", charset, NULL, NULL, NULL);
+		ret = encoding_multi_convert_to_utf8(msg, -1, charset, NULL, FALSE);
 
 	if(!ret)
 		ret = purple_utf8_try_convert(msg);
@@ -119,10 +173,7 @@
 		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);
+		ret = encoding_multi_convert_to_utf8(data, datalen, charsetstr, &err, fallback);
 		if (err != NULL) {
 			purple_debug_warning("oscar", "Conversion from %s failed: %s.\n",
 							   charsetstr, err->message);