X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/a514b8a78c447c8abc69386bee9f2c463b1c9362..63621a81d16ab743de6b57d47578a9a2c670ad22:/uip/mhstoresbr.c diff --git a/uip/mhstoresbr.c b/uip/mhstoresbr.c index 89a2f278..0e9b94cd 100644 --- a/uip/mhstoresbr.c +++ b/uip/mhstoresbr.c @@ -1,6 +1,4 @@ - -/* - * mhstoresbr.c -- routines to save/store the contents of MIME messages +/* mhstoresbr.c -- routines to save/store the contents of MIME messages * * This code is Copyright (c) 2002, by the authors of nmh. See the * COPYRIGHT file in the root directory of the nmh distribution for @@ -9,13 +7,17 @@ #include #include -#include #include #include #include +#include #include #include #include +#include "mhmisc.h" +#include "mhshowsbr.h" +#include "sbr/m_maildir.h" +#include "sbr/m_mktemp.h" enum clobber_policy_t { NMH_CLOBBER_ALWAYS = 0, @@ -25,7 +27,7 @@ enum clobber_policy_t { NMH_CLOBBER_NEVER }; -static enum clobber_policy_t clobber_policy (const char *); +static enum clobber_policy_t clobber_policy (const char *) PURE; struct mhstoreinfo { CT *cts; /* Top-level list of contents to store. */ @@ -41,12 +43,13 @@ struct mhstoreinfo { enum clobber_policy_t clobber_policy; /* -clobber selection */ }; -typedef struct mhstoreinfo *mhstoreinfo_t; +static bool use_param_as_filename(const char *p); mhstoreinfo_t mhstoreinfo_create (CT *ct, char *pwd, const char *csw, int asw, int vsw) { - mhstoreinfo_t info = mh_xmalloc (sizeof *info); + mhstoreinfo_t info; + NEW(info); info->cts = ct; info->cwd = pwd; info->autosw = asw; @@ -61,6 +64,7 @@ mhstoreinfo_create (CT *ct, char *pwd, const char *csw, int asw, int vsw) { void mhstoreinfo_free (mhstoreinfo_t info) { free (info->cwd); + free (info->dir); free (info); } @@ -77,19 +81,6 @@ mhstoreinfo_files_not_clobbered (const mhstoreinfo_t info) { typedef int (*qsort_comp) (const void *, const void *); -/* mhmisc.c */ -int part_ok (CT, int); -int type_ok (CT, int); -void flush_errors (void); - -/* mhshowsbr.c */ -int show_content_aux (CT, int, int, char *, char *); - -/* - * prototypes - */ -void store_all_messages (mhstoreinfo_t); - /* * static prototypes */ @@ -125,7 +116,7 @@ store_all_messages (mhstoreinfo_t info) * store any contents. */ if ((cp = context_find (nmhstorage)) && *cp) - info->dir = getcpy (cp); + info->dir = mh_xstrdup(cp); else info->dir = getcpy (info->cwd); @@ -184,6 +175,7 @@ store_switch (CT ct, mhstoreinfo_t info) } case CT_APPLICATION: + default: return store_application (ct, info); case CT_TEXT: @@ -191,9 +183,6 @@ store_switch (CT ct, mhstoreinfo_t info) case CT_IMAGE: case CT_VIDEO: return store_generic (ct, info); - - default: - adios (NULL, "unknown content type %d", ct->c_type); } return OK; /* NOT REACHED */ @@ -227,7 +216,6 @@ store_generic (CT ct, mhstoreinfo_t info) static int store_application (CT ct, mhstoreinfo_t info) { - char **ap, **ep; CI ci = &ct->c_ctinfo; /* Check if the content specifies a filename */ @@ -241,28 +229,23 @@ store_application (CT ct, mhstoreinfo_t info) */ if (!ct->c_storeproc && ct->c_subtype == APPLICATION_OCTETS) { int tarP = 0, zP = 0, gzP = 0; + char *cp; - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - /* check for "type=tar" attribute */ - if (!strcasecmp (*ap, "type")) { - if (strcasecmp (*ep, "tar")) - break; - + if ((cp = get_param(ci->ci_first_pm, "type", ' ', 1))) { + if (strcasecmp (cp, "tar") == 0) tarP = 1; - continue; - } + } - /* check for "conversions=compress" attribute */ - if ((!strcasecmp (*ap, "conversions") || !strcasecmp (*ap, "x-conversions")) - && (!strcasecmp (*ep, "compress") || !strcasecmp (*ep, "x-compress"))) { + /* check for "conversions=compress" attribute */ + if ((cp = get_param(ci->ci_first_pm, "conversions", ' ', 1)) || + (cp = get_param(ci->ci_first_pm, "x-conversions", ' ', 1))) { + if (strcasecmp (cp, "compress") == 0 || + strcasecmp (cp, "x-compress") == 0) { zP = 1; - continue; } - /* check for "conversions=gzip" attribute */ - if ((!strcasecmp (*ap, "conversions") || !strcasecmp (*ap, "x-conversions")) - && (!strcasecmp (*ep, "gzip") || !strcasecmp (*ep, "x-gzip"))) { + if (strcasecmp (cp, "gzip") == 0 || + strcasecmp (cp, "x-gzip") == 0) { gzP = 1; - continue; } } @@ -304,15 +287,14 @@ store_multi (CT ct, mhstoreinfo_t info) for (part = m->mp_parts; part; part = part->mp_next) { CT p = part->mp_part; - if (part_ok (p, 1) && type_ok (p, 1)) { + if (part_ok (p) && type_ok (p, 1)) { if (ct->c_storage) { /* Support mhstore -outfile. The MIME parser doesn't load c_storage, so we know that p->c_storage is NULL here. */ - p->c_storage = ct->c_storage; + p->c_storage = mh_xstrdup(ct->c_storage); } result = store_switch (p, info); - p->c_storage = NULL; if (result == OK && ct->c_subtype == MULTI_ALTERNATE) break; @@ -359,13 +341,11 @@ store_partial (CT ct, mhstoreinfo_t info) } if (hi == 0) { - advise (NULL, "missing (at least) last part of multipart message"); + inform("missing (at least) last part of multipart message"); return NOTOK; } - if ((base = (CT *) calloc ((size_t) (i + 1), sizeof(*base))) == NULL) - adios (NULL, "out of memory"); - + base = mh_xcalloc(i + 1, sizeof *base); ctq = base; for (ctp = info->cts; *ctp; ctp++) { p = *ctp; @@ -384,22 +364,21 @@ store_partial (CT ct, mhstoreinfo_t info) for (ctq = base; *ctq; ctq++) { p = *ctq; pm = (struct partial *) p->c_ctparams; - if (pm->pm_marked != cur) { - if (pm->pm_marked == cur - 1) { - admonish (NULL, - "duplicate part %d of %d part multipart message", - pm->pm_marked, hi); - continue; - } + if (pm->pm_marked == cur) { + cur++; + continue; + } + + if (pm->pm_marked == cur - 1) { + inform("duplicate part %d of %d part multipart message, continuing...", + pm->pm_marked, hi); + continue; + } missing_part: - advise (NULL, - "missing %spart %d of %d part multipart message", - cur != hi ? "(at least) " : "", cur, hi); - goto losing; - } - else - cur++; + inform("missing %spart %d of %d part multipart message", + cur != hi ? "(at least) " : "", cur, hi); + goto losing; } if (hi != --cur) { cur = hi; @@ -415,7 +394,7 @@ missing_part: ct = *ctq++; if (store_content (ct, NULL, info) == NOTOK) { losing: - free ((char *) base); + free(base); return NOTOK; } @@ -425,7 +404,7 @@ losing: goto losing; } - free ((char *) base); + free(base); return OK; } @@ -451,16 +430,11 @@ store_external (CT ct, mhstoreinfo_t info) if (info->autosw) { char *cp; - if ((cp = e->eb_name) - && *cp != '/' - && *cp != '.' - && *cp != '|' - && *cp != '!' - && !strchr (cp, '%')) { + if ((cp = e->eb_name) && use_param_as_filename(cp)) { if (!ct->c_storeproc) - ct->c_storeproc = add (cp, NULL); + ct->c_storeproc = mh_xstrdup(cp); if (!p->c_storeproc) - p->c_storeproc = add (cp, NULL); + p->c_storeproc = mh_xstrdup(cp); } } @@ -476,10 +450,9 @@ store_external (CT ct, mhstoreinfo_t info) if (ct->c_storage) { /* Support mhstore -outfile. The MIME parser doesn't load c_storage, so we know that p->c_storage is NULL here. */ - p->c_storage = ct->c_storage; + p->c_storage = mh_xstrdup(ct->c_storage); } result = store_switch (p, info); - p->c_storage = NULL; p->c_partno = NULL; return result; @@ -554,11 +527,11 @@ store_content (CT ct, CT p, mhstoreinfo_t info) if (p) { appending = 1; if (! ct->c_storage) { - ct->c_storage = add (p->c_storage, NULL); + ct->c_storage = mh_xstrdup(FENDNULL(p->c_storage)); /* record the folder name */ if (p->c_folder) { - ct->c_folder = add (p->c_folder, NULL); + ct->c_folder = mh_xstrdup(p->c_folder); } } goto got_filename; @@ -577,13 +550,9 @@ store_content (CT ct, CT p, mhstoreinfo_t info) if ((cp = ct->c_storeproc) == NULL || *cp == '\0') { CI ci = &ct->c_ctinfo; - snprintf (buffer, sizeof(buffer), "%s-store-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - if ((cp = context_find (buffer)) == NULL || *cp == '\0') { - snprintf (buffer, sizeof(buffer), "%s-store-%s", invo_name, ci->ci_type); - if ((cp = context_find (buffer)) == NULL || *cp == '\0') { - cp = ct->c_type == CT_MESSAGE ? "+" : "%m%P.%s"; - } + cp = context_find_by_type ("store", ci->ci_type, ci->ci_subtype); + if (cp == NULL) { + cp = ct->c_type == CT_MESSAGE ? "+" : "%m%P.%s"; } } @@ -600,7 +569,7 @@ store_content (CT ct, CT p, mhstoreinfo_t info) adios(NULL, "unable to create temporary file in %s", get_temp_dir()); } - ct->c_storage = add (tmpfilenam, NULL); + ct->c_storage = mh_xstrdup(tmpfilenam); /* Get the folder name */ if (cp[1]) @@ -612,7 +581,7 @@ store_content (CT ct, CT p, mhstoreinfo_t info) create_folder(m_mailpath(folder), 0, exit); /* Record the folder name */ - ct->c_folder = add (folder, NULL); + ct->c_folder = mh_xstrdup(folder); if (cp[1]) free (folder); @@ -631,16 +600,16 @@ store_content (CT ct, CT p, mhstoreinfo_t info) * content to standard input of a command and return. */ if (buffer[0] == '|' || buffer[0] == '!') - return show_content_aux (ct, 1, 0, buffer + 1, info->dir); + return show_content_aux (ct, 0, buffer + 1, info->dir, NULL); /* record the filename */ - if ((ct->c_storage = clobber_check (add (buffer, NULL), info)) == + if ((ct->c_storage = clobber_check (mh_xstrdup(buffer), info)) == NULL) { return NOTOK; } } else { /* The output filename was explicitly specified, so use it. */ - if ((ct->c_storage = clobber_check (add (ct->c_storage, NULL), info)) == + if ((ct->c_storage = clobber_check (ct->c_storage, info)) == NULL) { return NOTOK; } @@ -675,7 +644,7 @@ got_filename: if (first_partial) fprintf (stderr, "reassembling partials "); if (last_partial) - fprintf (stderr, "%s", ct->c_file); + fputs(ct->c_file, stderr); else fprintf (stderr, "%s,", ct->c_file); } else { @@ -699,7 +668,7 @@ got_filename: int cwdlen = strlen (info->cwd); fprintf (stderr, " as file %s\n", - strncmp (ct->c_storage, info->cwd, cwdlen) + !has_prefix(ct->c_storage, info->cwd) || ct->c_storage[cwdlen] != '/' ? ct->c_storage : ct->c_storage + cwdlen + 1); } @@ -734,7 +703,7 @@ output_content_file (CT ct, int appending) int cc, fd; if (!ct->c_ceopenfnx) { - advise (NULL, "don't know how to decode part %s of message %s", + inform("don't know how to decode part %s of message %s", ct->c_partno, ct->c_file); return NOTOK; } @@ -798,7 +767,9 @@ losing: break; default: - fwrite (buffer, sizeof(*buffer), cc, fp); + if ((int) fwrite (buffer, sizeof(*buffer), cc, fp) < cc) { + advise ("output_content_file", "fwrite"); + } continue; } break; @@ -858,7 +829,7 @@ losing: } } - while (fgets (buffer, sizeof(buffer) - 1, ct->c_fp)) { + while (fgets (buffer, sizeof buffer, ct->c_fp)) { if ((pos += strlen (buffer)) > last) { int diff; @@ -927,13 +898,12 @@ output_content_folder (char *folder, char *filename) struct msgs *mp; /* Read the folder. */ - if ((mp = folder_read (folder, 0))) { - /* Link file into folder */ - msgnum = folder_addmsg (&mp, filename, 0, 0, 0, 0, (char *)0); - } else { - advise (NULL, "unable to read folder %s", folder); + if (!(mp = folder_read(folder, 0))) { + inform("unable to read folder %s", folder); return NOTOK; } + /* Link file into folder */ + msgnum = folder_addmsg(&mp, filename, 0, 0, 0, 0, NULL); /* free folder structure */ folder_free (mp); @@ -976,7 +946,9 @@ parse_format_string (CT ct, char *cp, char *buffer, int buflen, char *dir) * appropriate directory. */ if (*cp != '/' && *cp != '|' && *cp != '!') { - snprintf (bp, buflen, "%s/", dir[1] ? dir : ""); + if (!strcmp(dir, "/")) + dir = ""; /* Don't start with "//". */ + snprintf (bp, buflen, "%s/", dir); len = strlen (bp); bp += len; buflen -= len; @@ -997,13 +969,14 @@ parse_format_string (CT ct, char *cp, char *buffer, int buflen, char *dir) *bp = '\0'; buflen--; continue; - } else { - char **ap, **ep; + } + { + PM pm; char *s = ""; - for (ap = ci->ci_attrs, ep = ci->ci_values; - *ap; ap++, ep++) { - snprintf (bp, buflen, "%s%s=\"%s\"", s, *ap, *ep); + for (pm = ci->ci_first_pm; pm; pm = pm->pm_next) { + snprintf (bp, buflen, "%s%s=\"%s\"", s, + pm->pm_name, get_param_value(pm, '?')); len = strlen (bp); bp += len; buflen -= len; @@ -1024,7 +997,7 @@ parse_format_string (CT ct, char *cp, char *buffer, int buflen, char *dir) break; case 'p': - /* insert part number withouth leading dot */ + /* insert part number without leading dot */ if (ct->c_partno) strncpy (bp, ct->c_partno, buflen); break; @@ -1075,7 +1048,7 @@ raw: static void get_storeproc (CT ct) { - char **ap, **ep, *cp; + char *cp; CI ci; /* @@ -1091,29 +1064,13 @@ get_storeproc (CT ct) * use that (RFC-2183). */ if (ct->c_dispo) { - char *cp = strchr (ct->c_dispo, ';'); - CI ci = calloc (1, sizeof *ci); - int status; - int found_filename = 0; - - if (cp && parse_header_attrs (ct->c_file, strlen (invo_name) + 2, &cp, - ci, &status) == OK) { - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - if (! strcasecmp (*ap, "filename") - && *(cp = *ep) != '/' - && *cp != '.' - && *cp != '|' - && *cp != '!' - && !strchr (cp, '%')) { - ct->c_storeproc = add (cp, NULL); - found_filename = 1; - } - free (*ap); - } + if ((cp = get_param(ct->c_dispo_first, "filename", '_', 0)) && + use_param_as_filename(cp)) { + ct->c_storeproc = mh_xstrdup(cp); + free(cp); + return; } - - free (ci); - if (found_filename) return; + free(cp); } /* @@ -1122,17 +1079,12 @@ get_storeproc (CT ct) * the storeproc. */ ci = &ct->c_ctinfo; - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - if (! strcasecmp (*ap, "name") - && *(cp = *ep) != '/' - && *cp != '.' - && *cp != '|' - && *cp != '!' - && !strchr (cp, '%')) { - ct->c_storeproc = add (cp, NULL); - return; - } + if ((cp = get_param(ci->ci_first_pm, "name", '_', 0)) && + use_param_as_filename(cp)) { + ct->c_storeproc = mh_xstrdup(cp); + } + free(cp); } @@ -1172,19 +1124,22 @@ static enum clobber_policy_t clobber_policy (const char *value) { if (value == NULL || ! strcasecmp (value, "always")) { - } else if (! strcasecmp (value, "auto")) { + return NMH_CLOBBER_ALWAYS; + } + if (! strcasecmp (value, "auto")) { return NMH_CLOBBER_AUTO; - } else if (! strcasecmp (value, "suffix")) { + } + if (! strcasecmp (value, "suffix")) { return NMH_CLOBBER_SUFFIX; - } else if (! strcasecmp (value, "ask")) { + } + if (! strcasecmp (value, "ask")) { return NMH_CLOBBER_ASK; - } else if (! strcasecmp (value, "never")) { + } + if (! strcasecmp (value, "never")) { return NMH_CLOBBER_NEVER; - } else { - adios (NULL, "invalid argument, %s, to clobber", value); } - return NMH_CLOBBER_ALWAYS; + adios (NULL, "invalid argument, %s, to clobber", value); } @@ -1219,7 +1174,7 @@ next_version (char *file, enum clobber_policy_t clobber_policy) { default: /* Should never get here. */ - advise (NULL, "will not overwrite %s, invalid clobber policy", buffer); + inform("will not overwrite %s, invalid clobber policy", buffer); free (buffer); return NULL; } @@ -1240,7 +1195,7 @@ next_version (char *file, enum clobber_policy_t clobber_policy) { free (file); if (version >= max_versions) { - advise (NULL, "will not overwrite %s, too many versions", buffer); + inform("will not overwrite %s, too many versions", buffer); free (buffer); buffer = NULL; } @@ -1264,17 +1219,23 @@ clobber_check (char *original_file, mhstoreinfo_t info) { char *cwd = NULL; int check_again; + if (! strcmp (original_file, "-")) { + return original_file; + } + if (info->clobber_policy == NMH_CLOBBER_ASK) { /* Save cwd for possible use in loop below. */ char *slash; - cwd = add (original_file, NULL); + cwd = mh_xstrdup(original_file); slash = strrchr (cwd, '/'); if (slash) { *slash = '\0'; } else { - /* original_file wasn't a full path, which shouldn't happen. */ + /* original_file isn't a full path, which should only happen if + it is -. */ + free (cwd); cwd = NULL; } } @@ -1312,11 +1273,11 @@ clobber_check (char *original_file, mhstoreinfo_t info) { if (isatty (fileno (stdin))) { char *prompt = concat ("Overwrite \"", file, "\" [y/n/rename]? ", NULL); - ans = getans (prompt, answer); + ans = read_switch_multiword (prompt, answer); free (prompt); } else { /* Overwrite, that's what nmh used to do. And warn. */ - advise (NULL, "-clobber ask but no tty, so overwrite %s", file); + inform("-clobber ask but no tty, so overwrite %s", file); break; } @@ -1336,20 +1297,17 @@ clobber_check (char *original_file, mhstoreinfo_t info) { file = NULL; ++info->files_not_clobbered; } else { - char *newline = strchr (buf, '\n'); - if (newline) { - *newline = '\0'; - } + trim_suffix_c(buf, '\n'); } free (file); if (buf[0] == '/') { /* Full path, use it. */ - file = add (buf, NULL); + file = mh_xstrdup(buf); } else { /* Relative path. */ - file = cwd ? concat (cwd, "/", buf, NULL) : add (buf, NULL); + file = cwd ? concat (cwd, "/", buf, NULL) : mh_xstrdup(buf); } check_again = 1; @@ -1363,7 +1321,7 @@ clobber_check (char *original_file, mhstoreinfo_t info) { if (stat (file, &st) == OK) { /* Keep count of files that would have been clobbered, and return that as process exit status. */ - advise (NULL, "will not overwrite %s with -clobber never", file); + inform("will not overwrite %s with -clobber never", file); free (file); file = NULL; ++info->files_not_clobbered; @@ -1374,12 +1332,17 @@ clobber_check (char *original_file, mhstoreinfo_t info) { original_file = file; } while (check_again); - if (cwd) { - free (cwd); - } + free (cwd); return file; } +static bool use_param_as_filename(const char *p) +{ + /* Preserve result of original test that considered an empty string + * OK. */ + return !*p || (!strchr("/.|!", *p) && !strchr(p, '%')); +} + /* -clobber support */ /******************************************************************************/