From f37393fd44cd2c7efc0a487dd85dfbd5ac232e55 Mon Sep 17 00:00:00 2001 From: Joey Schulze Date: Wed, 8 Feb 2006 08:55:16 +0000 Subject: [PATCH] Convert a header line according to RFC 2047 --- rfc2047.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ rfc2047.h | 19 ++++ 2 files changed, 283 insertions(+) create mode 100644 rfc2047.c create mode 100644 rfc2047.h diff --git a/rfc2047.c b/rfc2047.c new file mode 100644 index 0000000..c85756e --- /dev/null +++ b/rfc2047.c @@ -0,0 +1,264 @@ +/* + Copyright (c) 2006 Joey Schulze + + 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 +#include +#include +#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 + +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 index 0000000..3bcc232 --- /dev/null +++ b/rfc2047.h @@ -0,0 +1,19 @@ +/* + Copyright (c) 2006 Joey Schulze + + 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); -- 2.20.1