-
-/*
- * 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
* complete copyright information.
*/
-#include <h/mh.h>
+#include "h/mh.h"
+#include "sbr/read_switch_multiword.h"
+#include "sbr/concat.h"
+#include "sbr/smatch.h"
+#include "sbr/r1bindex.h"
+#include "sbr/uprf.h"
+#include "sbr/getcpy.h"
+#include "sbr/getfolder.h"
+#include "sbr/folder_read.h"
+#include "sbr/folder_free.h"
+#include "sbr/folder_addmsg.h"
+#include "sbr/context_find.h"
+#include "sbr/path.h"
+#include "sbr/error.h"
#include <fcntl.h>
-#include <h/md5.h>
-#include <h/mts.h>
-#include <h/tws.h>
-#include <h/mime.h>
-#include <h/mhparse.h>
-#include <h/utils.h>
+#include "h/md5.h"
+#include "h/mts.h"
+#include "h/tws.h"
+#include "h/fmt_scan.h"
+#include "h/mime.h"
+#include "h/mhparse.h"
+#include "h/utils.h"
+#include "mhmisc.h"
+#include "mhshowsbr.h"
+#include "sbr/m_maildir.h"
+#include "sbr/m_mktemp.h"
enum clobber_policy_t {
NMH_CLOBBER_ALWAYS = 0,
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. */
enum clobber_policy_t clobber_policy; /* -clobber selection */
};
+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_create (CT *ct, char *pwd, const char *csw, int asw, int vsw)
+{
mhstoreinfo_t info;
NEW(info);
}
void
-mhstoreinfo_free (mhstoreinfo_t info) {
+mhstoreinfo_free (mhstoreinfo_t info)
+{
free (info->cwd);
free (info->dir);
free (info);
}
int
-mhstoreinfo_files_not_clobbered (const mhstoreinfo_t info) {
+mhstoreinfo_files_not_clobbered (const mhstoreinfo_t info)
+{
return info->files_not_clobbered;
}
typedef int (*qsort_comp) (const void *, const void *);
-/* mhmisc.c */
-int part_ok (CT);
-int type_ok (CT, int);
-void flush_errors (void);
-
/*
* static prototypes
*/
* attribute/value pairs which specify if this a tar file.
*/
if (!ct->c_storeproc && ct->c_subtype == APPLICATION_OCTETS) {
- int tarP = 0, zP = 0, gzP = 0;
+ bool tarP = false;
+ bool zP = false;
+ bool gzP = false;
char *cp;
if ((cp = get_param(ci->ci_first_pm, "type", ' ', 1))) {
if (strcasecmp (cp, "tar") == 0)
- tarP = 1;
+ tarP = true;
}
/* check for "conversions=compress" attribute */
(cp = get_param(ci->ci_first_pm, "x-conversions", ' ', 1))) {
if (strcasecmp (cp, "compress") == 0 ||
strcasecmp (cp, "x-compress") == 0) {
- zP = 1;
+ zP = true;
}
if (strcasecmp (cp, "gzip") == 0 ||
strcasecmp (cp, "x-gzip") == 0) {
- gzP = 1;
+ gzP = true;
}
}
/* Support mhstore -outfile. The MIME parser doesn't
load c_storage, so we know that p->c_storage is
NULL here. */
- p->c_storage = add (ct->c_storage, NULL);
+ p->c_storage = mh_xstrdup(ct->c_storage);
}
result = store_switch (p, 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;
}
*ctq = NULL;
if (i > 1)
- qsort ((char *) base, i, sizeof(*base), (qsort_comp) ct_compar);
+ qsort(base, i, sizeof(*base), (qsort_comp) ct_compar);
cur = 1;
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;
ct = *ctq++;
if (store_content (ct, NULL, info) == NOTOK) {
losing:
- free ((char *) base);
+ free(base);
return NOTOK;
}
goto losing;
}
- free ((char *) base);
+ free(base);
return OK;
}
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);
}
}
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 = add (ct->c_storage, NULL);
+ p->c_storage = mh_xstrdup(ct->c_storage);
}
result = store_switch (p, info);
struct partial *am = (struct partial *) ((*a)->c_ctparams);
struct partial *bm = (struct partial *) ((*b)->c_ctparams);
- return (am->pm_marked - bm->pm_marked);
+ return am->pm_marked - bm->pm_marked;
}
static int
store_content (CT ct, CT p, mhstoreinfo_t info)
{
- int appending = 0, msgnum = 0;
- int is_partial = 0, first_partial = 0;
- int last_partial = 0;
+ bool appending = false;
+ int msgnum = 0;
+ bool is_partial = false;
+ bool first_partial = false;
+ bool last_partial = false;
char *cp, buffer[BUFSIZ];
/*
struct partial *pm = (struct partial *) ct->c_ctparams;
/* Yep, it's a message/partial */
- is_partial = 1;
+ is_partial = true;
/* But is it the first and/or last in the collection? */
if (pm->pm_partno == 1)
- first_partial = 1;
+ first_partial = true;
if (pm->pm_maxno && pm->pm_partno == pm->pm_maxno)
- last_partial = 1;
+ last_partial = true;
/*
* If "p" is a valid pointer, then it points to the
* from the previous iteration of this function.
*/
if (p) {
- appending = 1;
+ appending = true;
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;
/* Store content in temporary file for now */
if ((tmpfilenam = m_mktemp(invo_name, NULL, NULL)) == NULL) {
- adios(NULL, "unable to create temporary file in %s",
+ die("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])
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);
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;
}
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 {
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);
}
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;
}
fclose (fp);
- return (cc != NOTOK ? OK : NOTOK);
+ return cc == NOTOK ? NOTOK : OK;
}
if (!ct->c_fp && (ct->c_fp = fopen (ct->c_file, "r")) == NULL) {
}
}
- while (fgets (buffer, sizeof(buffer) - 1, ct->c_fp)) {
+ while (fgets (buffer, sizeof buffer, ct->c_fp)) {
if ((pos += strlen (buffer)) > last) {
int diff;
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, NULL);
- } 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);
* 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;
*bp = '\0';
buflen--;
continue;
- } else {
+ }
+ {
PM pm;
char *s = "";
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;
* use that (RFC-2183).
*/
if (ct->c_dispo) {
- if ((cp = get_param(ct->c_dispo_first, "filename", '_', 0))
- && *cp != '/'
- && *cp != '.'
- && *cp != '|'
- && *cp != '!'
- && !strchr (cp, '%')) {
- ct->c_storeproc = add (cp, NULL);
+ if ((cp = get_param(ct->c_dispo_first, "filename", '_', 0)) &&
+ use_param_as_filename(cp)) {
+ ct->c_storeproc = mh_xstrdup(cp);
free(cp);
return;
}
- if (cp)
- free(cp);
+ free(cp);
}
/*
* the storeproc.
*/
ci = &ct->c_ctinfo;
- if ((cp = get_param(ci->ci_first_pm, "name", '_', 0))
- && *cp != '/'
- && *cp != '.'
- && *cp != '|'
- && *cp != '!'
- && !strchr (cp, '%')) {
- ct->c_storeproc = add (cp, NULL);
+ if ((cp = get_param(ci->ci_first_pm, "name", '_', 0)) &&
+ use_param_as_filename(cp)) {
+ ct->c_storeproc = mh_xstrdup(cp);
}
- if (cp)
- free(cp);
+ free(cp);
}
/******************************************************************************/
/* -clobber support */
-static
-enum clobber_policy_t
-clobber_policy (const char *value) {
+static enum clobber_policy_t
+clobber_policy (const char *value)
+{
if (value == NULL || ! strcasecmp (value, "always")) {
return NMH_CLOBBER_ALWAYS;
}
return NMH_CLOBBER_NEVER;
}
- adios (NULL, "invalid argument, %s, to clobber", value);
+ die("invalid argument, %s, to clobber", value);
}
static char *
-next_version (char *file, enum clobber_policy_t clobber_policy) {
+next_version (char *file, enum clobber_policy_t clobber_policy)
+{
const size_t max_versions = 1000000;
/* 8 = log max_versions + one for - or . + one for null terminator */
const size_t buflen = strlen (file) + 8;
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;
}
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;
}
static char *
-clobber_check (char *original_file, mhstoreinfo_t info) {
+clobber_check (char *original_file, mhstoreinfo_t info)
+{
/* clobber policy return value
* -------------- ------------
* -always original_file
char *file;
char *cwd = NULL;
- int check_again;
+ bool check_again;
if (! strcmp (original_file, "-")) {
return original_file;
/* 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) {
struct stat st;
file = original_file;
- check_again = 0;
+ check_again = false;
switch (info->clobber_policy) {
case NMH_CLOBBER_ALWAYS:
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;
}
break;
case NMH_RENAME: {
char buf[PATH_MAX];
- printf ("Enter filename or full path of the new file: ");
+ fputs("Enter filename or full path of the new file: ", stdout);
if (fgets (buf, sizeof buf, stdin) == NULL ||
buf[0] == '\0') {
file = NULL;
++info->files_not_clobbered;
} else {
- TrimSuffixC(buf, '\n');
+ 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;
+ check_again = true;
break;
}
}
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;
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 */
/******************************************************************************/