aboutsummaryrefslogtreecommitdiffstats
path: root/camel/gmime-rfc2047.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/gmime-rfc2047.c')
-rw-r--r--camel/gmime-rfc2047.c179
1 files changed, 97 insertions, 82 deletions
diff --git a/camel/gmime-rfc2047.c b/camel/gmime-rfc2047.c
index 7266cb1159..2a44a20dd6 100644
--- a/camel/gmime-rfc2047.c
+++ b/camel/gmime-rfc2047.c
@@ -49,10 +49,11 @@ hexval (gchar c) {
return c - 'a' + 10;
}
-static void
-decode_quoted (const gchar *text, gchar *to)
-{
- while (*text) {
+static gchar *
+decode_quoted(const gchar *text, const gchar *end) {
+ gchar *to = malloc(end - text + 1), *to_2 = to;
+ if (!to) return NULL;
+ while (*text && text < end) {
if (*text == '=') {
gchar a = hexval (text[1]);
gchar b = hexval (text[2]);
@@ -70,20 +71,23 @@ decode_quoted (const gchar *text, gchar *to)
text++;
}
}
- *to = 0;
+ return to_2;
}
-static void
-decode_base64 (const gchar *what, gchar *where)
-{
+static gchar *
+decode_base64(const gchar *data, const gchar *end) {
unsigned short pattern = 0;
int bits = 0;
int delimiter = '=';
gchar x;
- gchar *t = where;
+ gchar *buffer = g_malloc((end - data) * 3);
+ gchar *t = buffer;
int Q = 0;
- while (*what != delimiter) {
- x = base64_rank[(unsigned char)(*what++)];
+
+ if (!buffer) return NULL;
+
+ while (*data != delimiter) {
+ x = base64_rank[(unsigned char)(*data++)];
if (x == NOT_RANKED)
continue;
pattern <<= 6;
@@ -97,6 +101,7 @@ decode_base64 (const gchar *what, gchar *where)
}
}
*t = 0;
+ return buffer;
}
static void
@@ -113,86 +118,96 @@ build_base64_rank_table (void)
}
}
-gchar
-*gmime_rfc2047_decode (const gchar *data, const gchar *into_what)
+
+gchar*
+rfc2047_decode_word (const gchar *data, const gchar *into_what)
{
- gchar buffer[4096] /* FIXME : constant sized buffer */, *b = buffer;
+ const char *charset = strstr(data, "=?"), *encoding, *text, *end;
+
+ char *buffer, *b, *cooked_data;
+ buffer = g_malloc(strlen(data) * 2);
+ b = buffer;
+
+ if (!charset) return strdup(data);
+ charset+=2;
+
+ encoding = strchr(charset, '?');
+ if (!encoding) return strdup(data);
+ encoding++;
+
+ text = strchr(encoding, '?');
+ if (!text) return strdup(data);
+ text++;
+
+ end = strstr(text, "?=");
+ if (!end) return strdup(data);
+
+ b[0] = 0;
+
+ if (toupper(*encoding)=='Q')
+ cooked_data = decode_quoted(text, end);
+ else if (toupper(*encoding)=='B')
+ cooked_data = decode_base64(text, end);
+ else
+ return g_strdup(data);
+
+ {
+ char *c = strchr(charset, '?');
+ char *q = g_malloc(c - charset + 1);
+ char *cook_2 = cooked_data;
+ int cook_len = strlen(cook_2);
+ int b_len = 4096;
+ iconv_t i;
+ strncpy(q, charset, c - charset);
+ i = unicode_iconv_open(into_what, q);
+ if (!i) {
+ g_free(q);
+ return g_strdup(buffer);
+ }
+ unicode_iconv(i, &cook_2, &cook_len, &b, &b_len);
+ unicode_iconv_close(i);
+ }
+
+ return g_strdup(buffer);
+}
+
+gchar *
+gmime_rfc2047_decode (const gchar *data, const gchar *into_what)
+{
+ char *buffer = malloc(strlen(data) * 4), *b = buffer;
+
+ int was_encoded_word = 0;
+
build_base64_rank_table ();
-
- while (*data) {
-
- /* If we encounter an error we just break out of the loop and copy the rest
- * of the text as-is */
-
- if (*data=='=') {
- data++;
- if (*data=='?') {
- gchar *charset, *encoding, *text, *end;
- gchar dc[4096];
- charset = data+1;
- encoding = strchr (charset, '?');
-
- if (!encoding) break;
- encoding++;
- text = strchr (encoding, '?');
- if (!text) break;
- text++;
- end = strstr (text, "?=");
- if (!end) break;
- end++;
-
- *(encoding-1)=0;
- *(text-1)=0;
- *(end-1)=0;
-
- if (strcasecmp (encoding, "q") == 0) {
- decode_quoted(text, dc);
- } else if (strcasecmp (encoding, "b") == 0) {
- decode_base64 (text, dc);
- } else {
- /* What to do here? */
- break;
- }
-
- {
- int f;
- iconv_t i;
- const gchar *d2 = dc;
- int l = strlen (d2), l2 = 4000;
-
- i = unicode_iconv_open (into_what, charset);
- if (!i)
- break;
-
- unicode_iconv (i, &d2, &l, &b, &l2);
-
- unicode_iconv_close (i);
- data = end;
- }
+
+ while (data && *data) {
+ char *word_start = strstr(data, "=?"), *decoded;
+ if (!word_start) {
+ strcpy(b, data);
+ return buffer;
+ }
+ if (word_start != data) {
+
+ if (strspn(data, " \t\n\r") != (word_start - data)) {
+ strncpy(b, data, word_start - data);
+ b += word_start - data;
}
- } else {
- *b = *data;
- b++;
}
-
- data++;
-
- }
-
- while (*data) {
- *b = *data;
- b++;
- data++;
+ decoded = rfc2047_decode_word(word_start, into_what);
+ strcpy(b, decoded);
+ b += strlen(decoded);
+ g_free(decoded);
+
+ data = strstr(data, "?=") + 2;
}
-
+
*b = 0;
-
- return g_strdup (buffer);
+ return buffer;
}
gchar
-*rfc2047_encode (const gchar *string, const gchar *charset)
+*gmime_rfc2047_encode (const gchar *string, const gchar *charset)
{
gchar buffer[4096] /* FIXME : constant sized buffer */;
gchar *b = buffer;
@@ -213,7 +228,7 @@ gchar
while (*s) {
if (*s == ' ') b += sprintf (b, "_");
else if (*s < 0x20 || *s >= 0x7f || *s == '=' || *s == '?' || *s == '_') {
- b += sprintf (b, "=%2x", *s);
+ b += sprintf (b, "=%2x", (unsigned char)*s);
} else {
b += sprintf (b, "%c", *s);
}