X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=lib-mime%2Frfc2047.c;h=264caff2db57fb85fbba4715d0731ec6a8c0dd2a;hp=6e79beec9e0c8fe0ea05b562c15d7d162627e53f;hb=05a3bbbe420e4afc76e0eea24ce32f859405dc4a;hpb=83532821ae9fab034d0d630b78330c9ea4ff4cf3 diff --git a/lib-mime/rfc2047.c b/lib-mime/rfc2047.c index 6e79bee..264caff 100644 --- a/lib-mime/rfc2047.c +++ b/lib-mime/rfc2047.c @@ -33,10 +33,10 @@ #include -#include "mutt.h" #include "charset.h" #include "thread.h" +#include #include #include #include @@ -49,19 +49,14 @@ #ifdef NDEBUG #define assert(x) #else -#include #endif #define ENCWORD_LEN_MAX 75 #define ENCWORD_LEN_MIN 9 /* m_strlen("=?.?.?.?=") */ #define HSPACE(x) ((x) == '\0' || (x) == ' ' || (x) == '\t') - #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 @@ -70,12 +65,11 @@ typedef size_t (*encoder_t) (char *, const char *, size_t, */ static ssize_t convert_string(const char *from, const char *f, ssize_t flen, - const char *to, char **t, size_t *tlen) + const char *to, char **t, ssize_t *tlen) { iconv_t cd; char *buf, *ob; - size_t obl, n; - int e; + ssize_t obl, n; cd = mutt_iconv_open(to, from, 0); @@ -87,109 +81,134 @@ convert_string(const char *from, const char *f, ssize_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]; + + if (dst && dlen) { + *dst = res; + *dlen = reslen; + } else { + p_delete(&res); + } - mutt_canonical_charset(canonical_buff, sizeof(canonical_buff), tocode); - m_strreplace(&tocode, canonical_buff); + 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 */ +/****************************************************************************/ + +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)]; @@ -197,32 +216,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; } @@ -235,95 +258,96 @@ 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, - const char *fromcode, const char *tocode, - encoder_t * encoder, size_t * wlen) +static size_t try_block(const char *d, ssize_t dlen, + const char *fromcode, const char *tocode, + 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; - 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); - if (my_iconv(cd, &ib, &ibl, &ob, &obl) == (size_t) (-1) || - my_iconv(cd, 0, 0, &ob, &obl) == (size_t) (-1)) { - assert (errno == E2BIG); - iconv_close (cd); - assert (ib > d); + 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 && ib > d); + iconv_close(cd); return (ib - d == dlen) ? dlen : ib - d + 1; } iconv_close (cd); - } - else { - if (dlen > sizeof (buf1) - m_strlen(tocode)) - return sizeof (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 (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) { + *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; } /* * 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, - const char *fromcode, const char *tocode, - encoder_t encoder) +static size_t +encode_block(char *s, char *d, ssize_t dlen, + const char *fromcode, const char *tocode, 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); + cd = mutt_iconv_open(tocode, fromcode, 0); assert (cd != (iconv_t) (-1)); - ib = d, ibl = dlen, ob = buf1, obl = sizeof (buf1) - m_strlen(tocode); + 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); + return (*encoder)(s, buf1, ob - buf1, tocode); + } else { + return (*encoder)(s, d, dlen, tocode); } - else - return (*encoder) (s, d, dlen, tocode); } /* @@ -332,24 +356,25 @@ 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"); + int utf8 = mime_which_token(fromcode, -1) == MIME_UTF_8; n = dlen; for (;;) { assert (d + n > d); - nn = try_block (d, n, fromcode, tocode, encoder, wlen); + nn = try_block(d, n, fromcode, tocode, encoder, wlen); if (!nn && (col + *wlen <= ENCWORD_LEN_MAX + 1 || n <= 1)) break; n = (nn ? nn : n) - 1; assert (n > 0); - if (utf8) - while (n > 1 && CONTINUATION_BYTE (d[n])) + if (utf8) { + while (n > 1 && CONTINUATION_BYTE(d[n])) --n; + } } return n; } @@ -364,30 +389,31 @@ 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, - const char *fromcode, const char *charsets, - char **e, size_t * elen, char *specials) +/*** XXX: simplify that one day ***/ +static int rfc2047_encode(const char *d, ssize_t dlen, int col, + const char *fromcode, const char *charsets, + char **e, ssize_t *elen, const char *specials) { int ret = 0; char *buf; - size_t bufpos, buflen; - char *u, *t0, *t1, *t; - char *s0, *s1; - size_t ulen, r, n, wlen; - encoder_t encoder; + ssize_t bufpos, buflen; + char *u, *t; + char *s0, *s1, *t0, *t1; char *tocode1 = 0; const char *tocode; const char *icode = "UTF-8"; + ssize_t ulen, r, n, wlen; + encoder_t *encoder; /* Try to convert to UTF-8. */ if (convert_string(fromcode, d, dlen, icode, &u, &ulen)) { ret = 1; - icode = 0; + icode = NULL; u = p_dupstr(d, ulen = dlen); } /* Find earliest and latest things we must encode. */ - s0 = s1 = t0 = t1 = 0; + s0 = s1 = t0 = t1 = NULL; for (t = u; t < u + ulen; t++) { if ((*t & 0x80) || (*t == '=' && t[1] == '?' && (t == u || HSPACE (*(t - 1))))) { @@ -418,14 +444,15 @@ 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; } /* Hack to avoid labelling 8-bit data as us-ascii. */ - if (!icode && mutt_is_us_ascii (tocode)) + if (!icode && mutt_is_us_ascii(tocode)) tocode = "unknown-8bit"; /* Adjust t0 for maximum length of line. */ @@ -438,27 +465,29 @@ static int rfc2047_encode (const char *d, size_t dlen, int col, /* Adjust t0 until we can encode a character after a space. */ for (; t0 > u; t0--) { - if (!HSPACE (*(t0 - 1))) + if (!HSPACE(t0[-1])) continue; t = t0 + 1; - if (icode) - while (t < u + ulen && CONTINUATION_BYTE (*t)) + if (icode) { + while (t < u + ulen && CONTINUATION_BYTE(*t)) ++t; - if (!try_block (t0, t - t0, icode, tocode, &encoder, &wlen) && - col + (t0 - u) + wlen <= ENCWORD_LEN_MAX + 1) + } + if (!try_block(t0, t - t0, icode, tocode, &encoder, &wlen) + && col + (t0 - u) + wlen <= ENCWORD_LEN_MAX + 1) break; } /* Adjust t1 until we can encode a character before a space. */ for (; t1 < u + ulen; t1++) { - if (!HSPACE (*t1)) + if (!HSPACE(*t1)) continue; t = t1 - 1; - if (icode) - while (CONTINUATION_BYTE (*t)) + if (icode) { + while (CONTINUATION_BYTE(*t)) --t; - if (!try_block (t, t1 - t, icode, tocode, &encoder, &wlen) && - 1 + wlen + (u + ulen - t1) <= ENCWORD_LEN_MAX + 1) + } + if (!try_block (t, t1 - t, icode, tocode, &encoder, &wlen) + && 1 + wlen + (u + ulen - t1) <= ENCWORD_LEN_MAX + 1) break; } @@ -468,7 +497,7 @@ static int rfc2047_encode (const char *d, size_t dlen, int col, buflen = 2 * ulen; buf = p_new(char, buflen); bufpos = t0 - u; - memcpy (buf, u, t0 - u); + memcpy(buf, u, t0 - u); col += t0 - u; @@ -500,8 +529,8 @@ static int rfc2047_encode (const char *d, size_t dlen, int col, /* Add to output buffer. */ #define LINEBREAK "\n\t" - if (bufpos + wlen + m_strlen(LINEBREAK) > buflen) { - buflen = bufpos + wlen + m_strlen(LINEBREAK); + if (bufpos + wlen + 2 > buflen) { + buflen = bufpos + wlen + 2; p_realloc(&buf, buflen); } r = encode_block (buf + bufpos, t, n, icode, tocode, encoder); @@ -534,118 +563,132 @@ static int rfc2047_encode (const char *d, size_t dlen, int col, return ret; } -void _rfc2047_encode_string (char **pd, int encode_specials, 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) return; - charsets = SendCharset; - if (!charsets || !*charsets) - charsets = "UTF-8"; + charsets = m_strisempty(SendCharset) ? "UTF-8" : SendCharset; - rfc2047_encode (*pd, m_strlen(*pd), col, - Charset, charsets, &e, &elen, - encode_specials ? RFC822Specials : NULL); + rfc2047_encode(*pd, m_strlen(*pd), col, + Charset, charsets, &e, &elen, + encode_specials ? RFC822Specials : NULL); p_delete(pd); *pd = e; } void rfc2047_encode_string(char **pd) { - _rfc2047_encode_string(a, 0, 32); + _rfc2047_encode_string(pd, 0, 32); } -void rfc2047_encode_adrlist (address_t * addr, const char *tag) +void rfc2047_encode_adrlist(address_t *addr, const char *tag) { address_t *ptr = addr; int col = tag ? m_strlen(tag) + 2 : 32; while (ptr) { if (ptr->personal) - _rfc2047_encode_string (&ptr->personal, 1, col); + _rfc2047_encode_string(&ptr->personal, 1, col); ptr = ptr->next; } } -static int rfc2047_decode_word (char *d, const char *s, size_t len) + +/****************************************************************************/ +/* Decoding functions */ +/****************************************************************************/ + +/* decode one word into d[len] */ +static int rfc2047_decode_word(char *d, size_t len, const char *s) { - const char *pp, *pp1; - char *pd, *d0; - const char *t, *t1; - int enc = 0, count = 0; + const char *p, *eotoken; char *charset = NULL; + int enc = 0, count = 0; + char *d0; - pd = d0 = p_new(char, m_strlen(s)); + /* =?[QB]?cset?.?= */ + for (p = s; (eotoken = strchr(p, '?')); p = eotoken + 1) { + switch (++count) { + const char *t; + char *q; - for (pp = s; (pp1 = strchr (pp, '?')); pp = pp1 + 1) { - count++; - switch (count) { case 2: /* ignore language specification a la RFC 2231 */ - t = pp1; - if ((t1 = memchr (pp, '*', t - pp))) - t = t1; - charset = p_dupstr(pp, t - pp); + t = memchr(p, '*', eotoken - p) ?: eotoken; + charset = p_dupstr(p, t - p); break; + case 3: - if (toupper ((unsigned char) *pp) == 'Q') + switch (*p) { + case 'q': case 'Q': enc = ENCQUOTEDPRINTABLE; - else if (toupper ((unsigned char) *pp) == 'B') + break; + + case 'b': case 'B': enc = ENCBASE64; - else { + break; + + default: p_delete(&charset); - p_delete(&d0); - return (-1); + return -1; } break; + case 4: + d0 = q = p_new(char, m_strlen(s) + 1); + if (enc == ENCQUOTEDPRINTABLE) { - for (; pp < pp1; pp++) { - if (*pp == '_') - *pd++ = ' '; - else if (*pp == '=' && hexval(pp[1]) >= 0 && hexval(pp[2]) >= 0) { - *pd++ = (hexval (pp[1]) << 4) | hexval (pp[2]); - pp += 2; + 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++; } - else - *pd++ = *pp; } - *pd = 0; - } - else if (enc == ENCBASE64) { + *q = 0; + } else { /* enc == ENCBASE64 */ int c, b = 0, k = 0; - for (; pp < pp1; pp++) { - if (*pp == '=') + while (p < eotoken) { + if (*p == '=') break; - if ((c = base64val(*pp)) < 0) + + c = base64val(*p++); + if (c < 0) continue; + if (k + 6 >= 8) { k -= 2; - *pd++ = b | (c >> k); + *q++ = b | (c >> k); b = c << (8 - k); - } - else { + } else { b |= c << (k + 2); k += 6; } } - *pd = 0; + *q = 0; } break; } } if (charset) - mutt_convert_string (&d0, charset, Charset, M_ICONV_HOOK_FROM); + mutt_convert_string(&d0, charset, Charset, M_ICONV_HOOK_FROM); m_strcpy(d, len, d0); p_delete(&charset); p_delete(&d0); - return (0); + return 0; } /* @@ -654,50 +697,60 @@ static int rfc2047_decode_word (char *d, const char *s, size_t len) * must be B or Q. Also, we don't require the encoded word to be * separated by linear-white-space (section 5(1)). */ -static const char *find_encoded_word (const char *s, const char **x) +static const char *find_encoded_word(const char *s, const char **x) { - const char *p, *q; + const char *p; + + while ((p = strstr(s, "=?"))) { + s = p + 2; + while (0x20 < *s && *s < 0x7f && !strchr ("()<>@,;:\"/[]?.=", *s)) { + s++; + } - q = s; - while ((p = strstr (q, "=?"))) { - for (q = p + 2; - 0x20 < *q && *q < 0x7f && !strchr ("()<>@,;:\"/[]?.=", *q); q++); - if (q[0] != '?' || !strchr ("BbQq", q[1]) || q[2] != '?') + if (s[0] != '?' || !strchr("BbQq", s[1]) || s[2] != '?') continue; - for (q = q + 3; 0x20 <= *q && *q < 0x7f && *q != '?'; q++); - if (q[0] != '?' || q[1] != '=') { - --q; + + s += 3; + while (0x20 <= *s && *s < 0x7f && *s != '?') { + s++; + } + + if (s[0] != '?' || s[1] != '=') { + --s; continue; } - *x = q + 2; + *x = s + 2; return p; } - return 0; + return NULL; } /* return length of linear white space */ -static size_t lwslen (const char *s, size_t n) +static ssize_t lwslen(const char *s, ssize_t n) { - const char *p = s; - size_t len = n; + const char *p; + ssize_t len = n; if (n <= 0) return 0; - for (; p < s + n; p++) + for (p = s; p < s + n; p++) { if (!strchr (" \t\r\n", *p)) { - len = (size_t) (p - s); + len = p - s; break; } - if (strchr ("\r\n", *(p - 1))) /* LWS doesn't end with CRLF */ - len = (size_t) 0; + } + + if (p[-1] == '\r' || p[-1] == '\n') /* LWS cannot end with CRLF */ + return 0; + return len; } /* return length of linear white space : reverse */ -static size_t lwsrlen (const char *s, size_t n) +static ssize_t lwsrlen(const char *s, ssize_t n) { const char *p = s + n - 1; size_t len = n; @@ -705,28 +758,31 @@ static size_t lwsrlen (const char *s, size_t n) if (n <= 0) return 0; - if (strchr ("\r\n", *p)) /* LWS doesn't end with CRLF */ - return (size_t) 0; + if (*p == '\r' || *p == '\n') /* LWS doesn't end with CRLF */ + return 0; - for (; p >= s; p--) - if (!strchr (" \t\r\n", *p)) { - len = (size_t) (s + n - 1 - p); + while (p >= s) { + if (!strchr(" \t\r\n", *p)) { + len = s + n - 1 - p; break; } + p--; + } + return len; } /* try to decode anything that looks like a valid RFC2047 encoded * header field, ignoring RFC822 parsing rules */ -void rfc2047_decode (char **pd) +void rfc2047_decode(char **pd) { - const char *p, *q; - size_t m, n; - int found_encoded = 0; - char *d0, *d; + const int strict_mime = option(OPTSTRICTMIME); + const char *s = *pd; - size_t dlen; + char *d0, *d; + ssize_t dlen; + int found_encoded = 0; if (!s || !*s) return; @@ -735,108 +791,103 @@ void rfc2047_decode (char **pd) d = d0 = p_new(char, dlen + 1); while (*s && dlen > 0) { - if (!(p = find_encoded_word (s, &q))) { + const char *p, *q; + + p = find_encoded_word(s, &q); + + if (!p) { /* no encoded words */ - if (!option (OPTSTRICTMIME)) { + if (!strict_mime) { + ssize_t m, n; + n = m_strlen(s); - if (found_encoded && (m = lwslen (s, n)) != 0) { + if (found_encoded && (m = lwslen(s, n)) != 0) { if (m != n) - *d = ' ', d++, dlen--; + *d++ = ' ', dlen--; n -= m, s += m; } - if (ascii_strcasecmp (AssumedCharset, "us-ascii")) { + + if (mime_which_token(AssumedCharset, -1) == MIME_US_ASCII) { char *t; - size_t tlen; t = p_dupstr(s, n); - if (mutt_convert_nonmime_string (&t) == 0) { - tlen = m_strlen(t); - strncpy (d, t, tlen); - d += tlen; - } - else { - strncpy (d, s, n); - d += 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; } } - strncpy (d, s, dlen); - d += dlen; + d += m_strcpy(d, dlen, s); break; } if (p != s) { - n = (size_t) (p - s); + ssize_t m, n; + + n = (p - s); /* ignore spaces between encoded words * and linear white spaces between encoded word and *text */ - if (!option (OPTSTRICTMIME)) { - if (found_encoded && (m = lwslen (s, n)) != 0) { + if (!strict_mime) { + if (found_encoded && (m = lwslen(s, n)) != 0) { if (m != n) - *d = ' ', d++, dlen--; + *d++ = ' ', dlen--; n -= m, s += m; } - if ((m = n - lwsrlen (s, n)) != 0) { - if (m > dlen) - m = dlen; - memcpy (d, s, m); + if ((m = n - lwsrlen(s, n)) != 0) { + m = m_strncpy(d, dlen, s, m); d += m; dlen -= m; if (m != n) - *d = ' ', d++, dlen--; + *d++ = ' ', dlen--; } - } - else if (!found_encoded || strspn (s, " \t\r\n") != n) { - if (n > dlen) - n = dlen; - memcpy (d, s, n); + } else + if (!found_encoded || (ssize_t)strspn(s, " \t\r\n") != n) { + n = m_strncpy(d, dlen, s, n); d += n; dlen -= n; } } - rfc2047_decode_word (d, p, dlen); + rfc2047_decode_word(d, dlen, p); found_encoded = 1; s = q; - n = m_strlen(d); - dlen -= n; - d += n; + while (*d && dlen) + d++, dlen--; } - *d = 0; p_delete(pd); *pd = d0; - 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); } }