X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/0c6b83703435d837e756d2006c56f643e7e1b7d6..41a19760d9369daba89e4ad963a06ebb6f04321e:/uip/mhparse.c diff --git a/uip/mhparse.c b/uip/mhparse.c index 444bf7d5..96af58e9 100644 --- a/uip/mhparse.c +++ b/uip/mhparse.c @@ -34,10 +34,14 @@ int checksw = 0; /* check Content-MD5 field */ * 1) Instruct parser not to detect invalid Content-Transfer-Encoding * in a multipart. * 2) Suppress the warning about bogus multipart content, and report it. + * 3) Suppress the warning about extraneous trailing ';' in header parameter + * lists, and report it. */ int skip_mp_cte_check; int suppress_bogus_mp_content_warning; int bogus_mp_content; +int suppress_extraneous_trailing_semicolon_warning; +int extraneous_trailing_semicolon; /* * Structures for TEXT messages @@ -59,6 +63,7 @@ struct k2v SubMultiPart[] = { { "alternative", MULTI_ALTERNATE }, { "digest", MULTI_DIGEST }, { "parallel", MULTI_PARALLEL }, + { "related", MULTI_RELATED }, { NULL, MULTI_UNKNOWN } /* this one must be last! */ }; @@ -115,7 +120,7 @@ static int get_comment (const char *, const char *, char **, char **); static int InitGeneric (CT); static int InitText (CT); static int InitMultiPart (CT); -void reverse_parts (CT); +static void reverse_parts (CT); static int InitMessage (CT); static int InitApplication (CT); static int init_encoding (CT, OpenCEFunc); @@ -194,6 +199,7 @@ parse_mime (char *file) char buffer[BUFSIZ]; FILE *fp; CT ct; + size_t n; /* * Check if file is actually standard input @@ -207,8 +213,13 @@ parse_mime (char *file) } file = add (tfile, NULL); - while (fgets (buffer, sizeof(buffer), stdin)) - fputs (buffer, fp); + while ((n = fread(buffer, 1, sizeof(buffer), stdin)) > 0) { + if (fwrite(buffer, 1, n, fp) != n) { + (void) m_unlink (file); + advise (file, "error copying to temporary file"); + return NULL; + } + } fflush (fp); if (ferror (stdin)) { @@ -277,7 +288,7 @@ get_content (FILE *in, char *file, int toplevel) m_getfld_state_t gstate = 0; /* allocate the content structure */ - if (!(ct = (CT) calloc (1, sizeof(*ct)))) + if (!(ct = (CT) mh_xcalloc (1, sizeof(*ct)))) adios (NULL, "out of memory"); ct->c_fp = in; @@ -1012,7 +1023,7 @@ InitText (CT ct) ct->c_subtype = kv->kv_value; /* allocate text character set structure */ - if ((t = (struct text *) calloc (1, sizeof(*t))) == NULL) + if ((t = (struct text *) mh_xcalloc (1, sizeof(*t))) == NULL) adios (NULL, "out of memory"); ct->c_ctparams = (void *) t; @@ -1057,7 +1068,10 @@ InitMultiPart (CT ct) long last, pos; char *cp, *dp; PM pm; - char *bp, buffer[BUFSIZ]; + char *bp; + char *bufp = NULL; + size_t buflen; + ssize_t gotlen; struct multipart *m; struct k2v *kv; struct part *part, **next; @@ -1117,7 +1131,7 @@ InitMultiPart (CT ct) } /* allocate primary structure for multipart info */ - if ((m = (struct multipart *) calloc (1, sizeof(*m))) == NULL) + if ((m = (struct multipart *) mh_xcalloc (1, sizeof(*m))) == NULL) adios (NULL, "out of memory"); ct->c_ctparams = (void *) m; @@ -1151,24 +1165,25 @@ InitMultiPart (CT ct) part = NULL; inout = 1; - while (fgets (buffer, sizeof(buffer) - 1, fp)) { + while ((gotlen = getline(&bufp, &buflen, fp)) != -1) { if (pos > last) break; - pos += strlen (buffer); - if (buffer[0] != '-' || buffer[1] != '-') + pos += gotlen; + if (bufp[0] != '-' || bufp[1] != '-') continue; if (inout) { - if (strcmp (buffer + 2, m->mp_start)) + if (strcmp (bufp + 2, m->mp_start)) continue; next_part: - if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL) + if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL) adios (NULL, "out of memory"); *next = part; next = &part->mp_next; if (!(p = get_content (fp, ct->c_file, ct->c_subtype == MULTI_DIGEST ? -1 : 0))) { + free(bufp); ct->c_fp = NULL; return NOTOK; } @@ -1178,18 +1193,18 @@ next_part: fseek (fp, pos, SEEK_SET); inout = 0; } else { - if (strcmp (buffer + 2, m->mp_start) == 0) { + if (strcmp (bufp + 2, m->mp_start) == 0) { inout = 1; end_part: p = part->mp_part; - p->c_end = ftell(fp) - (strlen(buffer) + 1); + p->c_end = ftell(fp) - (gotlen + 1); if (p->c_end < p->c_begin) p->c_begin = p->c_end; if (inout) goto next_part; goto last_part; } else { - if (strcmp (buffer + 2, m->mp_stop) == 0) + if (strcmp (bufp + 2, m->mp_stop) == 0) goto end_part; } } @@ -1244,6 +1259,7 @@ last_part: /* initialize the content of the subparts */ if (p->c_ctinitfnx && (*p->c_ctinitfnx) (p) == NOTOK) { + free(bufp); fclose (ct->c_fp); ct->c_fp = NULL; return NOTOK; @@ -1254,6 +1270,7 @@ last_part: get_leftover_mp_content (ct, 1); get_leftover_mp_content (ct, 0); + free(bufp); fclose (ct->c_fp); ct->c_fp = NULL; return OK; @@ -1264,7 +1281,7 @@ last_part: * reverse the order of the parts of a multipart/alternative */ -void +static void reverse_parts (CT ct) { struct multipart *m = (struct multipart *) ct->c_ctparams; @@ -1281,6 +1298,30 @@ reverse_parts (CT ct) } + + +/* parse_mime() arranges alternates in reverse (priority) order. This + function can be used to reverse them back. This will put, for + example, a text/plain part before a text/html part in a + multipart/alternative part, for example, where it belongs. */ +void +reverse_alternative_parts (CT ct) { + if (ct->c_type == CT_MULTIPART) { + struct multipart *m = (struct multipart *) ct->c_ctparams; + struct part *part; + + if (ct->c_subtype == MULTI_ALTERNATE) { + reverse_parts (ct); + } + + /* And call recursively on each part of a multipart. */ + for (part = m->mp_parts; part; part = part->mp_next) { + reverse_alternative_parts (part->mp_part); + } + } +} + + /* * MESSAGE */ @@ -1317,7 +1358,7 @@ InitMessage (CT ct) PM pm; struct partial *p; - if ((p = (struct partial *) calloc (1, sizeof(*p))) == NULL) + if ((p = (struct partial *) mh_xcalloc (1, sizeof(*p))) == NULL) adios (NULL, "out of memory"); ct->c_ctparams = (void *) p; @@ -1366,7 +1407,7 @@ invalid_param: CT p; FILE *fp; - if ((e = (struct exbody *) calloc (1, sizeof(*e))) == NULL) + if ((e = (struct exbody *) mh_xcalloc (1, sizeof(*e))) == NULL) adios (NULL, "out of memory"); ct->c_ctparams = (void *) e; @@ -1698,15 +1739,7 @@ openBase64 (CT ct, char **file) /* sbeck@cise.ufl.edu -- handle suffixes */ ci = &ct->c_ctinfo; - snprintf (buffer, sizeof(buffer), "%s-suffix-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - cp = context_find (buffer); - if (cp == NULL || *cp == '\0') { - snprintf (buffer, sizeof(buffer), "%s-suffix-%s", invo_name, - ci->ci_type); - cp = context_find (buffer); - } - if (cp != NULL && *cp != '\0') { + if ((cp = context_find_by_type ("suffix", ci->ci_type, ci->ci_subtype))) { if (ce->ce_unlink) { /* Create temporary file with filename extension. */ if ((ce->ce_file = m_mktemps(invo_name, cp, NULL, NULL)) == NULL) { @@ -1908,7 +1941,9 @@ openQuoted (CT ct, char **file) { int cc, digested, len, quoted, own_ct_fp = 0; char *cp, *ep; - char buffer[BUFSIZ]; + char *bufp = NULL; + size_t buflen; + ssize_t gotlen; unsigned char mask; CE ce = &ct->c_cefile; /* sbeck -- handle suffixes */ @@ -1937,15 +1972,7 @@ openQuoted (CT ct, char **file) /* sbeck@cise.ufl.edu -- handle suffixes */ ci = &ct->c_ctinfo; - snprintf (buffer, sizeof(buffer), "%s-suffix-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - cp = context_find (buffer); - if (cp == NULL || *cp == '\0') { - snprintf (buffer, sizeof(buffer), "%s-suffix-%s", invo_name, - ci->ci_type); - cp = context_find (buffer); - } - if (cp != NULL && *cp != '\0') { + if ((cp = context_find_by_type ("suffix", ci->ci_type, ci->ci_subtype))) { if (ce->ce_unlink) { /* Create temporary file with filename extension. */ if ((ce->ce_file = m_mktemps(invo_name, cp, NULL, NULL)) == NULL) { @@ -1990,16 +2017,16 @@ openQuoted (CT ct, char **file) fseek (ct->c_fp, ct->c_begin, SEEK_SET); while (len > 0) { - if (fgets (buffer, sizeof(buffer) - 1, ct->c_fp) == NULL) { + if ((gotlen = getline(&bufp, &buflen, ct->c_fp)) == -1) { content_error (NULL, ct, "premature eof"); goto clean_up; } - if ((cc = strlen (buffer)) > len) + if ((cc = gotlen) > len) cc = len; len -= cc; - for (ep = (cp = buffer) + cc - 1; cp <= ep; ep--) + for (ep = (cp = bufp) + cc - 1; cp <= ep; ep--) if (!isspace ((unsigned char) *ep)) break; *++ep = '\n', ep++; @@ -2104,6 +2131,7 @@ ready_to_go: fclose (ct->c_fp); ct->c_fp = NULL; } + free (bufp); return fileno (ce->ce_fp); clean_up: @@ -2112,6 +2140,7 @@ clean_up: fclose (ct->c_fp); ct->c_fp = NULL; } + free (bufp); return NOTOK; } @@ -2163,15 +2192,7 @@ open7Bit (CT ct, char **file) /* sbeck@cise.ufl.edu -- handle suffixes */ ci = &ct->c_ctinfo; - snprintf (buffer, sizeof(buffer), "%s-suffix-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - cp = context_find (buffer); - if (cp == NULL || *cp == '\0') { - snprintf (buffer, sizeof(buffer), "%s-suffix-%s", invo_name, - ci->ci_type); - cp = context_find (buffer); - } - if (cp != NULL && *cp != '\0') { + if ((cp = context_find_by_type ("suffix", ci->ci_type, ci->ci_subtype))) { if (ce->ce_unlink) { /* Create temporary file with filename extension. */ if ((ce->ce_file = m_mktemps(invo_name, cp, NULL, NULL)) == NULL) { @@ -2259,7 +2280,9 @@ open7Bit (CT ct, char **file) cc = len; len -= cc; - fwrite (buffer, sizeof(*buffer), cc, ce->ce_fp); + if ((int) fwrite (buffer, sizeof(*buffer), cc, ce->ce_fp) < cc) { + advise ("open7Bit", "fwrite"); + } if (ferror (ce->ce_fp)) { content_error (ce->ce_file, ct, "error writing to"); goto clean_up; @@ -2326,6 +2349,7 @@ openExternal (CT ct, CT cb, CE ce, char **file, int *fd) } } + *fd = fileno (ce->ce_fp); return OK; ready_already: @@ -2393,7 +2417,9 @@ openFile (CT ct, char **file) while ((cc = fread (buffer, sizeof(*buffer), sizeof(buffer), gp)) > 0) - fwrite (buffer, sizeof(*buffer), cc, fp); + if ((int) fwrite (buffer, sizeof(*buffer), cc, fp) < cc) { + advise ("openFile", "fwrite"); + } fflush (fp); if (ferror (gp)) { @@ -2602,7 +2628,9 @@ openFTP (CT ct, char **file) while ((cc= fread (buffer, sizeof(*buffer), sizeof(buffer), gp)) > 0) - fwrite (buffer, sizeof(*buffer), cc, fp); + if ((int) fwrite (buffer, sizeof(*buffer), cc, fp) < cc) { + advise ("openFTP", "fwrite"); + } fflush (fp); if (ferror (gp)) { @@ -2862,7 +2890,9 @@ openURL (CT ct, char **file) while ((cc = fread(buffer, sizeof(*buffer), sizeof(buffer), gp)) > 0) - fwrite(buffer, sizeof(*buffer), cc, fp); + if ((int) fwrite(buffer, sizeof(*buffer), cc, fp) < cc) { + advise ("openURL", "fwrite"); + } fflush(fp); @@ -2960,12 +2990,15 @@ invalid_digest: after the last subpart that hasn't been stored anywhere else, so do that. */ int -get_leftover_mp_content (CT ct, int before /* or after */) { +get_leftover_mp_content (CT ct, int before /* or after */) +{ struct multipart *m = (struct multipart *) ct->c_ctparams; char *boundary; int found_boundary = 0; - char buffer[BUFSIZ]; int max = BUFSIZ; + char *bufp = NULL; + size_t buflen; + ssize_t gotlen; int read = 0; char *content = NULL; @@ -2998,18 +3031,18 @@ get_leftover_mp_content (CT ct, int before /* or after */) { } /* Back up by 1 to pick up the newline. */ - while (fgets (buffer, sizeof(buffer) - 1, ct->c_fp)) { - read += strlen (buffer); + while ((gotlen = getline(&bufp, &buflen, ct->c_fp)) != -1) { + read += gotlen; /* Don't look beyond beginning of first subpart (before) or next part (after). */ - if (read > max) buffer[read-max] = '\0'; + if (read > max) bufp[read-max] = '\0'; if (before) { - if (! strcmp (buffer, boundary)) { + if (! strcmp (bufp, boundary)) { found_boundary = 1; } } else { - if (! found_boundary && ! strcmp (buffer, boundary)) { + if (! found_boundary && ! strcmp (bufp, boundary)) { found_boundary = 1; continue; } @@ -3018,12 +3051,12 @@ get_leftover_mp_content (CT ct, int before /* or after */) { if ((before && ! found_boundary) || (! before && found_boundary)) { if (content) { char *old_content = content; - content = concat (content, buffer, NULL); + content = concat (content, bufp, NULL); free (old_content); } else { content = before - ? concat ("\n", buffer, NULL) - : concat (buffer, NULL); + ? concat ("\n", bufp, NULL) + : concat (bufp, NULL); } } @@ -3057,6 +3090,7 @@ get_leftover_mp_content (CT ct, int before /* or after */) { } free (boundary); + free (bufp); return OK; } @@ -3120,6 +3154,8 @@ ct_subtype_str (int type, int subtype) { return "digest"; case MULTI_PARALLEL: return "parallel"; + case MULTI_RELATED: + return "related"; default: return "unknown_multipart_subtype"; } @@ -3244,10 +3280,13 @@ parse_header_attrs (const char *filename, const char *fieldname, } if (*cp == 0) { - advise (NULL, - "extraneous trailing ';' in message %s's %s: " - "parameter list", - filename, fieldname); + if (! suppress_extraneous_trailing_semicolon_warning) { + advise (NULL, + "extraneous trailing ';' in message %s's %s: " + "parameter list", + filename, fieldname); + } + extraneous_trailing_semicolon = 1; return DONE; } @@ -3522,6 +3561,7 @@ bad_quote: "%s's %s: field\n%*s(parameter %s)", sp->index, filename, fieldname, strlen(invo_name) + 2, "", nameptr); + free (nameptr); return NOTOK; } if (sp2->index < sp->index && @@ -3537,6 +3577,7 @@ bad_quote: "param in message %s's %s: field\n%*s(parameter %s)", filename, fieldname, strlen(invo_name) + 2, "", nameptr); + free (nameptr); return NOTOK; } } @@ -3612,21 +3653,16 @@ bad_quote: } /* - * Return the charset for a particular content type. Return pointer is - * only valid until the next call to content_charset(). + * Return the charset for a particular content type. */ char * content_charset (CT ct) { - static char *ret_charset = NULL; - - if (ret_charset != NULL) { - free(ret_charset); - } + char *ret_charset = NULL; ret_charset = get_param(ct->c_ctinfo.ci_first_pm, "charset", '?', 0); - return ret_charset ? ret_charset : "US-ASCII"; + return ret_charset ? ret_charset : getcpy ("US-ASCII"); } @@ -3856,8 +3892,12 @@ param_len(PM pm, int index, size_t valueoff, int *encode, int *cont, * add them now. */ - if (! pm->pm_charset) + if (! pm->pm_charset) { pm->pm_charset = getcpy(write_charset_8bit()); + if (strcasecmp(pm->pm_charset, "US-ASCII") == 0) + adios(NULL, "8-bit characters in parameter \"%s\", but " + "local character set is US-ASCII", pm->pm_name); + } if (! pm->pm_lang) pm->pm_lang = getcpy(NULL); /* Default to a blank lang tag */