simplify block_try function.
[apps/madmutt.git] / lib-mime / rfc2047.c
index 06db456..5b88b4b 100644 (file)
@@ -59,9 +59,6 @@
 
 #define CONTINUATION_BYTE(c) (((c) & 0xc0) == 0x80)
 
-typedef size_t (*encoder_t) (char *, const char *, size_t,
-                             const char *);
-
 /* converts f of len flen and charset from
        into *t of len *tlen and charset to 
 
@@ -115,9 +112,9 @@ char *mutt_choose_charset(const char *fromcode, const char *charsets,
 
     while (*p) {
         char cset[SHORT_STRING];
-        ssize_t slen, n;
         const char *q;
         char *s;
+        ssize_t slen, n;
 
         q = strchr(p, ':');
         if (q) {
@@ -128,11 +125,11 @@ char *mutt_choose_charset(const char *fromcode, const char *charsets,
             p += n;
         }
 
-        if (!n ||
+        if (!n || n > (ENCWORD_LEN_MAX - ENCWORD_LEN_MIN + 2 - 12)) {
             /* Assume that we never need more than 12 characters of
                encoded-text to encode a single character. */
-            n > (ENCWORD_LEN_MAX - ENCWORD_LEN_MIN + 2 - 12))
             continue;
+        }
 
         n = convert_string(fromcode, u, ulen, cset, &s, &slen);
         if (n < 0)
@@ -169,32 +166,51 @@ char *mutt_choose_charset(const char *fromcode, const char *charsets,
     return tocode;
 }
 
-static size_t b_encoder (char *s, const char *d, size_t dlen,
-                         const char *tocode)
+
+/****************************************************************************/
+/* Encoding functions                                                       */
+/****************************************************************************/
+
+static const char __qp_special[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,
+    0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+typedef size_t (encoder_t)(char *, const char *, ssize_t, const char *);
+
+static size_t
+b_encoder(char *s, const char *d, ssize_t dlen, const char *tocode)
 {
     char *s0 = s;
 
-    memcpy (s, "=?", 2), s += 2;
-    memcpy (s, tocode, m_strlen(tocode)), s += m_strlen(tocode);
-    memcpy (s, "?B?", 3), s += 3;
+    s += sprintf(s, "=?%s?B?", tocode);
+
     for (;;) {
-        if (!dlen)
-            break;
-        else if (dlen == 1) {
+        switch (dlen) {
+          case 0:
+            goto done;
+
+          case 1:
             *s++ = __m_b64chars[(*d >> 2) & 0x3f];
             *s++ = __m_b64chars[(*d & 0x03) << 4];
             *s++ = '=';
             *s++ = '=';
-            break;
-        }
-        else if (dlen == 2) {
+            goto done;
+
+          case 2:
             *s++ = __m_b64chars[(*d >> 2) & 0x3f];
             *s++ = __m_b64chars[((*d & 0x03) << 4) | ((d[1] >> 4) & 0x0f)];
             *s++ = __m_b64chars[(d[1] & 0x0f) << 2];
             *s++ = '=';
-            break;
-        }
-        else {
+            goto done;
+
+          default:
             *s++ = __m_b64chars[(*d >> 2) & 0x3f];
             *s++ = __m_b64chars[((*d & 0x03) << 4) | ((d[1] >> 4) & 0x0f)];
             *s++ = __m_b64chars[((d[1] & 0x0f) << 2) | ((d[2] >> 6) & 0x03)];
@@ -202,32 +218,36 @@ static size_t b_encoder (char *s, const char *d, size_t dlen,
             d += 3, dlen -= 3;
         }
     }
-    memcpy (s, "?=", 2), s += 2;
+
+  done:
+    *s++ = '?';
+    *s++ = '=';
     return s - s0;
 }
 
-static size_t q_encoder (char *s, const char *d, size_t dlen,
-                         const char *tocode)
+static size_t
+q_encoder(char *s, const char *d, ssize_t dlen, const char *tocode)
 {
     char *s0 = s;
 
-    memcpy (s, "=?", 2), s += 2;
-    memcpy (s, tocode, m_strlen(tocode)), s += m_strlen(tocode);
-    memcpy (s, "?Q?", 3), s += 3;
+    s += sprintf(s, "=?%s?Q?", tocode);
     while (dlen--) {
         unsigned char c = *d++;
 
-        if (c == ' ')
+        if (c == ' ') {
             *s++ = '_';
-        else if (c >= 0x7f || c < 0x20 || c == '_' || strchr (MimeSpecials, c)) {
+        } else
+        if (c & 0x80 || __qp_special[c]) {
             *s++ = '=';
             *s++ = __m_b36chars_upper[c >> 4];
             *s++ = __m_b36chars_upper[c & 0xf];
-        }
-        else
+        } else {
             *s++ = c;
+        }
     }
-    memcpy (s, "?=", 2), s += 2;
+
+    *s++ = '?';
+    *s++ = '=';
     return s - s0;
 }
 
@@ -242,66 +262,66 @@ static size_t q_encoder (char *s, const char *d, size_t dlen,
  */
 static size_t try_block (const char *d, ssize_t dlen,
                          const char *fromcode, const char *tocode,
-                         encoder_t * encoder, ssize_t *wlen)
+                         encoder_t **encoder, ssize_t *wlen)
 {
     char buf1[ENCWORD_LEN_MAX - ENCWORD_LEN_MIN + 1];
-    iconv_t cd;
-    const char *ib;
-    char *ob, *p;
-    ssize_t ibl, obl;
-    int count, len, len_b, len_q;
+    ssize_t obl = sizeof(buf1) - m_strlen(tocode);
+    char *ob;
 
     if (fromcode) {
-        cd = mutt_iconv_open (tocode, fromcode, 0);
-        assert (cd != (iconv_t) (-1));
-        ib = d, ibl = dlen, ob = buf1, obl = sizeof (buf1) - m_strlen(tocode);
+        const char *ib = d;
+        ssize_t ibl = dlen;
+        iconv_t cd = mutt_iconv_open(tocode, fromcode, 0);
+
+        assert (cd != (iconv_t)(-1));
+
+        ob = buf1;
+
         if (my_iconv(cd, &ib, &ibl, &ob, &obl) < 0
         ||  my_iconv(cd, 0, 0, &ob, &obl) < 0)
         {
-            assert (errno == E2BIG);
-            iconv_close (cd);
-            assert (ib > d);
+            assert (errno == E2BIG && ib > d);
+            iconv_close(cd);
             return (ib - d == dlen) ? dlen : ib - d + 1;
         }
         iconv_close (cd);
-    }
-    else {
-        if (dlen > ssizeof(buf1) - m_strlen(tocode))
-            return ssizeof(buf1) - m_strlen(tocode) + 1;
-        memcpy (buf1, d, dlen);
+    } else {
+        if (dlen > obl)
+            return obl + 1;
+        memcpy(buf1, d, dlen);
         ob = buf1 + dlen;
     }
 
-    count = 0;
-    for (p = buf1; p < ob; p++) {
-        unsigned char c = *p;
+    {
+        const char *p;
+        int count, len, len_b, len_q;
 
-        assert (strchr (MimeSpecials, '?'));
-        if (c >= 0x7f || c < 0x20 || *p == '_' ||
-            (c != ' ' && strchr (MimeSpecials, *p)))
-            ++count;
-    }
-
-    len = ENCWORD_LEN_MIN - 2 + m_strlen(tocode);
-    len_b = len + (((ob - buf1) + 2) / 3) * 4;
-    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"))
-        len_q = ENCWORD_LEN_MAX + 1;
+        count = 0;
+        for (p = buf1; p < ob; p++) {
+            count += (*p & 0x80 || __qp_special[(int)*p]);
+        }
 
-    if (len_b < len_q && len_b <= ENCWORD_LEN_MAX) {
-        *encoder = b_encoder;
-        *wlen = len_b;
-        return 0;
-    }
-    else if (len_q <= ENCWORD_LEN_MAX) {
-        *encoder = q_encoder;
-        *wlen = len_q;
-        return 0;
+        len = ENCWORD_LEN_MIN - 2 + m_strlen(tocode);
+        len_b = len + (((ob - buf1) + 2) / 3) * 4;
+        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"))
+            len_q = ENCWORD_LEN_MAX + 1;
+
+        if (len_b < len_q && len_b <= ENCWORD_LEN_MAX) {
+            *encoder = b_encoder;
+            *wlen = len_b;
+            return 0;
+        } else
+        if (len_q <= ENCWORD_LEN_MAX) {
+            *encoder = q_encoder;
+            *wlen = len_q;
+            return 0;
+        } else {
+            return dlen;
+        }
     }
-    else
-        return dlen;
 }
 
 /*
@@ -310,7 +330,7 @@ static size_t try_block (const char *d, ssize_t dlen,
  */
 static size_t encode_block (char *s, char *d, ssize_t dlen,
                             const char *fromcode, const char *tocode,
-                            encoder_t encoder)
+                            encoder_t *encoder)
 {
     char buf1[ENCWORD_LEN_MAX - ENCWORD_LEN_MIN + 1];
     ssize_t ibl, obl, n1, n2;
@@ -327,9 +347,9 @@ static size_t encode_block (char *s, char *d, ssize_t dlen,
         assert (n1 >= 0 && n2 >= 0);
         iconv_close (cd);
         return (*encoder) (s, buf1, ob - buf1, tocode);
-    }
-    else
+    } else {
         return (*encoder) (s, d, dlen, tocode);
+    }
 }
 
 /*
@@ -340,7 +360,7 @@ static size_t encode_block (char *s, char *d, ssize_t dlen,
  */
 static size_t choose_block(char *d, size_t dlen, int col,
                            const char *fromcode, const char *tocode,
-                           encoder_t *encoder, ssize_t *wlen)
+                           encoder_t **encoder, ssize_t *wlen)
 {
     size_t n, nn;
     int utf8 = fromcode && !ascii_strcasecmp (fromcode, "UTF-8");
@@ -380,7 +400,7 @@ static int rfc2047_encode (const char *d, ssize_t dlen, int col,
     char *u, *t0, *t1, *t;
     char *s0, *s1;
     ssize_t ulen, r, n, wlen;
-    encoder_t encoder;
+    encoder_t *encoder;
     char *tocode1 = 0;
     const char *tocode;
     const char *icode = "UTF-8";