small fixes.
[apps/madmutt.git] / lib-mime / rfc2047.c
index 442d2e4..c09a97e 100644 (file)
@@ -37,6 +37,7 @@
 #include "charset.h"
 #include "thread.h"
 
+#include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
@@ -49,7 +50,6 @@
 #ifdef NDEBUG
 #define assert(x)
 #else
-#include <assert.h>
 #endif
 
 #define ENCWORD_LEN_MAX 75
@@ -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 
 
@@ -69,14 +66,12 @@ typedef size_t (*encoder_t) (char *, const char *, size_t,
    returns number of converted chars from f, see iconv(3)
  */
 static ssize_t
-convert_string(const char *from, const char *f, size_t flen,
-               const char *to,   char **t, size_t *tlen)
+convert_string(const char *from, const char *f, ssize_t flen,
+               const char *to,   char **t, ssize_t *tlen)
 {
     iconv_t cd;
     char *buf, *ob;
-    size_t obl;
-    ssize_t n;
-    int e;
+    ssize_t obl, n;
 
     cd = mutt_iconv_open(to, from, 0);
 
@@ -88,109 +83,123 @@ convert_string(const char *from, const char *f, size_t flen,
     n = my_iconv(cd, &f, &flen, &ob, &obl);
 
     if (n < 0 || my_iconv(cd, 0, 0, &ob, &obl) < 0) {
-        e = errno;
-        p_delete(&buf);
-        iconv_close (cd);
+        int e = errno;
+        iconv_close(cd);
         errno = e;
+        p_delete(&buf);
         return -1;
     }
+    iconv_close(cd);
 
     *ob = '\0';
     *tlen = ob - buf;
-
-    p_realloc(&buf, ob - buf + 1);
-    *t = buf;
-    iconv_close (cd);
+    *t  = buf;
 
     return n;
 }
 
+/* choose the shortest encoding for u */
 char *mutt_choose_charset(const char *fromcode, const char *charsets,
-                          char *u, size_t ulen, char **d, size_t *dlen)
+                          char *u, ssize_t ulen, char **dst, ssize_t *dlen)
 {
-    char canonical_buff[LONG_STRING];
-    char *e = 0, *tocode = 0;
-    size_t elen = 0, bestn = 0;
-    const char *p, *q;
+    char *res = NULL;
+    ssize_t reslen = 0;
+
+    char *tocode = NULL;
+    ssize_t bestn = 0;
 
-    for (p = charsets; p; p = q ? q + 1 : 0) {
-        char *s, *t;
-        size_t slen, n;
+    const char *p = charsets;
 
-        q = strchr (p, ':');
+    while (*p) {
+        char cset[SHORT_STRING];
+        const char *q;
+        char *s;
+        ssize_t slen, n;
 
-        n = q ? q - p : m_strlen(p);
+        q = strchr(p, ':');
+        if (q) {
+            n = m_strncpy(cset, sizeof(cset), p, q - p);
+            p = ++q;
+        } else {
+            n = m_strcpy(cset, sizeof(cset), p);
+            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;
+        }
 
-        t = p_dupstr(p, n);
-
-        n = convert_string(fromcode, u, ulen, t, &s, &slen);
-        if (n == (size_t) (-1))
+        n = convert_string(fromcode, u, ulen, cset, &s, &slen);
+        if (n < 0)
             continue;
 
         if (!tocode || n < bestn) {
+            m_strreplace(&tocode, cset);
             bestn = n;
-            p_delete(&tocode);
-            tocode = t;
-            if (d) {
-                p_delete(&e);
-                e = s;
-            } else {
-                p_delete(&s);
-            }
-            elen = slen;
+
+            p_delete(&res);
+            res = s;
+            reslen = slen;
             if (!bestn)
                 break;
         } else {
-            p_delete(&t);
             p_delete(&s);
         }
     }
 
     if (tocode) {
-        if (d)
-            *d = e;
-        if (dlen)
-            *dlen = elen;
+        char buf[LONG_STRING];
 
-        mutt_canonical_charset(canonical_buff, sizeof(canonical_buff), tocode);
-        m_strreplace(&tocode, canonical_buff);
+        if (dst && dlen) {
+            *dst  = res;
+            *dlen = reslen;
+        } else {
+            p_delete(&res);
+        }
+
+        mutt_canonical_charset(buf, sizeof(buf), tocode);
+        m_strreplace(&tocode, buf);
     }
 
     return tocode;
 }
 
-static size_t b_encoder (char *s, const char *d, size_t dlen,
-                         const char *tocode)
+
+/****************************************************************************/
+/* Encoding functions                                                       */
+/****************************************************************************/
+
+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)];
@@ -198,32 +207,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 || c < 0x20 || c == '_' || strchr (MimeSpecials, 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;
 }
 
@@ -236,15 +249,15 @@ static size_t q_encoder (char *s, const char *d, size_t dlen,
  * tocode, unless fromcode is 0, in which case the data is assumed to
  * be already in tocode, which should be 8-bit and stateless.
  */
-static size_t try_block (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, size_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;
-    size_t ibl, obl;
+    ssize_t ibl, obl;
     int count, len, len_b, len_q;
 
     if (fromcode) {
@@ -262,8 +275,8 @@ static size_t try_block (const char *d, size_t dlen,
         iconv_close (cd);
     }
     else {
-        if (dlen > sizeof (buf1) - m_strlen(tocode))
-            return sizeof (buf1) - m_strlen(tocode) + 1;
+        if (dlen > ssizeof(buf1) - m_strlen(tocode))
+            return ssizeof(buf1) - m_strlen(tocode) + 1;
         memcpy (buf1, d, dlen);
         ob = buf1 + dlen;
     }
@@ -304,15 +317,15 @@ static size_t try_block (const char *d, size_t dlen,
  * Encode the data (d, dlen) into s using the encoder.
  * Return the length of the encoded word.
  */
-static size_t encode_block (char *s, char *d, size_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;
     iconv_t cd;
     const char *ib;
     char *ob;
-    size_t ibl, obl, n1, n2;
 
     if (fromcode) {
         cd = mutt_iconv_open (tocode, fromcode, 0);
@@ -320,12 +333,12 @@ static size_t encode_block (char *s, char *d, size_t dlen,
         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);
-        assert (n1 != (size_t) (-1) && n2 != (size_t) (-1));
+        assert (n1 >= 0 && n2 >= 0);
         iconv_close (cd);
         return (*encoder) (s, buf1, ob - buf1, tocode);
-    }
-    else
+    } else {
         return (*encoder) (s, d, dlen, tocode);
+    }
 }
 
 /*
@@ -334,9 +347,9 @@ static size_t encode_block (char *s, char *d, size_t dlen,
  * and set the length *wlen of the encoded word and *encoder.
  * We start in column col, which limits the length of the word.
  */
-static size_t choose_block (char *d, size_t dlen, int col,
-                            const char *fromcode, const char *tocode,
-                            encoder_t * encoder, size_t * wlen)
+static size_t choose_block(char *d, size_t dlen, int col,
+                           const char *fromcode, const char *tocode,
+                           encoder_t **encoder, ssize_t *wlen)
 {
     size_t n, nn;
     int utf8 = fromcode && !ascii_strcasecmp (fromcode, "UTF-8");
@@ -366,17 +379,17 @@ static size_t choose_block (char *d, size_t dlen, int col,
  * The input data is assumed to be a single line starting at column col;
  * if col is non-zero, the preceding character was a space.
  */
-static int rfc2047_encode (const char *d, size_t dlen, int col,
+static int rfc2047_encode (const char *d, ssize_t dlen, int col,
                            const char *fromcode, const char *charsets,
-                           char **e, size_t * elen, char *specials)
+                           char **e, ssize_t *elen, const char *specials)
 {
     int ret = 0;
     char *buf;
-    size_t bufpos, buflen;
+    ssize_t bufpos, buflen;
     char *u, *t0, *t1, *t;
     char *s0, *s1;
-    size_t ulen, r, n, wlen;
-    encoder_t encoder;
+    ssize_t ulen, r, n, wlen;
+    encoder_t *encoder;
     char *tocode1 = 0;
     const char *tocode;
     const char *icode = "UTF-8";
@@ -420,7 +433,8 @@ static int rfc2047_encode (const char *d, size_t dlen, int col,
     /* Choose target charset. */
     tocode = fromcode;
     if (icode) {
-        if ((tocode1 = mutt_choose_charset (icode, charsets, u, ulen, 0, 0)))
+        if ((tocode1 = mutt_choose_charset(icode, charsets, u, ulen,
+                                           NULL, NULL)))
             tocode = tocode1;
         else
             ret = 2, icode = 0;
@@ -539,7 +553,7 @@ static int rfc2047_encode (const char *d, size_t dlen, int col,
 void _rfc2047_encode_string (char **pd, int encode_specials, int col)
 {
     char *e;
-    size_t elen;
+    ssize_t elen;
     const char *charsets;
 
     if (!Charset || !*pd)
@@ -748,7 +762,7 @@ void rfc2047_decode (char **pd)
                 }
                 if (ascii_strcasecmp (AssumedCharset, "us-ascii")) {
                     char *t;
-                    size_t tlen;
+                    ssize_t tlen;
 
                     t = p_dupstr(s, n);
                     if (mutt_convert_nonmime_string (&t) == 0) {
@@ -770,7 +784,7 @@ void rfc2047_decode (char **pd)
         }
 
         if (p != s) {
-            n = (size_t) (p - s);
+            n = (p - s);
             /* ignore spaces between encoded words
              * and linear white spaces between encoded word and *text */
             if (!option (OPTSTRICTMIME)) {
@@ -813,32 +827,31 @@ void rfc2047_decode (char **pd)
     str_adjust (pd);
 }
 
-void rfc2047_decode_adrlist (address_t * a)
+void rfc2047_decode_adrlist(address_t *a)
 {
     while (a) {
         if (a->personal)
-            rfc2047_decode (&a->personal);
+            rfc2047_decode(&a->personal);
         a = a->next;
     }
 }
 
-void rfc2047_decode_envelope (ENVELOPE* e) {
-
-    if (!e)
-        return;
+void rfc2047_decode_envelope(ENVELOPE* e)
+{
+    assert (e);
 
     /* do RFC2047 decoding */
-    rfc2047_decode_adrlist (e->from);
-    rfc2047_decode_adrlist (e->to);
-    rfc2047_decode_adrlist (e->cc);
-    rfc2047_decode_adrlist (e->bcc);
-    rfc2047_decode_adrlist (e->reply_to);
-    rfc2047_decode_adrlist (e->mail_followup_to);
-    rfc2047_decode_adrlist (e->return_path);
-    rfc2047_decode_adrlist (e->sender);
+    rfc2047_decode_adrlist(e->from);
+    rfc2047_decode_adrlist(e->to);
+    rfc2047_decode_adrlist(e->cc);
+    rfc2047_decode_adrlist(e->bcc);
+    rfc2047_decode_adrlist(e->reply_to);
+    rfc2047_decode_adrlist(e->mail_followup_to);
+    rfc2047_decode_adrlist(e->return_path);
+    rfc2047_decode_adrlist(e->sender);
 
     if (e->subject) {
-        rfc2047_decode (&e->subject);
-        mutt_adjust_subject (e);
+        rfc2047_decode(&e->subject);
+        mutt_adjust_subject(e);
     }
 }