X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=lib-mime%2Frfc2231.c;h=e7c10533e40bb0367a0641de209641d673c37928;hp=b21c4254c479a1938654a17d73cf0f275f675f66;hb=0f6739c5be4203bec0fa32962e6ab13349da703b;hpb=2a06362a155582cd59ae2ef6f0df71694a7eede3 diff --git a/lib-mime/rfc2231.c b/lib-mime/rfc2231.c index b21c425..e7c1053 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,315 @@ #include -#include "mutt.h" #include "charset.h" -#include "rfc2047.h" -#include -#include -#include +typedef struct rfc2231_param { + struct rfc2231_param *next; -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) + char *attribute; + char *value; + int idx; + int encoded; +} rfc2231_param; + +DO_INIT(rfc2231_param, rfc2231_param); +static inline void rfc2231_param_wipe(rfc2231_param *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_param, rfc2231_param); +DO_DELETE(rfc2231_param, rfc2231_param); - -void rfc2231_decode_parameters (PARAMETER ** headp) +/* TODO: MC: replace with a str_unescape */ +static void rfc2231_decode_one(char *dst, const char *src) { - 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. - */ - - if (!headp) - return; - - purge_empty_parameters (headp); + 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++; + } + } - for (last = &head, p = *headp; p; p = q) { - q = p->next; + *dst = '\0'; +} - if (!(s = strchr (p->attribute, '*'))) { +/* read the 'foo' part into charset, and skip that */ +static char *rfc2231_get_charset(char *value, char *charset, size_t chslen) +{ + char *t, *u; - /* - * 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. - */ + t = strchr(value, '\''); + if (!t) { + charset[0] = '\0'; + return value; + } - 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); - } + *t = '\0'; + m_strcpy(charset, chslen, value); - *last = p; - last = &p->next; - p->next = NULL; + if ((u = strchr(t + 1, '\''))) { + return u + 1; + } else { + return t + 1; } - 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; +/* insert parameter into an ordered list. + * + * Primary sorting key: attribute + * Secondary sorting key: idx + * + * XXX: MC: looks very unclear to me + */ +static void +rfc2231_list_insert(rfc2231_param **list, rfc2231_param *par) +{ + int c; - dirty = 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); - } - } + while (*list) { + rfc2231_param *q = *list; - if (conthead) { - rfc2231_join_continuations (last, conthead); - dirty = 1; - } + list = &(*list)->next; - *headp = head; + c = m_strcmp(par->value, q->value); + if ((c > 0) || (c == 0 && par->idx >= q->idx)) + break; + } - if (dirty) - purge_empty_parameters (headp); + par->next = *list; + *list = par; } -static struct rfc2231_parameter *rfc2231_new_parameter (void) +static void purge_empty_parameters(PARAMETER **headp) { - return p_new(struct rfc2231_parameter, 1); + while (*headp) { + PARAMETER *p = *headp; + + if (!p->attribute || !p->value) { + *headp = p->next; + p->next = NULL; + parameter_delete(&p); + } else { + headp = &(*headp)->next; + } + } } -static void rfc2231_free_parameter (struct rfc2231_parameter **p) +/* process continuation parameters */ +/* XXX: MC: not read */ +static void +rfc2231_join_continuations(PARAMETER **head, rfc2231_param *par) { - if (*p) { - p_delete(&(*p)->attribute); - p_delete(&(*p)->value); - p_delete(p); - } + rfc2231_param *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_param_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 = parameter_new(); + (*head)->attribute = m_strdup(attribute); + (*head)->value = value; + head = &(*head)->next; + } + } } -static char *rfc2231_get_charset (char *value, char *charset, size_t chslen) +/****************************************************************************/ +/* Public API */ +/****************************************************************************/ + +/* XXX: MC: not read */ +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_param *conthead = NULL; + rfc2231_param *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; /* 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 (mime_which_token(AssumedCharset, -1) == MIME_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_param_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 */ +#define RFC2231_SPECIALS "@.,;:<>[]\\\"()?/= \t*'%" -static void rfc2231_join_continuations (PARAMETER ** head, - struct rfc2231_parameter *par) +int rfc2231_encode_string(char **s) { - 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; + char *charset = NULL; + char *e, *p, *t, *d = NULL; + int escapes = 0; + ssize_t dlen = 0; + + /* + * A shortcut to detect pure 7bit data. + * + * This should prevent the worst when character set handling is flawed. + */ + + for (p = *s; ; p++) { + if (*p & 0x80) + break; + if (!*p) + return 0; } - } -} -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'; + if (Charset && SendCharset) { + charset = mutt_choose_charset(Charset, SendCharset, + *s, m_strlen(*s), &d, &dlen); + } + + if (!charset) { + charset = m_strdup(Charset ? Charset : "unknown-8bit"); + d = *s; + dlen = m_strlen(d); + } - if (d != *pd) - p_delete(&d); - p_delete(pd); - *pd = e; - } - else if (d != *pd) { - p_delete(pd); - *pd = d; - } + for (p = d; *p; p++) { + if (*p < 0x20 || *p >= 0x7f || strchr(RFC2231_SPECIALS, *p)) { + ++escapes; + } + } + + e = p_new(char, dlen + 2 * escapes + m_strlen(charset) + 3); + + t = e + sprintf(e, "%s''", charset); + for (p = d; *p; p++) { + if (*p < 0x20 || *p >= 0x7f || strchr(RFC2231_SPECIALS, *p)) { + *t++ = '%'; + *t++ = __m_b36chars_upper[*p >> 4]; + *t++ = __m_b36chars_upper[*p & 0xf]; + } else { + *t++ = *p; + } + } + *t = '\0'; - p_delete(&charset); + if (d != *s) + p_delete(&d); + p_delete(s); + p_delete(&charset); - return encode; + *s = e; + return 1; }