-
/*
* show.c -- show/list messages
*
- * $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.
#include <h/mime.h>
#include <h/utils.h>
-static struct swit switches[] = {
-#define CHECKMIMESW 0
- { "checkmime", 0 },
-#define NOCHECKMIMESW 1
- { "nocheckmime", 0 },
-#define HEADSW 2
- { "header", 0 },
-#define NHEADSW 3
- { "noheader", 0 },
-#define FORMSW 4
- { "form formfile", 0 },
-#define PROGSW 5
- { "moreproc program", 0 },
-#define NPROGSW 6
- { "nomoreproc", 0 },
-#define LENSW 7
- { "length lines", 0 },
-#define WIDTHSW 8
- { "width columns", 0 },
-#define SHOWSW 9
- { "showproc program", 0 },
-#define SHOWMIMESW 10
- { "showmimeproc program", 0 },
-#define NSHOWSW 11
- { "noshowproc", 0 },
-#define DRFTSW 12
- { "draft", 0 },
-#define FILESW 13
- { "file file", -4 }, /* interface from showfile */
-#define VERSIONSW 14
- { "version", 0 },
-#define HELPSW 15
- { "help", 0 },
- { NULL, 0 }
-};
+#define SHOW_SWITCHES \
+ X("checkmime", 0, CHECKMIMESW) \
+ X("nocheckmime", 0, NOCHECKMIMESW) \
+ X("header", 0, HEADSW) \
+ X("noheader", 0, NHEADSW) \
+ X("form formfile", 0, FORMSW) \
+ X("moreproc program", 0, PROGSW) \
+ X("nomoreproc", 0, NPROGSW) \
+ X("length lines", 0, LENSW) \
+ X("width columns", 0, WIDTHSW) \
+ X("showproc program", 0, SHOWSW) \
+ X("showmimeproc program", 0, SHOWMIMESW) \
+ X("noshowproc", 0, NSHOWSW) \
+ X("draft", 0, DRFTSW) \
+ X("file file", -4, FILESW) /* interface from showfile */ \
+ X("fmtproc program", 0, FMTPROCSW) \
+ X("nofmtproc", 0, NFMTPROCSW) \
+ X("version", 0, VERSIONSW) \
+ X("help", 0, HELPSW) \
+ /* \
+ * switches for mhlproc \
+ */ \
+ X("concat", 0, CONCATSW) \
+ X("noconcat", 0, NCONCATSW) \
+ /* \
+ * switches for mhshow \
+ */ \
+ X("part number", 0, PARTSW) \
+ X("type content", 0, TYPESW) \
+ X("prefer content", 0, PREFERSW) \
+ X("markform file", 0, MARKFORMSW) \
+ X("rcache policy", 0, RCACHESW) \
+ X("wcache policy", 0, WCACHESW) \
+
+#define X(sw, minchars, id) id,
+DEFINE_SWITCH_ENUM(SHOW);
+#undef X
+
+#define X(sw, minchars, id) { sw, minchars, id },
+DEFINE_SWITCH_ARRAY(SHOW, switches);
+#undef X
/*
* static prototypes
*/
static int is_nontext(char *);
-/* prototype from mhlsbr.c */
-int mhl (int, char **);
-
#define SHOW 0
#define NEXT 1
#define PREV 2
int
main (int argc, char **argv)
{
- int draftsw = 0, headersw = 1, msgp = 0;
- int nshow = 0, checkmime = 1, mime;
- int vecp = 1, procp = 1, isdf = 0, mode = SHOW, msgnum;
- char *cp, *maildir, *file = NULL, *folder = NULL, *proc;
+ int draftsw = 0, headersw = 1;
+ int nshow = 0, checkmime = 1, mime = 0;
+ int isdf = 0, mode = SHOW, msgnum;
+ char *cp, *maildir, *file = NULL, *folder = NULL, *proc, *program;
char buf[BUFSIZ], **argp, **arguments;
- char *msgs[MAXARGS], *vec[MAXARGS];
- struct msgs *mp;
-
-#ifdef LOCALE
- setlocale(LC_ALL, "");
-#endif
- invo_name = r1bindex (argv[0], '/');
+ struct msgs *mp = NULL;
+ struct msgs_array msgs = { 0, 0, NULL };
+ struct msgs_array vec = { 0, 0, NULL }, non_mhl_vec = { 0, 0, NULL };
- /* read user profile/context */
- context_read();
+ if (nmh_init(argv[0], 1)) { return 1; }
if (!strcasecmp (invo_name, "next")) {
mode = NEXT;
while ((cp = *argp++)) {
if (*cp == '-') {
switch (smatch (++cp, switches)) {
- case AMBIGSW:
+ case AMBIGSW:
ambigsw (cp, switches);
done (1);
- case UNKWNSW:
+
+ case HEADSW:
+ headersw = 1;
+ goto non_mhl_switches;
+ case NHEADSW:
+ headersw = 0;
+ case CONCATSW:
+ case NCONCATSW:
+non_mhl_switches:
+ /* mhl can't handle these, so keep them separate. */
+ app_msgarg(&non_mhl_vec, --cp);
+ continue;
+
+ case UNKWNSW:
case NPROGSW:
- vec[vecp++] = --cp;
+ case NFMTPROCSW:
+ app_msgarg(&vec, --cp);
continue;
- case HELPSW:
+ case HELPSW:
snprintf (buf, sizeof(buf),
"%s [+folder] %s[switches] [switches for showproc]",
invo_name, mode == SHOW ? "[msgs] ": "");
print_help (buf, switches, 1);
- done (1);
+ done (0);
case VERSIONSW:
print_version(invo_name);
- done (1);
+ done (0);
- case DRFTSW:
+ case DRFTSW:
if (file)
adios (NULL, "only one file at a time!");
draftsw++;
adios (NULL,
"usage: %s [+folder] [switches] [switches for showproc]",
invo_name);
- case FILESW:
+ case FILESW:
if (mode != SHOW)
goto usage;
if (draftsw || file)
file = path (cp, TFILE);
continue;
- case HEADSW:
- headersw++;
- continue;
- case NHEADSW:
- headersw = 0;
- continue;
-
case FORMSW:
- vec[vecp++] = --cp;
+ app_msgarg(&vec, --cp);
if (!(cp = *argp++) || *cp == '-')
adios (NULL, "missing argument to %s", argp[-2]);
- vec[vecp++] = getcpy (etcpath(cp));
+ app_msgarg(&vec, getcpy (etcpath(cp)));
continue;
case PROGSW:
case LENSW:
case WIDTHSW:
- vec[vecp++] = --cp;
+ case FMTPROCSW:
+ case PARTSW:
+ case TYPESW:
+ case PREFERSW:
+ case MARKFORMSW:
+ case RCACHESW:
+ case WCACHESW:
+ app_msgarg(&vec, --cp);
if (!(cp = *argp++) || *cp == '-')
adios (NULL, "missing argument to %s", argp[-2]);
- vec[vecp++] = cp;
+ app_msgarg(&vec, cp);
continue;
- case SHOWSW:
+ case SHOWSW:
if (!(showproc = *argp++) || *showproc == '-')
adios (NULL, "missing argument to %s", argp[-2]);
nshow = 0;
continue;
- case NSHOWSW:
+ case NSHOWSW:
nshow++;
continue;
if (folder)
adios (NULL, "only one folder at a time!");
else
- folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
+ folder = pluspath (cp);
} else {
if (mode != SHOW)
goto usage;
- else
- msgs[msgp++] = cp;
+ app_msgarg(&msgs, cp);
}
}
- procp = vecp;
if (!context_find ("path"))
free (path ("./", TFOLDER));
if (draftsw || file) {
- if (msgp)
+ if (msgs.size)
adios (NULL, "only one file at a time!");
- vec[vecp++] = draftsw
- ? getcpy (m_draft (folder, msgp ? msgs[0] : NULL, 1, &isdf))
- : file;
- goto go_to_it;
- }
-
-#ifdef WHATNOW
- if (!msgp && !folder && mode == SHOW && (cp = getenv ("mhdraft")) && *cp) {
- draftsw++;
- vec[vecp++] = cp;
+ if (draftsw)
+ app_msgarg(&vec, getcpy (m_draft (folder, NULL, 1, &isdf)));
+ else
+ app_msgarg(&vec, file);
+ headersw = 0;
goto go_to_it;
}
-#endif /* WHATNOW */
- if (!msgp) {
+ if (!msgs.size) {
switch (mode) {
case NEXT:
- msgs[msgp++] = "next";
+ app_msgarg(&msgs, "next");
break;
case PREV:
- msgs[msgp++] = "prev";
+ app_msgarg(&msgs, "prev");
break;
default:
- msgs[msgp++] = "cur";
+ app_msgarg(&msgs, "cur");
break;
}
}
adios (maildir, "unable to change directory to");
/* read folder and create message structure */
- if (!(mp = folder_read (folder)))
+ if (!(mp = folder_read (folder, 1)))
adios (NULL, "unable to read folder %s", folder);
/* check for empty folder */
adios (NULL, "no messages in %s", folder);
/* parse all the message ranges/sequences and set SELECTED */
- for (msgnum = 0; msgnum < msgp; msgnum++)
- if (!m_convert (mp, msgs[msgnum]))
+ for (msgnum = 0; msgnum < msgs.size; msgnum++)
+ if (!m_convert (mp, msgs.msgs[msgnum]))
done (1);
/*
seq_setprev (mp); /* set the Previous-Sequence */
seq_setunseen (mp, 1); /* unset the Unseen-Sequence */
- if (mp->numsel > MAXARGS - 2)
- adios (NULL, "more than %d messages for show exec", MAXARGS - 2);
-
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
if (is_selected(mp, msgnum))
- vec[vecp++] = getcpy (m_name (msgnum));
+ app_msgarg(&vec, mh_xstrdup(m_name (msgnum)));
seq_setcur (mp, mp->hghsel); /* update current message */
seq_save (mp); /* synchronize sequences */
context_replace (pfolder, folder); /* update current folder */
context_save (); /* save the context file */
- if (headersw && vecp == 2)
- printf ("(Message %s:%s)\n", folder, vec[1]);
-
go_to_it: ;
- fflush (stdout);
-
- vec[vecp] = NULL;
/*
* Decide which "proc" to use
*/
- mime = 0;
if (nshow) {
proc = catproc;
} else {
/* check if any messages are non-text MIME messages */
- if (checkmime && !getenv ("NOMHNPROC")) {
+ if (! mime && checkmime) {
if (!draftsw && !file) {
/* loop through selected messages and check for MIME */
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
}
} else {
/* check the file or draft for MIME */
- if (is_nontext (vec[vecp - 1]))
+ if (is_nontext (vec.msgs[vec.size - 1]))
mime = 1;
}
}
if (folder && !draftsw && !file)
m_putenv ("mhfolder", folder);
- /*
- * For backward compatibility, if the "proc" is mhn,
- * then add "-show" option. Add "-file" if showing
- * file or draft.
- */
- if (strcmp (r1bindex (proc, '/'), "mhn") == 0) {
- if (draftsw || file) {
- vec[vecp] = vec[vecp - 1];
- vec[vecp - 1] = "-file";
- vecp++;
- }
- vec[vecp++] = "-show";
- vec[vecp] = NULL;
- }
+ if (strcmp (r1bindex (proc, '/'), "cat") == 0) {
- /* If the "proc" is "mhshow", add "-file" if showing file or draft.
- */
- if (strcmp (r1bindex (proc, '/'), "mhshow") == 0 && (draftsw || file) ) {
- vec[vecp] = vec[vecp - 1];
- vec[vecp - 1] = "-file";
- vec[++vecp] = NULL;
- }
+ if (headersw && vec.size == 1)
+ printf ("(Message %s:%s)\n", folder, vec.msgs[0]);
- /*
- * If "proc" is mhl, then run it internally
- * rather than exec'ing it.
- */
- if (strcmp (r1bindex (proc, '/'), "mhl") == 0) {
- vec[0] = "mhl";
- mhl (vecp, vec);
+ } else if (strcmp (r1bindex (proc, '/'), "mhl") == 0) {
+
+ if (headersw && vec.size == 1)
+ printf ("(Message %s:%s)\n", folder, vec.msgs[0]);
+
+ /* If "mhl", then run it internally */
+ argsplit_insert(&vec, "mhl", &program);
+ app_msgarg(&vec, NULL);
+ mhl (vec.size, vec.msgs);
done (0);
- }
- /*
- * If you are not using a nmh command as your "proc", then
- * add the path to the message names. Currently, we are just
- * checking for mhn here, since we've already taken care of mhl.
- */
- if (!strcmp (r1bindex (proc, '/'), "mhl")
- && !draftsw
- && !file
- && chdir (maildir = concat (m_maildir (""), "/", NULL)) != NOTOK) {
- mp->foldpath = concat (mp->foldpath, "/", NULL);
- cp = ssequal (maildir, mp->foldpath)
- ? mp->foldpath + strlen (maildir)
- : mp->foldpath;
- for (msgnum = procp; msgnum < vecp; msgnum++)
- vec[msgnum] = concat (cp, vec[msgnum], NULL);
+ } else {
+ int i;
+ char **mp;
+
+ for (i = 0, mp = non_mhl_vec.msgs; i < non_mhl_vec.size; ++i, ++mp) {
+ if (draftsw || file) {
+ /* Insert the switch before the filename. */
+ app_msgarg(&vec, vec.msgs[vec.size - 1]);
+ vec.msgs[vec.size - 2] = *mp;
+ } else {
+ app_msgarg(&vec, *mp);
+ }
+ }
+
+ if (strcmp (r1bindex (proc, '/'), "mhn") == 0) {
+ /* Add "-file" if showing file or draft, */
+ if (draftsw || file) {
+ app_msgarg(&vec, vec.msgs[vec.size - 1]);
+ vec.msgs[vec.size - 2] = "-file";
+ }
+ /* and add -show for backward compatibility */
+ app_msgarg(&vec, "-show");
+ } else if (strcmp (r1bindex (proc, '/'), "mhshow") == 0) {
+ /* If "mhshow", add "-file" if showing file or draft. */
+ if (draftsw || file) {
+ app_msgarg(&vec, vec.msgs[vec.size - 1]);
+ vec.msgs[vec.size - 2] = "-file";
+ }
+ } else {
+ if (headersw && vec.size == 1)
+ printf ("(Message %s:%s)\n", folder, vec.msgs[0]);
+ }
}
- vec[0] = r1bindex (proc, '/');
- execvp (proc, vec);
+ fflush (stdout);
+
+ argsplit_insert(&vec, proc, &program);
+ app_msgarg(&vec, NULL);
+ execvp (program, vec.msgs);
adios (proc, "unable to exec");
return 0; /* dead code to satisfy the compiler */
}
-/*
- * Cheat: we are loaded with adrparse, which wants a routine called
- * OfficialName(). We call adrparse:getm() with the correct arguments
- * to prevent OfficialName() from being called. Hence, the following
- * is to keep the loader happy.
- */
-
-char *
-OfficialName (char *name)
-{
- return name;
-}
-
/*
* Check if a message or file contains any non-text parts
is_nontext (char *msgnam)
{
int result, state;
- char *bp, *cp, *dp;
+ char *bp, *dp, *cp;
char buf[BUFSIZ], name[NAMESZ];
FILE *fp;
+ m_getfld_state_t gstate = 0;
if ((fp = fopen (msgnam, "r")) == NULL)
return 0;
- for (state = FLD;;) {
- switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) {
+ for (;;) {
+ int bufsz = sizeof buf;
+ switch (state = m_getfld (&gstate, name, buf, &bufsz, fp)) {
case FLD:
case FLDPLUS:
- case FLDEOF:
/*
* Check Content-Type field
*/
cp = add (buf, NULL);
while (state == FLDPLUS) {
- state = m_getfld (state, name, buf, sizeof(buf), fp);
+ bufsz = sizeof buf;
+ state = m_getfld (&gstate, name, buf, &bufsz, fp);
cp = add (buf, cp);
}
bp = cp;
passno = 1;
again:
- for (; isspace (*bp); bp++)
+ for (; isspace ((unsigned char) *bp); bp++)
continue;
if (*bp == '(') {
int i;
if ((result = (strcasecmp (bp, "plain") != 0)))
goto out;
*dp = c;
- for (dp++; isspace (*dp); dp++)
+ for (dp++; isspace ((unsigned char) *dp); dp++)
continue;
if (*dp) {
if ((result = !uprf (dp, "charset")))
goto out;
- dp += sizeof("charset") - 1;
- while (isspace (*dp))
+ dp += LEN("charset");
+ while (isspace ((unsigned char) *dp))
dp++;
if (*dp++ != '=')
goto invalid;
- while (isspace (*dp))
+ while (isspace ((unsigned char) *dp))
dp++;
if (*dp == '"') {
if ((bp = strchr(++dp, '"')))
free (cp);
if (result) {
fclose (fp);
+ m_getfld_state_destroy (&gstate);
return result;
}
break;
if (!strcasecmp (name, ENCODING_FIELD)) {
cp = add (buf, NULL);
while (state == FLDPLUS) {
- state = m_getfld (state, name, buf, sizeof(buf), fp);
+ bufsz = sizeof buf;
+ state = m_getfld (&gstate, name, buf, &bufsz, fp);
cp = add (buf, cp);
}
- for (bp = cp; isspace (*bp); bp++)
+ for (bp = cp; isspace ((unsigned char) *bp); bp++)
continue;
- for (dp = bp; istoken (*dp); dp++)
+ for (dp = bp; istoken ((unsigned char) *dp); dp++)
continue;
*dp = '\0';
result = (strcasecmp (bp, "7bit")
free (cp);
if (result) {
fclose (fp);
+ m_getfld_state_destroy (&gstate);
return result;
}
break;
* Just skip the rest of this header
* field and go to next one.
*/
- while (state == FLDPLUS)
- state = m_getfld (state, name, buf, sizeof(buf), fp);
+ while (state == FLDPLUS) {
+ bufsz = sizeof buf;
+ state = m_getfld (&gstate, name, buf, &bufsz, fp);
+ }
break;
/*
*/
default:
fclose (fp);
+ m_getfld_state_destroy (&gstate);
return 0;
}
}