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.c221
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);
+}