diff uip/mshcmds.c @ 0:bce86c4163a3

Initial revision
author kono
date Mon, 18 Apr 2005 23:46:02 +0900
parents
children a6481689f99c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uip/mshcmds.c	Mon Apr 18 23:46:02 2005 +0900
@@ -0,0 +1,3634 @@
+/* mshcmds.c - command handlers in msh */
+#ifndef	lint
+static char ident[] = "@(#)$Id$";
+#endif	/* lint */
+
+#include "../h/mh.h"
+#include "../h/dropsbr.h"
+#include "../h/formatsbr.h"
+#include "../h/scansbr.h"
+#include "../zotnet/tws.h"
+#ifdef	_AIX		/* AIX 1.2.1 <stdio.h> declares getws() */
+#define getws _getws
+#endif
+#include <stdio.h>
+#ifdef	_AIX
+#undef getws
+#endif
+#include "../zotnet/mts.h"
+#include <ctype.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "../h/mshsbr.h"
+#ifdef	MIME
+#include "../h/mhn.h"
+#endif	/* MIME */
+
+/*  */
+
+extern int errno;
+
+				/* BURST */
+static char delim3[] = "-------";/* from burst.c */
+
+
+				/* SHOW */
+static int  mhlnum;
+static FILE *mhlfp;
+
+void clear_screen ();
+static int     eom_action ();
+static FP	mhl_action ();
+#ifdef	MIME
+static int     nontext();
+#endif
+
+
+static burst(), forw(), rmm(), show(), ask(), copy_message(), copy_digest();
+static int	process();
+				/* SORTM */
+static int	msgsort (), subsort();
+static int	getws ();
+static char    *sosmash ();
+
+#if	defined(NNTP) && defined(MPOP)
+#undef	MPOP
+#endif
+#ifdef	MPOP
+#ifdef	BPOP
+extern	int	pmsh;
+extern	char	response[];
+#endif
+#endif /* MPOP */
+
+/*  */
+
+forkcmd (args, pgm)
+char  **args,
+       *pgm;
+{
+    int     child_id;
+    char   *vec[MAXARGS];
+
+    vec[0] = r1bindex (pgm, '/');
+    (void) copyip (args, vec + 1);
+
+    if (fmsh) {
+	(void) m_delete (pfolder);
+	m_replace (pfolder, fmsh);
+	m_sync (mp);
+	m_update ();
+    }
+    (void) fflush (stdout);
+    switch (child_id = fork ()) {
+	case NOTOK: 
+	    advise ("fork", "unable to");
+	    return;
+
+	case OK: 
+	    closefds (3);
+	    (void) signal (SIGINT, istat);
+	    (void) signal (SIGQUIT, qstat);
+
+	    execvp (pgm, vec);
+	    fprintf (stderr, "unable to exec ");
+	    perror (cmd_name);
+	    _exit (1);
+
+	default: 
+	    (void) pidXwait (child_id, NULLCP);
+	    break;
+    }
+    if (fmsh) {			/* assume the worst case */
+	mp -> msgflags |= MODIFIED;
+	modified++;
+    }
+}
+
+/*  */
+
+static struct swit distswit[] = {
+#define	DIANSW	0
+    "annotate", 0,
+#define	DINANSW	1
+    "noannotate", 0,
+#define	DIDFSW	2
+    "draftfolder +folder", 0,
+#define	DIDMSW	3
+    "draftmessage msg", 0,
+#define	DINDFSW	4
+    "nodraftfolder", 0,
+#define	DIEDTSW	5
+    "editor editor", 0,
+#define	DINEDSW	6
+    "noedit", 0,
+#define	DIFRMSW	7
+    "form formfile", 0,
+#define	DIINSW	8
+    "inplace", 0,
+#define	DININSW	9
+    "noinplace", 0,
+#define	DIWHTSW	10
+    "whatnowproc program", 0,
+#define	DINWTSW	11
+    "nowhatnowproc", 0,
+#define	DIHELP	12
+    "help", 4,
+
+    NULL, 0
+};
+
+/*  */
+
+distcmd (args)
+char  **args;
+{
+    int     vecp = 1;
+    char   *cp,
+           *msg = NULL,
+            buf[BUFSIZ],
+           *vec[MAXARGS];
+
+    if (fmsh) {
+	forkcmd (args, cmd_name);
+	return;
+    }
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (smatch (++cp, distswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, distswit);
+		    return;
+		case UNKWNSW: 
+		    fprintf (stderr, "-%s unknown\n", cp);
+		    return;
+		case DIHELP: 
+		    (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
+		    help (buf, distswit);
+		    return;
+
+		case DIANSW:	/* not implemented */
+		case DINANSW: 
+		case DIINSW: 
+		case DININSW: 
+		    continue;
+
+		case DINDFSW:
+		case DINEDSW:
+		case DINWTSW:
+		    vec[vecp++] = --cp;
+		    continue;
+
+		case DIEDTSW: 
+		case DIFRMSW: 
+		case DIDFSW:
+		case DIDMSW:
+		case DIWHTSW:
+		    vec[vecp++] = --cp;
+		    if (!(cp = *args++) || *cp == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    vec[vecp++] = cp;
+		    continue;
+	    }
+	if (*cp == '+' || *cp == '@') {
+	    advise (NULLCP, "sorry, no folders allowed!");
+	    return;
+	}
+	else
+	    if (msg) {
+		advise (NULLCP, "only one message at a time!");
+		return;
+	    }
+	    else
+		msg = cp;
+    }
+
+    vec[0] = cmd_name;
+    vec[vecp++] = "-file";
+    vec[vecp] = NULL;
+    if (!msg)
+	msg = "cur";
+    if (!m_convert (mp, msg))
+	return;
+    m_setseq (mp);
+
+    if (mp -> numsel > 1) {
+	advise (NULLCP, "only one message at a time!");
+	return;
+    }
+    (void) process (mp -> hghsel, cmd_name, vecp, vec);
+    m_setcur (mp, mp -> hghsel);
+}
+
+/*  */
+
+static struct swit explswit[] = {
+#define	EXINSW	0
+    "inplace", 0,
+#define	EXNINSW	1
+    "noinplace", 0,
+#define	EXQISW	2
+    "quiet", 0,
+#define	EXNQISW	3
+    "noquiet", 0,
+#define	EXVBSW	4
+    "verbose", 0,
+#define	EXNVBSW	5
+    "noverbose", 0,
+#define	EXHELP	6
+    "help", 4,
+
+    NULL, 0
+};
+
+/*  */
+
+explcmd (args)
+char  **args;
+{
+    int     inplace = 0,
+            quietsw = 0,
+            verbosw = 0,
+            msgp = 0,
+            hi,
+            msgnum;
+    char   *cp,
+            buf[BUFSIZ],
+           *msgs[MAXARGS];
+    struct Msg *smsgs;
+
+    if (fmsh) {
+	forkcmd (args, cmd_name);
+	return;
+    }
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (smatch (++cp, explswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, explswit);
+		    return;
+		case UNKWNSW: 
+		    fprintf (stderr, "-%s unknown\n", cp);
+		    return;
+		case EXHELP: 
+		    (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
+		    help (buf, explswit);
+		    return;
+
+		case EXINSW: 
+		    inplace++;
+		    continue;
+		case EXNINSW: 
+		    inplace = 0;
+		    continue;
+		case EXQISW: 
+		    quietsw++;
+		    continue;
+		case EXNQISW: 
+		    quietsw = 0;
+		    continue;
+		case EXVBSW: 
+		    verbosw++;
+		    continue;
+		case EXNVBSW: 
+		    verbosw = 0;
+		    continue;
+	    }
+	if (*cp == '+' || *cp == '@') {
+	    advise (NULLCP, "sorry, no folders allowed!");
+	    return;
+	}
+	else
+	    msgs[msgp++] = cp;
+    }
+
+    if (!msgp)
+	msgs[msgp++] = "cur";
+    for (msgnum = 0; msgnum < msgp; msgnum++)
+	if (!m_convert (mp, msgs[msgnum]))
+	    return;
+    m_setseq (mp);
+
+    smsgs = (struct Msg *)
+		calloc ((unsigned) (MAXFOLDER + 2), sizeof *smsgs);
+    if (smsgs == NULL)
+	adios (NULLCP, "unable to allocate folder storage");
+
+    hi = mp -> hghmsg + 1;
+    interrupted = 0;
+    for (msgnum = mp -> lowsel;
+	    msgnum <= mp -> hghsel && !interrupted;
+	    msgnum++)
+	if (mp -> msgstats[msgnum] & SELECTED)
+	    if (burst (smsgs, msgnum, inplace, quietsw, verbosw) != OK)
+		break;
+
+    free ((char *) smsgs);
+
+    if (inplace)
+	m_setcur (mp, mp -> lowsel);
+    else
+	if (hi <= mp -> hghmsg)
+	    m_setcur (mp, hi);
+
+    mp -> msgflags |= MODIFIED;
+    modified++;
+}
+
+/*  */
+
+static  burst (smsgs, msgnum, inplace, quietsw, verbosw)
+struct Msg *smsgs;
+int     msgnum,
+        inplace,
+        quietsw,
+        verbosw;
+{
+    int     i,
+            j,
+            ld3,
+	    wasdlm,
+            msgp;
+    long    pos;
+    char    c,
+	    cc,
+            buffer[BUFSIZ];
+    register FILE *zp;
+
+    ld3 = strlen (delim3);
+
+    if (Msgs[msgnum].m_scanl) {
+	free (Msgs[msgnum].m_scanl);
+	Msgs[msgnum].m_scanl = NULL;
+    }
+
+    pos = ftell (zp = msh_ready (msgnum, 1));
+    for (msgp = 0; msgp <= MAXFOLDER;) {
+	while (fgets (buffer, sizeof buffer, zp) != NULL
+		&& buffer[0] == '\n'
+		&& pos < Msgs[msgnum].m_stop)
+	    pos += (long) strlen (buffer);
+	if (feof (zp) || pos >= Msgs[msgnum].m_stop)
+	    break;
+	(void) fseek (zp, pos, 0);
+	smsgs[msgp].m_start = pos;
+
+	for (c = 0;
+		pos < Msgs[msgnum].m_stop
+		&& fgets (buffer, sizeof buffer, zp) != NULL;
+		c = buffer[0])
+	    if (strncmp (buffer, delim3, ld3) == 0
+		    && (msgp == 1 || c == '\n')
+		    && peekc (zp) == '\n')
+		break;
+	    else
+		pos += (long) strlen (buffer);
+
+	wasdlm = strncmp (buffer, delim3, ld3) == 0;
+	if (smsgs[msgp].m_start != pos)
+	    smsgs[msgp++].m_stop = (c == '\n' && wasdlm) ? pos - 1 : pos;
+	if (feof (zp) || pos >= Msgs[msgnum].m_stop) {
+	    if (wasdlm)
+		smsgs[msgp - 1].m_stop -= ((long) strlen (buffer) + 1);
+	    break;
+	}
+	pos += (long) strlen (buffer);
+    }
+
+    switch (msgp--) {		/* toss "End of XXX Digest" */
+	case 0: 
+	    adios (NULLCP, "burst() botch -- you lose big");
+
+	case 1: 
+	    if (!quietsw)
+		printf ("message %d not in digest format\n", msgnum);
+	    return OK;
+
+	default: 
+	    if (verbosw)
+		printf ("%d message%s exploded from digest %d\n",
+			msgp, msgp != 1 ? "s" : "", msgnum);
+	    break;
+    }
+
+    if ((i = msgp + mp -> hghmsg) > MAXFOLDER) {
+	advise (NULLCP, "more than %d messages", MAXFOLDER);
+	return NOTOK;
+    }
+    if ((mp = m_remsg (mp, 0, i)) == NULL)
+	adios (NULLCP, "unable to allocate folder storage");
+
+    j = mp -> hghmsg;
+    mp -> hghmsg += msgp;
+    mp -> nummsg += msgp;
+    if (mp -> hghsel > msgnum)
+	mp -> hghsel += msgp;
+
+    if (inplace)
+	for (i = mp -> hghmsg; j > msgnum; i--, j--) {
+	    if (verbosw)
+		printf ("message %d becomes message %d\n", j, i);
+
+	    Msgs[i].m_bboard_id = Msgs[j].m_bboard_id;
+	    Msgs[i].m_top = Msgs[j].m_top;
+	    Msgs[i].m_start = Msgs[j].m_start;
+	    Msgs[i].m_stop = Msgs[j].m_stop;
+	    Msgs[i].m_scanl = NULL;
+	    if (Msgs[j].m_scanl) {
+		free (Msgs[j].m_scanl);
+		Msgs[j].m_scanl = NULL;
+	    }
+	    mp -> msgstats[i] = mp -> msgstats[j];
+	}
+
+    if (Msgs[msgnum].m_bboard_id == 0)
+	(void) readid (msgnum);
+
+    mp -> msgstats[msgnum] &= ~SELECTED;
+    i = inplace ? msgnum + msgp : mp -> hghmsg;
+    for (j = msgp; j >= (inplace ? 0 : 1); i--, j--) {
+	if (verbosw && i != msgnum)
+	    printf ("message %d of digest %d becomes message %d\n",
+		    j, msgnum, i);
+
+	Msgs[i].m_bboard_id = Msgs[msgnum].m_bboard_id;
+	Msgs[i].m_top = Msgs[j].m_top;
+	Msgs[i].m_start = smsgs[j].m_start;
+	Msgs[i].m_stop = smsgs[j].m_stop;
+	Msgs[i].m_scanl = NULL;
+	mp -> msgstats[i] = mp -> msgstats[msgnum];
+    }
+
+    return OK;
+}
+
+/*  */
+
+static struct swit fileswit[] = {
+#define	FIDRFT	0
+    "draft", 0,
+#define	FILINK	1
+    "link", 0,
+#define	FINLINK	2
+    "nolink", 0,
+#define	FIPRES	3
+    "preserve", 0,
+#define FINPRES	4
+    "nopreserve", 0,
+#define	FISRC	5
+    "src +folder", 0,
+#define	FIFILE	6
+    "file file", 0,
+#define	FIPROC	7
+    "rmmproc program", 0,
+#define	FINPRC	8
+    "normmproc", 0,
+#define	FIHELP	9
+    "help", 4,
+
+    NULL, 0
+};
+
+/*  */
+
+filecmd (args)
+char  **args;
+{
+    int	    linksw = 0,
+	    msgp = 0,
+            vecp = 1,
+	    i,
+            msgnum;
+    char   *cp,
+            buf[BUFSIZ],
+           *msgs[MAXARGS],
+           *vec[MAXARGS];
+
+    if (fmsh) {
+	forkcmd (args, cmd_name);
+	return;
+    }
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (i = smatch (++cp, fileswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, fileswit);
+		    return;
+		case UNKWNSW: 
+		    fprintf (stderr, "-%s unknown\n", cp);
+		    return;
+		case FIHELP: 
+		    (void) sprintf (buf, "%s +folder... [msgs] [switches]",
+			    cmd_name);
+		    help (buf, fileswit);
+		    return;
+
+		case FILINK:
+		    linksw++;
+		    continue;
+		case FINLINK: 
+		    linksw = 0;
+		    continue;
+
+		case FIPRES: 
+		case FINPRES: 
+		    continue;
+
+		case FISRC: 
+		case FIDRFT:
+		case FIFILE: 
+		case FIPROC:
+		case FINPRC:
+		    advise (NULLCP, "sorry, -%s not allowed!", fileswit[i].sw);
+		    return;
+	    }
+	if (*cp == '+' || *cp == '@')
+	    vec[vecp++] = cp;
+	else
+	    msgs[msgp++] = cp;
+    }
+
+    vec[0] = cmd_name;
+    vec[vecp++] = "-file";
+    vec[vecp] = NULL;
+    if (!msgp)
+	msgs[msgp++] = "cur";
+    for (msgnum = 0; msgnum < msgp; msgnum++)
+	if (!m_convert (mp, msgs[msgnum]))
+	    return;
+    m_setseq (mp);
+
+    interrupted = 0;
+    for (msgnum = mp -> lowsel;
+	    msgnum <= mp -> hghsel && !interrupted;
+	    msgnum++)
+	if (mp -> msgstats[msgnum] & SELECTED)
+	    if (process (msgnum, fileproc, vecp, vec)) {
+		mp -> msgstats[msgnum] &= ~SELECTED;
+		mp -> numsel--;
+	    }
+
+    if (mp -> numsel != mp -> nummsg || linksw)
+	m_setcur (mp, mp -> hghsel);
+    if (!linksw)
+	rmm ();
+}
+
+/*  */
+
+int	filehak (args)
+char  **args;
+{
+    int	    result,
+	    vecp = 0;
+    char   *cp,
+	   *cwd,
+           *vec[MAXARGS];
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (smatch (++cp, fileswit)) {
+		case AMBIGSW: 
+		case UNKWNSW: 
+		case FIHELP: 
+		    return NOTOK;
+
+		case FILINK:
+		case FINLINK: 
+		case FIPRES: 
+		case FINPRES: 
+		    continue;
+
+		case FISRC: 
+		case FIDRFT:
+		case FIFILE: 
+		    return NOTOK;
+	    }
+	if (*cp == '+' || *cp == '@')
+	    vec[vecp++] = cp;
+    }
+    vec[vecp] = NULL;
+
+    result = NOTOK;
+    cwd = NULL;
+    for (vecp = 0; (cp = vec[vecp]) && result == NOTOK; vecp++) {
+	if (cwd == NULL)
+	    cwd = getcpy (pwd ());
+	(void) chdir (m_maildir (""));
+	cp = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
+	if (access (m_maildir (cp), 0) == NOTOK)
+	    result = OK;
+	free (cp);
+    }
+    if (cwd)
+	(void) chdir (cwd);
+
+    return result;
+}
+
+/*  */
+
+static struct swit foldswit[] = {
+#define	FLALSW	0
+    "all", 0,
+#define	FLFASW	1
+    "fast", 0,
+#define	FLNFASW	2
+    "nofast", 0,
+#define	FLHDSW	3
+    "header", 0,
+#define	FLNHDSW	4
+    "noheader", 0,
+#define	FLPKSW	5
+    "pack", 0,
+#define	FLNPKSW	6
+    "nopack", 0,
+#define	FLRCSW	7
+    "recurse", 0,
+#define	FLNRCSW	8
+    "norecurse", 0,
+#define	FLTLSW	9
+    "total", 0,
+#define	FLNTLSW	10
+    "nototal", 0,
+#define	FLPRSW	11
+    "print", 0,
+#define	FLPUSW	12
+    "push", 0,
+#define	FLPOSW	13
+    "pop", 0,
+#define	FLLISW	14
+    "list", 0,
+#define	FLHELP	15
+    "help", 4,
+
+    NULL, 0
+};
+
+/*  */
+
+foldcmd (args)
+char  **args;
+{
+    int     fastsw = 0,
+            headersw = 0,
+	    packsw = 0,
+	    hole,
+	    msgnum;
+    char   *cp,
+           *folder = NULL,
+           *msg = NULL,
+            buf[BUFSIZ],
+	  **vec = args;
+
+    if (args == NULL)
+	goto fast;
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (smatch (++cp, foldswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, foldswit);
+		    return;
+		case UNKWNSW: 
+		    fprintf (stderr, "-%s unknown\n", cp);
+		    return;
+		case FLHELP: 
+		    (void) sprintf (buf, "%s [+folder] [msg] [switches]",
+			    cmd_name);
+		    help (buf, foldswit);
+		    return;
+
+		case FLALSW:	/* not implemented */
+		case FLRCSW: 
+		case FLNRCSW: 
+		case FLTLSW: 
+		case FLNTLSW: 
+		case FLPRSW:
+		case FLPUSW:
+		case FLPOSW:
+		case FLLISW:
+		    continue;
+
+		case FLFASW: 
+		    fastsw++;
+		    continue;
+		case FLNFASW: 
+		    fastsw = 0;
+		    continue;
+		case FLHDSW: 
+		    headersw++;
+		    continue;
+		case FLNHDSW: 
+		    headersw = 0;
+		    continue;
+		case FLPKSW: 
+		    packsw++;
+		    continue;
+		case FLNPKSW: 
+		    packsw = 0;
+		    continue;
+	    }
+	if (*cp == '+' || *cp == '@')
+	    if (folder) {
+		advise (NULLCP, "only one folder at a time!\n");
+		return;
+	    }
+	    else
+		folder = fmsh ? path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF)
+			    : cp + 1;
+	else
+	    if (msg) {
+		advise (NULLCP, "only one message at a time!\n");
+		return;
+	    }
+	    else
+		msg = cp;
+    }
+
+    if (folder) {
+	if (*folder == 0) {
+	    advise (NULLCP, "null folder names are not permitted");
+	    return;
+	}
+	if (fmsh) {
+	    if (access (m_maildir (folder), 04) == NOTOK) {
+		advise (folder, "unable to read");
+		return;
+	    }
+	}
+	else {
+	    (void) strcpy (buf, folder);
+	    if (expand (buf) == NOTOK)
+		return;
+	    folder = buf;
+	    if (access (folder, 04) == NOTOK) {
+		advise (folder, "unable to read");
+		return;
+	    }
+	}
+	m_reset ();
+
+	if (fmsh)
+	    fsetup (folder);
+	else
+	    setup (folder);
+	readids (0);
+	display_info (0);
+    }
+
+    if (msg) {
+	if (!m_convert (mp, msg))
+	    return;
+	m_setseq (mp);
+
+	if (mp -> numsel > 1) {
+	    advise (NULLCP, "only one message at a time!");
+	    return;
+	}
+	m_setcur (mp, mp -> hghsel);
+    }
+
+    if (packsw) {
+	if (fmsh) {
+	    forkcmd (vec, cmd_name);
+	    return;
+	}
+
+	if (mp -> lowmsg > 1 && (mp = m_remsg (mp, 1, mp -> hghmsg)) == NULL)
+	    adios (NULLCP, "unable to allocate folder storage");
+	for (msgnum = mp -> lowmsg, hole = 1; msgnum <= mp -> hghmsg; msgnum++)
+	    if (mp -> msgstats[msgnum] & EXISTS) {
+		if (msgnum != hole) {
+		    Msgs[hole].m_bboard_id = Msgs[msgnum].m_bboard_id;
+		    Msgs[hole].m_top = Msgs[msgnum].m_top;
+		    Msgs[hole].m_start = Msgs[msgnum].m_start;
+		    Msgs[hole].m_stop = Msgs[msgnum].m_stop;
+		    Msgs[hole].m_scanl = NULL;
+		    if (Msgs[msgnum].m_scanl) {
+			free (Msgs[msgnum].m_scanl);
+			Msgs[msgnum].m_scanl = NULL;
+		    }
+		    mp -> msgstats[hole] = mp -> msgstats[msgnum];
+		    if (mp -> curmsg == msgnum)
+			m_setcur (mp, hole);
+		}
+		hole++;
+	    }
+	if (mp -> nummsg > 0) {
+	    mp -> lowmsg = 1;
+	    mp -> hghmsg = hole - 1;
+	}
+	mp -> msgflags |= MODIFIED;
+	modified++;
+    }
+
+fast: ;
+    if (fastsw)
+	printf ("%s\n", fmsh ? fmsh : mp -> foldpath);
+    else {
+	if (headersw)
+	    printf ("\t\tFolder  %*s# of messages (%*srange%*s); cur%*smsg\n",
+		DMAXFOLDER, "", DMAXFOLDER - 2, "", DMAXFOLDER - 2, "",
+		DMAXFOLDER - 2, "");
+	printf (args ? "%22s  " : "%s ", fmsh ? fmsh : mp -> foldpath);
+	if (mp -> hghmsg == 0)
+	    printf ("has   no messages%*s",
+		    mp -> msgflags & OTHERS ? DMAXFOLDER * 2 + 4 : 0, "");
+	else {
+	    printf ("has %*d message%s (%*d-%*d)",
+		    DMAXFOLDER, mp -> nummsg, mp -> nummsg != 1 ? "s" : "",
+		    DMAXFOLDER, mp -> lowmsg, DMAXFOLDER, mp -> hghmsg);
+	    if (mp -> curmsg >= mp -> lowmsg
+		    && mp -> curmsg <= mp -> hghmsg)
+		printf ("; cur=%*d", DMAXFOLDER, mp -> curmsg);
+	}
+	printf (".\n");
+    }
+}
+
+/*  */
+
+#ifndef	MIME
+#define	MIMEminc(a)	(a)
+#else	/* MIME */
+#define	MIMEminc(a)	0
+#endif	/* MIME */
+
+static struct swit forwswit[] = {
+#define	FOANSW	0
+    "annotate", 0,
+#define	FONANSW	1
+    "noannotate", 0,
+#define	FODFSW	2
+    "draftfolder +folder", 0,
+#define	FODMSW	3
+    "draftmessage msg", 0,
+#define	FONDFSW	4
+    "nodraftfolder", 0,
+#define	FOEDTSW	5
+    "editor editor", 0,
+#define	FONEDSW	6
+    "noedit", 0,
+#define	FOFTRSW	7
+    "filter filterfile", 0,
+#define	FOFRMSW	8
+    "form formfile", 0,
+#define	FOFTSW	9
+    "format", 5,
+#define	FONFTSW	10
+    "noformat", 7,
+#define	FOINSW	11
+    "inplace", 0,
+#define	FONINSW	12
+    "noinplace", 0,
+#define	FOMISW	13
+    "mime", MIMEminc(-4),
+#define	FONMISW	14
+    "nomime", MIMEminc(-6),
+#define	FOWHTSW	15
+    "whatnowproc program", 0,
+#define	FONWTSW	16
+    "nowhatnow", 0,
+#define	FOHELP	17
+    "help", 4,
+
+    NULL, 0
+};
+
+/*  */
+
+forwcmd (args)
+char  **args;
+{
+    int	    msgp = 0,
+            vecp = 1,
+	    mime = 0,
+            msgnum;
+    char   *cp,
+           *filter = NULL,
+            buf[BUFSIZ],
+           *msgs[MAXARGS],
+           *vec[MAXARGS];
+    char   *mktemp ();
+
+    if (fmsh) {
+	forkcmd (args, cmd_name);
+	return;
+    }
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (smatch (++cp, forwswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, forwswit);
+		    return;
+		case UNKWNSW: 
+		    fprintf (stderr, "-%s unknown\n", cp);
+		    return;
+		case FOHELP: 
+		    (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
+		    help (buf, forwswit);
+		    return;
+
+		case FOANSW:	/* not implemented */
+		case FONANSW: 
+		case FOINSW: 
+		case FONINSW: 
+		    continue;
+
+		case FOMISW:
+#ifdef	MIME
+		    mime = 1;
+		    filter = NULL;
+#endif	/* MIME */
+		    continue;
+		case FONMISW:
+		    mime = 0;
+		    continue;
+
+		case FONDFSW:
+		case FONEDSW:
+		case FONWTSW:
+		    vec[vecp++] = --cp;
+		    continue;
+
+		case FOEDTSW: 
+		case FOFRMSW: 
+		case FODFSW:
+		case FODMSW:
+		case FOWHTSW:
+		    vec[vecp++] = --cp;
+		    if (!(cp = *args++) || *cp == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    vec[vecp++] = cp;
+		    continue;
+		case FOFTRSW: 
+		    if (!(filter = *args++) || *filter == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    mime = 0;
+		    continue;
+		case FOFTSW: 
+		    if (access (filter = myfilter, 04) == NOTOK) {
+			advise (filter, "unable to read default filter file");
+			return;
+		    }
+		    continue;
+		case FONFTSW: 
+		    filter = NULL;
+		    continue;
+	    }
+	if (*cp == '+' || *cp == '@') {
+	    advise (NULLCP, "sorry, no folders allowed!");
+	    return;
+	}
+	else
+	    msgs[msgp++] = cp;
+    }
+
+					/* foil search of .mh_profile */
+    (void) sprintf (buf, "%sXXXXXX", invo_name);
+    vec[0] = (char *)mktemp (buf);
+    vec[vecp++] = "-file";
+    vec[vecp] = NULL;
+    if (!msgp)
+	msgs[msgp++] = "cur";
+    for (msgnum = 0; msgnum < msgp; msgnum++)
+	if (!m_convert (mp, msgs[msgnum]))
+	    return;
+    m_setseq (mp);
+
+    if (filter) {
+	(void) strcpy (buf, filter);
+	if (expand (buf) == NOTOK)
+	    return;
+	if (access (filter = getcpy (libpath (buf)), 04) == NOTOK) {
+	    advise (filter, "unable to read");
+	    free (filter);
+	    return;
+	}
+    }
+    forw (cmd_name, filter, vecp, vec, mime);
+    m_setcur (mp, mp -> hghsel);
+    if (filter)
+	free (filter);
+}
+
+/*  */
+
+static	forw (proc, filter, vecp, vec, mime)
+int     vecp,
+    	mime;
+char   *proc,
+       *filter,
+      **vec;
+{
+    int     i,
+            child_id,
+            msgnum,
+            msgcnt;
+    char    tmpfil[80],
+           *args[MAXARGS];
+    FILE   *out;
+#ifdef	MIME
+    int	    nedit = 0;
+    char   *ed = NULL;
+#endif	/* MIME */
+
+    (void) strcpy (tmpfil, m_tmpfil (invo_name));
+    interrupted = 0;
+    if (filter)
+	switch (child_id = fork ()) {
+	    case NOTOK: 
+		advise ("fork", "unable to");
+		return;
+
+	    case OK: 		/* "trust me" */
+		if (freopen (tmpfil, "w", stdout) == NULL) {
+		    fprintf (stderr, "unable to create ");
+		    perror (tmpfil);
+		    _exit (1);
+		}
+		args[0] = r1bindex (mhlproc, '/');
+		i = 1;
+		args[i++] = "-forwall";
+		args[i++] = "-form";
+		args[i++] = filter;
+		for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
+		    if (mp -> msgstats[msgnum] & SELECTED)
+			args[i++] = getcpy (m_name (msgnum));
+		args[i] = NULL;
+		(void) mhlsbr (i, args, mhl_action);
+		m_eomsbr ((int (*) ()) 0);
+		(void) fclose (stdout);
+		_exit (0);
+
+	    default: 
+		if (pidXwait (child_id, NULLCP))
+		    interrupted++;
+		break;
+	}
+#ifdef	MIME
+    else if (mime) {
+	int	isdf = 0,
+		len,
+		nwhat = 0;
+#define	INITIAL_PREFIX	"----- =_aaaaaaaaaa"
+	char   *cp,
+	       *form = NULL,
+		buffer[BUFSIZ],
+		prefix[sizeof INITIAL_PREFIX];
+	FILE   *zp;
+
+	proc = whatnowproc;
+	for (vecp = 1; cp = vec[vecp++]; )
+	    if (*cp == '-')
+		switch (smatch (++cp, forwswit)) {
+		    case FOEDTSW:
+		        ed = vec[vecp++];
+			nedit = 0;
+			continue;
+		    case FONEDSW:
+			nedit++;
+			continue;
+
+		    case FOFRMSW:
+			form = vec[vecp++];
+			continue;
+			
+		    case FOWHTSW:
+			proc = vec[vecp++];
+			nwhat = 0;
+			continue;
+		    case FONWTSW:
+			nwhat++;
+			continue;
+
+/* ignore -draftfolder / -draftmessage / -nodraftfolder */
+		    case FODFSW:
+		    case FODMSW:
+			vecp++;
+		    case FONDFSW:
+			continue;
+		}
+	(void) strcpy (tmpfil, m_draft (NULLCP, NULLCP, NOUSE, &isdf));
+	if (!ed && !(ed = m_find ("editor")))
+	    ed = sysed;
+
+	(void) strcpy (prefix, INITIAL_PREFIX);
+	cp = index (prefix, 'a');
+	len = strlen (prefix);
+
+	for (;;) {
+	    int    hit = 0;
+	    long    pos;
+	    
+	    for (msgnum = mp -> lowsel;
+		     msgnum <= mp -> hghsel && !interrupted && !hit;
+		     msgnum++)
+		if (mp -> msgstats[msgnum] & SELECTED) {
+		    zp = msh_ready (msgnum, 1);
+		    if (!fmsh)
+			pos = ftell (zp);
+		    while (fgets (buffer, sizeof buffer, zp) != NULL
+			       && !fmsh
+			       && pos < Msgs[msgnum].m_stop) {
+			register char   *pp;
+
+			if (buffer[0] != '-' || buffer[1] != '-')
+			    continue;
+
+			for (pp = buffer + strlen (buffer) - 1;
+			         pp >= buffer;
+			         pp--)
+			    if (!isspace (*pp))
+				break;
+			*pp++ = '\0';
+
+			if (strncmp (buffer + 2, prefix, len))
+			    continue;
+
+			hit = 1;
+			break;
+		    }
+		}
+
+	    if (!hit)
+		break;
+
+	    if (*cp < 'z')
+		(*cp)++;
+	    else
+		if (*++cp == 0) {
+		    advise (NULLCP,
+			    "unable to determine unique delimiter string?!?");
+		    return;
+		}
+	        else
+		    (*cp)++;
+	}
+
+	if ((out = fopen (tmpfil, "w")) == NULL) {
+	    advise (tmpfil, "unable to create temporary file");
+	    return;
+	}
+	(void) chmod (tmpfil, m_gmprot ());
+
+	fprintf (out, "%s: %s\n", VRSN_FIELD, VRSN_VALUE);
+	fprintf (out, "%s: multipart/digest; boundary=\"%s\"\n", TYPE_FIELD,
+		 prefix);
+
+	if (!(zp = fopen (libpath (form ? form : forwcomps), "r"))) {
+	    if (form)
+		advise (form, "unable to open form file");
+	    else
+		advise (forwcomps, "unable to open default components file");
+	    (void) fclose (out);
+	    (void) unlink (tmpfil);
+	    return;
+	}
+	while (fgets (buffer, sizeof buffer, zp))
+	    (void) fputs (buffer, out);
+	(void) fclose (zp);
+
+	for (msgnum = mp -> lowsel;
+	         msgnum <= mp -> hghsel && !interrupted;
+	         msgnum++)
+	    if (mp -> msgstats[msgnum] & SELECTED) {
+		fprintf (out, "\n--%s\n%s: message/rfc822\n\n", prefix,
+			 TYPE_FIELD);
+
+		copy_message (msgnum, out);
+	    }
+	fprintf (out, "\n--%s--\n", prefix);
+
+	(void) fclose (out);
+	if (nwhat)
+	    return;
+    }
+#endif	/* MIME */
+    else {
+	if ((out = fopen (tmpfil, "w")) == NULL) {
+	    advise (tmpfil, "unable to create temporary file");
+	    return;
+	}
+
+	msgcnt = 1;
+	for (msgnum = mp -> lowsel;
+		msgnum <= mp -> hghsel && !interrupted;
+		msgnum++)
+	    if (mp -> msgstats[msgnum] & SELECTED) {
+		fprintf (out, "\n\n-------");
+		if (msgnum == mp -> lowsel)
+		    fprintf (out, " Forwarded Message%s",
+			    mp -> numsel > 1 ? "s" : "");
+		else
+		    fprintf (out, " Message %d", msgcnt);
+		fprintf (out, "\n\n");
+		copy_digest (msgnum, out);
+		msgcnt++;
+	    }
+
+	fprintf (out, "\n\n------- End of Forwarded Message%s\n",
+		mp -> numsel > 1 ? "s" : "");
+	(void) fclose (out);
+    }
+
+    (void) fflush (stdout);
+    if (!interrupted)
+	switch (child_id = fork ()) {
+	    case NOTOK: 
+		advise ("fork", "unable to");
+		break;
+
+	    case OK: 
+		closefds (3);
+		(void) signal (SIGINT, istat);
+		(void) signal (SIGQUIT, qstat);
+
+#ifdef	MIME
+		if (mime) {
+		    vecp = 0;
+		    vec[vecp++] = r1bindex (proc, '/');
+		    (void) m_putenv ("mhdraft", tmpfil);
+		    (void) unputenv ("mhfolder");
+		    (void) unputenv ("mhaltmsg");
+		    (void) m_putenv ("mhdist", "0");
+		    if (nedit)
+			(void) unputenv ("mheditor");
+		    else
+			(void) m_putenv ("mheditor", ed);
+		    (void) m_putenv ("mhuse", "0");
+		    (void) unputenv ("mhmessages");
+		    (void) unputenv ("mhannotate");
+		    (void) unputenv ("mhinplace");
+		}
+		else
+#endif	/* MIME */
+
+		vec[vecp++] = tmpfil;
+		vec[vecp] = NULL;
+
+		execvp (proc, vec);
+		fprintf (stderr, "unable to exec ");
+		perror (proc);
+		_exit (1);
+
+	    default: 
+		(void) pidXwait (child_id, NULLCP);
+		break;
+	}
+
+#ifdef	MIME
+    if (!mime)
+#endif	/* MIME */
+    (void) unlink (tmpfil);
+}
+
+/*  */
+
+static char *hlpmsg[] = {
+    "The %s program emulates many of the commands found in the Rand MH",
+    "system.  Instead of operating on MH folders, commands to %s concern",
+    "a single file.",
+    "",
+    "To see the list of commands available, just type a ``?'' followed by",
+    "the RETURN key.  To find out what switches each command takes, type",
+    "the name of the command followed by ``-help''.  To leave %s, use the",
+    "``quit'' command.",
+    "",
+    "Although a lot of MH commands are found in %s, not all are fully",
+    "implemented.  %s will always recognize all legal switches for a",
+    "given command though, and will let you know when you ask for an",
+    "option that it is unable to perform.",
+    "",
+    "Running %s is fun, but using MH from your shell is far superior.",
+    "After you have familiarized yourself with the MH style by using %s,",
+    "you should try using MH from the shell.  You can still use %s for",
+    "message files that aren't in MH format, such as BBoard files.",
+    NULL
+};
+
+
+/* ARGSUSED */
+
+helpcmd (args)
+char  **args;
+{
+    int     i;
+
+    for (i = 0; hlpmsg[i]; i++) {
+	printf (hlpmsg[i], invo_name);
+	(void) putchar ('\n');
+    }
+}
+
+/*  */
+
+static struct swit markswit[] = {
+#define	MADDSW	0
+    "add", 0,
+#define	MDELSW	1
+    "delete", 0,
+#define	MLSTSW	2
+    "list", 0,
+#define	MSEQSW	3
+    "sequence name", 0,
+#define	MPUBSW	4
+    "public", 0,
+#define	MNPUBSW	5
+    "nopublic", 0,
+#define	MZERSW	6
+    "zero", 0,
+#define	MNZERSW	7
+    "nozero", 0,
+#define	MHELP	8
+    "help", 4,
+#define	MDBUGSW	9
+    "debug", -5,
+
+    NULL, 0
+};
+
+/*  */
+
+markcmd (args)
+char  **args;
+{
+    int     addsw = 0,
+            deletesw = 0,
+            debugsw = 0,
+            listsw = 0,
+            zerosw = 0,
+            seqp = 0,
+            msgp = 0,
+            i,
+            msgnum;
+    char   *cp,
+            buf[BUFSIZ],
+           *seqs[NATTRS + 1],
+           *msgs[MAXARGS];
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (smatch (++cp, markswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, markswit);
+		    return;
+		case UNKWNSW: 
+		    fprintf (stderr, "-%s unknown\n", cp);
+		    return;
+		case MHELP: 
+		    (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
+		    help (buf, markswit);
+		    return;
+
+		case MADDSW: 
+		    addsw++;
+		    deletesw = listsw = 0;
+		    continue;
+		case MDELSW: 
+		    deletesw++;
+		    addsw = listsw = 0;
+		    continue;
+		case MLSTSW: 
+		    listsw++;
+		    addsw = deletesw = 0;
+		    continue;
+
+		case MSEQSW: 
+		    if (!(cp = *args++) || *cp == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    if (seqp < NATTRS)
+			seqs[seqp++] = cp;
+		    else {
+			advise (NULLCP, "only %d sequences allowed!", NATTRS);
+			return;
+		    }
+		    continue;
+
+		case MPUBSW: 	/* not implemented */
+		case MNPUBSW: 
+		    continue;
+
+		case MDBUGSW: 
+		    debugsw++;
+		    continue;
+
+		case MZERSW: 
+		    zerosw++;
+		    continue;
+		case MNZERSW: 
+		    zerosw = 0;
+		    continue;
+	    }
+	if (*cp == '+' || *cp == '@') {
+	    advise (NULLCP, "sorry, no folders allowed!");
+	    return;
+	}
+	else
+	    msgs[msgp++] = cp;
+    }
+
+    if (!addsw && !deletesw && !listsw)
+	if (seqp)
+	    addsw++;
+	else
+	    if (debugsw)
+		listsw++;
+	    else {
+		seqs[seqp++] = "unseen";
+		deletesw++;
+		zerosw = 0;
+		if (!msgp)
+		    msgs[msgp++] = "all";
+	    }
+
+    if (!msgp)
+	msgs[msgp++] = listsw ? "all" :"cur";
+    for (msgnum = 0; msgnum < msgp; msgnum++)
+	if (!m_convert (mp, msgs[msgnum]))
+	    return;
+
+    if (debugsw) {
+	printf ("invo_name=%s mypath=%s defpath=%s\n",
+		invo_name, mypath, defpath);
+	printf ("ctxpath=%s context flags=%s\n",
+		ctxpath, sprintb (buf, (unsigned) ctxflags, DBITS));
+	printf ("foldpath=%s flags=%s\n",
+		mp -> foldpath,
+		sprintb (buf, (unsigned) mp -> msgflags, FBITS));
+	printf ("hghmsg=%d lowmsg=%d nummsg=%d curmsg=%d\n",
+		mp -> hghmsg, mp -> lowmsg, mp -> nummsg, mp -> curmsg);
+	printf ("lowsel=%d hghsel=%d numsel=%d\n",
+		mp -> lowsel, mp -> hghsel, mp -> numsel);
+#ifndef	MTR
+	printf ("lowoff=%d hghoff=%d\n",
+		mp -> lowoff, mp -> hghoff);
+#else	/* MTR */
+	printf ("lowoff=%d hghoff=%d msgbase=0x%x msgstats=0x%x\n",
+		mp -> lowoff, mp -> hghoff, mp -> msgbase, mp -> msgstats);
+#endif	/* MTR */
+    }
+
+    if (seqp == 0 && (addsw || deletesw)) {
+	advise (NULLCP, "-%s requires at least one -sequence argument",
+		addsw ? "add" : "delete");
+	return;
+    }
+    seqs[seqp] = NULL;
+
+    if (addsw)
+	for (seqp = 0; seqs[seqp]; seqp++) {
+	    if (zerosw && !m_seqnew (mp, seqs[seqp], 0))
+		return;
+	    for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
+		if (mp -> msgstats[msgnum] & SELECTED)
+		    if (!m_seqadd (mp, seqs[seqp], msgnum, 0))
+			return;
+	}
+
+    if (deletesw)
+	for (seqp = 0; seqs[seqp]; seqp++) {
+	    if (zerosw)
+		for (msgnum = mp -> lowmsg; msgnum <= mp -> hghmsg; msgnum++)
+		    if (mp -> msgstats[msgnum] & EXISTS)
+			if (!m_seqadd (mp, seqs[seqp], msgnum, 0))
+			    return;
+	    for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
+		if (mp -> msgstats[msgnum] & SELECTED)
+		    if (!m_seqdel (mp, seqs[seqp], msgnum))
+			return;
+	}
+
+    if (listsw) {
+	int     bits = FFATTRSLOT;
+
+#define	empty(s)	((s) ? (s) : "")
+	if (seqp == 0)
+	    for (i = 0; mp -> msgattrs[i]; i++)
+		printf ("%s%s: %s\n", mp -> msgattrs[i],
+			mp -> attrstats & (1 << (bits + i))
+			? " (private)" : "",
+			empty(m_seq (mp, mp -> msgattrs[i])));
+	else
+	    for (seqp = 0; seqs[seqp]; seqp++)
+		printf ("%s%s: %s\n", seqs[seqp],
+			empty(m_seq (mp, seqs[seqp])));
+#undef	empty
+
+	interrupted = 0;
+	if (debugsw)
+	    for (msgnum = mp -> lowsel;
+		    msgnum <= mp -> hghsel && !interrupted;
+		    msgnum++)
+		if (mp -> msgstats[msgnum] & SELECTED) {
+		    printf ("%*d: id=%d top=%d start=%ld stop=%ld %s\n",
+			    DMAXFOLDER, msgnum,
+			    Msgs[msgnum].m_bboard_id, Msgs[msgnum].m_top,
+			    Msgs[msgnum].m_start, Msgs[msgnum].m_stop,
+			    sprintb (buf, (unsigned) mp -> msgstats[msgnum],
+				m_seqbits (mp)));
+		    if (Msgs[msgnum].m_scanl)
+			printf ("%s", Msgs[msgnum].m_scanl);
+		}			    
+    }
+}
+
+/*  */
+
+#ifdef MIME
+static struct swit mhnswit[] = {
+#define	MHNAUTOSW	  0
+    "auto", 0,
+#define	MHNNAUTOSW	  1
+    "noauto", 0,
+#define	MHNDEBUGSW	  2
+    "debug", -5,
+#define	MHNEBCDICSW 	 3
+    "ebcdicsafe", 0,
+#define	MHNNEBCDICSW	 4
+    "noebcdicsafe", 0,
+#define	MHNFORMSW	  5
+    "form formfile", 4,
+#define	MHNHEADSW	  6
+    "headers", 0,
+#define	MHNNHEADSW	  7
+    "noheaders", 0,
+#define	MHNLISTSW	  8
+    "list", 0,
+#define	MHNNLISTSW	  9
+    "nolist", 0,
+#define	MHNPARTSW	 10
+    "part number", 0,
+#define	MHNSIZESW	 11
+    "realsize", 0,
+#define	MHNNSIZESW	 12
+    "norealsize", 0,
+#define	MHNRFC934SW	 13
+    "rfc934mode", 0,
+#define	MHNNRFC934SW	 14
+    "norfc934mode", 0,
+#define	MHNSERIALSW	 15
+    "serialonly", 0,
+#define	MHNNSERIALSW	 16
+    "noserialonly", 0,
+#define	MHNSHOWSW	 17
+    "show", 0,
+#define	MHNNSHOWSW	 18
+    "noshow", 0,
+#define	MHNSTORESW	 19
+    "store", 0,
+#define	MHNNSTORESW	 20
+    "nostore", 0,
+#define	MHNTYPESW	 21
+    "type content", 0,
+#define	MHNVERBSW	 22
+    "verbose", 0,
+#define	MHNNVERBSW	 23
+    "noverbose", 0,
+#define	MHNHELPSW	 24
+    "help", 4,
+#define	MHNPROGSW	 25
+    "moreproc program", -4,
+#define	MHNNPROGSW	 26
+    "nomoreproc", -3,
+#define	MHNLENSW	 27
+    "length lines", -4,
+#define	MHNWIDSW	 28
+    "width columns", -4,
+
+    NULL, 0
+};
+
+/*  */
+
+mhncmd (args)
+char  **args;
+{
+    int     msgp = 0,
+	    vecp = 1,
+	    i,
+	    msgnum;
+    char   *cp,
+            buf[BUFSIZ],
+	   *msgs[MAXARGS],
+           *vec[MAXARGS];
+
+    if (fmsh) {
+	forkcmd (args, cmd_name);
+	return;
+    }
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (smatch (++cp, mhnswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, mhnswit);
+		    return;
+		case UNKWNSW: 
+		    fprintf (stderr, "-%s unknown\n", cp);
+		    return;
+		case MHNHELPSW:
+		    (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
+		    help (buf, mhnswit);
+		    return;
+
+		case MHNAUTOSW:
+		case MHNNAUTOSW:
+		case MHNDEBUGSW:
+		case MHNEBCDICSW:
+		case MHNNEBCDICSW:
+		case MHNHEADSW:
+		case MHNNHEADSW:
+		case MHNLISTSW:
+		case MHNNLISTSW:
+		case MHNSIZESW:
+		case MHNNSIZESW:
+		case MHNRFC934SW:
+		case MHNNRFC934SW:
+		case MHNSERIALSW:
+		case MHNNSERIALSW:
+		case MHNSHOWSW:
+		case MHNNSHOWSW:
+		case MHNSTORESW:
+		case MHNNSTORESW:
+		case MHNVERBSW:
+		case MHNNVERBSW:
+		case MHNNPROGSW:
+		    vec[vecp++] = --cp;
+		    continue;
+
+		case MHNFORMSW:
+		case MHNPARTSW:
+		case MHNTYPESW:
+		case MHNPROGSW:
+		case MHNLENSW:
+		case MHNWIDSW:
+		    vec[vecp++] = --cp;
+		    if (!(cp = *args++) || *cp == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    vec[vecp++] = cp;
+		    continue;
+	    }
+	if (*cp == '+' || *cp == '@') {
+	    advise (NULLCP, "sorry, no folders allowed!");
+	    return;
+	}
+	else
+	    msgs[msgp++] = cp;
+    }
+
+    vec[0] = cmd_name;
+    vec[vecp++] = "-file";
+    vec[vecp] = NULL;
+    if (!msgp)
+	msgs[msgp++] = "cur";
+    for (msgnum = 0; msgnum < msgp; msgnum++)
+	if (!m_convert (mp, msgs[msgnum]))
+	    return;
+    m_setseq (mp);
+
+    interrupted = 0;
+    for (msgnum = mp -> lowsel;
+	    msgnum <= mp -> hghsel && !interrupted;
+	    msgnum++)
+	if (mp -> msgstats[msgnum] & SELECTED)
+	    if (process (msgnum, cmd_name, vecp, vec)) {
+		mp -> msgstats[msgnum] &= ~SELECTED;
+		mp -> numsel--;
+	    }
+
+    m_setcur (mp, mp -> hghsel);
+}
+
+/*  */
+
+#endif /* MIME */
+static struct swit packswit[] = {
+#define	PAFISW	0
+    "file name", 0,
+
+#define	PAHELP	1
+    "help", 4,
+
+    NULL, 0
+};
+
+/*  */
+
+packcmd (args)
+char  **args;
+{
+    int     msgp = 0,
+            md,
+            msgnum;
+    char   *cp,
+           *file = NULL,
+            buf[BUFSIZ],
+           *msgs[MAXARGS];
+    struct stat st;
+
+    if (fmsh) {
+	forkcmd (args, cmd_name);
+	return;
+    }
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (smatch (++cp, packswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, packswit);
+		    return;
+		case UNKWNSW: 
+		    fprintf (stderr, "-%s unknown\n", cp);
+		    return;
+		case PAHELP: 
+		    (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
+		    help (buf, packswit);
+		    return;
+
+		case PAFISW: 
+		    if (!(file = *args++) || *file == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    continue;
+	    }
+	if (*cp == '+' || *cp == '@') {
+	    advise (NULLCP, "sorry, no folders allowed!");
+	    return;
+	}
+	else
+	    msgs[msgp++] = cp;
+    }
+
+    if (!file)
+	file = "./msgbox";
+    file = path (file, TFILE);
+    if (stat (file, &st) == NOTOK) {
+	if (errno != ENOENT) {
+	    advise (file, "error on file");
+	    goto done_pack;
+	}
+	md = getanswer (cp = concat ("Create file \"", file, "\"? ", NULLCP));
+	free (cp);
+	if (!md)
+	    goto done_pack;
+    }
+
+    if (!msgp)
+	msgs[msgp++] = "all";
+    for (msgnum = 0; msgnum < msgp; msgnum++)
+	if (!m_convert (mp, msgs[msgnum]))
+	    goto done_pack;
+    m_setseq (mp);
+
+    if ((md = mbx_open (file, getuid (), getgid (), m_gmprot ())) == NOTOK) {
+	advise (file, "unable to open");
+	goto done_pack;
+    }
+    for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
+	if (mp -> msgstats[msgnum] & SELECTED)
+	    if (pack (file, md, msgnum) == NOTOK)
+		break;
+    (void) mbx_close (file, md);
+
+    if (mp -> hghsel != mp -> curmsg)
+	m_setcur (mp, mp -> lowsel);
+
+done_pack: ;
+    free (file);
+}
+
+/*  */
+
+int	pack (mailbox, md, msgnum)
+char   *mailbox;
+int     md,
+        msgnum;
+{
+    register FILE *zp;
+
+    if (Msgs[msgnum].m_bboard_id == 0)
+	(void) readid (msgnum);
+
+    zp = msh_ready (msgnum, 1);
+    return mbx_write (mailbox, md, zp, Msgs[msgnum].m_bboard_id,
+	    0L, ftell (zp), Msgs[msgnum].m_stop, 1, 1);
+}
+
+/*  */
+
+int	packhak (args)
+char  **args;
+{
+    int	    result;
+    char   *cp,
+	   *file = NULL;
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (smatch (++cp, packswit)) {
+		case AMBIGSW: 
+		case UNKWNSW: 
+		case PAHELP: 
+		    return NOTOK;
+
+		case PAFISW: 
+		    if (!(file = *args++) || *file == '-') 
+			return NOTOK;
+		    continue;
+	    }
+	if (*cp == '+' || *cp == '@')
+	    return NOTOK;
+    }
+
+    file = path (file ? file : "./msgbox", TFILE);
+    result = access (file, 0) == NOTOK ? OK : NOTOK;
+    free (file);
+
+    return result;
+}
+
+/*  */
+
+static struct swit pickswit[] = {
+#define	PIANSW	0
+    "and", 0,
+#define	PIORSW	1
+    "or", 0,
+#define	PINTSW	2
+    "not", 0,
+#define	PILBSW	3
+    "lbrace", 0,
+#define	PIRBSW	4
+    "rbrace", 0,
+
+#define	PICCSW	5
+    "cc  pattern", 0,
+#define	PIDASW	6
+    "date  pattern", 0,
+#define	PIFRSW	7
+    "from  pattern", 0,
+#define	PISESW	8
+    "search  pattern", 0,
+#define	PISUSW	9
+    "subject  pattern", 0,
+#define	PITOSW	10
+    "to  pattern", 0,
+#define	PIOTSW	11
+    "-othercomponent  pattern", 15,
+#define	PIAFSW	12
+    "after date", 0,
+#define	PIBFSW	13
+    "before date", 0,
+#define	PIDFSW	14
+    "datefield field", 5,
+#define	PISQSW	15
+    "sequence name", 0,
+#define	PIPUSW	16
+    "public", 0,
+#define	PINPUSW	17
+    "nopublic", 0,
+#define	PIZRSW	18
+    "zero", 0,
+#define	PINZRSW	19
+    "nozero", 0,
+#define	PILISW	20
+    "list", 0,
+#define	PINLISW	21
+    "nolist", 0,
+#define	PIHELP	22
+    "help", 4,
+
+    NULL, 0
+};
+
+/*  */
+
+pickcmd (args)
+char  **args;
+{
+    int     zerosw = 1,
+            msgp = 0,
+            seqp = 0,
+            vecp = 0,
+            hi,
+            lo,
+            msgnum;
+    char   *cp,
+            buf[BUFSIZ],
+           *msgs[MAXARGS],
+           *seqs[NATTRS],
+           *vec[MAXARGS];
+    register FILE *zp;
+
+    while (cp = *args++) {
+	if (*cp == '-') {
+	    if (*++cp == '-') {
+		vec[vecp++] = --cp;
+		goto pattern;
+	    }
+	    switch (smatch (cp, pickswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, pickswit);
+		    return;
+		case UNKWNSW: 
+		    fprintf (stderr, "-%s unknown\n", cp);
+		    return;
+		case PIHELP: 
+		    (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
+		    help (buf, pickswit);
+		    return;
+
+		case PICCSW: 
+		case PIDASW: 
+		case PIFRSW: 
+		case PISUSW: 
+		case PITOSW: 
+		case PIDFSW: 
+		case PIAFSW: 
+		case PIBFSW: 
+		case PISESW: 
+		    vec[vecp++] = --cp;
+pattern: ;
+		    if (!(cp = *args++)) {/* allow -xyz arguments */
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    vec[vecp++] = cp;
+		    continue;
+		case PIOTSW: 
+		    advise (NULLCP, "internal error!");
+		    return;
+		case PIANSW: 
+		case PIORSW: 
+		case PINTSW: 
+		case PILBSW: 
+		case PIRBSW: 
+		    vec[vecp++] = --cp;
+		    continue;
+
+		case PISQSW: 
+		    if (!(cp = *args++) || *cp == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    if (seqp < NATTRS)
+			seqs[seqp++] = cp;
+		    else {
+			advise (NULLCP, "only %d sequences allowed!", NATTRS);
+			return;
+		    }
+		    continue;
+		case PIZRSW: 
+		    zerosw++;
+		    continue;
+		case PINZRSW: 
+		    zerosw = 0;
+		    continue;
+
+		case PIPUSW: 	/* not implemented */
+		case PINPUSW: 
+		case PILISW: 
+		case PINLISW: 
+		    continue;
+	    }
+	}
+	if (*cp == '+' || *cp == '@') {
+	    advise (NULLCP, "sorry, no folders allowed!");
+	    return;
+	}
+	else
+	    msgs[msgp++] = cp;
+    }
+    vec[vecp] = NULL;
+
+    if (!msgp)
+	msgs[msgp++] = "all";
+    for (msgnum = 0; msgnum < msgp; msgnum++)
+	if (!m_convert (mp, msgs[msgnum]))
+	    return;
+    m_setseq (mp);
+
+    interrupted = 0;
+    if (!pcompile (vec, NULLCP))
+	return;
+
+    lo = mp -> lowsel;
+    hi = mp -> hghsel;
+
+    for (msgnum = mp -> lowsel;
+	    msgnum <= mp -> hghsel && !interrupted;
+	    msgnum++)
+	if (mp -> msgstats[msgnum] & SELECTED) {
+	    zp = msh_ready (msgnum, 1);
+	    if (pmatches (zp, msgnum, fmsh ? 0L : Msgs[msgnum].m_start,
+			fmsh ? 0L : Msgs[msgnum].m_stop)) {
+		if (msgnum < lo)
+		    lo = msgnum;
+		if (msgnum > hi)
+		    hi = msgnum;
+	    }
+	    else {
+		mp -> msgstats[msgnum] &= ~SELECTED;
+		mp -> numsel--;
+	    }
+	}
+
+    if (interrupted)
+	return;
+
+    mp -> lowsel = lo;
+    mp -> hghsel = hi;
+
+    if (mp -> numsel <= 0) {
+	advise (NULLCP, "no messages match specification");
+	return;
+    }
+
+    seqs[seqp] = NULL;
+    for (seqp = 0; seqs[seqp]; seqp++) {
+	if (zerosw && !m_seqnew (mp, seqs[seqp], 0))
+	    return;
+	for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
+	    if (mp -> msgstats[msgnum] & SELECTED)
+		if (!m_seqadd (mp, seqs[seqp], msgnum, 0))
+		    return;
+    }
+
+    printf ("%d hit%s\n", mp -> numsel, mp -> numsel == 1 ? "" : "s");
+}
+
+/*  */
+
+static struct swit replswit[] = {
+#define	REANSW	0
+    "annotate", 0,
+#define	RENANSW	1
+    "noannotate", 0,
+#define	RECCSW	2
+    "cc type", 0,
+#define	RENCCSW	3
+    "nocc type", 0,
+#define	REDFSW	4
+    "draftfolder +folder", 0,
+#define	REDMSW	5
+    "draftmessage msg", 0,
+#define	RENDFSW	6
+    "nodraftfolder", 0,
+#define	REEDTSW	7
+    "editor editor", 0,
+#define	RENEDSW	8
+    "noedit", 0,
+#define	REFCCSW	9
+    "fcc +folder", 0,
+#define	REFLTSW	10
+    "filter filterfile", 0,
+#define	REFRMSW	11
+    "form formfile", 0,
+#define	REINSW	12
+    "inplace", 0,
+#define	RENINSW	13
+    "noinplace", 0,
+#define	REQUSW	14
+    "query", 0,
+#define	RENQUSW	15
+    "noquery", 0,
+#define	REWHTSW	16
+    "whatnowproc program", 0,
+#define	RENWTSW	17
+    "nowhatnow", 0,
+#define	REWIDSW	19
+    "width columns", 0,
+#define	REHELP	20
+    "help", 4,
+
+    NULL, 0
+};
+
+/*  */
+
+replcmd (args)
+char  **args;
+{
+    int     vecp = 1;
+    char   *cp,
+           *msg = NULL,
+            buf[BUFSIZ],
+           *vec[MAXARGS];
+
+    if (fmsh) {
+	forkcmd (args, cmd_name);
+	return;
+    }
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (smatch (++cp, replswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, replswit);
+		    return;
+		case UNKWNSW: 
+		    fprintf (stderr, "-%s unknown\n", cp);
+		    return;
+		case REHELP: 
+		    (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
+		    help (buf, replswit);
+		    return;
+
+		case REANSW:	/* not implemented */
+		case RENANSW: 
+		case REINSW: 
+		case RENINSW: 
+		    continue;
+
+		case REQUSW:
+		case RENQUSW:
+		case RENDFSW:
+		case RENEDSW:
+		case RENWTSW:
+		    vec[vecp++] = --cp;
+		    continue;
+
+		case RECCSW: 
+		case RENCCSW: 
+		case REEDTSW: 
+		case REFCCSW: 
+		case REFLTSW:
+		case REFRMSW: 
+		case REWIDSW: 
+		case REDFSW:
+		case REDMSW:
+		case REWHTSW:
+		    vec[vecp++] = --cp;
+		    if (!(cp = *args++) || *cp == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    vec[vecp++] = cp;
+		    continue;
+	    }
+	if (*cp == '+' || *cp == '@') {
+	    advise (NULLCP, "sorry, no folders allowed!");
+	    return;
+	}
+	else
+	    if (msg) {
+		advise (NULLCP, "only one message at a time!");
+		return;
+	    }
+	    else
+		msg = cp;
+    }
+
+    vec[0] = cmd_name;
+    vec[vecp++] = "-file";
+    vec[vecp] = NULL;
+    if (!msg)
+	msg = "cur";
+    if (!m_convert (mp, msg))
+	return;
+    m_setseq (mp);
+
+    if (mp -> numsel > 1) {
+	advise (NULLCP, "only one message at a time!");
+	return;
+    }
+    (void) process (mp -> hghsel, cmd_name, vecp, vec);
+    m_setcur (mp, mp -> hghsel);
+}
+
+/*  */
+
+static struct swit rmmswit[] = {
+#define	RMHELP	0
+    "help", 4,
+
+    NULL, 0
+};
+
+/*  */
+
+rmmcmd (args)
+char  **args;
+{
+    int	    msgp = 0,
+            msgnum;
+    char   *cp,
+            buf[BUFSIZ],
+           *msgs[MAXARGS];
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (smatch (++cp, rmmswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, rmmswit);
+		    return;
+		case UNKWNSW: 
+		    fprintf (stderr, "-%s unknown\n", cp);
+		    return;
+		case RMHELP: 
+		    (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
+		    help (buf, rmmswit);
+		    return;
+	    }
+	if (*cp == '+' || *cp == '@') {
+	    advise (NULLCP, "sorry, no folders allowed!");
+	    return;
+	}
+	else
+	    msgs[msgp++] = cp;
+    }
+
+    if (!msgp)
+	msgs[msgp++] = "cur";
+    for (msgnum = 0; msgnum < msgp; msgnum++)
+	if (!m_convert (mp, msgs[msgnum]))
+	    return;
+    m_setseq (mp);
+
+    rmm ();
+}
+
+/*  */
+
+#ifdef MH_PLUS
+struct msgs	*opntrashf ();
+struct msgs	*trash ();
+#endif /* MH_PLUS */
+
+static  rmm () {
+    register int    msgnum,
+                    vecp;
+    register char  *cp;
+    char    buffer[BUFSIZ],
+	   *vec[MAXARGS];
+
+    if (fmsh) {
+	if (rmmproc) {
+	    if (mp -> numsel > MAXARGS - 1) {
+		advise (NULLCP, "more than %d messages for %s exec",
+			MAXARGS - 1, rmmproc);
+		return;
+	    }
+	    vecp = 0;
+	    for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
+		if (mp -> msgstats[msgnum] & SELECTED)
+		    vec[vecp++] = getcpy (m_name (msgnum));
+	    vec[vecp] = NULL;
+	    forkcmd (vec, rmmproc);
+	    for (vecp = 0; vec[vecp]; vecp++)
+		free (vec[vecp]);
+	}
+	else {
+#ifdef MH_PLUS
+	    int rmp;
+	    char *tfold;
+	    struct msgs *tmp;
+
+	    if ((tfold = m_find ("Trash-Folder")))
+		tmp = opntrashf (tfold, m_maildir (fmsh), &rmp);
+#endif /* MH_PLUS */
+	    for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
+		if (mp -> msgstats[msgnum] & SELECTED) {
+#ifdef MH_PLUS
+		    if (tfold) {
+			tmp = trash (msgnum, tmp, rmp);
+			continue;
+		    }
+#endif /* MH_PLUS */
+		    (void) strcpy (buffer, m_backup (cp = m_name (msgnum)));
+		    if (rename (cp, buffer) == NOTOK)
+			admonish (buffer, "unable to rename %s to", cp);
+		}
+	  }
+    }
+
+    for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
+	if (mp -> msgstats[msgnum] & SELECTED) {
+	    mp -> msgstats[msgnum] |= DELETED;
+	    mp -> msgstats[msgnum] &= ~EXISTS;
+#ifdef	MPOP
+#ifdef	BPOP
+	    if (pmsh && pop_dele (msgnum) != OK)
+		fprintf (stderr, "%s", response);
+#endif
+#endif /* MPOP */
+	}
+
+    if ((mp -> nummsg -= mp -> numsel) <= 0) {
+	if (fmsh)
+	    admonish (NULLCP, "no messages remaining in +%s", fmsh);
+	else
+	    admonish (NULLCP, "no messages remaining in %s", mp -> foldpath);
+	mp -> lowmsg = mp -> hghmsg = mp -> nummsg = 0;
+    }
+    if (mp -> lowsel == mp -> lowmsg) {
+	for (msgnum = mp -> lowmsg + 1; msgnum <= mp -> hghmsg; msgnum++)
+	    if (mp -> msgstats[msgnum] & EXISTS)
+		break;
+	mp -> lowmsg = msgnum;
+    }
+    if (mp -> hghsel == mp -> hghmsg) {
+	for (msgnum = mp -> hghmsg - 1; msgnum >= mp -> lowmsg; msgnum--)
+	    if (mp -> msgstats[msgnum] & EXISTS)
+		break;
+	mp -> hghmsg = msgnum;
+    }
+
+    mp -> msgflags |= MODIFIED;
+    modified++;
+}
+
+/*  */
+
+#ifdef MH_PLUS
+struct msgs *
+opntrashf (tfold, cwd, rmp)
+char    *tfold,
+        *cwd;
+int     *rmp;
+{
+    int     len;
+    char   *tf,
+           *cp,
+           *trashdir;
+    struct stat  st;
+    struct msgs *tmp;
+
+    tf = path (*tfold == '+' || *tfold == '@' ? tfold + 1 : tfold,
+	       *tfold != '@' ? TFOLDER : TSUBCWF);
+    if (*tfold == '@' && *(tfold + 1) != '/') {
+	cp = tfold + 1;
+	while (*cp) {
+	    if (strncmp (cp, "./", 2) == 0)
+		cp += 2;
+	    else if (strncmp (cp, "../", 3) == 0)
+		cp += 3;
+	    else
+		break;
+	}
+	len = strlen(cp);
+	if (strncmp(cwd + strlen(cwd) - len, cp, len) == 0) {
+	    trashdir = ".";
+	    tf = path ("./", TSUBCWF);
+	} else
+	    trashdir = m_maildir (tf);
+    } else
+	trashdir = m_maildir (tf);
+    if (strcmp(cwd, trashdir) == 0)
+	trashdir = ".";
+    *rmp = strcmp(trashdir, ".") ? 0 : 1;
+
+    if (stat (trashdir, &st) == NOTOK) {
+	if (errno != ENOENT)
+	    adios (trashdir, "error on folder");
+	cp = concat ("Create folder \"", trashdir, "\"? ", NULLCP);
+	if (!getanswer (cp))
+	    done (1);
+	free (cp);
+	if (!makedir (trashdir))
+	    adios (NULLCP, "unable to create folder %s", trashdir);
+    }
+    if (chdir (trashdir) == NOTOK)
+	adios (trashdir, "unable to change directory to");
+    if (!(tmp = m_gmsg (tf)))
+	adios (NULLCP, "unable to read folder %s", tfold);
+    tmp -> curmsg = 0;
+    chdir (cwd);
+    return tmp;
+}
+
+struct msgs *
+trash (msgnum, tmp, rmp)
+struct msgs *tmp;
+int     msgnum,
+        rmp;
+{ 
+    int     newnum;
+    char   *msg,
+            newmsg[BUFSIZ];
+
+    if (rmp) {
+	msg = m_name (msgnum);
+	if (unlink (msg) == NOTOK)
+	    admonish (msg, "unable to unlink");
+	return tmp;
+    }
+
+    if (tmp -> hghmsg >= tmp -> hghoff)
+	if (!(tmp = m_remsg (tmp, 0, tmp -> hghoff + MAXFOLDER)))
+	    adios (NULLCP, "unable to allocate folder storage");
+
+    newnum = ++tmp -> hghmsg;
+    tmp -> nummsg++;
+    tmp -> msgstats[newnum] |= EXISTS | SELECTED;
+    if (tmp -> lowmsg == 0)
+	tmp -> lowmsg = newnum;
+    if (tmp -> lowsel == 0 || newnum < tmp -> lowsel)
+	tmp -> lowsel = newnum;
+    if (newnum > tmp -> hghsel)
+	tmp -> hghsel = newnum;
+
+    (void) sprintf (newmsg, "%s/%s", tmp -> foldpath, m_name (newnum));
+    msg = m_name (msgnum);
+    if (rename (msg, newmsg) == NOTOK) {
+	int in, out;
+	struct stat st;
+	if (stat (newmsg, &st) != NOTOK) {
+	    admonish (newmsg, "unable to rename %s to", msg);
+	    return tmp;
+	}
+	if ((in = open(msg, 0)) == NOTOK) {
+	    admonish (msg, "unable to open message");
+	    return tmp;
+	}
+	(void) fstat (in, &st);
+	if ((out = creat (newmsg, (int) st.st_mode & 0777)) == NOTOK) {
+	    admonish (newmsg, "unable to create");
+	    (void) close (in);
+	    return tmp;
+	}
+	cpydata (in, out, msg, newmsg);
+	(void) close (in);
+	(void) close (out);
+	if (unlink (msg) == NOTOK)
+	    admonish (msg, "unable to unlink");
+    }
+    return tmp;
+}
+#endif /* MH_PLUS */
+
+
+/*  */
+
+static struct swit scanswit[] = {
+#define	SCCLR	0
+    "clear", 0,
+#define	SCNCLR	1
+    "noclear", 0,
+#define	SCFORM	2
+    "form formatfile", 0,
+#define	SCFMT	3
+    "format string", 5,
+#define	SCHEAD	4
+    "header", 0,
+#define SCNHEAD	5
+    "noheader", 0,
+#define	SCWID	6
+    "width columns", 0,
+#define	SCHELP	7
+    "help", 4,
+
+    NULL, 0
+};
+
+/*  */
+
+scancmd (args)
+char  **args;
+{
+#define	equiv(a,b)	(a ? b && !strcmp (a, b) : !b)
+
+    int     clearsw = 0,
+            headersw = 0,
+	    width = 0,
+            msgp = 0,
+            msgnum,
+	    optim,
+	    state;
+    char   *cp,
+	   *form = NULL,
+	   *format = NULL,
+            buf[BUFSIZ],
+	   *nfs,
+           *msgs[MAXARGS];
+    register FILE *zp;
+#ifdef	MPOP
+#ifdef	BPOP
+    static int p_optim = 0;
+#endif
+#endif /* MPOP */
+    static int s_optim = 0;
+    static char *s_form = NULL,
+		*s_format = NULL;
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (smatch (++cp, scanswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, scanswit);
+		    return;
+		case UNKWNSW: 
+		    fprintf (stderr, "-%s unknown\n", cp);
+		    return;
+		case SCHELP: 
+		    (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
+		    help (buf, scanswit);
+		    return;
+
+		case SCCLR: 
+		    clearsw++;
+		    continue;
+		case SCNCLR: 
+		    clearsw = 0;
+		    continue;
+		case SCHEAD: 
+		    headersw++;
+		    continue;
+		case SCNHEAD: 
+		    headersw = 0;
+		    continue;
+		case SCFORM: 
+		    if (!(form = *args++) || *form == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    format = NULL;
+		    continue;
+		case SCFMT: 
+		    if (!(format = *args++) || *format == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    form = NULL;
+		    continue;
+		case SCWID: 
+		    if (!(cp = *args++) || *cp == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    width = atoi (cp);
+		    continue;
+	    }
+	if (*cp == '+' || *cp == '@') {
+	    advise (NULLCP, "sorry, no folders allowed!");
+	    return;
+	}
+	else
+	    msgs[msgp++] = cp;
+    }
+
+    if (!msgp)
+	msgs[msgp++] = "all";
+    for (msgnum = 0; msgnum < msgp; msgnum++)
+	if (!m_convert (mp, msgs[msgnum]))
+	    return;
+    m_setseq (mp);
+
+    nfs = new_fs (form, format, FORMAT);
+    if (scanl) {		/* force scansbr to (re)compile format */
+	(void) free (scanl);
+	scanl = NULL;
+    }
+
+    if (s_optim == 0) {
+	s_optim = optim = 1;
+	s_form = form ? getcpy (form) : NULL;
+	s_format = format ? getcpy (format) : NULL;
+
+#ifdef	MPOP
+#ifdef	BPOP
+	if (pmsh) {
+	    int	    i;
+	    char   *dp,
+		   *ep,
+		   *fp;
+
+	    if (width == 0)
+		width = sc_width ();
+
+	    for (dp = nfs, i = 0; *dp; dp++, i++)
+		if (*dp == '\\' || *dp == '"' || *dp == '\n')
+		    i++;
+	    i++;
+	    if ((ep = malloc ((unsigned) i)) == NULL)
+		adios (NULLCP, "out of memory");
+	    for (dp = nfs, fp = ep; *dp; dp++) {
+		if (*dp == '\n') {
+		    *fp++ = '\\', *fp++ = 'n';
+		    continue;
+		}
+		if (*dp == '"' || *dp == '\\')
+		    *fp++ = '\\';
+		*fp++ = *dp;
+	    }
+	    *fp = '\0';
+
+	    if (pop_command ("XTND SCAN %d \"%s\"", width, ep) == OK)
+		p_optim = 1;
+
+	    free (ep);
+	}
+#endif
+#endif	/* MPOP */
+    }
+    else
+	optim = equiv (s_form, form) && equiv (s_format, format);
+
+#ifdef	MPOP
+#ifdef	BPOP
+    if (p_optim && optim) {
+	for (msgnum = mp -> lowmsg; msgnum <= mp -> hghmsg; msgnum++)
+	    if (!(mp -> msgstats[msgnum] & SELECTED) || Msgs[msgnum].m_scanl)
+		break;
+	if (msgnum > mp -> hghmsg && pop_command ("LIST") == OK) {
+	    fprintf (stderr, "Stand-by...");
+	    fflush (stderr);
+
+	    for (;;) {
+		int	size;
+
+		switch (pop_multiline ()) {
+		    case NOTOK:
+		        fprintf (stderr, "%s", response);
+		        /* and fall... */
+		    case DONE:
+		        fprintf (stderr,"\n");
+		        break;
+
+		    case OK:
+			if (sscanf (response, "%d %d", &msgnum, &size) == 2
+			        && mp -> lowmsg <= msgnum
+			        && msgnum <= mp -> hghmsg
+			        && (cp = index (response, '#'))
+			        && *++cp)
+			    Msgs[msgnum].m_scanl = concat (cp, "\n", NULLCP);
+			continue;
+		}
+		break;
+	    }
+	}
+    }
+#endif
+#endif /* MPOP */
+
+    interrupted = 0;
+    for (msgnum = mp -> lowsel;
+	    msgnum <= mp -> hghsel && !interrupted;
+	    msgnum++)
+	if (mp -> msgstats[msgnum] & SELECTED) {
+	    if (optim && Msgs[msgnum].m_scanl)
+		printf ("%s", Msgs[msgnum].m_scanl);
+	    else {
+#ifdef	MPOP
+#ifdef	BPOP
+		if (p_optim
+		        && optim
+			&& (mp -> msgstats[msgnum] & VIRTUAL)
+		        && pop_command ("LIST %d", msgnum) == OK
+			&& (cp = index (response, '#'))
+		        && *++cp) {
+		    Msgs[msgnum].m_scanl = concat (cp, "\n", NULLCP);
+		    printf ("%s", Msgs[msgnum].m_scanl);		    
+		    continue;
+		}
+#endif
+#endif /* MPOP */
+
+		zp = msh_ready (msgnum, 0);
+		switch (state = scan (zp, msgnum, 0, nfs, width,
+			msgnum == mp -> curmsg,
+			mp -> msgstats[msgnum] & UNSEEN,	/* ?? */
+			headersw, fmsh ? fmsh : mp -> foldpath,
+			fmsh ? 0L : (long) (Msgs[msgnum].m_stop - Msgs[msgnum].m_start),
+			1)) {
+		    case SCNMSG:
+		    case SCNENC:
+		    case SCNERR:
+			if (optim)
+			    Msgs[msgnum].m_scanl = getcpy (scanl);
+			break;
+
+		    default:
+			advise (NULLCP, "scan() botch (%d)", state);
+			return;
+
+		    case SCNEOF:
+			printf ("%*d  empty\n", DMAXFOLDER, msgnum);
+			break;
+		    }
+	    }
+	    headersw = 0;
+	}
+
+    if (clearsw)
+	clear_screen ();
+}
+
+/*  */
+
+static struct swit showswit[] = {
+#define	SHDRAFT	0
+    "draft", 5,
+#define	SHFORM	1
+    "form formfile", 4,
+#define	SHPROG	2
+    "moreproc program", 4,
+#define	SHNPROG	3
+    "nomoreproc", 3,
+#define	SHLEN	4
+    "length lines", 4,
+#define	SHWID	5
+    "width columns", 4,
+#define	SHSHOW	6
+    "showproc program", 4,
+#define	SHNSHOW	7
+    "noshowproc", 3,
+#define	SHHEAD	8
+    "header", 4,
+#define SHNHEAD	9
+    "noheader", 3,
+#define	SHHELP	10
+    "help", 4,
+
+    NULL, 0
+};
+
+/*  */
+
+showcmd (args)
+char  **args;
+{
+    int	    headersw = 1,
+            nshow = 0,
+            msgp = 0,
+            vecp = 1,
+            mhl = 0,
+            seen = 0,
+            mode = 0,
+	    i,
+            msgnum;
+    char   *cp,
+           *proc = showproc,
+            buf[BUFSIZ],
+           *msgs[MAXARGS],
+           *vec[MAXARGS];
+
+    if (uleq (cmd_name, "next"))
+	mode = 1;
+    else
+	if (uleq (cmd_name, "prev"))
+	    mode = -1;
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (i = smatch (++cp, showswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, showswit);
+		    return;
+		case UNKWNSW: 
+		case SHNPROG:
+		    vec[vecp++] = --cp;
+		    continue;
+		case SHHELP: 
+		    (void) sprintf (buf,
+			    "%s %s[switches] [switches for showproc]",
+			    cmd_name, mode ? NULL : "[msgs] ");
+		    help (buf, showswit);
+		    return;
+
+		case SHFORM: 
+		case SHPROG:
+		case SHLEN:
+		case SHWID:
+		    vec[vecp++] = --cp;
+		    if (!(cp = *args++) || *cp == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    vec[vecp++] = cp;
+		    continue;
+		case SHHEAD: 
+		    headersw++;
+		    continue;
+		case SHNHEAD: 
+		    headersw = 0;
+		    continue;
+		case SHSHOW: 
+		    if (!(proc = *args++) || *proc == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    nshow = 0;
+		    continue;
+		case SHNSHOW: 
+		    nshow++;
+		    continue;
+
+		case SHDRAFT: 
+		    advise (NULLCP, "sorry, -%s not allowed!", showswit[i].sw);
+		    return;
+	    }
+	if (*cp == '+' || *cp == '@') {
+	    advise (NULLCP, "sorry, no folders allowed!");
+	    return;
+	}
+	else
+	    if (mode) {
+		fprintf (stderr,
+			"usage: %s [switches] [switches for showproc]\n",
+			cmd_name);
+		return;
+	    }
+	    else
+		msgs[msgp++] = cp;
+    }
+    vec[vecp] = NULL;
+
+    if (!msgp)
+	msgs[msgp++] = mode > 0 ? "next" : mode < 0 ? "prev" : "cur";
+    for (msgnum = 0; msgnum < msgp; msgnum++)
+	if (!m_convert (mp, msgs[msgnum]))
+	    return;
+    m_setseq (mp);
+
+#ifdef	MIME
+    if (!nshow && !getenv ("NOMHNPROC"))
+	for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
+	    if ((mp -> msgstats[msgnum] & SELECTED) && nontext (msgnum)) {
+		proc = (cp = m_find ("mhnproc")) ? cp : "mhn";
+		vec[vecp++] = "-show";
+		vec[vecp++] = "-file";
+		vec[vecp] = NULL;
+		goto finish;
+	    }
+#endif	/* MIME */
+
+    if (nshow)
+	proc = "cat";
+    else
+	if (strcmp (showproc, "mhl") == 0) {
+	    proc = mhlproc;
+	    mhl++;
+	}
+
+finish: ;
+    seen = m_seqflag (mp, "unseen");
+    vec[0] = r1bindex (proc, '/');
+    if (mhl) {
+	msgp = vecp;
+	for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
+	    if (mp -> msgstats[msgnum] & SELECTED) {
+		vec[vecp++] = getcpy (m_name (msgnum));
+		if (seen)
+		    (void) m_seqdel (mp, "unseen", msgnum);
+	    }
+	vec[vecp] = NULL;
+	if (mp -> numsel == 1 && headersw)
+	    show (mp -> lowsel);
+	(void) mhlsbr (vecp, vec, mhl_action);
+	if (!fmsh)
+	    m_eomsbr ((int (*)()) 0);
+	while (msgp < vecp)
+	    free (vec[msgp++]);
+    }
+    else {
+	interrupted = 0;
+	for (msgnum = mp -> lowsel;
+		msgnum <= mp -> hghsel && !interrupted;
+		msgnum++)
+	    if (mp -> msgstats[msgnum] & SELECTED) {
+		switch (ask (msgnum)) {
+		    case NOTOK: /* QUIT */
+			break;
+
+		    case OK: 	/* INTR */
+			continue;
+
+		    default:
+			if (mp -> numsel == 1 && headersw)
+			    show (msgnum);
+			if (nshow)
+			    copy_message (msgnum, stdout);
+			else
+			    (void) process (msgnum, proc, vecp, vec);
+
+			if (seen)
+			    (void) m_seqdel (mp, "unseen", msgnum);
+			continue;
+		}
+		break;
+	    }
+    }
+
+    m_setcur (mp, mp -> hghsel);
+}
+
+/*  */
+
+static  show (msgnum)
+int     msgnum;
+{
+    if (Msgs[msgnum].m_bboard_id == 0)
+	(void) readid (msgnum);
+
+    printf ("(Message %d", msgnum);
+    if (Msgs[msgnum].m_bboard_id > 0)
+	printf (", %s: %d", BBoard_ID, Msgs[msgnum].m_bboard_id);
+    printf (")\n");
+}
+
+
+/* ARGSUSED */
+
+static	int eom_action (c)
+int     c;
+{
+    return (ftell (mhlfp) >= Msgs[mhlnum].m_stop);
+}
+
+
+static	FP mhl_action (name)
+char   *name;
+{
+    int     msgnum;
+
+    if ((msgnum = m_atoi (name)) < mp -> lowmsg
+	    || msgnum > mp -> hghmsg
+	    || !(mp -> msgstats[msgnum] & EXISTS))
+	return NULL;
+    mhlnum = msgnum;
+
+    mhlfp = msh_ready (msgnum, 1);
+    if (!fmsh)
+	m_eomsbr (eom_action);
+
+    return mhlfp;
+}
+
+
+/*  */
+
+static  ask (msgnum)
+int     msgnum;
+{
+    char    buf[BUFSIZ];
+
+    if (mp -> numsel == 1 || !interactive || redirected)
+	return DONE;
+
+    if (SOprintf ("Press <return> to list \"%d\"...", msgnum)) {
+	if (mp -> lowsel != msgnum)
+	    printf ("\n\n\n");
+	printf ("Press <return> to list \"%d\"...", msgnum);
+    }
+    (void) fflush (stdout);
+    buf[0] = 0;
+#if !defined(BSD42) && !defined(SVR4)
+    (void) read (fileno (stdout), buf, sizeof buf);
+#else	/* BSD42 || SVR4 */
+    switch (setjmp (sigenv)) {
+	case OK: 
+	    should_intr = 1;
+	    (void) read (fileno (stdout), buf, sizeof buf);/* fall... */
+
+	default: 
+	    should_intr = 0;
+	    break;
+    }
+#endif	/* BSD42 || SVR4 */
+    if (index (buf, '\n') == NULL)
+	(void) putchar ('\n');
+
+    if (told_to_quit) {
+	told_to_quit = interrupted = 0;
+	return NOTOK;
+    }
+    if (interrupted) {
+	interrupted = 0;
+	return OK;
+    }
+
+    return DONE;
+}
+
+/*  */
+
+#ifdef	MIME
+#include "../h/mhn.h"
+
+
+static int  nontext (msgnum)
+int	msgnum;
+{
+    int	    result,
+	    state;
+    register char   *bp,
+		    *dp;
+    char   *chset,
+	   *cp,
+	    buf[BUFSIZ],
+	    name[NAMESZ];
+    FILE   *fp;
+
+    if (Msgs[msgnum].m_flags & MHNCHK)
+	return (Msgs[msgnum].m_flags & MHNYES);
+    Msgs[msgnum].m_flags |= MHNCHK;
+
+    fp = msh_ready (msgnum, 1);
+
+    if (!(chset = getenv ("MM_CHARSET")))
+#ifdef JAPAN
+	chset = "iso-2022-jp";
+#else
+	chset = "us-ascii";
+#endif /* JAPAN */
+
+    for (state = FLD;;)
+	switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
+	    case FLD:
+	    case FLDPLUS:
+	    case FLDEOF:
+	        if (uleq (name, TYPE_FIELD)) {
+		    int	    passno;
+		    char    c;
+
+		    cp = add (buf, NULLCP);
+		    while (state == FLDPLUS) {
+			state = m_getfld (state, name, buf, sizeof buf, fp);
+			cp = add (buf, cp);
+		    }
+		    bp = cp;
+		    passno = 1;
+
+again: ;
+		    for (; isspace (*bp); bp++)
+			continue;
+		    if (*bp == '(') {
+			int	i;
+
+			for (bp++, i = 0;;) {
+			    switch (*bp++) {
+				case '\0':
+invalid: ;
+				    result = 0;
+				    goto out;
+				case '\\':
+				    if (*bp++ == '\0')
+					goto invalid;
+    				    continue;
+				case '(':
+    				    i++;
+    				    /* and fall... */
+    				default:
+    				    continue;
+    				case ')':
+    				    if (--i < 0)
+					break;
+				continue;
+			    }
+			    break;
+			}
+			for (; isspace (*bp); bp++)
+			    continue;
+		    }
+		    if (passno == 2) {
+			if (*bp != '/')
+			    goto invalid;
+			bp++;
+			passno = 3;
+			goto again;
+		    }
+		    else if (passno == 4) {
+			if (*bp != ';')
+			    goto invalid;
+			bp++;
+			passno = 5;
+			goto again;
+		    }
+		    for (dp = bp; istoken (*dp); dp++)
+			continue;
+		    c = *dp, *dp = '\0';
+		    if (*bp == '\0')
+			goto invalid;
+		    if (passno == 3) {
+			if (result = !uleq (bp, "plain"))
+			    goto out;
+			*dp = c;
+			bp = dp;
+			passno = 4;
+			goto again;
+		    }
+		    if (passno > 1) {
+			if (result = !uprf (bp, "charset"))
+			    goto invalid;
+			*dp = c;
+			while (isspace (*dp))
+			    dp++;
+			if (*dp++ != '=')
+			    goto invalid;
+			while (isspace (*dp))
+			    dp++;
+			if (*dp == '"') {
+			    if (bp = index (++dp, '"'))
+				*bp = '\0';
+			}
+			else
+			    for (bp = dp; *bp; bp++)
+				if (!istoken (*bp)) {
+				    *bp = '\0';
+				    break;
+				}
+			if ((result = !uleq (dp, chset))
+			        && uleq (dp, "us-ascii")
+#ifdef JAPAN
+			        && (uleq (chset, "iso-2022-jp")
+				    || uleq (chset, "euc-jp")
+				    || uleq (chset, "shift_jis")
+				    || (uprf (chset, "iso-8859-")
+					&& m_atoi (chset+9) >= 1)))
+#else /* JAPAN */
+			        /* && uleq (chset, "iso-8859-1")) */
+			        && uprf (chset, "iso-8859-")
+				&& m_atoi (chset+9) >= 1)
+#endif /* JAPAN */
+			    result = 0;
+		    }
+		    else
+			if (!(result = !uleq (bp, "text"))) {
+			    *dp = c;
+			    bp = dp;
+			    passno = 2;
+			    goto again;
+			}
+
+out: ;
+		    free (cp);
+
+		    if (result) {
+			Msgs[msgnum].m_flags |= MHNYES;
+			return result;
+		    }
+		    break;
+		}
+	        if (uleq (name, ENCODING_FIELD)) {
+		    cp = add (buf, NULLCP);
+		    while (state == FLDPLUS) {
+			state = m_getfld (state, name, buf, sizeof buf, fp);
+			cp = add (buf, cp);
+		    }
+		    for (bp = cp; isspace (*bp); bp++)
+			continue;
+		    for (dp = bp; istoken (*dp); dp++)
+			continue;
+		    *dp = '\0';
+		    result = !uleq (bp, "7bit")
+				&& !uleq (bp, "8bit")
+				&& !uleq (bp, "binary");
+
+		    free (cp);
+		    if (result) {
+			Msgs[msgnum].m_flags |= MHNYES;
+			return result;
+		    }
+		    break;
+		}
+		while (state == FLDPLUS)
+		    state = m_getfld (state, name, buf, sizeof buf, fp);
+		break;
+
+	    default:
+		return 0;
+	}
+}
+#endif	/* MIME */
+
+/*  */
+
+static struct swit sortswit[] = {
+#define	SODATE	0
+    "datefield field", 0,
+#define	SOSUBJ	1
+    "textfield field", 0,
+#define	SONSUBJ	2
+    "notextfield", 0,
+#define	SOLIMT	3
+    "limit days", 0,
+#define	SONLIMT	4
+    "nolimit", 0,
+#define	SOVERB	5
+    "verbose", 0,
+#define	SONVERB	6
+    "noverbose", 0,
+#define	SOHELP	7
+    "help", 4,
+
+    NULL, 0
+};
+
+/*  */
+
+sortcmd (args)
+char  **args;
+{
+    int     msgp = 0,
+            msgnum;
+    char   *cp,
+           *datesw = NULL,
+    	   *subjsw = NULL,
+            buf[BUFSIZ],
+           *msgs[MAXARGS];
+    struct tws  tb,
+               *tw;
+
+    if (fmsh) {
+	forkcmd (args, cmd_name);
+	return;
+    }
+
+    while (cp = *args++) {
+	if (*cp == '-')
+	    switch (smatch (++cp, sortswit)) {
+		case AMBIGSW: 
+		    ambigsw (cp, sortswit);
+		    return;
+		case UNKWNSW: 
+		    fprintf (stderr, "-%s unknown\n", cp);
+		    return;
+		case SOHELP: 
+		    (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
+		    help (buf, sortswit);
+		    return;
+
+		case SODATE: 
+		    if (datesw) {
+			advise (NULLCP, "only one date field at a time!");
+			return;
+		    }
+		    if (!(datesw = *args++) || *datesw == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    continue;
+
+		case SOSUBJ:
+		    if (subjsw) {
+			advise (NULLCP, "only one text field at a time!");
+			return;
+		    }
+		    if (!(subjsw = *args++) || *subjsw == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		    continue;
+		case SONSUBJ:
+		    subjsw = (char *)0;
+		    continue;
+
+		case SOLIMT:		/* too hard */
+		    if (!(cp = *args++) || *cp == '-') {
+			advise (NULLCP, "missing argument to %s", args[-2]);
+			return;
+		    }
+		case SONLIMT:
+		case SOVERB: 		/* not implemented */
+		case SONVERB: 
+		    continue;
+	    }
+	if (*cp == '+' || *cp == '@') {
+	    advise (NULLCP, "sorry, no folders allowed!");
+	    return;
+	}
+	else
+	    msgs[msgp++] = cp;
+    }
+
+    if (!msgp)
+	msgs[msgp++] = "all";
+    if (!datesw)
+	datesw = "Date";
+    for (msgnum = 0; msgnum < msgp; msgnum++)
+	if (!m_convert (mp, msgs[msgnum]))
+	    return;
+    m_setseq (mp);
+
+    twscopy (&tb, dtwstime ());
+
+    for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++) {
+	if (Msgs[msgnum].m_scanl) {
+	    free (Msgs[msgnum].m_scanl);
+	    Msgs[msgnum].m_scanl = NULL;
+	}
+	if (mp -> msgstats[msgnum] & SELECTED) {
+	    if (getws (datesw, subjsw, msgnum, &Msgs[msgnum]))
+		twscopy (&Msgs[msgnum].m_tb,
+			msgnum != mp -> lowsel ? &Msgs[msgnum - 1].m_tb : &tb);
+	}
+	else			/* m_scaln is already NULL */
+	    twscopy (&Msgs[msgnum].m_tb, &tb);
+	Msgs[msgnum].m_stats = mp -> msgstats[msgnum];
+	if (mp -> curmsg == msgnum)
+	    Msgs[msgnum].m_stats |= CUR;
+    }
+
+    qsort ((char *) &Msgs[mp -> lowsel], mp -> hghsel - mp -> lowsel + 1,
+	    sizeof (struct Msg),
+	    subjsw ? subsort : msgsort);
+
+    for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++) {
+	if (subjsw && Msgs[msgnum].m_scanl) {
+	    free (Msgs[msgnum].m_scanl);	/* from subjsort */
+	    Msgs[msgnum].m_scanl = NULL;
+	}
+	mp -> msgstats[msgnum] = Msgs[msgnum].m_stats & ~CUR;
+	if (Msgs[msgnum].m_stats & CUR)
+	    m_setcur (mp, msgnum);
+    }
+	    
+    mp -> msgflags |= MODIFIED;
+    modified++;
+}
+
+/*  */
+
+/* 
+ * getws - parse message, and get date and subject if needed.  We'll use
+ * the msgp->m_tb tws struct for the date, and overload the msgp->m_scanl
+ * field with our subject string.
+ */
+static int   getws (datesw, subjsw, msgnum, msgp)
+char   *datesw,
+       *subjsw;
+int	msgnum;
+struct	Msg	*msgp;
+{
+    int	    state,
+	    gotdate = 0;
+    char   *bp,
+            buf[BUFSIZ],
+            name[NAMESZ];
+    struct tws *tw = (struct tws *)0;
+    register FILE *zp;
+
+    zp = msh_ready (msgnum, 0);
+    for (state = FLD;;) {
+	switch (state = m_getfld (state, name, buf, sizeof buf, zp)) {
+	    case FLD: 
+	    case FLDEOF: 
+	    case FLDPLUS: 
+		if (uleq (name, datesw)) {
+		    bp = getcpy (buf);
+		    while (state == FLDPLUS) {
+			state = m_getfld (state, name, buf, sizeof buf, zp);
+			bp = add (buf, bp);
+		    }
+		    if ((tw = dparsetime (bp)) == NULL)
+			admonish (NULLCP,
+				"unable to parse %s field in message %d",
+				datesw, msgnum);
+		    else
+			twscopy (&(msgp->m_tb), tw);
+		    free (bp);
+		    if (!subjsw)	/* not using this, or already done */
+			break;		/* all done! */
+		    gotdate++;
+		}
+		else if (subjsw && uleq(name, subjsw)) {
+		    bp = getcpy (buf);
+		    while (state == FLDPLUS) {
+			state = m_getfld (state, name, buf, sizeof buf, zp);
+			bp = add (buf, bp);
+		    }
+		    msgp->m_scanl = sosmash(subjsw, bp);
+		    if (gotdate)
+			break;		/* date done so we're done */
+		    else
+			subjsw = (char *)0;/* subject done, need date */
+		} else {
+		    while (state == FLDPLUS)	/* flush this one */
+			state = m_getfld (state, name, buf, sizeof buf, zp);
+		}
+		continue;
+
+	    case BODY: 
+	    case BODYEOF: 
+	    case FILEEOF: 
+		break;
+
+	    case LENERR: 
+	    case FMTERR: 
+		admonish (NULLCP, "format error in message %d", msgnum);
+		if (msgp->m_scanl) {	/* this might need free'd */
+		    free (msgp->m_scanl); /* probably can't use subj anyway */
+		    msgp->m_scanl = NULL;
+		}
+		return NOTOK;
+
+	    default: 
+		adios (NULLCP, "internal error -- you lose");
+	}
+	break;
+    }
+    if (tw)
+	return OK;	/* not an error if subj not found */
+
+    admonish (NULLCP, "no %s field in message %d", datesw, msgnum);
+    return NOTOK;	/* NOTOK means use some other date */
+}
+
+/* sort routines */
+
+static int  msgsort (a, b)
+struct Msg *a,
+           *b;
+{
+    return twsort (&a -> m_tb, &b -> m_tb);
+}
+
+static int  subsort (a, b)
+struct Msg *a,
+           *b;
+{
+	register int i;
+
+	if (a->m_scanl && b->m_scanl)
+	    if (i = strcmp (a->m_scanl, b->m_scanl))
+		return (i);
+
+	return twsort (&a -> m_tb, &b -> m_tb);
+}
+
+/*
+ * try to make the subject "canonical": delete leading "re:", everything
+ * but letters & smash letters to lower case. 
+ */
+static char *
+sosmash (subj, s)
+char *subj;
+register char *s;
+{
+    register char  *cp,
+		   *dp,
+		    c;
+    if (s) {
+	cp = s;
+	dp = s;	/* dst pointer */
+	if (uleq (subj, "subject"))
+	    while (c = *cp) {
+		if (! isspace(c)) {
+		    if(uprf(cp, "re:"))
+			cp += 2;
+		    else {
+			if (isalnum(c))
+			    *dp++ = isupper(c) ? tolower(c) : c;
+			break;
+		    }
+		}
+		cp++;
+	    }
+	while (c = *cp++) {
+	    if (isalnum(c))
+		*dp++ = isupper(c) ? tolower(c) : c;
+
+	}
+	*dp = '\0';
+    }
+    return s;
+}
+
+/*  */
+
+static int  process (msgnum, proc, vecp, vec)
+int     msgnum,
+        vecp;
+char   *proc,
+      **vec;
+{
+    int	    child_id,
+	    status;
+    char    tmpfil[80];
+    FILE   *out;
+
+    if (fmsh) {
+	(void) strcpy (tmpfil, m_name (msgnum));
+	(void) m_delete (pfolder);
+	m_replace (pfolder, fmsh);
+	m_sync (mp);
+	m_update ();
+	goto ready;
+    }
+
+    (void) strcpy (tmpfil, m_scratch ("", invo_name));
+    if ((out = fopen (tmpfil, "w")) == NULL) {
+	int     olderr;
+	extern int  errno;
+	char    newfil[80];
+
+	olderr = errno;
+	(void) strcpy (newfil, m_tmpfil (invo_name));
+	if ((out = fopen (newfil, "w")) == NULL) {
+	    errno = olderr;
+	    advise (tmpfil, "unable to create temporary file");
+	    return NOTOK;
+	}
+	else
+	    (void) strcpy (tmpfil, newfil);
+    }
+    copy_message (msgnum, out);
+    (void) fclose (out);
+
+ready: ;
+    (void) fflush (stdout);
+    switch (child_id = fork ()) {
+	case NOTOK: 
+	    advise ("fork", "unable to");
+	    status = NOTOK;
+	    break;
+	    
+	case OK: 
+	    closefds (3);
+	    (void) signal (SIGINT, istat);
+	    (void) signal (SIGQUIT, qstat);
+
+	    vec[vecp++] = tmpfil;
+	    vec[vecp] = NULL;
+
+	    execvp (proc, vec);
+	    fprintf (stderr, "unable to exec ");
+	    perror (proc);
+	    _exit (1);
+
+	default: 
+	    status = pidXwait (child_id, NULLCP);
+	    break;
+    }
+
+    if (!fmsh)
+	(void) unlink (tmpfil);
+    return status;
+}
+
+/*  */
+
+static  copy_message (msgnum, out)
+int     msgnum;
+FILE * out;
+{
+    long    pos;
+    static char buffer[BUFSIZ];
+    register    FILE * zp;
+
+    zp = msh_ready (msgnum, 1);
+    if (fmsh) {
+	while (fgets (buffer, sizeof buffer, zp) != NULL) {
+	    fputs (buffer, out);
+	    if (interrupted && out == stdout)
+		break;
+	}
+    }
+    else {
+	pos = ftell (zp);
+	while (fgets (buffer, sizeof buffer, zp) != NULL
+		&& pos < Msgs[msgnum].m_stop) {
+	    fputs (buffer, out);
+	    pos += (long) strlen (buffer);
+	    if (interrupted && out == stdout)
+		break;
+	}
+    }
+}
+
+
+static  copy_digest (msgnum, out)
+int     msgnum;
+FILE * out;
+{
+    char    c;
+    long    pos;
+    static char buffer[BUFSIZ];
+    register FILE *zp;
+
+    c = '\n';
+    zp = msh_ready (msgnum, 1);
+    if (!fmsh)
+	pos = ftell (zp);
+    while (fgets (buffer, sizeof buffer, zp) != NULL
+	    && !fmsh && pos < Msgs[msgnum].m_stop) {
+	if (c == '\n' && *buffer == '-')
+	    (void) fputc (' ', out);
+	fputs (buffer, out);
+	c = buffer[strlen (buffer) - 1];
+	if (!fmsh)
+	    pos += (long) strlen (buffer);
+	if (interrupted && out == stdout)
+	    break;
+    }
+}