From 86cf852af75aa1f893b25a5fd615ac1fdb1b6033 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 2 Nov 2006 00:43:44 +0100 Subject: [PATCH] more work in the lib-mime. begin to "rewr^H^Had" the code in rfc2231.c be more clever when we use hexval, it already does isxdigit job. Signed-off-by: Pierre Habouzit --- charset.h | 6 + gnupgparse.c | 2 - lib-lib/str.h | 3 +- lib-mime/Makefile.am | 1 + lib-mime/mime.h | 91 +++++++ lib-mime/rfc2231.c | 556 +++++++++++++++++++++---------------------- mutt.h | 8 +- rfc2047.c | 4 +- rfc2047.h | 2 + url.c | 5 +- 10 files changed, 377 insertions(+), 301 deletions(-) create mode 100644 lib-mime/mime.h diff --git a/charset.h b/charset.h index 9cbd2bd..f8fcc98 100644 --- a/charset.h +++ b/charset.h @@ -10,6 +10,12 @@ #ifndef _CHARSET_H #define _CHARSET_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mutt.h" + #ifdef HAVE_ICONV_H #include #endif diff --git a/gnupgparse.c b/gnupgparse.c index a05d2da..b9f00ba 100644 --- a/gnupgparse.c +++ b/gnupgparse.c @@ -42,8 +42,6 @@ #include "pgp.h" #include "charset.h" -/* for hexval */ - #include "lib/debug.h" /**************** diff --git a/lib-lib/str.h b/lib-lib/str.h index 88af4d7..e1b3511 100644 --- a/lib-lib/str.h +++ b/lib-lib/str.h @@ -44,8 +44,7 @@ extern char const __m_b64chars[64]; /****************************************************************************/ static inline int hexval(int c) { - int v = __m_strdigits[c]; - return !(c & ~127) && v < 16 ? v : -1; + return !(c & ~127) && __m_strdigits[c] < 16 ? __m_strdigits[c] : -1; } static inline int base64val(int c) { diff --git a/lib-mime/Makefile.am b/lib-mime/Makefile.am index 1e8cda2..97db918 100644 --- a/lib-mime/Makefile.am +++ b/lib-mime/Makefile.am @@ -4,3 +4,4 @@ libmime_a_SOURCES = mime.h rfc2231.c noinst_HEADERS = mime.h +-include ../cflags.mk diff --git a/lib-mime/mime.h b/lib-mime/mime.h new file mode 100644 index 0000000..97b1611 --- /dev/null +++ b/lib-mime/mime.h @@ -0,0 +1,91 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * Copyright © 2006 Pierre Habouzit + */ + +/* + * Copyright notice from original mutt: + * Copyright (C) 1999-2000 Thomas Roessler + * + * This file is part of mutt-ng, see http://www.muttng.org/. + * It's licensed under the GNU General Public License, + * please see the file GPL in the top level source directory. + */ + +#ifndef MUTT_LIB_MIME_MIME_H +#define MUTT_LIB_MIME_MIME_H + +/* Content-Type */ +enum { + TYPEOTHER, + TYPEAUDIO, + TYPEAPPLICATION, + TYPEIMAGE, + TYPEMESSAGE, + TYPEMODEL, + TYPEMULTIPART, + TYPETEXT, + TYPEVIDEO, + TYPEANY +}; + +/* Content-Transfer-Encoding */ +enum { + ENCOTHER, + ENC7BIT, + ENC8BIT, + ENCQUOTEDPRINTABLE, + ENCBASE64, + ENCBINARY, + ENCUUENCODED +}; + +/* Content-Disposition values */ +enum { + DISPINLINE, + DISPATTACH, + DISPFORMDATA +}; + +typedef struct parameter { + char *attribute; + char *value; + struct parameter *next; +} PARAMETER; + +/* MIME encoding/decoding global vars */ + +#define is_multipart(x) \ + ((x)->type == TYPEMULTIPART \ + || ((x)->type == TYPEMESSAGE && (!strcasecmp((x)->subtype, "rfc822") \ + || !strcasecmp((x)->subtype, "news")))) + +extern const char *BodyTypes[]; +extern const char *BodyEncodings[]; + +#define TYPE(X) ((X->type == TYPEOTHER) && (X->xtype != NULL) ? X->xtype : BodyTypes[(X->type)]) +#define ENCODING(X) BodyEncodings[(X)] + +/* other MIME-related global variables */ +#ifndef _SENDLIB_C +extern char MimeSpecials[]; +#endif + +void rfc2231_decode_parameters (PARAMETER **); +int rfc2231_encode_string (char **); + +#endif /* MUTT_LIB_MIME_MIME_H */ diff --git a/lib-mime/rfc2231.c b/lib-mime/rfc2231.c index b21c425..b0fbd59 100644 --- a/lib-mime/rfc2231.c +++ b/lib-mime/rfc2231.c @@ -36,9 +36,9 @@ * */ -#if HAVE_CONFIG_H -# include "config.h" -#endif +#include +#include +#include #include #include @@ -46,334 +46,322 @@ #include -#include "mutt.h" #include "charset.h" #include "rfc2047.h" -#include -#include -#include +typedef struct rfc2231_parameter { + char *attribute; + char *value; + int idx; + int encoded; + struct rfc2231_parameter *next; +} rfc2231_parameter; -struct rfc2231_parameter { - char *attribute; - char *value; - int index; - int encoded; - struct rfc2231_parameter - *next; -}; - -static char *rfc2231_get_charset (char *, char *, size_t); -static struct rfc2231_parameter *rfc2231_new_parameter (void); -static void rfc2231_decode_one (char *, char *); -static void rfc2231_free_parameter (struct rfc2231_parameter **); -static void rfc2231_join_continuations (PARAMETER **, - struct rfc2231_parameter *); -static void rfc2231_list_insert (struct rfc2231_parameter **, - struct rfc2231_parameter *); - -static void purge_empty_parameters (PARAMETER ** headp) +DO_INIT(rfc2231_parameter, rfc2231_parameter); +static inline void rfc2231_parameter_wipe(rfc2231_parameter *param) { - PARAMETER *p, *q, **last; - - for (last = headp, p = *headp; p; p = q) { - q = p->next; - if (!p->attribute || !p->value) { - *last = q; - p->next = NULL; - mutt_free_parameter (&p); - } - else - last = &p->next; - } + p_delete(¶m->attribute); + p_delete(¶m->value); } +DO_NEW(rfc2231_parameter, rfc2231_parameter); +DO_DELETE(rfc2231_parameter, rfc2231_parameter); -void rfc2231_decode_parameters (PARAMETER ** headp) +/* insert parameter into an ordered list. + * + * Primary sorting key: attribute + * Secondary sorting key: idx + */ +static void +rfc2231_list_insert(rfc2231_parameter **list, rfc2231_parameter *par) { - PARAMETER *head = NULL; - PARAMETER **last; - PARAMETER *p, *q; - - struct rfc2231_parameter *conthead = NULL; - struct rfc2231_parameter *conttmp; - - char *s, *t; - char charset[STRING]; - - int encoded; - int index; - short dirty = 0; /* set to 1 when we may have created - * empty parameters. - */ + rfc2231_parameter **last = list; + rfc2231_parameter *p = *list, *q; + int c; + + while (p) { + last = &p->next; + q = p; + p = p->next; + + c = m_strcmp(par->value, q->value); + if ((c > 0) || (c == 0 && par->idx >= q->idx)) + break; + } - if (!headp) - return; + par->next = p; + *last = par; +} - purge_empty_parameters (headp); - for (last = &head, p = *headp; p; p = q) { - q = p->next; +static void rfc2231_decode_one(char *dst, const char *src) +{ + while (*src) { + int h1, h2; + + if (*src == '%' + && (h1 = hexval(src[1])) >= 0 && (h2 = hexval(src[2])) >= 0) + { + *dst++ = (h1 << 4) | h2; + src += 3; + } else { + *dst++ = *src++; + } + } - if (!(s = strchr (p->attribute, '*'))) { + *dst = '\0'; +} - /* - * Using RFC 2047 encoding in MIME parameters is explicitly - * forbidden by that document. Nevertheless, it's being - * generated by some software, including certain Lotus Notes to - * Internet Gateways. So we actually decode it. - */ +/* ---------------- TODO FIXME READ MARK ---------------- */ - if (option (OPTRFC2047PARAMS) && p->value && strstr (p->value, "=?")) - rfc2047_decode (&p->value); - else if (!option (OPTSTRICTMIME)) { - if (ascii_strcasecmp (AssumedCharset, "us-ascii")) - mutt_convert_nonmime_string (&p->value); - } +static char *rfc2231_get_charset(char *value, char *charset, size_t chslen) +{ + char *t, *u; - *last = p; - last = &p->next; - p->next = NULL; + t = strchr(value, '\''); + if (!t) { + charset[0] = '\0'; + return value; } - else if (*(s + 1) == '\0') { - *s = '\0'; - - s = rfc2231_get_charset (p->value, charset, sizeof (charset)); - rfc2231_decode_one (p->value, s); - mutt_convert_string (&p->value, charset, Charset, M_ICONV_HOOK_FROM); - *last = p; - last = &p->next; - p->next = NULL; + *t = '\0'; + m_strcpy(charset, chslen, value); - dirty = 1; + if ((u = strchr(t + 1, '\''))) { + return u + 1; + } else { + return t + 1; } - else { - *s = '\0'; - s++; /* let s point to the first character of index. */ - for (t = s; *t && isdigit ((unsigned char) *t); t++); - encoded = (*t == '*'); - *t = '\0'; - - index = atoi (s); - - conttmp = rfc2231_new_parameter (); - conttmp->attribute = p->attribute; - conttmp->value = p->value; - conttmp->encoded = encoded; - conttmp->index = index; - - p->attribute = NULL; - p->value = NULL; - p_delete(&p); - - rfc2231_list_insert (&conthead, conttmp); - } - } +} - if (conthead) { - rfc2231_join_continuations (last, conthead); - dirty = 1; - } - *headp = head; +static void rfc2231_join_continuations(PARAMETER **, rfc2231_parameter *); - if (dirty) - purge_empty_parameters (headp); -} - -static struct rfc2231_parameter *rfc2231_new_parameter (void) +static void purge_empty_parameters (PARAMETER **headp) { - return p_new(struct rfc2231_parameter, 1); + PARAMETER *p, *q, **last; + + for (last = headp, p = *headp; p; p = q) { + q = p->next; + if (!p->attribute || !p->value) { + *last = q; + p->next = NULL; + mutt_free_parameter (&p); + } + else + last = &p->next; + } } -static void rfc2231_free_parameter (struct rfc2231_parameter **p) -{ - if (*p) { - p_delete(&(*p)->attribute); - p_delete(&(*p)->value); - p_delete(p); - } -} -static char *rfc2231_get_charset (char *value, char *charset, size_t chslen) +void rfc2231_decode_parameters (PARAMETER ** headp) { - char *t, *u; + PARAMETER *head = NULL; + PARAMETER **last; + PARAMETER *p, *q; - if (!(t = strchr (value, '\''))) { - charset[0] = '\0'; - return value; - } + rfc2231_parameter *conthead = NULL; + rfc2231_parameter *conttmp; - *t = '\0'; - m_strcpy(charset, chslen, value); + char *s, *t; + char charset[STRING]; - if ((u = strchr (t + 1, '\''))) - return u + 1; - else - return t + 1; -} + int encoded; + int idx; + short dirty = 0; /* set to 1 when we may have created + * empty parameters. + */ -static void rfc2231_decode_one (char *dest, char *src) -{ - char *d; - - for (d = dest; *src; src++) { - if (*src == '%' && - isxdigit ((unsigned char) *(src + 1)) && - isxdigit ((unsigned char) *(src + 2))) { - *d++ = (hexval (*(src + 1)) << 4) | (hexval (*(src + 2))); - src += 2; + if (!headp) + return; + + purge_empty_parameters (headp); + + for (last = &head, p = *headp; p; p = q) { + q = p->next; + + if (!(s = strchr (p->attribute, '*'))) { + + /* + * Using RFC 2047 encoding in MIME parameters is explicitly + * forbidden by that document. Nevertheless, it's being + * generated by some software, including certain Lotus Notes to + * Internet Gateways. So we actually decode it. + */ + + if (option (OPTRFC2047PARAMS) && p->value && strstr (p->value, "=?")) + rfc2047_decode (&p->value); + else if (!option (OPTSTRICTMIME)) { + if (ascii_strcasecmp (AssumedCharset, "us-ascii")) + mutt_convert_nonmime_string (&p->value); + } + + *last = p; + last = &p->next; + p->next = NULL; + } + else if (*(s + 1) == '\0') { + *s = '\0'; + + s = rfc2231_get_charset (p->value, charset, sizeof (charset)); + rfc2231_decode_one (p->value, s); + mutt_convert_string (&p->value, charset, Charset, M_ICONV_HOOK_FROM); + + *last = p; + last = &p->next; + p->next = NULL; + + dirty = 1; + } + else { + *s = '\0'; + s++; /* let s point to the first character of idx. */ + for (t = s; *t && isdigit ((unsigned char) *t); t++); + encoded = (*t == '*'); + *t = '\0'; + + idx = atoi (s); + + conttmp = rfc2231_parameter_new (); + conttmp->attribute = p->attribute; + conttmp->value = p->value; + conttmp->encoded = encoded; + conttmp->idx = idx; + + p->attribute = NULL; + p->value = NULL; + p_delete(&p); + + rfc2231_list_insert (&conthead, conttmp); + } } - else - *d++ = *src; - } - *d = '\0'; -} + if (conthead) { + rfc2231_join_continuations (last, conthead); + dirty = 1; + } -/* insert parameter into an ordered list. - * - * Primary sorting key: attribute - * Secondary sorting key: index - */ + *headp = head; -static void rfc2231_list_insert (struct rfc2231_parameter **list, - struct rfc2231_parameter *par) -{ - struct rfc2231_parameter **last = list; - struct rfc2231_parameter *p = *list, *q; - int c; - - while (p) { - last = &p->next; - q = p; - p = p->next; - - c = m_strcmp(par->value, q->value); - if ((c > 0) || (c == 0 && par->index >= q->index)) - break; - } - - par->next = p; - *last = par; + if (dirty) + purge_empty_parameters (headp); } /* process continuation parameters */ -static void rfc2231_join_continuations (PARAMETER ** head, - struct rfc2231_parameter *par) +static void +rfc2231_join_continuations(PARAMETER **head, rfc2231_parameter *par) { - struct rfc2231_parameter *q; - - char attribute[STRING]; - char charset[STRING]; - char *value = NULL; - char *valp; - int encoded; - - size_t l, vl; - - while (par) { - value = NULL; - l = 0; - - m_strcpy(attribute, sizeof(attribute), par->attribute); - - if ((encoded = par->encoded)) - valp = rfc2231_get_charset (par->value, charset, sizeof (charset)); - else - valp = par->value; - - do { - if (encoded && par->encoded) - rfc2231_decode_one (par->value, valp); - - vl = m_strlen(par->value); - - p_realloc(&value, l + vl + 1); - strcpy (value + l, par->value); /* __STRCPY_CHECKED__ */ - l += vl; - - q = par->next; - rfc2231_free_parameter (&par); - if ((par = q)) - valp = par->value; - } while (par && !m_strcmp(par->attribute, attribute)); - - if (value) { - if (encoded) - mutt_convert_string (&value, charset, Charset, M_ICONV_HOOK_FROM); - *head = mutt_new_parameter (); - (*head)->attribute = m_strdup(attribute); - (*head)->value = value; - head = &(*head)->next; + rfc2231_parameter *q; + + char attribute[STRING]; + char charset[STRING]; + char *value = NULL; + char *valp; + int encoded; + + size_t l, vl; + + while (par) { + value = NULL; + l = 0; + + m_strcpy(attribute, sizeof(attribute), par->attribute); + + if ((encoded = par->encoded)) + valp = rfc2231_get_charset (par->value, charset, sizeof (charset)); + else + valp = par->value; + + do { + if (encoded && par->encoded) + rfc2231_decode_one (par->value, valp); + + vl = m_strlen(par->value); + + p_realloc(&value, l + vl + 1); + strcpy (value + l, par->value); /* __STRCPY_CHECKED__ */ + l += vl; + + q = par->next; + rfc2231_parameter_delete (&par); + if ((par = q)) + valp = par->value; + } while (par && !m_strcmp(par->attribute, attribute)); + + if (value) { + if (encoded) + mutt_convert_string (&value, charset, Charset, M_ICONV_HOOK_FROM); + *head = mutt_new_parameter (); + (*head)->attribute = m_strdup(attribute); + (*head)->value = value; + head = &(*head)->next; + } } - } } int rfc2231_encode_string (char **pd) { - int ext = 0, encode = 0; - char *charset, *s, *t, *e, *d = 0; - size_t slen, dlen = 0; - - /* - * A shortcut to detect pure 7bit data. - * - * This should prevent the worst when character set handling - * is flawed. - */ - - for (s = *pd; *s; s++) - if (*s & 0x80) - break; - - if (!*s) - return 0; - - if (!Charset || !SendCharset || - !(charset = mutt_choose_charset (Charset, SendCharset, - *pd, m_strlen(*pd), &d, &dlen))) { - charset = m_strdup(Charset ? Charset : "unknown-8bit"); - d = *pd; - dlen = m_strlen(d); - } - - if (!mutt_is_us_ascii (charset)) - encode = 1; - - for (s = d, slen = dlen; slen; s++, slen--) - if (*s < 0x20 || *s >= 0x7f) - encode = 1, ++ext; - else if (strchr (MimeSpecials, *s) || strchr ("*'%", *s)) - ++ext; - - if (encode) { - e = p_new(char, dlen + 2 * ext + m_strlen(charset) + 3); - sprintf (e, "%s''", charset); /* __SPRINTF_CHECKED__ */ - t = e + m_strlen(e); - for (s = d, slen = dlen; slen; s++, slen--) - if (*s < 0x20 || *s >= 0x7f || - strchr (MimeSpecials, *s) || strchr ("*'%", *s)) { - sprintf (t, "%%%02X", (unsigned char) *s); - t += 3; - } - else - *t++ = *s; - *t = '\0'; + int ext = 0, encode = 0; + char *charset, *s, *t, *e, *d = 0; + size_t slen, dlen = 0; + + /* + * A shortcut to detect pure 7bit data. + * + * This should prevent the worst when character set handling + * is flawed. + */ + + for (s = *pd; *s; s++) + if (*s & 0x80) + break; + + if (!*s) + return 0; + + if (!Charset || !SendCharset || + !(charset = mutt_choose_charset (Charset, SendCharset, + *pd, m_strlen(*pd), &d, &dlen))) { + charset = m_strdup(Charset ? Charset : "unknown-8bit"); + d = *pd; + dlen = m_strlen(d); + } + + if (!mutt_is_us_ascii (charset)) + encode = 1; - if (d != *pd) - p_delete(&d); - p_delete(pd); - *pd = e; - } - else if (d != *pd) { - p_delete(pd); - *pd = d; - } + for (s = d, slen = dlen; slen; s++, slen--) + if (*s < 0x20 || *s >= 0x7f) + encode = 1, ++ext; + else if (strchr (MimeSpecials, *s) || strchr ("*'%", *s)) + ++ext; + + if (encode) { + e = p_new(char, dlen + 2 * ext + m_strlen(charset) + 3); + sprintf (e, "%s''", charset); /* __SPRINTF_CHECKED__ */ + t = e + m_strlen(e); + for (s = d, slen = dlen; slen; s++, slen--) + if (*s < 0x20 || *s >= 0x7f || + strchr (MimeSpecials, *s) || strchr ("*'%", *s)) { + sprintf (t, "%%%02X", (unsigned char) *s); + t += 3; + } + else + *t++ = *s; + *t = '\0'; + + if (d != *pd) + p_delete(&d); + p_delete(pd); + *pd = e; + } + else if (d != *pd) { + p_delete(pd); + *pd = d; + } - p_delete(&charset); + p_delete(&charset); - return encode; + return encode; } diff --git a/mutt.h b/mutt.h index 10e6c0c..75b6796 100644 --- a/mutt.h +++ b/mutt.h @@ -45,6 +45,8 @@ #include #include +#include + #include "rfc822.h" #include "charset.h" #include "lib/rx.h" @@ -565,12 +567,6 @@ typedef struct envelope { unsigned int refs_changed:1; /* References changed to break thread */ } ENVELOPE; -typedef struct parameter { - char *attribute; - char *value; - struct parameter *next; -} PARAMETER; - /* Information that helps in determing the Content-* of an attachment */ typedef struct content { long hibin; /* 8-bit characters */ diff --git a/rfc2047.c b/rfc2047.c index d8e4a5d..23fffd4 100644 --- a/rfc2047.c +++ b/rfc2047.c @@ -583,9 +583,7 @@ static int rfc2047_decode_word (char *d, const char *s, size_t len) for (; pp < pp1; pp++) { if (*pp == '_') *pd++ = ' '; - else if (*pp == '=' && - (!(pp[1] & ~127) && hexval (pp[1]) != -1) && - (!(pp[2] & ~127) && hexval (pp[2]) != -1)) { + else if (*pp == '=' && hexval(pp[1]) >= 0 && hexval(pp[2]) >= 0) { *pd++ = (hexval (pp[1]) << 4) | hexval (pp[2]); pp += 2; } diff --git a/rfc2047.h b/rfc2047.h index e05e558..670d299 100644 --- a/rfc2047.h +++ b/rfc2047.h @@ -7,6 +7,8 @@ * please see the file GPL in the top level source directory. */ +#include "mutt.h" + char *mutt_choose_charset (const char *fromcode, const char *charsets, char *u, size_t ulen, char **d, size_t * dlen); diff --git a/url.c b/url.c index 55204c5..9ca480b 100644 --- a/url.c +++ b/url.c @@ -50,10 +50,7 @@ static void url_pct_decode (char *s) return; for (d = s; *s; s++) { - if (*s == '%' && s[1] && s[2] && - isxdigit ((unsigned char) s[1]) && - isxdigit ((unsigned char) s[2]) && - hexval (s[1]) >= 0 && hexval (s[2]) >= 0) { + if (*s == '%' && hexval (s[1]) >= 0 && hexval (s[2]) >= 0) { *d++ = (hexval (s[1]) << 4) | (hexval (s[2])); s += 2; } -- 2.20.1