X-Git-Url: http://git.marmaro.de/?p=mmh;a=blobdiff_plain;f=uip%2Fmhbuildsbr.c;h=c6f50981bf99ddf5d419ab8dc1e93e8216180586;hp=73907ab3f0a30f0ab8de9980f52a2979a1666b3b;hb=d2da15ecabb03fb2de72863abdf5f21e52fdf329;hpb=1691e80890e5d8ba258c51c214a3e91880e1db2b diff --git a/uip/mhbuildsbr.c b/uip/mhbuildsbr.c index 73907ab..c6f5098 100644 --- a/uip/mhbuildsbr.c +++ b/uip/mhbuildsbr.c @@ -3,6 +3,10 @@ * mhbuildsbr.c -- routines to expand/translate MIME composition files * * $Id$ + * + * This code is Copyright (c) 2002, by the authors of nmh. See the + * COPYRIGHT file in the root directory of the nmh distribution for + * complete copyright information. */ /* @@ -19,24 +23,35 @@ #include #include #include -#include -#include +#include +#include #include #include +#include + +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef TM_IN_SYS_TIME +# include +# else +# include +# endif +#endif #ifdef HAVE_SYS_WAIT_H # include #endif -extern int errno; - extern int debugsw; extern int verbosw; extern int ebcdicsw; extern int listsw; extern int rfc934sw; +extern int contentidsw; extern int endian; /* mhmisc.c */ @@ -171,6 +186,8 @@ static int scan_content (CT); static int build_headers (CT); static char *calculate_digest (CT, int); static int readDigest (CT, char *); +static char *incl_name_value (char *, char *, char *); +static char *extract_name_value (char *, char *); /* * Structures for mapping (content) types to @@ -227,8 +244,7 @@ pidcheck (int status) fflush (stdout); fflush (stderr); - done (1); - /* NOTREACHED */ + return done (1); } @@ -637,6 +653,16 @@ get_content (FILE *in, char *file, int toplevel) goto got_header; } + /* Get Content-Disposition field */ + if (!strcasecmp (name, DISPO_FIELD)) { + ct->c_dispo = add (buf, ct->c_dispo); + while (state == FLDPLUS) { + state = m_getfld (state, name, buf, sizeof(buf), in); + ct->c_dispo = add (buf, ct->c_dispo); + } + goto got_header; + } + /* Get Content-MD5 field */ if (!strcasecmp (name, MD5_FIELD)) { char *cp, *dp, *ep; @@ -773,8 +799,7 @@ add_header (CT ct, char *name, char *value) HF hp; /* allocate header field structure */ - if (!(hp = malloc (sizeof(*hp)))) - adios (NULL, "out of memory"); + hp = mh_xmalloc (sizeof(*hp)); /* link data into header structure */ hp->name = name; @@ -1045,15 +1070,56 @@ bad_quote: } /* + * Get any {Content-Disposition} given in buffer. + */ + if (magic && *cp == '{') { + ct->c_dispo = ++cp; + for (dp = cp + strlen (cp) - 1; dp >= cp; dp--) + if (*dp == '}') + break; + if (dp < cp) { + advise (NULL, "invalid disposition in message %s", ct->c_file); + ct->c_dispo = NULL; + return NOTOK; + } + + c = *dp; + *dp = '\0'; + if (*ct->c_dispo) + ct->c_dispo = concat (ct->c_dispo, "\n", NULL); + else + ct->c_dispo = NULL; + *dp++ = c; + cp = dp; + + while (isspace (*cp)) + cp++; + } + + /* * Check if anything is left over */ if (*cp) { - if (magic) + if (magic) { ci->ci_magic = add (cp, NULL); + + /* If there is a Content-Disposition header and it doesn't + have a *filename=, extract it from the magic contents. + The r1bindex call skips any leading directory + components. */ + if (ct->c_dispo) + ct->c_dispo = + incl_name_value (ct->c_dispo, + "filename", + r1bindex (extract_name_value ("name", + ci-> + ci_magic), + '/')); + } else advise (NULL, "extraneous information in message %s's %s: field\n%*.*s(%s)", - ct->c_file, TYPE_FIELD, i, i, "", cp); + ct->c_file, TYPE_FIELD, i, i, "", cp); } return OK; @@ -1433,9 +1499,9 @@ InitMessage (CT ct) struct k2v *kv; CI ci = &ct->c_ctinfo; - if (ct->c_encoding != CE_7BIT) { + if ((ct->c_encoding != CE_7BIT) && (ct->c_encoding != CE_8BIT)) { admonish (NULL, - "\"%s/%s\" type in message %s should be encoded in 7bit", + "\"%s/%s\" type in message %s should be encoded in 7bit or 8bit", ci->ci_type, ci->ci_subtype, ct->c_file); return NOTOK; } @@ -1541,8 +1607,7 @@ invalid_param: goto no_body; } - if ((e->eb_body = bp = malloc ((unsigned) size)) == NULL) - adios (NULL, "out of memory"); + e->eb_body = bp = mh_xmalloc ((unsigned) size); fseek (p->c_fp, p->c_begin, SEEK_SET); while (size > 0) switch (cc = fread (bp, sizeof(*bp), size, p->c_fp)) { @@ -2299,6 +2364,8 @@ open7Bit (CT ct, char **file) fprintf (ce->ce_fp, "%s:%s", ID_FIELD, ct->c_id); if (ct->c_descr) fprintf (ce->ce_fp, "%s:%s", DESCR_FIELD, ct->c_descr); + if (ct->c_dispo) + fprintf (ce->ce_fp, "%s:%s", DISPO_FIELD, ct->c_dispo); fprintf (ce->ce_fp, "\n"); } @@ -2662,7 +2729,7 @@ losing_ftp: goto losing_ftp; #endif - if (cachefile[0]) + if (cachefile[0]) { if (caching) chmod (cachefile, cachetype ? m_gmprot () : 0444); else { @@ -2676,7 +2743,7 @@ losing_ftp: fseek (gp, 0L, SEEK_SET); - while ((cc = fread (buffer, sizeof(*buffer), sizeof(buffer), gp)) + while ((cc= fread (buffer, sizeof(*buffer), sizeof(buffer), gp)) > 0) fwrite (buffer, sizeof(*buffer), cc, fp); fflush (fp); @@ -2694,6 +2761,7 @@ losing_ftp: } umask (mask); } + } fseek (ce->ce_fp, 0L, SEEK_SET); *file = ce->ce_file; @@ -2937,6 +3005,29 @@ again_descr: } } + if (headers >= 0 && uprf (buffer, DISPO_FIELD) + && buffer[i = strlen (DISPO_FIELD)] == ':') { + headers = 1; + +again_dispo: + ct->c_dispo = add (buffer + i + 1, ct->c_dispo); + if (!fgetstr (buffer, sizeof(buffer) - 1, in)) + adios (NULL, "end-of-file after %s: field in plaintext", DISPO_FIELD); + switch (buffer[0]) { + case ' ': + case '\t': + i = -1; + goto again_dispo; + + case '#': + adios (NULL, "#-directive after %s: field in plaintext", DISPO_FIELD); + /* NOTREACHED */ + + default: + break; + } + } + if (headers != 1 || buffer[0] != '\n') fputs (buffer, out); @@ -3159,11 +3250,12 @@ use_forw: /* search the arguments for a folder name */ for (ap = arguments; *ap; ap++) { cp = *ap; - if (*cp == '+' || *cp == '@') + if (*cp == '+' || *cp == '@') { if (folder) adios (NULL, "only one folder per #forw directive"); else folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF); + } } /* else, use the current folder */ @@ -3854,10 +3946,10 @@ build_headers (CT ct) /* * Skip the output of Content-Type, parameters, content - * description, and Content-ID if the content is of type - * "message" and the rfc934 compatibility flag is set - * (which means we are inside multipart/digest and the - * switch -rfc934mode was given). + * description and disposition, and Content-ID if the + * content is of type "message" and the rfc934 compatibility + * flag is set (which means we are inside multipart/digest + * and the switch -rfc934mode was given). */ if (ct->c_type == CT_MESSAGE && ct->c_rfc934) goto skip_headers; @@ -3919,9 +4011,9 @@ build_headers (CT ct) add_header (ct, np, vp); /* - * output the Content-ID + * output the Content-ID, unless disabled by -nocontentid */ - if (ct->c_id) { + if (contentidsw && ct->c_id) { np = add (ID_FIELD, NULL); vp = concat (" ", ct->c_id, NULL); add_header (ct, np, vp); @@ -3936,6 +4028,15 @@ build_headers (CT ct) add_header (ct, np, vp); } + /* + * output the Content-Disposition + */ + if (ct->c_dispo) { + np = add (DISPO_FIELD, NULL); + vp = concat (" ", ct->c_dispo, NULL); + add_header (ct, np, vp); + } + skip_headers: /* * If this is the internal content structure for a @@ -4214,3 +4315,88 @@ invalid_digest: return OK; } + + +/* Make sure that buf contains at least one appearance of name, + followed by =. If not, insert both name and value, just after + first semicolon, if any. Note that name should not contain a + trailing =. And quotes will be added around the value. Typical + usage: make sure that a Content-Disposition header contains + filename="foo". If it doesn't and value does, use value from + that. */ +static char * +incl_name_value (char *buf, char *name, char *value) { + char *newbuf = buf; + + /* Assume that name is non-null. */ + if (buf && value) { + char *name_plus_equal = concat (name, "=", NULL); + + if (! strstr (buf, name_plus_equal)) { + char *insertion; + char *cp; + char *prefix, *suffix; + + /* Trim trailing space, esp. newline. */ + for (cp = &buf[strlen (buf) - 1]; + cp >= buf && isspace (*cp); + --cp) { + *cp = '\0'; + } + + insertion = concat ("; ", name, "=", "\"", value, "\"", NULL); + + /* Insert at first semicolon, if any. If none, append to + end. */ + prefix = add (buf, NULL); + if ((cp = strchr (prefix, ';'))) { + suffix = concat (cp, NULL); + *cp = '\0'; + newbuf = concat (prefix, insertion, suffix, "\n", NULL); + free (suffix); + } else { + /* Append to end. */ + newbuf = concat (buf, insertion, "\n", NULL); + } + + free (prefix); + free (insertion); + free (buf); + } + + free (name_plus_equal); + } + + return newbuf; +} + + +/* Extract just name_suffix="foo", if any, from value. If there isn't + one, return the entire value. Note that, for example, a name_suffix + of name will match filename="foo", and return foo. */ +static char * +extract_name_value (char *name_suffix, char *value) { + char *extracted_name_value = value; + char *name_suffix_plus_quote = concat (name_suffix, "=\"", NULL); + char *name_suffix_equals = strstr (value, name_suffix_plus_quote); + char *cp; + + free (name_suffix_plus_quote); + if (name_suffix_equals) { + char *name_suffix_begin; + + /* Find first \". */ + for (cp = name_suffix_equals; *cp != '"'; ++cp) /* empty */; + name_suffix_begin = ++cp; + /* Find second \". */ + for (; *cp != '"'; ++cp) /* empty */; + + extracted_name_value = mh_xmalloc (cp - name_suffix_begin + 1); + memcpy (extracted_name_value, + name_suffix_begin, + cp - name_suffix_begin); + extracted_name_value[cp - name_suffix_begin] = '\0'; + } + + return extracted_name_value; +}