diff options
author | Thomas Roessler <roessler@does-not-exist.org> | 1999-07-26 12:30:54 +0000 |
---|---|---|
committer | Thomas Roessler <roessler@does-not-exist.org> | 1999-07-26 12:30:54 +0000 |
commit | b2ab265dd42ff9672e6c7a01a480af2277c38a7a (patch) | |
tree | 6c894114a5b6ac04a24c5f971311276cc43d805c /rfc2231.c | |
parent | ba321dc70c7547bf0b13f32b1bf21c8b72cc36a5 (diff) |
Implement RFC 2231.
Diffstat (limited to 'rfc2231.c')
-rw-r--r-- | rfc2231.c | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/rfc2231.c b/rfc2231.c new file mode 100644 index 00000000..2ef80b14 --- /dev/null +++ b/rfc2231.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) 1999 Thomas Roessler <roessler@guug.de> + * + * 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., 675 Mass Ave, Cambridge, MA + * 02139, USA. + */ + +/* + * Yet another MIME encoding for header data. This time, it's + * parameters, specified in RFC 2231, and modeled after the + * encoding used in URLs. + * + * Additionally, continuations and encoding are mixed in an, errrm, + * interesting manner. + * + */ + +#include "mutt.h" +#include "mime.h" +#include "charset.h" +#include "rfc2047.h" +#include "rfc2231.h" + +#include <ctype.h> +#include <string.h> +#include <stdlib.h> + +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 *, 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 *); + +void rfc2231_decode_parameters (PARAMETER **headp) +{ + 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; + + if (!headp) return; + + 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) && strstr (p->value, "=?")) + rfc2047_decode (p->value, p->value, strlen (p->value) + 1); + + *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, charset); + + *last = p; + last = &p->next; + p->next = NULL; + } + else + { + *s = '\0'; s++; /* let s point to the first character of index. */ + for (t = s; *t && isdigit (*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; + safe_free ((void **) &p); + + rfc2231_list_insert (&conthead, conttmp); + + } + } + + if (conthead) + rfc2231_join_continuations (last, conthead); + + *headp = head; +} + +static struct rfc2231_parameter *rfc2231_new_parameter (void) +{ + return safe_calloc (sizeof (struct rfc2231_parameter), 1); +} + +static void rfc2231_free_parameter (struct rfc2231_parameter **p) +{ + if (*p) + { + safe_free ((void **) &(*p)->attribute); + safe_free ((void **) &(*p)->value); + safe_free ((void **) p); + } +} + +static char *rfc2231_get_charset (char *value, char *charset, size_t chslen) +{ + char *t, *u; + + if (!(t = strchr (value, '\''))) + { + charset[0] = '\0'; + return value; + } + + *t = '\0'; + strfcpy (charset, value, chslen); + + if ((u = strchr (t + 1, '\''))) + return u + 1; + else + return t + 1; +} + +static void rfc2231_decode_one (char *dest, char *src, char *chs) +{ + char *d; + + for (d = dest; *src; src++) + { + if (*src == '%' && isxdigit (*(src + 1)) && isxdigit (*(src + 2))) + { + *d++ = (hexval (*(src + 1)) << 4) | (hexval (*(src + 2))); + src += 2; + } + else + *d++ = *src; + } + + *d = '\0'; + + if (chs && strcmp (chs, "us-ascii") && strcmp (chs, Charset)) + mutt_display_string (dest, mutt_get_translation (chs, Charset)); +} + +/* insert parameter into an ordered list. + * + * Primary sorting key: attribute + * Secondary sorting key: index + */ + +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 = strcmp (par->value, q->value); + if ((c > 0) || (c == 0 && par->index >= q->index)) + break; + } + + par->next = p; + *last = par; +} + +/* process continuation parameters */ + +static void rfc2231_join_continuations (PARAMETER **head, + struct 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; + + strfcpy (attribute, par->attribute, sizeof (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, charset); + + vl = strlen (par->value); + + safe_realloc ((void **) &value, l + vl + 1); + strcpy (value + l, par->value); + l += vl; + + q = par->next; + rfc2231_free_parameter (&par); + if ((par = q)) + valp = par->value; + } while (par && !strcmp (par->attribute, attribute)); + + if (value) + { + *head = mutt_new_parameter (); + (*head)->attribute = safe_strdup (attribute); + (*head)->value = value; + head = &(*head)->next; + } + } +} + +int rfc2231_encode (char *dest, size_t l, unsigned char *src) +{ + char buff[LONG_STRING]; + unsigned char *s; + char *t; + int encode = 0; + + for (s = src; *s && !encode; s++) + { + if (*s & 0x80) + encode = 1; + } + + if (!encode) + strfcpy (dest, (char *) src, l); + else + { + for (s = src, t = buff; *s && (t - buff) < sizeof (buff) - 4; s++) + { + if ((*s & 0x80) || *s == '\'') + { + sprintf ((char *) t, "%%%02x", (unsigned int) *s); + t += 3; + } + else + *t++ = *s; + } + *t = '\0'; + + if (Charset && SendCharset && mutt_strcasecmp (Charset, SendCharset)) + mutt_display_string (buff, mutt_get_translation (Charset, SendCharset)); + + snprintf (dest, l, "%s''%s", SendCharset ? SendCharset : + (Charset ? Charset : "unknown-8bit"), buff); + } + + return encode; +} + |