diff options
Diffstat (limited to 'camel/gmime-rfc2047.c')
-rw-r--r-- | camel/gmime-rfc2047.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/camel/gmime-rfc2047.c b/camel/gmime-rfc2047.c new file mode 100644 index 0000000000..2a90c1869e --- /dev/null +++ b/camel/gmime-rfc2047.c @@ -0,0 +1,221 @@ +/* + * gmime-rfc2047.c: implemention of RFC2047 + * + * Copyright (C) 1999 Robert Brady <rwb197@ecs.soton.ac.uk> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + */ + +#include <stdio.h> +#include <ctype.h> +#include <unicode.h> +#include <string.h> + +#include "gmime-rfc2047.h" + +#define NOT_RANKED -1 + +/* base64 code from tin. This should be changed to use the base64 code Miguel comitted */ + +const char base64_alphabet[64] = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; + +static unsigned char base64_rank[256]; +static int base64_rank_table_built; +static void build_base64_rank_table (void); + +static int hexval(gchar c) { + if (isdigit(c)) return c-'0'; + c = tolower(c); + return c - 'a' + 10; +} + +static void decode_quoted(const gchar *text, gchar *to) { + while (*text) { + if (*text == '=') { + gchar a = hexval(text[1]); + gchar b = hexval(text[2]); + int c = (a << 4) + b; + *to = c; + to++; + text+=3; + } else if (*text == '_') { + *to = ' '; + to++; + text++; + } else { + *to = *text; + to++; + text++; + } + } + *to = 0; +} + +static void decode_base64(const gchar *what, gchar *where) { + unsigned short pattern = 0; + int bits = 0; + int delimiter = '='; + gchar x; + gchar *t = where; + int Q = 0; + while (*what != delimiter) { + x = base64_rank[(unsigned char)(*what++)]; + if (x == NOT_RANKED) + continue; + pattern <<= 6; + pattern |= x; + bits += 6; + if (bits >= 8) { + x = (pattern >> (bits - 8)) & 0xff; + *t++ = x; + Q++; + bits -= 8; + } + } + *t = 0; +} + +static void +build_base64_rank_table ( + void) +{ + int i; + + if (!base64_rank_table_built) { + for (i = 0; i < 256; i++) + base64_rank[i] = NOT_RANKED; + for (i = 0; i < 64; i++) + base64_rank[(int) base64_alphabet[i]] = i; + base64_rank_table_built = 1; + } +} + +gchar *gmime_rfc2047_decode(const gchar *data, const gchar *into_what) { + gchar buffer[4096] /* FIXME : constant sized buffer */, *b = buffer; + + 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; + } + } + } + else { + *b = *data; + b++; + } + + data++; + + } + + while (*data) { + *b = *data; + b++; + data++; + } + + *b = 0; + + return g_strdup(buffer); +} + +gchar *rfc2047_encode(const gchar *string, const gchar *charset) { + gchar buffer[4096] /* FIXME : constant sized buffer */; + gchar *b = buffer; + const gchar *s = string; + int not_ascii = 0, not_latin1 = 0; + while (*s) { + if (*s <= 20 || *s >= 0x7f || *s == '=') { not_ascii = 1; } + s++; + } + + if (!not_ascii) { + b += sprintf(b, "%s", string); + } + + else { + b += sprintf(b, "=?%s?Q?", charset); + s = string; + while (*s) { + if (*s == ' ') b += sprintf(b, "_"); + else if (*s < 0x20 || *s >= 0x7f || *s == '=' || *s == '?' || *s == '_') { + b += sprintf(b, "=%2x", *s); + } else { + b += sprintf(b, "%c", *s); + } + s++; + } + b += sprintf(b, "?="); + } + + *b = 0; + + return g_strdup(buffer); +} |