X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/b236a6a2a2ff899564b9a88cfc377c3de145e37e..975b8341cc7ff17cbe4a5900b6ed41c47cceed62:/uip/mhparse.c?ds=sidebyside diff --git a/uip/mhparse.c b/uip/mhparse.c index daf7c40c..9873e0b1 100644 --- a/uip/mhparse.c +++ b/uip/mhparse.c @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include #include #include @@ -30,12 +28,6 @@ extern int wcachesw; /* mhcachesbr.c */ int checksw = 0; /* check Content-MD5 field */ -/* - * Directory to place temp files. This must - * be set before these routines are called. - */ -char *tmp; - /* * These are for mhfixmsg to: * 1) Instruct parser not to detect invalid Content-Transfer-Encoding @@ -88,6 +80,19 @@ struct k2v SubApplication[] = { { NULL, APPLICATION_UNKNOWN } /* this one must be last! */ }; +/* + * Mapping of names of CTE types in mhbuild directives + */ +static struct k2v EncodingType[] = { + { "8bit", CE_8BIT }, + { "qp", CE_QUOTED }, + { "q-p", CE_QUOTED }, + { "quoted-printable", CE_QUOTED }, + { "b64", CE_BASE64 }, + { "base64", CE_BASE64 }, + { NULL, 0 }, +}; + /* mhcachesbr.c */ int find_cache (CT, int, int *, char *, char *, int); @@ -202,23 +207,23 @@ parse_mime (char *file) if ((is_stdin = !(strcmp (file, "-")))) { char *tfile = m_mktemp2(NULL, invo_name, NULL, &fp); if (tfile == NULL) { - advise("mhparse", "unable to create temporary file"); + advise("mhparse", "unable to create temporary file in %s", + get_temp_dir()); return NULL; } file = add (tfile, NULL); - chmod (file, 0600); while (fgets (buffer, sizeof(buffer), stdin)) fputs (buffer, fp); fflush (fp); if (ferror (stdin)) { - unlink (file); + (void) m_unlink (file); advise ("stdin", "error reading"); return NULL; } if (ferror (fp)) { - unlink (file); + (void) m_unlink (file); advise (file, "error writing"); return NULL; } @@ -230,7 +235,7 @@ parse_mime (char *file) if (!(ct = get_content (fp, file, 1))) { if (is_stdin) - unlink (file); + (void) m_unlink (file); advise (NULL, "unable to decode %s", file); return NULL; } @@ -846,6 +851,47 @@ magic_skip: cp++; } + /* + * Get any extension directives (right now just the content transfer + * encoding, but maybe others) that we care about. + */ + + if (magic && *cp == '*') { + /* + * See if it's a CTE we match on + */ + struct k2v *kv; + + dp = ++cp; + while (*cp != '\0' && ! isspace((unsigned char) *cp)) + cp++; + + if (dp == cp) { + advise (NULL, "invalid null transfer encoding specification"); + return NOTOK; + } + + if (*cp != '\0') + *cp++ = '\0'; + + ct->c_reqencoding = CE_UNKNOWN; + + for (kv = EncodingType; kv->kv_key; kv++) { + if (strcasecmp(kv->kv_key, dp) == 0) { + ct->c_reqencoding = kv->kv_value; + break; + } + } + + if (ct->c_reqencoding == CE_UNKNOWN) { + advise (NULL, "invalid CTE specification: \"%s\"", dp); + return NOTOK; + } + + while (isspace ((unsigned char) *cp)) + cp++; + } + /* * Check if anything is left over */ @@ -1631,7 +1677,7 @@ static int openBase64 (CT ct, char **file) { int bitno, cc, digested; - int fd, len, skip, own_ct_fp = 0; + int fd, len, skip, own_ct_fp = 0, text = ct->c_type == CT_TEXT; uint32_t bits; unsigned char value, b; char *cp, *ep, buffer[BUFSIZ]; @@ -1654,7 +1700,6 @@ openBase64 (CT ct, char **file) } if (*file == NULL) { - ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL); ce->ce_unlink = 1; } else { ce->ce_file = add (*file, NULL); @@ -1672,19 +1717,22 @@ openBase64 (CT ct, char **file) cp = context_find (buffer); } if (cp != NULL && *cp != '\0') { - if (ce->ce_unlink) { - /* Temporary file already exists, so we rename to - version with extension. */ - char *file_org = strdup(ce->ce_file); - ce->ce_file = add (cp, ce->ce_file); - if (rename(file_org, ce->ce_file)) { - adios (ce->ce_file, "unable to rename %s to ", file_org); - } - free(file_org); - - } else { - ce->ce_file = add (cp, ce->ce_file); - } + if (ce->ce_unlink) { + /* Create temporary file with filename extension. */ + if ((ce->ce_file = m_mktemps(invo_name, cp, NULL, NULL)) == NULL) { + adios(NULL, "unable to create temporary file in %s", + get_temp_dir()); + } + } else { + ce->ce_file = add (cp, ce->ce_file); + } + } else if (*file == NULL) { + char *tempfile; + if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) { + adios(NULL, "unable to create temporary file in %s", + get_temp_dir()); + } + ce->ce_file = add (tempfile, NULL); } if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { @@ -1748,17 +1796,20 @@ openBase64 (CT ct, char **file) test_end: if ((bitno -= 6) < 0) { b = (bits >> 16) & 0xff; - putc ((char) b, ce->ce_fp); + if (!text || b != '\r') + putc ((char) b, ce->ce_fp); if (digested) MD5Update (&mdContext, &b, 1); if (skip < 2) { b = (bits >> 8) & 0xff; - putc ((char) b, ce->ce_fp); + if (! text || b != '\r') + putc ((char) b, ce->ce_fp); if (digested) MD5Update (&mdContext, &b, 1); if (skip < 1) { b = bits & 0xff; - putc ((char) b, ce->ce_fp); + if (! text || b != '\r') + putc ((char) b, ce->ce_fp); if (digested) MD5Update (&mdContext, &b, 1); } @@ -1888,7 +1939,6 @@ openQuoted (CT ct, char **file) } if (*file == NULL) { - ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL); ce->ce_unlink = 1; } else { ce->ce_file = add (*file, NULL); @@ -1906,19 +1956,22 @@ openQuoted (CT ct, char **file) cp = context_find (buffer); } if (cp != NULL && *cp != '\0') { - if (ce->ce_unlink) { - /* Temporary file already exists, so we rename to - version with extension. */ - char *file_org = strdup(ce->ce_file); - ce->ce_file = add (cp, ce->ce_file); - if (rename(file_org, ce->ce_file)) { - adios (ce->ce_file, "unable to rename %s to ", file_org); - } - free(file_org); - - } else { - ce->ce_file = add (cp, ce->ce_file); - } + if (ce->ce_unlink) { + /* Create temporary file with filename extension. */ + if ((ce->ce_file = m_mktemps(invo_name, cp, NULL, NULL)) == NULL) { + adios(NULL, "unable to create temporary file in %s", + get_temp_dir()); + } + } else { + ce->ce_file = add (cp, ce->ce_file); + } + } else if (*file == NULL) { + char *tempfile; + if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) { + adios(NULL, "unable to create temporary file in %s", + get_temp_dir()); + } + ce->ce_file = add (tempfile, NULL); } if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { @@ -2112,7 +2165,6 @@ open7Bit (CT ct, char **file) } if (*file == NULL) { - ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL); ce->ce_unlink = 1; } else { ce->ce_file = add (*file, NULL); @@ -2130,19 +2182,22 @@ open7Bit (CT ct, char **file) cp = context_find (buffer); } if (cp != NULL && *cp != '\0') { - if (ce->ce_unlink) { - /* Temporary file already exists, so we rename to - version with extension. */ - char *file_org = strdup(ce->ce_file); - ce->ce_file = add (cp, ce->ce_file); - if (rename(file_org, ce->ce_file)) { - adios (ce->ce_file, "unable to rename %s to ", file_org); - } - free(file_org); - - } else { - ce->ce_file = add (cp, ce->ce_file); - } + if (ce->ce_unlink) { + /* Create temporary file with filename extension. */ + if ((ce->ce_file = m_mktemps(invo_name, cp, NULL, NULL)) == NULL) { + adios(NULL, "unable to create temporary file in %s", + get_temp_dir()); + } + } else { + ce->ce_file = add (cp, ce->ce_file); + } + } else if (*file == NULL) { + char *tempfile; + if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) { + adios(NULL, "unable to create temporary file in %s", + get_temp_dir()); + } + ce->ce_file = add (tempfile, NULL); } if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { @@ -2363,12 +2418,12 @@ openFile (CT ct, char **file) if (ferror (gp)) { admonish (ce->ce_file, "error reading"); - unlink (cachefile); + (void) m_unlink (cachefile); } else if (ferror (fp)) { admonish (cachefile, "error writing"); - unlink (cachefile); + (void) m_unlink (cachefile); } fclose (fp); } @@ -2501,8 +2556,14 @@ openFTP (CT ct, char **file) ce->ce_file = add (*file, NULL); else if (caching) ce->ce_file = add (cachefile, NULL); - else - ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL); + else { + char *tempfile; + if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) { + adios(NULL, "unable to create temporary file in %s", + get_temp_dir()); + } + ce->ce_file = add (tempfile, NULL); + } if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { content_error (ce->ce_file, ct, "unable to fopen for reading/writing"); @@ -2573,12 +2634,12 @@ openFTP (CT ct, char **file) if (ferror (gp)) { admonish (ce->ce_file, "error reading"); - unlink (cachefile); + (void) m_unlink (cachefile); } else if (ferror (fp)) { admonish (cachefile, "error writing"); - unlink (cachefile); + (void) m_unlink (cachefile); } fclose (fp); } @@ -2690,7 +2751,12 @@ openMail (CT ct, char **file) } if (*file == NULL) { - ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL); + char *tempfile; + if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) { + adios(NULL, "unable to create temporary file in %s", + get_temp_dir()); + } + ce->ce_file = add (tempfile, NULL); ce->ce_unlink = 1; } else { ce->ce_file = add (*file, NULL); @@ -2783,8 +2849,14 @@ openURL (CT ct, char **file) ce->ce_file = add(*file, NULL); else if (caching) ce->ce_file = add(cachefile, NULL); - else - ce->ce_file = add(m_mktemp(tmp, NULL, NULL), NULL); + else { + char *tempfile; + if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) { + adios(NULL, "unable to create temporary file in %s", + get_temp_dir()); + } + ce->ce_file = add (tempfile, NULL); + } if ((ce->ce_fp = fopen(ce->ce_file, "w+")) == NULL) { content_error(ce->ce_file, ct, "unable to fopen for read/writing"); @@ -2837,7 +2909,7 @@ openURL (CT ct, char **file) if (ferror(gp)) { admonish(ce->ce_file, "error reading"); - unlink(cachefile); + (void) m_unlink (cachefile); } } umask(mask); @@ -3129,7 +3201,7 @@ ce_str (int encoding) { case CE_BASE64: return "base64"; case CE_QUOTED: - return "quoted"; + return "quoted-printable"; case CE_8BIT: return "8bit"; case CE_7BIT: @@ -3279,3 +3351,64 @@ bad_quote: *header_attrp = cp; return OK; } + + +char * +content_charset (CT ct) { + const char *const charset = "charset"; + char *default_charset = NULL; + CI ctinfo = &ct->c_ctinfo; + char **ap, **vp; + char **src_charset = NULL; + + for (ap = ctinfo->ci_attrs, vp = ctinfo->ci_values; *ap; ++ap, ++vp) { + if (! strcasecmp (*ap, charset)) { + src_charset = vp; + break; + } + } + + /* RFC 2045, Sec. 5.2: default to us-ascii. */ + if (src_charset == NULL) src_charset = &default_charset; + if (*src_charset == NULL) *src_charset = "US-ASCII"; + + return *src_charset; +} + + +/* Change the value of a name=value pair in a header field body. + If the name isn't there, append them. In any case, a new + string will be allocated and must be free'd by the caller. + Trims any trailing newlines. */ +char * +update_attr (char *body, const char *name, const char *value) { + char *bp = nmh_strcasestr (body, name); + char *new_body; + + if (bp) { + char *other_attrs = strchr (bp, ';'); + + *(bp + strlen (name)) = '\0'; + new_body = concat (body, "\"", value, "\"", NULL); + + if (other_attrs) { + char *cp; + + /* Trim any trailing newlines. */ + for (cp = &other_attrs[strlen (other_attrs) - 1]; + cp > other_attrs && *cp == '\n'; + *cp-- = '\0') continue; + new_body = add (other_attrs, new_body); + } + } else { + char *cp; + + /* Append name/value pair, after first removing a final newline + and (extraneous) semicolon. */ + if (*(cp = &body[strlen (body) - 1]) == '\n') *cp = '\0'; + if (*(cp = &body[strlen (body) - 1]) == ';') *cp = '\0'; + new_body = concat (body, "; ", name, "\"", value, "\"", NULL); + } + + return new_body; +}