From: Pierre Habouzit Date: Fri, 24 Nov 2006 00:39:11 +0000 (+0100) Subject: fix completely braindead rfc2047 parsing, that choke on something as X-Git-Url: http://git.madism.org/?a=commitdiff_plain;h=09a7c8b5bbcc1630207e799d07e4ac438c9c3f1c;p=apps%2Fmadmutt.git fix completely braindead rfc2047 parsing, that choke on something as stupid as: =?UTF-8?Q?foobar??= this is totally valid, and we choke on this because of the ? in that string. it's not ambiguous, so deal with it correctly, and get "foobar?" as a result instead of =?UTF-8?....?= --- diff --git a/lib-mime/rfc2047.c b/lib-mime/rfc2047.c index 208d932..8d444bc 100644 --- a/lib-mime/rfc2047.c +++ b/lib-mime/rfc2047.c @@ -595,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: - p_delete(&charset); - return -1; + default: + 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) + if (*charset) mutt_convert_string(&d0, charset, Charset, M_ICONV_HOOK_FROM); m_strcpy(d, len, d0); - p_delete(&charset); p_delete(&d0); return 0; } @@ -702,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++; } @@ -843,7 +834,7 @@ void rfc2047_decode(char **pd) } } - rfc2047_decode_word(d, dlen, p); + rfc2047_decode_word(d, dlen, p, q); found_encoded = 1; s = q; while (*d && dlen)