X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/c982212dc21459effbb206a7de2f6306f68bdefe..d7e260c9a302e465a2c40e75ff8bd506768a7dbf:/uip/mhparse.c diff --git a/uip/mhparse.c b/uip/mhparse.c index f2f3a246..444bf7d5 100644 --- a/uip/mhparse.c +++ b/uip/mhparse.c @@ -23,8 +23,6 @@ extern int debugsw; -extern pid_t xpid; /* mhshowsbr.c */ - /* cache policies */ extern int rcachesw; /* mhcachesbr.c */ extern int wcachesw; /* mhcachesbr.c */ @@ -183,19 +181,6 @@ struct str2init str2methods[] = { }; -int -pidcheck (int status) -{ - if ((status & 0xff00) == 0xff00 || (status & 0x007f) != SIGQUIT) - return status; - - fflush (stdout); - fflush (stderr); - done (1); - return 1; -} - - /* * Main entry point for parsing a MIME message or file. * It returns the Content structure for the top level @@ -838,7 +823,7 @@ magic_skip: if (ct->c_dispo_type && !get_param(ct->c_dispo_first, "filename", '_', 1)) { add_param(&ct->c_dispo_first, &ct->c_dispo_last, "filename", - r1bindex(ci->ci_magic, '/')); + r1bindex(ci->ci_magic, '/'), 0); } } else @@ -2478,13 +2463,6 @@ openFTP (CT ct, char **file) return NOTOK; } - if (xpid) { - if (xpid < 0) - xpid = -xpid; - pidcheck (pidwait (xpid, NOTOK)); - xpid = 0; - } - /* Get the buffer ready to go */ bp = buffer; buflen = sizeof(buffer); @@ -2684,13 +2662,6 @@ openMail (CT ct, char **file) return NOTOK; } - if (xpid) { - if (xpid < 0) - xpid = -xpid; - pidcheck (pidwait (xpid, NOTOK)); - xpid = 0; - } - /* Get buffer ready to go */ bp = buffer; buflen = sizeof(buffer); @@ -2821,13 +2792,6 @@ openURL (CT ct, char **file) return NOTOK; } - if (xpid) { - if (xpid < 0) - xpid = -xpid; - pidcheck (pidwait (xpid, NOTOK)); - xpid = 0; - } - ce->ce_unlink = (*file == NULL); caching = 0; cachefile[0] = '\0'; @@ -3255,19 +3219,20 @@ parse_header_attrs (const char *filename, const char *fieldname, struct sectlist { char *value; int index; + int len; struct sectlist *next; - } *sp; + } *sp, *sp2; struct parmlist { char *name; char *charset; char *lang; struct sectlist *sechead; struct parmlist *next; - } *pp, *phead = NULL; + } *pp, *pp2, *phead = NULL; while (*cp == ';') { - char *dp, *vp, *up, c, *nameptr, *valptr, *charset, *lang; - int encoded = 0, partial = 0, index = 0, len = 0; + char *dp, *vp, *up, *nameptr, *valptr, *charset = NULL, *lang = NULL; + int encoded = 0, partial = 0, len = 0, index = 0; cp++; while (isspace ((unsigned char) *cp)) @@ -3313,15 +3278,15 @@ parse_header_attrs (const char *filename, const char *fieldname, * If there's a * and one or more digits, then it's section N. * * Remember we can have one or the other, or both. cp points to - * beginning of name, up points to the last character in the + * beginning of name, up points past the last character in the * parameter name. */ - for (vp = cp; vp <= up; vp++) { - if (*vp == '*' && vp < up) { + for (vp = cp; vp < up; vp++) { + if (*vp == '*' && vp < up - 1) { partial = 1; continue; - } else if (*vp == '*' && vp == up) { + } else if (*vp == '*' && vp == up - 1) { encoded = 1; } else if (partial) { if (isdigit((unsigned char) *vp)) @@ -3357,7 +3322,8 @@ parse_header_attrs (const char *filename, const char *fieldname, */ if (index == 0) { vp = dp; - while (*vp != '\'' && !isspace((unsigned char) *vp)) + while (*vp != '\'' && !isspace((unsigned char) *vp) && + *vp != '\0') vp++; if (*vp == '\'') { if (vp != dp) { @@ -3368,36 +3334,41 @@ parse_header_attrs (const char *filename, const char *fieldname, } else { charset = NULL; } + vp++; } else { - advise(NULL, "missing charset in message %s's %s: + advise(NULL, "missing charset in message %s's %s: " "field\n%*s(parameter %s)", filename, fieldname, strlen(invo_name) + 2, "", nameptr); free(nameptr); return NOTOK; } - } + dp = vp; - vp = (dp = vp); - while (*vp != '\'' && !isspace((unsigned char) *vp)) - vp++; + while (*vp != '\'' && !isspace((unsigned char) *vp) && + *vp != '\0') + vp++; - if (*vp == '\'') { - if (vp != dp) { - len = vp - dp; - lang = mh_xmalloc(len + 1); - strncpy(lang, dp, len); - lang[len] = '\0'; + if (*vp == '\'') { + if (vp != dp) { + len = vp - dp; + lang = mh_xmalloc(len + 1); + strncpy(lang, dp, len); + lang[len] = '\0'; + } else { + lang = NULL; + } + vp++; } else { - charset = NULL; + advise(NULL, "missing language tag in message %s's %s: " + "field\n%*s(parameter %s)", filename, fieldname, + strlen(invo_name) + 2, "", nameptr); + free(nameptr); + if (charset) + free(charset); + return NOTOK; } - } else { - advise(NULL, "missing language tag in message %s's %s: " - "field\n%*s(parameter %s)", filename, fieldname, - strlen(invo_name) + 2, "", nameptr); - free(nameptr); - if (charset) - free(charset); - return NOTOK; + + dp = vp; } /* @@ -3407,8 +3378,7 @@ parse_header_attrs (const char *filename, const char *fieldname, * length so we can allocate the correct buffer size. */ - for (dp = vp, len = 0; *vp != '\0' && !isspace((unsigned char *vp); - vp++) { + for (vp = dp, len = 0; istoken(*vp); vp++) { if (*vp == '%') { if (*(vp + 1) == '\0' || !isxdigit((unsigned char) *(vp + 1)) || @@ -3432,8 +3402,8 @@ parse_header_attrs (const char *filename, const char *fieldname, up = valptr = mh_xmalloc(len + 1); - for (vp = dp; *vp != '\0' && !isspace((unsigned char *vp); vp++) { - if (*vp = '%') { + for (vp = dp; istoken(*vp); vp++) { + if (*vp == '%') { *up++ = decode_qp(*(vp + 1), *(vp + 2)); vp += 2; } else { @@ -3442,6 +3412,7 @@ parse_header_attrs (const char *filename, const char *fieldname, } *up = '\0'; + cp = vp; } else { /* * A "normal" string. If it's got a leading quote, then we @@ -3451,13 +3422,12 @@ parse_header_attrs (const char *filename, const char *fieldname, * buffer. */ - dp = vp; len = 0; if (*dp == '"') { for (cp = dp + 1;;) { switch (*cp++) { - case '\0: + case '\0': bad_quote: advise (NULL, "invalid quoted-string in message %s's %s: " @@ -3484,9 +3454,30 @@ bad_quote: break; } - valptr = mh_xmalloc(len + 1); - } else + } else { + for (cp = dp; istoken (*cp); cp++) { + len++; + } + } + valptr = mh_xmalloc(len + 1); + + if (*dp == '"') { + int i; + for (cp = dp + 1, vp = valptr, i = 0; i < len; i++) { + if (*cp == '\\') { + cp++; + } + *vp++ = *cp++; + } + cp++; + } else { + strncpy(valptr, cp = dp, len); + cp += len; + } + + valptr[len] = '\0'; + } /* * If 'partial' is set, we don't allocate a parameter now. We @@ -3506,64 +3497,66 @@ bad_quote: if (pp == NULL) { pp = mh_xmalloc(sizeof(*pp)); memset(pp, 0, sizeof(*pp)); + pp->name = nameptr; pp->next = phead; phead = pp; } - if (index == 0 && encoded) { - - pm = mh_xmalloc(sizeof(*pm)); - memset(pm, 0, sizeof(*pm)); - - /* This is all mega-bozo and needs cleanup */ - vp = (pm->pm_name = add (cp, NULL)) + (up - cp); - *vp = '\0'; - - /* Now store the attribute value. */ + /* + * Insert this into the section linked list + */ - vp = pm->pm_name + (dp - cp); + sp = mh_xmalloc(sizeof(*sp)); + memset(sp, 0, sizeof(*sp)); + sp->value = valptr; + sp->index = index; + sp->len = len; - if (*dp == '"') { - for (cp = ++dp, dp = vp;;) { - switch (*cp++) { - case '\0': -bad_quote: - advise (NULL, - "invalid quoted-string in message %s's %s: " - "field\n%*s(parameter %s)", + if (pp->sechead == NULL || pp->sechead->index > index) { + sp->next = pp->sechead; + pp->sechead = sp; + } else { + for (sp2 = pp->sechead; sp2 != NULL; sp2 = sp2->next) { + if (sp2->index == sp->index) { + advise (NULL, "duplicate index (%d) in message " + "%s's %s: field\n%*s(parameter %s)", sp->index, filename, fieldname, strlen(invo_name) + 2, "", - pm->pm_name); + nameptr); return NOTOK; + } + if (sp2->index < sp->index && + (sp2->next == NULL || sp2->next->index > sp->index)) { + sp->next = sp2->next; + sp2->next = sp; + break; + } + } - case '\\': - *dp++ = c; - if ((c = *cp++) == '\0') - goto bad_quote; - /* else fall... */ + if (sp2 == NULL) { + advise(NULL, "Internal error: cannot insert partial " + "param in message %s's %s: field\n%*s(parameter %s)", + filename, fieldname, strlen(invo_name) + 2, "", + nameptr); + return NOTOK; + } + } - default: - *dp++ = c; - continue; + /* + * Save our charset and lang tags. + */ - case '"': - *dp = '\0'; - break; - } - break; + if (index == 0 && encoded) { + if (pp->charset) + free(pp->charset); + pp->charset = charset; + if (pp->lang) + free(pp->lang); + pp->lang = lang; } } else { - for (cp = dp, dp = vp; istoken (*cp); cp++, dp++) - continue; - *dp = '\0'; - } - pm->pm_value = getcpy(vp); - if (!*vp) { - advise (NULL, - "invalid parameter in message %s's %s: " - "field\n%*s(parameter %s)", - filename, fieldname, strlen(invo_name) + 2, "", - pm->pm_name); - return NOTOK; + pm = add_param(param_head, param_tail, nameptr, valptr, 1); + pm->pm_charset = charset; + pm->pm_lang = lang; } while (isspace ((unsigned char) *cp)) @@ -3573,20 +3566,70 @@ bad_quote: get_comment (filename, fieldname, &cp, commentp) == NOTOK) { return NOTOK; } + } - if (*param_head == NULL) { - *param_head = pm; - *param_tail = pm; - } else { - (*param_tail)->pm_next = pm; - *param_tail = pm; + /* + * Now that we're done, reassemble all of the partial parameters. + */ + + for (pp = phead; pp != NULL; ) { + char *p, *q; + size_t tlen = 0; + int pindex = 0; + for (sp = pp->sechead; sp != NULL; sp = sp->next) { + if (sp->index != pindex++) { + advise(NULL, "missing section %d for parameter in " + "message %s's %s: field\n%*s(parameter %s)", pindex - 1, + filename, fieldname, strlen(invo_name) + 2, "", + pp->name); + return NOTOK; + } + tlen += sp->len; } + + p = q = mh_xmalloc(tlen + 1); + for (sp = pp->sechead; sp != NULL; ) { + memcpy(q, sp->value, sp->len); + q += sp->len; + free(sp->value); + sp2 = sp->next; + free(sp); + sp = sp2; + } + + p[tlen] = '\0'; + + pm = add_param(param_head, param_tail, pp->name, p, 1); + pm->pm_charset = pp->charset; + pm->pm_lang = pp->lang; + pp2 = pp->next; + free(pp); + pp = pp2; } *header_attrp = cp; return OK; } +/* + * Return the charset for a particular content type. Return pointer is + * only valid until the next call to content_charset(). + */ + +char * +content_charset (CT ct) { + static char *ret_charset = NULL; + + if (ret_charset != NULL) { + free(ret_charset); + } + + ret_charset = get_param(ct->c_ctinfo.ci_first_pm, "charset", '?', 0); + + return ret_charset ? ret_charset : "US-ASCII"; +} + + /* * Create a string based on a list of output parameters. Assume that this * parameter string will be appended to an existing header, so start out @@ -3994,14 +4037,14 @@ normal_param(PM pm, char *output, size_t len, size_t valuelen, */ PM -add_param(PM *first, PM *last, const char *name, const char *value) +add_param(PM *first, PM *last, char *name, char *value, int nocopy) { PM pm = mh_xmalloc(sizeof(*pm)); memset(pm, 0, sizeof(*pm)); - pm->pm_name = getcpy(name); - pm->pm_value = getcpy(value); + pm->pm_name = nocopy ? name : getcpy(name); + pm->pm_value = nocopy ? value : getcpy(value); if (*first) { (*last)->pm_next = pm; @@ -4014,6 +4057,33 @@ add_param(PM *first, PM *last, const char *name, const char *value) return pm; } +/* + * Either replace a current parameter with a new value, or add the parameter + * to the parameter linked list. + */ + +PM +replace_param(PM *first, PM *last, char *name, char *value, int nocopy) +{ + PM pm; + + for (pm = *first; pm != NULL; pm = pm->pm_next) { + if (strcasecmp(name, pm->pm_name) == 0) { + /* + * If nocopy is set, it's assumed that we own both name + * and value. We don't need name, so we discard it now. + */ + if (nocopy) + free(name); + free(pm->pm_value); + pm->pm_value = nocopy ? value : getcpy(value); + return pm; + } + } + + return add_param(first, last, name, value, nocopy); +} + /* * Retrieve a parameter value from a parameter linked list. If the parameter * value needs converted to the local character set, do that now. @@ -4049,7 +4119,10 @@ char *get_param_value(PM pm, char replace) int utf8; iconv_t cd; ICONV_CONST char *p; +#else /* HAVE_ICONV */ + char *p; #endif /* HAVE_ICONV */ + char *q; /* @@ -4124,9 +4197,10 @@ char *get_param_value(PM pm, char replace) *q = '\0'; return buffer; -#endif /* HAVE_ICONV */ noiconv: +#endif /* HAVE_ICONV */ + /* * Take everything non-ASCII and substituite the replacement character */