Convert a header line according to RFC 2047
authorJoey Schulze <joey@infodrom.org>
Wed, 8 Feb 2006 08:55:16 +0000 (08:55 +0000)
committerJoey Schulze <joey@infodrom.org>
Wed, 8 Feb 2006 08:55:16 +0000 (08:55 +0000)
rfc2047.c [new file with mode: 0644]
rfc2047.h [new file with mode: 0644]

diff --git a/rfc2047.c b/rfc2047.c
new file mode 100644 (file)
index 0000000..c85756e
--- /dev/null
+++ b/rfc2047.c
@@ -0,0 +1,264 @@
+/*
+    Copyright (c) 2006  Joey Schulze <joey@infodrom.org>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "charset.h"
+
+/*
+ * Index_hex and Index_64 imported from Mutt:handler.c
+ * decode_quotedprintable() and decode_base64() as well
+ */
+int Index_hex[128] = {
+  -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+  -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+  -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+  0, 1, 2, 3,  4, 5, 6, 7,  8, 9,-1,-1, -1,-1,-1,-1,
+  -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+  -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+  -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+  -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
+};
+
+int Index_64[128] = {
+  -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+  -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+  -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+  52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
+  -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
+  15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
+  -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+  41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+};
+#define hexval(c) Index_hex[(unsigned int)(c)]
+#define base64val(c) Index_64[(unsigned int)(c)]
+
+
+/*
+ * Decode a string from quoted printable
+ */
+char *decode_quotedprintable(char *buf)
+{
+  char *inp, *outp;
+  char *endp;
+
+  endp = buf+strlen(buf);
+  
+  for (inp = outp = buf; inp < endp; inp++) {
+    if (*inp == '_')
+      *(outp++) = ' ';
+    else if (*inp == '=' && inp+2 < endp &&
+            (!(*(inp+1) & ~127) && hexval(*(inp+1)) != -1) &&
+            (!(*(inp+2) & ~127) && hexval(*(inp+2)) != -1)) {
+      *(outp++) = (hexval(*(inp+1)) << 4) | hexval(*(inp+2));
+      inp += 2;
+    } else
+      *(outp++) = *inp;
+  }
+  *outp = '\0';
+
+  return buf;
+}
+
+/*
+ * Decode a string from base43
+ */
+char *decode_base64(char *buf)
+{
+  char *inp, *outp;
+  char *endp;
+  int c, b = 0, k = 0;
+
+  endp = buf+strlen(buf);
+
+  for (inp = outp = buf; inp < endp; inp++) {
+    if (*inp == '=')
+      break;
+    if ((*inp & ~127) || (c = base64val(*inp)) == -1)
+      continue;
+    if (k + 6 >= 8)
+      {
+       k -= 2;
+       *(outp++) = b | (c >> k);
+       b = c << (8 - k);
+      }
+    else
+      {
+       b |= c << (k + 2);
+       k += 6;
+      }
+    *outp = '\0';
+  }
+
+  return buf;
+}
+
+/*
+ * converts a header line into the current character set if required
+ */
+char *convert_header(char *buf)
+{
+  char *charset;
+  int encoding;
+  char *inp, *outp, *encstart, *wordp, *encp, *endp;
+  char *decode;
+  size_t size;
+
+  endp = buf+strlen(buf);
+  inp = outp = buf;
+
+  while ((encstart = strstr (inp, "=?"))) {
+    if (inp == outp)
+      outp = encstart;
+    else {
+      memmove (outp, inp, encstart-inp-1);
+      outp += encstart-inp-1;
+    }
+    charset = encstart+2;
+
+    if ((encp = strchr (charset, '?')) == NULL) {
+      memmove (outp, inp, strlen(inp)+1);
+      break;
+    }
+
+    *encp = '\0';
+
+    if ((encp + 3 >= endp) || !strchr ("BbQq", *encp) || (*(encp+2) != '?')) {
+      memmove (outp, inp, strlen(inp)+1);
+      break;
+    }
+
+    encoding = toupper(*(encp+1));
+
+    inp = encp + 3;
+
+    if ((wordp = strstr (inp, "?=")) == NULL) {
+      memmove (outp, encstart, strlen(encstart)+1);
+      strcat (outp, "?");
+      encstart += strlen(encstart)+1;
+      memmove (outp, encstart, strlen(encstart)+1);
+      break;
+    }
+
+    *wordp = '\0';
+    wordp += 2;
+
+    switch (encoding) {
+    case 'B':
+      decode = decode_base64 (inp);
+      break;
+    case 'Q':
+      decode = decode_quotedprintable (inp);
+      break;
+    default:
+      decode = inp;
+      break;
+    }
+
+    size = wordp - outp -1;
+    decode = convert_word (charset, decode, outp, size);
+
+    memmove (outp, decode, strlen(decode));
+    outp += strlen(decode);
+
+    inp = wordp;
+  }
+
+  if (inp != outp)
+    memmove (outp, inp, strlen(inp)+1);
+
+  return buf;
+}
+
+
+/*
+ * Needs to be called with LANG=de_DE.ISO-8859-1
+
+#include <stdio.h>
+
+void test_rfc2047()
+{
+  char *qp;
+  char *b64;
+  char *subject;
+
+  set_charset();
+
+  qp = strdup ("f=FCr");
+  printf ("\t%s -> ", qp);
+  b64 = decode_quotedprintable (qp);
+  printf ("%s\n", qp);
+  if (!strcmp (qp, "für"))
+    printf ("rfc2047.c: decode_quotedprintable() passed\n");
+  else
+    printf ("rfc2047.c: decode_quotedprintable() failed\n");
+  free (qp);
+
+  qp = strdup ("f=FCr_Umlaute_=EFm_Sub");
+  printf ("\t%s -> ", qp);
+  b64 = decode_quotedprintable (qp);
+  printf ("%s\n", qp);
+  if (!strcmp (qp, "für Umlaute ïm Sub"))
+    printf ("rfc2047.c: decode_quotedprintable() passed\n");
+  else
+    printf ("rfc2047.c: decode_quotedprintable() failed\n");
+  free (qp);
+
+  b64 = strdup ("ZvxyINxtbOT8dOs=");
+  printf ("\t%s -> ", b64);
+  b64 = decode_base64 (b64);
+  printf ("%s\n", b64);
+  if (!strcmp (b64, "für Ümläütë"))
+    printf ("rfc2047.c: decode_base64() passed\n");
+  else
+    printf ("rfc2047.c: decode_base64() failed\n");
+  free (b64);
+
+  subject = strdup ("Vorschlag =?ISO-8859-1?Q?f=FCr?= ein Eintrittskonzept");
+  printf ("\t%s\n", subject);
+  subject = convert_header (subject);
+  printf ("\t%s\n", subject);
+  if (!strcmp (subject, "Vorschlag für ein Eintrittskonzept"))
+    printf ("rfc2047.c: convert_header() passed\n");
+  else
+    printf ("rfc2047.c: convert_header() failed\n");
+  free (subject);
+
+  subject = strdup ("=?utf-8?q?Google=3A_Chat_f=C3=BCr_die_Ewigkeit?=");
+  printf ("\t%s\n", subject);
+  subject = convert_header (subject);
+  printf ("\t%s\n", subject);
+  if (!strcmp (subject, "Google: Chat für die Ewigkeit"))
+    printf ("rfc2047.c: convert_header() passed\n");
+  else
+    printf ("rfc2047.c: convert_header() failed\n");
+  free (subject);
+
+  subject = strdup ("=?iso-8859-1?B?ZvxyINxtbOT8dOs=?= testen");
+  printf ("\t%s\n", subject);
+  subject = convert_header (subject);
+  printf ("\t%s\n", subject);
+  if (!strcmp (subject, "für Ümläütë testen"))
+    printf ("rfc2047.c: convert_header() passed\n");
+  else
+    printf ("rfc2047.c: convert_header() failed\n");
+  free (subject);
+
+}
+*/
diff --git a/rfc2047.h b/rfc2047.h
new file mode 100644 (file)
index 0000000..3bcc232
--- /dev/null
+++ b/rfc2047.h
@@ -0,0 +1,19 @@
+/*
+    Copyright (c) 2006  Joey Schulze <joey@infodrom.org>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+char *convert_header(char *buf);