Move (un)?lists and (un)subscribe to MAlias.
[apps/madmutt.git] / lib-mime / rfc2047.c
index 3bd353c..4aa6ee4 100644 (file)
  * please see the file GPL in the top level source directory.
  */
 
-#include <lib-lib/mem.h>
-#include <lib-lib/str.h>
-#include <lib-lib/ascii.h>
+#include <lib-lib/lib-lib.h>
 
 #include <lib-mime/mime.h>
 
 #include "charset.h"
 #include "thread.h"
 
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 /* If you are debugging this file, comment out the following line. */
 /*#define NDEBUG*/
 
@@ -73,7 +64,7 @@ convert_string(const char *from, const char *f, ssize_t flen,
 
     cd = mutt_iconv_open(to, from, 0);
 
-    if (cd == (iconv_t)(-1))
+    if (cd == MUTT_ICONV_ERROR)
         return -1;
 
     obl = 4 * flen + 1;
@@ -109,7 +100,7 @@ char *mutt_choose_charset(const char *fromcode, const char *charsets,
     const char *p = charsets;
 
     while (*p) {
-        char cset[SHORT_STRING];
+        char cset[STRING];
         const char *q;
         char *s;
         ssize_t slen, n;
@@ -157,7 +148,7 @@ char *mutt_choose_charset(const char *fromcode, const char *charsets,
             p_delete(&res);
         }
 
-        mutt_canonical_charset(buf, sizeof(buf), tocode);
+        charset_canonicalize(buf, sizeof(buf), tocode);
         m_strreplace(&tocode, buf);
     }
 
@@ -271,7 +262,7 @@ static size_t try_block(const char *d, ssize_t dlen,
         ssize_t ibl = dlen;
         iconv_t cd = mutt_iconv_open(tocode, fromcode, 0);
 
-        assert (cd != (iconv_t)(-1));
+        assert (cd != MUTT_ICONV_ERROR);
 
         ob = buf1;
 
@@ -304,7 +295,7 @@ static size_t try_block(const char *d, ssize_t dlen,
         len_q = len + (ob - buf1) + 2 * count;
 
         /* Apparently RFC 1468 says to use B encoding for iso-2022-jp. */
-        if (!ascii_strcasecmp(tocode, "ISO-2022-JP"))
+        if (mime_which_token(tocode, -1) == MIME_ISO_2022_JP)
             len_q = ENCWORD_LEN_MAX + 1;
 
         if (len_b < len_q && len_b <= ENCWORD_LEN_MAX) {
@@ -338,7 +329,7 @@ encode_block(char *s, char *d, ssize_t dlen,
 
     if (fromcode) {
         cd = mutt_iconv_open(tocode, fromcode, 0);
-        assert (cd != (iconv_t) (-1));
+        assert (cd != MUTT_ICONV_ERROR);
         ib = d, ibl = dlen, ob = buf1, obl = sizeof(buf1) - m_strlen(tocode);
         n1 = my_iconv(cd, &ib, &ibl, &ob, &obl);
         n2 = my_iconv(cd, 0, 0, &ob, &obl);
@@ -361,7 +352,7 @@ static size_t choose_block(char *d, size_t dlen, int col,
                            encoder_t **encoder, ssize_t *wlen)
 {
     size_t n, nn;
-    int utf8 = fromcode && !ascii_strcasecmp(fromcode, "UTF-8");
+    int utf8 = mime_which_token(fromcode, -1) == MIME_UTF_8;
 
     n = dlen;
     for (;;) {
@@ -452,7 +443,7 @@ static int rfc2047_encode(const char *d, ssize_t dlen, int col,
     }
 
     /* Hack to avoid labelling 8-bit data as us-ascii. */
-    if (!icode && mutt_is_us_ascii(tocode))
+    if (!icode && charset_is_us_ascii(tocode))
         tocode = "unknown-8bit";
 
     /* Adjust t0 for maximum length of line. */
@@ -564,19 +555,19 @@ static int rfc2047_encode(const char *d, ssize_t dlen, int col,
 }
 
 
-void _rfc2047_encode_string(char **pd, int encode_specials, int col)
+static void _rfc2047_encode_string(char **pd, int encode_specials, int col)
 {
     char *e;
     ssize_t elen;
     const char *charsets;
 
-    if (!Charset || !*pd)
+    if (!MCharset.charset || !*pd)
         return;
 
-    charsets = m_strisempty(SendCharset) ? "UTF-8" : SendCharset;
+    charsets = m_strisempty(MCharset.send_charset) ? "utf-8" : MCharset.send_charset;
 
     rfc2047_encode(*pd, m_strlen(*pd), col,
-                   Charset, charsets, &e, &elen,
+                   MCharset.charset, charsets, &e, &elen,
                    encode_specials ? RFC822Specials : NULL);
 
     p_delete(pd);
@@ -604,89 +595,80 @@ void rfc2047_encode_adrlist(address_t *addr, const char *tag)
 /* Decoding functions                                                       */
 /****************************************************************************/
 
-/* decode one word into d[len] */
-static int rfc2047_decode_word(char *d, size_t len, const char *s)
+/* decode one word into d[len] =?cst?[QB]?....?= */
+static int
+rfc2047_decode_word(char *d, size_t len, const char *p, const char *end)
 {
-    const char *p, *eotoken;
-    char *charset = NULL;
-    int enc = 0, count = 0;
-    char *d0;
+    char charset[STRING] = "";
+    const char *t;
+    char *q, *d0 = NULL;
+    int enc = 0;
 
-    /* =?[QB]?cset?.?= */
-    for (p = s; (eotoken = strchr(p, '?')); p = eotoken + 1) {
-        switch (++count) {
-            const char *t;
-            char *q;
+    p += 2;                                 /* =? */
 
-          case 2:
-            /* ignore language specification a la RFC 2231 */
-            t = memchr(p, '*', eotoken - p) ?: eotoken;
-            charset = p_dupstr(p, t - p);
-            break;
+    t = strchr(p, '?');
+    if (!t)
+        return -1;
+    m_strncpy(charset, sizeof(charset), p, t - p);
 
-          case 3:
-            switch (*p) {
-              case 'q': case 'Q':
-                enc = ENCQUOTEDPRINTABLE;
-                break;
+    switch (t[1]) {
+      case 'q': case 'Q':
+        enc = ENCQUOTEDPRINTABLE;
+        break;
 
-              case 'b': case 'B':
-                enc = ENCBASE64;
-                break;
+      case 'b': case 'B':
+        enc = ENCBASE64;
+        break;
+
+      default:
+        return -1;
+    }
 
-              default:
-                p_delete(&charset);
-                return -1;
+    if (t[2] != '?')
+        return -1;
+
+    p = t + 3;                              /* skip ?[QB]? */
+    d0 = q = p_new(char, end - p + 1);      /* it's enough space to decode */
+
+    if (enc == ENCQUOTEDPRINTABLE) {
+        while (p < end - 2) {
+            if (*p == '=' && hexval(p[1]) >= 0 && hexval(p[2]) >= 0) {
+                *q++ = (hexval (p[1]) << 4) | hexval (p[2]);
+                p += 3;
+            } else
+            if (*p == '_') {
+                *q++ = ' ';
+                p++;
+            } else {
+                *q++ = *p++;
             }
-            break;
+        }
+    } else { /* enc == ENCBASE64 */
+        int c, b = 0, k = 0;
 
-          case 4:
-            d0 = q = p_new(char, m_strlen(s) + 1);
-
-            if (enc == ENCQUOTEDPRINTABLE) {
-                while (p < eotoken) {
-                    if (*p == '=' && hexval(p[1]) >= 0 && hexval(p[2]) >= 0) {
-                        *q++ = (hexval (p[1]) << 4) | hexval (p[2]);
-                        p += 3;
-                    } else
-                    if (*p == '_') {
-                        *q++ = ' ';
-                        p++;
-                    } else {
-                        *q++ = *p++;
-                    }
-                }
-                *q = 0;
-            } else { /* enc == ENCBASE64 */
-                int c, b = 0, k = 0;
-
-                while (p < eotoken) {
-                    if (*p == '=')
-                        break;
-
-                    c = base64val(*p++);
-                    if (c < 0)
-                        continue;
-
-                    if (k + 6 >= 8) {
-                        k -= 2;
-                        *q++ = b | (c >> k);
-                        b = c << (8 - k);
-                    } else {
-                        b |= c << (k + 2);
-                        k += 6;
-                    }
-                }
-                *q = 0;
+        while (p < end - 2) {
+            if (*p == '=')
+                break;
+
+            c = base64val(*p++);
+            if (c < 0)
+                continue;
+
+            if (k + 6 >= 8) {
+                k -= 2;
+                *q++ = b | (c >> k);
+                b = c << (8 - k);
+            } else {
+                b |= c << (k + 2);
+                k += 6;
             }
-            break;
         }
     }
+    *q = '\0';
 
-    if (charset)
-        mutt_convert_string(&d0, charset, Charset, M_ICONV_HOOK_FROM);
+    if (*charset)
+        mutt_convert_string(&d0, charset, MCharset.charset, M_ICONV_HOOK_FROM);
     m_strcpy(d, len, d0);
-    p_delete(&charset);
     p_delete(&d0);
     return 0;
 }
@@ -711,7 +693,7 @@ static const char *find_encoded_word(const char *s, const char **x)
             continue;
 
         s += 3;
-        while (0x20 <= *s && *s < 0x7f && *s != '?') {
+        while (0x20 <= *s && *s < 0x7f && (*s != '?' || s[1] != '=')) {
             s++;
         }
 
@@ -777,8 +759,6 @@ static ssize_t lwsrlen(const char *s, ssize_t n)
  */
 void rfc2047_decode(char **pd)
 {
-    const int strict_mime = option(OPTSTRICTMIME);
-
     const char *s = *pd;
     char *d0, *d;
     ssize_t dlen;
@@ -797,29 +777,28 @@ void rfc2047_decode(char **pd)
 
         if (!p) {
             /* no encoded words */
-            if (!strict_mime) {
-                ssize_t m, n;
-
-                n = m_strlen(s);
-                if (found_encoded && (m = lwslen(s, n)) != 0) {
-                    if (m != n)
-                        *d++ = ' ', dlen--;
-                    n -= m, s += m;
-                }
+            ssize_t m, n;
 
-                if (ascii_strcasecmp(AssumedCharset, "us-ascii")) {
-                    char *t;
-
-                    t = p_dupstr(s, n);
-                    if (mutt_convert_nonmime_string(&t) == 0) {
-                        d += m_strcpy(d, dlen, t);
-                    } else {
-                        d += m_strcpy(d, dlen, s);
-                    }
-                    p_delete(&t);
-                    break;
+            n = m_strlen(s);
+            if (found_encoded && (m = lwslen(s, n)) != 0) {
+                if (m != n)
+                    *d++ = ' ', dlen--;
+                n -= m, s += m;
+            }
+
+            if (mime_which_token(MCharset.assumed_charset, -1) == MIME_US_ASCII) {
+                char *t;
+
+                t = p_dupstr(s, n);
+                if (mutt_convert_nonmime_string(&t) == 0) {
+                    d += m_strcpy(d, dlen, t);
+                } else {
+                    d += m_strcpy(d, dlen, s);
                 }
+                p_delete(&t);
+                break;
             }
+
             d += m_strcpy(d, dlen, s);
             break;
         }
@@ -830,29 +809,22 @@ void rfc2047_decode(char **pd)
             n = (p - s);
             /* ignore spaces between encoded words
              * and linear white spaces between encoded word and *text */
-            if (!strict_mime) {
-                if (found_encoded && (m = lwslen(s, n)) != 0) {
-                    if (m != n)
-                        *d++ = ' ', dlen--;
-                    n -= m, s += m;
-                }
+            if (found_encoded && (m = lwslen(s, n)) != 0) {
+                if (m != n)
+                    *d++ = ' ', dlen--;
+                n -= m, s += m;
+            }
 
-                if ((m = n - lwsrlen(s, n)) != 0) {
-                    m  = m_strncpy(d, dlen, s, m);
-                    d += m;
-                    dlen -= m;
-                    if (m != n)
-                        *d++ = ' ', dlen--;
-                }
-            } else
-            if (!found_encoded || (ssize_t)strspn(s, " \t\r\n") != n) {
-                n  = m_strncpy(d, dlen, s, n);
-                d += n;
-                dlen -= n;
+            if ((m = n - lwsrlen(s, n)) != 0) {
+                m  = m_strncpy(d, dlen, s, m);
+                d += m;
+                dlen -= m;
+                if (m != n)
+                    *d++ = ' ', dlen--;
             }
         }
 
-        rfc2047_decode_word(d, dlen, p);
+        rfc2047_decode_word(d, dlen, p, q);
         found_encoded = 1;
         s = q;
         while (*d && dlen)