--- /dev/null
+# %M% %I% %E%
+#
+DESTDIR=
+
+all:
+ cd cmds; make ${MFLAGS}
+
+cp: all
+ cd cmds; make DESTDIR=${DESTDIR} cp
+ cd man; make DESTDIR=${DESTDIR} cp
+
+clean:
+ cd cmds; make ${MFLAGS} clean
--- /dev/null
+Title: MH
+
+Authors: Bruce Borden
+ Stockton Gaines
+ Norman Shapiro
+
+Help from: Phyllis Kantar
+ Robert Anderson
+ David Crocker
+
+
+Description:
+
+The user command interface to MH is the UNIX ``shell'' (the standard
+UNIX command interpreter). Each separable component of message handling,
+such as message composition or message display, is a separate command.
+Each program is driven from and updates a private user environment,
+which is stored as a file between program invocations. This private
+environment also contains information to ``custom tailor'' MH to the
+individuals's tastes. MH stores each message as a separate file under
+UNIX, and it utilizes the tree-structured UNIX file system to organize
+groups of files within separate directories or ``folders.'' All of
+the UNIX facilities for dealing with files and directories, such as
+renaming, copying, deleting, cataloging, off-line printing, etc., are
+applicable to messages and directories of messages (folders). Thus,
+important capabilities needed in a message system are available in MH
+without the need (often seen in other message systems) for code that
+duplicates the facilities of the supporting operating system. It also
+allows users familiar with the shell to use MH with minimal effort.
--- /dev/null
+# @(#)Makefile 4.9 (Berkeley) 83/07/07
+#
+# define UCB to get #files instead of ,files
+#
+LIBS= subs.a strings.a /usr/src/ucb/libndir/libndir.a
+CFLAGS= -O -DUNIXCOMP -DUCB -I. -I/usr/src/ucb/libndir
+BINDIR= /usr/new/mh
+LIBDIR= /usr/new/lib
+MHDIR= ${LIBDIR}/mh
+SUBS = ../subs
+STRINGS = ../strings
+PROGS= comp deliver folder forw inc install-mh \
+ next news pick prev prompter refile repl rescue rmf rmm scan \
+ send show unixtomh
+DESTDIR=
+
+all: ${PROGS}
+
+subs.a: mh.h
+ rm -f ${SUBS}/subs.a subs.a
+ cd ${SUBS}; make
+ ranlib ${SUBS}/subs.a
+ ln ${SUBS}/subs.a subs.a
+
+strings.a:
+ rm -f ${STRINGS}/strings.a strings.a
+ cd ${STRINGS}; make
+ ranlib ${STRINGS}/strings.a
+ ln ${STRINGS}/strings.a strings.a
+
+comp: mh.h comp.o ${LIBS}
+ ${CC} -o comp comp.o ${LIBS}
+
+deliver:mh.h deliver.o ${LIBS}
+ ${CC} -o deliver deliver.o ${LIBS}
+
+refile: mh.h refile.o ${LIBS}
+ ${CC} -o refile refile.o ${LIBS}
+
+folder: mh.h folder.o ${LIBS}
+ ${CC} -o folder folder.o ${LIBS}
+
+forw: mh.h forw.o annotate.o ${LIBS}
+ ${CC} -o forw forw.o annotate.o ${LIBS}
+
+inc: mh.h inc.o scansub.o ${LIBS}
+ ${CC} -o inc inc.o scansub.o ${LIBS}
+
+install-mh: mh.h install-mh.o ${LIBS}
+ ${CC} -o install-mh install-mh.o ${LIBS}
+
+news: mh.h news.o ${LIBS}
+ ${CC} -o news news.o ${LIBS}
+
+next: mh.h nexthdr.o next.o ${LIBS}
+ ${CC} -o next nexthdr.o next.o ${LIBS}
+
+pick: mh.h pick.o grep.o ${LIBS}
+ ${CC} -o pick pick.o grep.o ${LIBS}
+
+prev: mh.h prevhdr.o next.o ${LIBS}
+ ${CC} -o prev prevhdr.o next.o ${LIBS}
+
+prompter: mh.h prompter.o ${LIBS}
+ ${CC} -o prompter prompter.o ${LIBS}
+
+repl: mh.h reply.o replsubs.o annotate.o ${LIBS}
+ ${CC} -o repl reply.o replsubs.o annotate.o ${LIBS}
+
+rescue: rescue.o emitl.o
+ ${CC} -o rescue rescue.o
+
+rmf: mh.h rmf.o ${LIBS}
+ ${CC} -o rmf rmf.o ${LIBS}
+
+rmm: mh.h rmm.o ${LIBS}
+ ${CC} -o rmm rmm.o ${LIBS}
+
+scan: mh.h scan.o scansub.o ${LIBS}
+ ${CC} -o scan scan.o scansub.o ${LIBS}
+
+send: mh.h send.o ${LIBS}
+ ${CC} -o send send.o ${LIBS}
+
+show: mh.h show.o ${LIBS}
+ ${CC} -o show show.o ${LIBS}
+
+unixtomh: unixtomh.o
+ ${CC} -o unixtomh unixtomh.o subs.a
+
+onceonly:
+ -@if [ ! -f ${DESTDIR}/usr/bin/filetype -a \
+ ! -f ${DESTDIR}/bin/filetype -a -f ${DESTDIR}/bin/file ] ; then \
+ mv ${DESTDIR}/bin/file ${DESTDIR}/bin/filetype; \
+ echo "${DESTDIR}/bin/file => ${DESTDIR}/bin/filetype" ; \
+ else true ; \
+ fi
+ -@if [ ! -f ${DESTDIR}/bin/filetype -a \
+ ! -f ${DESTDIR}/usr/bin/filetype -a \
+ -f ${DESTDIR}/usr/bin/file ] ; then \
+ mv ${DESTDIR}/usr/bin/file ${DESTDIR}/usr/bin/filetype; \
+ echo "${DESTDIR}/usr/bin/file => ${DESTDIR}/usr/bin/filetype"; \
+ else true ; \
+ fi
+ -@if [ ! -f ${DESTDIR}/bin/bellmail -a -f ${DESTDIR}/bin/mail ] ; then \
+ mv ${DESTDIR}/bin/mail ${DESTDIR}/bin/bellmail; \
+ echo "${DESTDIR}/bin/mail => ${DESTDIR}/bin/bellmail" ;\
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/comp ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/comp" ; \
+ else true ; \
+ fi
+# -@if [ -f ${DESTDIR}/${BINDIR}/dist ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/dist" ; \
+ else true ; \
+ fi
+# -@if [ -f ${DESTDIR}/${BINDIR}/file ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/file" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/folder ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/folder" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/forw ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/forw" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/inc ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/inc" ; \
+ else true ; \
+ fi
+# -@if [ -f ${DESTDIR}/${BINDIR}/mail ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/mail" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/news ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/news" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/next ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/next" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/pick ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/pick" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/prev ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/prev" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/prompter ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/prompter" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/repl ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/repl" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/rmf ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/rmf" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/rmm ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/rmm" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/scan ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/scan" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/send ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/send" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/show ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/show" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${MHDIR} -o -d ${DESTDIR}/${MHDIR} ] ; then \
+ echo "${DESTDIR}/${MHDIR} already exists!"; \
+ else true ; \
+ fi
+
+cp: all
+ -mkdir ${DESTDIR}/${BINDIR}
+ -mkdir ${DESTDIR}/${LIBDIR}
+ -mkdir ${DESTDIR}/${MHDIR}
+ cp comp ${DESTDIR}/${BINDIR}; chmod 1755 ${DESTDIR}/${BINDIR}/comp ; strip ${DESTDIR}/${BINDIR}/comp
+ cp deliver ${DESTDIR}/${MHDIR}; strip ${DESTDIR}/${MHDIR}/deliver; chmod 4755 ${DESTDIR}/${MHDIR}/deliver
+ cp folder ${DESTDIR}/${BINDIR}; strip ${DESTDIR}/${BINDIR}/folder
+ cp forw ${DESTDIR}/${BINDIR}; strip ${DESTDIR}/${BINDIR}/forw
+ cp inc ${DESTDIR}/${BINDIR}; chmod 1755 ${DESTDIR}/${BINDIR}/inc ; strip ${DESTDIR}/${BINDIR}/inc
+ cp install-mh ${DESTDIR}/${MHDIR}; strip ${DESTDIR}/${MHDIR}/install-mh
+ cp next ${DESTDIR}/${BINDIR}; chmod 1755 ${DESTDIR}/${BINDIR}/next ; strip ${DESTDIR}/${BINDIR}/next
+ cp news ${DESTDIR}/${BINDIR}; strip ${DESTDIR}/${BINDIR}/news
+ cp pick ${DESTDIR}/${BINDIR}; strip ${DESTDIR}/${BINDIR}/pick
+ cp prev ${DESTDIR}/${BINDIR}; strip ${DESTDIR}/${BINDIR}/prev
+ cp prompter ${DESTDIR}/${BINDIR}; chmod 1755 ${DESTDIR}/${BINDIR}/prompter ; strip ${DESTDIR}/${BINDIR}/prompter
+ cp refile ${DESTDIR}/${BINDIR}; strip ${DESTDIR}/${BINDIR}/refile
+ cp repl ${DESTDIR}/${BINDIR}; strip ${DESTDIR}/${BINDIR}/repl
+ cp rmf ${DESTDIR}/${BINDIR}; strip ${DESTDIR}/${BINDIR}/rmf
+ cp rmm ${DESTDIR}/${BINDIR}; strip ${DESTDIR}/${BINDIR}/rmm
+ cp scan ${DESTDIR}/${BINDIR}; strip ${DESTDIR}/${BINDIR}/scan
+ cp send ${DESTDIR}/${BINDIR}; strip ${DESTDIR}/${BINDIR}/send
+ cp show ${DESTDIR}/${BINDIR}; chmod 1755 ${DESTDIR}/${BINDIR}/show ; strip ${DESTDIR}/${BINDIR}/show
+ cp unixtomh ${DESTDIR}/${MHDIR}; strip ${DESTDIR}/${MHDIR}/unixtomh
+ rm -f ${DESTDIR}/${BINDIR}/folders
+ ln ${DESTDIR}/${BINDIR}/folder ${DESTDIR}/${BINDIR}/folders
+ cp ../support/components ${DESTDIR}/${MHDIR}/components;
+ cp ../support/distcomps ${DESTDIR}/${MHDIR}/distcomps;
+
+cleanup:
+ rm -f ${PROGS}
+
+clean:
+ cd ${SUBS}; make ${MFLAG} clean
+ cd ${STRINGS}; make ${MFLAG} clean
+ rm -f ${PROGS} subs.a strings.a *.o
--- /dev/null
+#include <stdio.h>
+#include <ctype.h>
+#include <grp.h>
+#include <sys/param.h>
+#include <dir.h>
+
+char *AliasFile = "/usr/local/lib/MailAliases";
+char *Password = "/etc/passwd";
+char *MailDir = "/usr/spool/mail";
+
+char *termptr;
+
+struct mailname {
+ struct mailname *m_next;
+ char *m_name;
+ int m_seen;
+} users, bad;
+
+
+char *parse(ptr, buf)
+register char *ptr;
+char *buf;
+{
+ register char *cp;
+
+ cp = buf;
+ while(isspace(*ptr) || *ptr == ',' || *ptr == ':')
+ ptr++;
+ while(isalnum(*ptr) || *ptr == '/' || *ptr == '-' || *ptr == '.')
+ *cp++ = *ptr++;
+ if(cp == buf) {
+ switch(*ptr) {
+ case '<':
+ case '*':
+ case '=':
+ *cp++ = *ptr++;
+ }
+ }
+ *cp = 0;
+ if(cp == buf)
+ return 0;
+ termptr = ptr;
+ return buf;
+}
+
+
+char *mail = 0;
+FILE *out;
+int donecd = 0;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register char *cp, *pp, **cpp;
+ register struct mailname *lp;
+ register struct group *gp;
+ struct direct *dir;
+ DIR *dirp;
+ char line[256], pbuf[64];
+ FILE *a;
+
+ if(argc == 3 && strcmp(argv[1], "-mail") == 0)
+ mail = argv[2];
+ if(!mail)
+ out = stdout;
+ if((a = fopen(Password, "r")) == NULL) {
+ om();
+ fprintf(out, "Can't open password file ");
+ perror(Password);
+ done(1);
+ }
+ while(fgets(line, sizeof line, a)) {
+ if(line[0] == '\n' || line[0] == ';')
+ continue;
+ cp = parse(line, pbuf);
+ add(cp, &users);
+ }
+ fclose(a);
+ if((a = fopen(AliasFile, "r")) == NULL) {
+ om();
+ fprintf(out, "Can't open alias file: %s\n", AliasFile);
+ donecd = 1;
+ } else {
+ while(fgets(line, sizeof line, a)) {
+ if(line[0] == '\n' || line[0] == ';')
+ continue;
+ cp = parse(line, pbuf);
+ if(check(cp, 0)) {
+ add(line, &bad);
+ donecd = 1;
+ }
+ }
+ fclose(a);
+ if(donecd < 1) {
+ if(out)
+ fprintf(out, "No Alias Inconsistencies.\n");
+ } else {
+ om();
+ fprintf(out, "%s :: %s Collisions:\n",
+ Password, AliasFile);
+ fprintf(out, "Colliding alias lines:\n");
+ for(lp = bad.m_next; lp; lp = lp->m_next)
+ fprintf(out, "%s", lp->m_name);
+ donecd = 1;
+ }
+ }
+ while(gp = getgrent()) {
+ for(cpp = gp->gr_mem; *cpp; cpp++)
+ if(!check(*cpp, 1)) {
+ om();
+ fprintf(out, "Group: %s--User: %s not in /etc/passwd\n",
+ gp->gr_name, *cpp);
+ donecd = 2;
+ }
+ }
+ if(donecd < 2 && out)
+ fprintf(out, "No extraneous group entries.\n");
+#ifdef RAND
+ for(lp = users.m_next; lp; lp = lp->m_next)
+ if(lp->m_seen == 0) {
+ om();
+ fprintf(out, "User: %s not in a group.\n", lp->m_name);
+ donecd = 3;
+ }
+ if(donecd < 3 && out)
+ fprintf(out, "No Users not in any group.\n");
+#endif
+ if ((dirp = opendir(MailDir)) == 0) {
+ om();
+ fprintf(out, "Can't open mail directory: %s\n", MailDir);
+ donecd = 4;
+ } else {
+ (void) readdir(dirp); /* skip . */
+ (void) readdir(dirp); /* skip .. */
+ while (dir = readdir(dirp)) {
+ if (!check(dir->d_name, 0)) {
+ om();
+ fprintf(out, "Mail drop: %s--Nonexistent user.\n",
+ dir->d_name);
+ donecd = 4;
+ }
+ }
+ closedir(dirp);
+ }
+ if(donecd < 4 && out)
+ fprintf(out, "No Extra mail drops.\n");
+
+ done(donecd);
+}
+
+
+add(name, list)
+char *name;
+struct mailname *list;
+{
+ register struct mailname *mp;
+ char *getcpy();
+
+ for(mp = list; mp->m_next; mp = mp->m_next)
+ ;
+ mp->m_next = (struct mailname *) malloc(sizeof *mp->m_next);
+ mp = mp->m_next;
+ mp->m_next = 0;
+ mp->m_name = getcpy(name);
+}
+
+check(name, mark)
+ char *name;
+ int mark;
+{
+ register struct mailname *mp;
+
+ for(mp = users.m_next; mp; mp = mp->m_next)
+ if(uleq(name, mp->m_name)) {
+ if(mark)
+ mp->m_seen = 1;
+ return 1;
+ }
+ return 0;
+}
+
+
+om()
+{
+ int pipes[2], child;
+
+ if(out)
+ return;
+ if(mail) {
+ pipe(pipes);
+ out = fdopen(pipes[1], "w");
+ if((child = fork()) == -1) {
+ fprintf(stderr, "Aliascheck: no forks!\n");
+ done(1);
+ }
+ if(child == 0) {
+ close(pipes[1]);
+ close(0);
+ dup(pipes[0]);
+ close(pipes[0]);
+ execl("/bin/mail", "mail", mail, 0);
+ execl("/usr/bin/mail", "mail", mail, 0);
+ perror("mail");
+ done(1);
+ }
+ fprintf(out, "Aliascheck: ");
+ }
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)annotate.c 4.1 2/23/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* annotate file component data
+ *
+ * prepends Component: data
+ * date stamp
+ */
+
+annotate(file, comp, text, inplace)
+ char *file, *comp, *text;
+{
+ register int src;
+ register char *cp;
+ register FILE *tmp;
+ int cnt, fd;
+ char buf[BUFSIZ], *sp, tmpfil[128];
+ long now;
+ struct stat stbuf;
+ char *cdate();
+
+ if((src = open((cp = file), 2)) == -1) { /* this should be an X-open*/
+ fprintf(stderr, "Can't open ");
+ perror(cp);
+ return(1);
+ }
+ copy(cp, buf);
+ sp = r1bindex(buf);
+ if(sp != buf) {
+ *sp = 0;
+ cp = copy(buf, tmpfil);
+ } else
+ cp = tmpfil;
+ copy(makename("ano",".tmp"), cp);
+ fstat(src, &stbuf);
+ if((tmp = fopen(tmpfil, "w")) == NULL) {
+ fprintf(stderr, "Can't create ");
+ perror(tmpfil);
+ return(1);
+ }
+ chmod(tmpfil, stbuf.st_mode&0777);
+ cp = comp;
+ if(*cp >= 'a' && *cp <= 'z') *cp -= 040;
+ time(&now);
+ cp = cdate(&now);
+ cp[9] = ' '; cp[15] = 0;
+ if(*cp == ' ') cp++;
+ fprintf(tmp, "%s: <<%s>>\n", comp, cp);
+ cp = text;
+ do {
+ if(*cp == ' ' || *cp == '\t') cp++;
+ sp = cp;
+ while(*cp && *cp++ != '\n') ;
+ if(cp - sp)
+ fprintf(tmp, "%s: %*s", comp, cp-sp, sp);
+ } while(*cp);
+ if(cp[-1] != '\n' && cp != text) putc('\n', tmp);
+ do
+ if((cnt = read(src, buf, sizeof buf)) > 0)
+ fwrite(buf, cnt, 1, tmp);
+ while(cnt == sizeof buf);
+ fclose(tmp);
+ if(inplace) {
+ fd = open(tmpfil, 0); /* reopen for reading */
+ lseek(src, 0l, 0);
+ do
+ if((cnt = read(fd, buf, sizeof buf)) > 0)
+ write(src, buf, cnt);
+ while(cnt == sizeof buf);
+ close(fd);
+ } else {
+ /* cp = copy(file, buf); */
+ /* *--cp =| 0200; */
+ /* copy(".bak", copy(file, buf)); */
+ cp = copy(file, buf);
+ cp[1] = 0;
+ do
+ *cp = cp[-1];
+ while(--cp >= buf && *cp != '/');
+ *++cp =
+#ifdef UCB
+ '#';
+#else
+ ',';
+#endif
+ unlink(buf);
+ if(link(file, buf) == -1) {
+ fprintf(stderr, "Can't rename %s to bak file.\n", file);
+ return(1);
+ }
+ if(unlink(file) == -1) {
+ fprintf(stderr, "Can't unlink %s\n", file);
+ return(1);
+ }
+ if(link(tmpfil, file) == -1) {
+ fprintf(stderr, "Can't lnk temp file \"%s\" to %s\n",
+ tmpfil, file);
+ return(1);
+ }
+ }
+ close(src);
+ unlink(tmpfil);
+ return(0);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <strings.h>
+#include <signal.h>
+
+/* #define NEWS 1 */
+#define NONE 0
+
+/* #define TEST 1 */
+
+char *anyul[] = {
+ "no", 0,
+ "yes", 0,
+ "use", 0,
+ "list", 0,
+ 0
+};
+
+char *aleqs[] = {
+ "list", 0, /* 0 */
+ "edit [<editor>]", 0, /* 1 */
+ "quit [delete]", 0, /* 2 */
+ "send [verbose]", 0, /* 3 */
+ 0
+};
+
+
+struct swit switches[] = {
+ "editor editor", 0, /* 0 */
+ "form formfile", 0, /* 1 */
+ "use", 0, /* 2 */
+ "nouse", 0, /* 3 */
+ "help", 4, /* 4 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp;
+ register int in, out;
+ int use, cnt, status, intr;
+ char buf[BUFSIZ], *ed, *file, *form;
+ static char path[128];
+ char **ap;
+ char *arguments[50], **argp;
+
+/*** setbuf(stdout, _sobuf); ***/
+#ifdef NEWS
+ m_news();
+#endif
+ form = 0; use = 0; file = 0; ed = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-') {
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "comp: -%s unknown\n", cp);
+ goto leave;
+ case 0: if(!(ed = *argp++)) { /* -editor */
+ missing: fprintf(stderr, "comp: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 1: if(!(form = *argp++)) /* -form */
+ goto missing;
+ continue;
+ case 2: use = 1; continue; /* -use */
+ case 3: use = 0; continue; /* -nouse */
+ case 4: help("comp [file] [switches]",
+ switches);
+ goto leave;
+ }
+ }
+ file = cp;
+ }
+ if(form) {
+ if((in = open(m_maildir(form), 0)) < 0) {
+ fprintf(stderr, "comp: Can't open form file: %s\n", form);
+ goto leave;
+ }
+ } else if((in = open(m_maildir(components), 0)) < 0 &&
+ (in = open(stdcomps, 0)) < 0) {
+ fprintf(stderr, "comp: Can't open default components file!!\n");
+ goto leave;
+ }
+ if(!file)
+ file = draft;
+ copy(m_maildir(file), path);
+ if((out = open(path, 0)) >= 0) {
+ cp = concat("\n\"", path, "\" exists; delete? ", 0);
+ if(use || fdcompare(in, out))
+ goto editit;
+ while((status = gans(cp, anyul)) == 3)
+ showfile(path);
+ if(status == 2) {
+ use++;
+ goto editit;
+ }
+ if(status == 0)
+ goto leave;
+ close(out);
+ } else if(use) {
+ fprintf(stderr, "comp: \"%s\" doesn't exist!\n", path);
+ goto leave;
+ }
+ if((out = creat(path, m_gmprot())) < 0) {
+ fprintf(stderr, "comp: Can't create \"%s\"\n", path);
+ goto leave;
+ }
+ do
+ if(cnt = read(in, buf, sizeof buf))
+ write(out, buf, cnt);
+ while(cnt == sizeof buf);
+ close(in);
+editit:
+ close(out);
+ if(m_edit(&ed, path, use, NONE) < 0)
+ goto leave;
+#ifdef TEST
+ fprintf(stderr, "!! Test Version of SEND Being Run !!\n");
+ fprintf(stderr, " Send verbose !\n\n");
+#endif
+
+ for(;;) {
+ if(!(argp = getans("\nWhat now? ", aleqs)))
+ goto leave;
+ switch(smatch(*argp, aleqs)) {
+ case 0: showfile(path); /* list */
+ break;
+ case 1: if(*++argp) /* edit */
+ ed = *argp;
+ if(m_edit(&ed, path, use, NONE) == -1)
+ goto leave;
+ break;
+ case 2: if(*++argp && *argp[0] == 'd') /* quit */
+ if(unlink(path) == -1) {
+ fprintf(stderr, "Can't unlink %s ", path);
+ perror("");
+ }
+ goto leave;
+ case 3: if(*++argp) cp = *argp; else cp = ""; /* send */
+ if(! m_send(cp, path))
+ goto leave;
+ default:fprintf(stderr, "comp: illegal option\n"); /*##*/
+ break;
+ }
+ }
+
+leave:
+ m_update();
+ done(0);
+}
+
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)deliver.c 4.3 3/5/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <strings.h>
+
+/*#define DELIVERMAIL "/etc/delivermail"*/
+#define EVERYONE 10
+#define RECVPROG "/.mh_receive"
+#define FCCS 10 /* Max number of fcc's allowed */
+
+struct shome { /* Internal name/uid/home database */
+ struct shome *h_next;
+ char *h_name;
+ int h_uid;
+ int h_gid;
+ char *h_home;
+} *homes, *home();
+
+struct swit switches[] = {
+ "debug", -1, /* 0 */
+ "format", 0, /* 1 */
+ "noformat", 0, /* 2 */
+ "msgid", 0, /* 3 */
+ "nomsgid", 0, /* 4 */
+ "verbose", 0, /* 5 */
+ "noverbose", 0, /* 6 */
+ "help", 4, /* 7 */
+ 0, 0
+};
+
+int verbose, format, msgid, debug, myuid, addrp;
+int lockwait; /* Secs to wait for mail lock (From strings/lockdir.c) */
+#define LOCKWAIT (lockwait * 5) /* Ignore lock if older than this */
+int donecd;
+long now;
+char tmpfil[32], fccfold[FCCS][128];
+char tmp2fil[32];
+int fccind;
+char *rindex();
+
+struct mailname {
+ struct mailname *m_next;
+ char *m_name;
+} addrlist;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register char *cp, *addrs, **argp;
+ register struct mailname *lp;
+ char buf[BUFSIZ], name[NAMESZ];
+ char *msg;
+ int state, compnum, fd;
+ FILE *in, *out;
+ char *getname();
+
+ msg = 0;
+ argp = argv + 1;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ done(1);
+ /* unknown */
+ case -1:fprintf(stderr, "sndmsg: -%s unknown switch.\n", cp);
+ done(1);
+ case 0: verbose++; debug++; continue; /* -debug */
+ case 1: fprintf(stderr, "Deliver: -format not yet.\n");
+ done(1);
+/*** case 1: format = 1; continue; /* -format */
+ case 2: format = 0; continue; /* -noformat */
+ case 3: msgid = 1; continue; /* -msgid */
+ case 4: msgid = 0; continue; /* -nomsgid */
+ case 5: verbose = 1; continue; /* -verbose */
+ case 6: verbose = 0; continue; /* -noverbose */
+ case 7: help("deliver [switches] file",
+ switches);
+ done(1);
+ }
+ if(msg) {
+ fprintf(stderr, "Deliver: Only one message at a time!\n");
+ done(1);
+ } else
+ msg = cp;
+ }
+ if(!msg) {
+ fprintf(stderr, "Deliver: No Message specified.\n");
+ fprintf(stderr, "Deliver: Usage: deliver [switches] file\n");
+ done(1);
+ }
+ if((in = fopen(msg, "r")) == NULL) {
+ fprintf(stderr, "Deliver: Can't open ");
+ perror(msg);
+ done(1);
+ }
+ copy(makename("locs", ".tmp"), copy("/tmp/", tmpfil));
+ if(!debug) {
+ if((out = fopen(tmpfil, "w")) == NULL) {
+ fprintf(stderr, "Can't create %s\n", tmpfil);
+ done(1);
+ }
+ chmod(tmpfil, 0744);
+ } else
+ out = stdout;
+
+ gethomes();
+ myuid = getuid();
+#ifndef UNIXCOMP
+ putdate(0, out); /* Tack on the date */
+ putfrom(out); /* Tack on the from */
+#endif
+ putmsgid(out); /* and msg id if desired */
+ for(addrs = 0, compnum = 1, state = FLD;;) {
+ state = m_getfld(state, name, buf, sizeof buf, in);
+ swt: switch(state) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ compnum++;
+ if(uleq(name, "to") || uleq(name, "cc") ||
+ uleq(name, "bcc"))
+ addrs = add(buf, addrs);
+ if(!uleq(name, "bcc")) {
+ cp = buf;
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+ fprintf(out, "%s: %s", name, cp);
+ if(uleq(name, "fcc")) {
+ if(fccind >= FCCS) {
+ fprintf(stderr, "Deliver: too many fcc's.\n");
+ done(1);
+ }
+ copy(cp, fccfold[fccind]);
+ if(cp = rindex(fccfold[fccind], '\n'))
+ *cp = 0;
+ fccind++;
+ }
+ }
+ while(state == FLDPLUS || state == FLDEOF) {
+ state = m_getfld(state, name, buf, sizeof buf, in);
+ addrs = add(buf, addrs);
+ fputs(buf, out);
+ }
+ if(state == FLDEOF)
+ goto process;
+ break;
+
+ case BODY:
+ case BODYEOF:
+ fprintf(out, "\n%s", buf);
+ while(state == BODY) {
+ state=m_getfld(state,name,buf,sizeof buf,in);
+ fputs(buf, out);
+ }
+
+ case FILEEOF:
+ goto process;
+
+ case LENERR:
+ case FMTERR:
+ fprintf(stderr, "??Message Format Error ");
+ fprintf(stderr, "in Component #%d.\n", compnum);
+ done(1);
+
+ default:
+ fprintf(stderr, "Getfld returned %d\n", state);
+ done(1);
+ }
+ }
+process:
+ if(!debug)
+ fclose(out);
+ else
+ printf("-----\n");
+ fclose(in);
+ while(cp = getname(addrs)) /* Put addrs in chain */
+ insert(cp);
+ if(debug) {
+ printf("Before alias(): "); pl();
+ }
+
+ alias(); /* Map names if needed */
+
+ for(lp = addrlist.m_next; lp; lp = lp->m_next) {
+#ifdef UNIXCOMP
+ if (netname(lp->m_name))
+ continue;
+#endif
+#ifndef DELIVERMAIL
+ if(home(lp->m_name) == NULL) {
+ fprintf(stderr, "Deliver: Unknown User: %s.\n", lp->m_name);
+ fprintf(stderr, "Deliver: Message Not Delivered.\n");
+ if(!debug)
+ unlink(tmpfil);
+ done(1);
+ }
+#endif DELIVERMAIL
+ }
+ if(debug) {
+ printf("Addrs: "); pl();
+ }
+
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ if(!debug) { /* Send the mail */
+ fd = open(tmpfil, 0);
+ for(lp = addrlist.m_next; lp; lp = lp->m_next)
+ sendmail(lp->m_name, fd);
+#ifdef DELIVERMAIL
+ stflush(fd);
+#endif
+ close(fd);
+ if(fccind) {
+#ifdef UNIXCOMP
+ strcpy(tmp2fil, "/tmp/mhFXXXXXX");
+ mktemp(tmp2fil);
+ out = fopen(tmp2fil, "w");
+ putdate(0, out); /* Tack on the date */
+ putfrom(out); /* Tack on the from */
+ appendfile(tmpfil, out);
+ fclose(out);
+ for(state = 0; state < fccind; state++)
+ fcc(tmp2fil, fccfold[state]);
+ unlink(tmp2fil);
+#else
+ for(state = 0; state < fccind; state++)
+ fcc(tmp2fil, fccfold[state]);
+#endif
+ }
+ unlink(tmpfil);
+ }
+ done(donecd);
+}
+
+#ifdef UNIXCOMP
+
+appendfile(name, fout)
+ char name[];
+ register FILE *fout;
+{
+ register int c;
+ register FILE *fin;
+
+ if ((fin = fopen(name, "r")) == NULL) {
+ perror(name);
+ return;
+ }
+ while ((c = getc(fin)) != EOF)
+ putc(c, fout);
+ fclose(fin);
+}
+
+netname(name)
+ char name[];
+{
+ register char *cp;
+ char *index();
+
+ cp = name;
+ if (index(cp, ':') || index(cp, '!') ||
+ index(cp, '@') || index(cp, '^'))
+ return(1);
+ return(0);
+}
+#endif
+
+
+gethomes()
+{
+ register struct passwd *pw;
+ register struct shome *h, *ph;
+ struct passwd *getpwent();
+
+ ph = (struct shome *) &homes;
+ while((pw = getpwent()) != NULL) {
+ h = (struct shome *) malloc(sizeof *h);
+ h->h_next = NULL;
+ h->h_name = (char *) malloc(strlen(pw->pw_name)+1);
+ strcpy(h->h_name, pw->pw_name);
+ h->h_uid = pw->pw_uid;
+ h->h_gid = pw->pw_gid;
+ h->h_home = (char *) malloc(strlen(pw->pw_dir)+1);
+ strcpy(h->h_home, pw->pw_dir);
+ ph->h_next = h;
+ ph = h;
+ }
+}
+
+
+struct shome *
+home(name)
+ register char *name;
+{
+ register struct shome *h;
+
+ for(h = homes; h; h = h->h_next)
+ if(uleq(name, h->h_name))
+ return(h);
+ return(NULL);
+}
+
+
+char *
+getname(addrs)
+ char *addrs;
+{
+ register char *tp;
+ static char name[32];
+ static char *getaddrs;
+
+ if(!getaddrs)
+ getaddrs = addrs;
+ tp = name;
+
+ while(*getaddrs && !isalpha(*getaddrs))
+ getaddrs++;
+ if(!*getaddrs) {
+ getaddrs = 0;
+ return NULL;
+ }
+#ifdef UNIXCOMP
+ while(!isspace(*getaddrs))
+ *tp++ = *getaddrs++;
+#else
+ while(isalnum(*getaddrs) || index(".:@/-", *getaddrs))
+ *tp++ = *getaddrs++;
+#endif
+ *tp = 0;
+ if(name[0] == 0)
+ return NULL;
+ return name;
+}
+
+char *bracket = "\1\1\1\1\n";
+
+sendmail(name, fd) /* Runs with signals ignored! */
+ char *name;
+ register int fd;
+{
+ char buf[BUFSIZ], *myname;
+ register int i, m, c;
+ register char *mail, *receive, *lock = 0;
+ register struct shome *h;
+ int pid, status;
+ struct stat stbuf;
+
+ if(verbose) {
+ printf("%s: ", name);
+ fflush(stdout);
+ }
+ lseek(fd, 0l, 0);
+ h = home(name);
+
+ /*
+ * If no home for this user, as in network address
+ * being forced down this path, just assume normal
+ * delivery
+ */
+
+ if (h == NULL)
+ goto force;
+
+ mail = concat(mailboxes, h->h_name, 0);
+/*** mail = concat(h->h_home, mailbox, 0); ***/
+ receive = concat(h->h_home, RECVPROG, 0);
+ if(access(receive, 1) == 0) { /* User has a receive prog */
+
+ calluserprog(receive, mail, fd, h);
+
+ } else {
+
+force:
+
+#ifdef UNIXCOMP
+#ifdef DELIVERMAIL
+ nstash(name);
+ if (verbose)
+ printf("Sent.\n");
+ return;
+#endif DELIVERMAIL
+#ifndef DELIVERMAIL
+ myname = getenv("USER");
+ if (myname == (char *) 0)
+ myname = "nobody";
+ pid = fork();
+ switch (pid) {
+ case 0:
+ /* fiddle with files, then . . . */
+ lseek(fd, 0L, 0);
+ close(0);
+ dup(fd);
+ close(fd);
+ execl(Mailprog, "Mail", "-r", myname, name, 0);
+ execl("/bin/mail", "mail", "-r", myname, name, 0);
+ perror(Mailprog);
+ _exit(1);
+
+ case -1:
+ perror("fork");
+ return;
+
+ default:
+ while (wait(&status) != pid)
+ ;
+ }
+#endif DELIVERMAIL
+#endif UNIXCOMP
+#ifndef UNIXCOMP
+ if((m = open(mail, 2)) < 0) {
+ if((m = creat(mail, 0600)) < 0) {
+ fprintf(stderr, "Deliver: Can't write ");
+ perror(mail);
+ goto out;
+ }
+ chown(mail, h->h_uid, h->h_gid);
+ if(verbose) {
+ fprintf(stderr, "Creating %s ", mail);
+ fflush(stdout);
+ }
+ }
+ lock = concat(lockdir, h->h_name, 0);
+ for(i = 0; i < lockwait; i += 2) {
+ if(link(mail, lock) >= 0)
+ break;
+ if(i == 0 && stat(mail, &stbuf) >= 0 &&
+ stbuf.st_ctime + LOCKWAIT < time((long *) 0)) {
+ i = lockwait;
+ break;
+ }
+ if(verbose) {
+ printf("Busy ");
+ fflush(stdout);
+ }
+ sleep(2);
+ }
+ if(i >= lockwait) {
+ unlink(lock);
+ if(verbose) {
+ printf("Removing lock. ");
+ fflush(stdout);
+ }
+ if(link(mail, lock) < 0) {
+ fprintf(stderr, "Can't lock %s to %s\n",
+ mail, lock);
+ donecd = 1;
+ goto out1;
+ }
+ }
+ lseek(m, 0l, 2);
+ write(m, bracket, 5);
+ do
+ if((c = read(fd, buf, sizeof buf)) > 0)
+ if(write(m, buf, c) != c) {
+ fprintf(stderr, "Write error on ");
+ perror(mail);
+ donecd = 1;
+ goto out1;
+ }
+ while(c == sizeof buf);
+ write(m, bracket, 5);
+out1: close(m);
+out: cndfree(mail);
+ if(lock) {
+ unlink(lock);
+ cndfree(lock);
+ }
+#endif UNIXCOMP
+ }
+ if(verbose && !donecd)
+ printf("Sent.\n");
+}
+
+#ifdef DELIVERMAIL
+
+/*
+ * Salt away a name to send to, ultimately.
+ */
+
+char *stashname[100];
+char **stashp;
+
+nstash(name)
+ char name[];
+{
+ register char *cp;
+
+ cp = (char *) calloc(1, strlen(name) + 1);
+ strcpy(cp, name);
+ if (stashp == 0) {
+ stashp = stashname;
+ *stashp++ = "delivermail";
+ *stashp++ = "-i";
+ }
+ *stashp++ = cp;
+}
+
+stflush(fd)
+{
+ int pid;
+
+ if (stashp == 0)
+ return;
+ while ((pid = fork()) == -1)
+ sleep(2);
+ if (pid == 0) {
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ close(0);
+ dup(fd);
+ close(fd);
+ execv(DELIVERMAIL, stashname);
+ perror(DELIVERMAIL);
+ _exit(1);
+ }
+}
+#endif
+
+putfrom(out)
+ register FILE *out;
+{
+ register struct shome *h;
+
+ for(h = homes; h; h = h->h_next)
+ if(h->h_uid == myuid) {
+ fprintf(out, "From: %s\n", h->h_name);
+ return;
+ }
+ fprintf(stderr, "Deliver: WHO ARE YOU?\n");
+ done(1);
+}
+
+
+putmsgid(sp)
+ FILE *sp;
+{
+
+ if(!msgid)
+ return;
+ if(!now)
+ time(&now);
+ fprintf(sp, "Message-ID: <%u.%u.%ld.%s@%s>\n", getpid(), myuid,
+ now, localname, hostname);
+}
+
+/***/
+pl()
+{
+ register struct mailname *mp;
+
+ for(mp = addrlist.m_next; mp; mp=mp->m_next)
+ printf("%s%s", mp->m_name, mp->m_next?", ":"");
+ printf("\n");
+}
+/***/
+
+insert(name)
+ char *name;
+{
+ register struct mailname *mp;
+ char *getcpy();
+
+/*** printf("insert(%s)\n", name); ***/
+
+ for(mp = &addrlist; mp->m_next; mp = mp->m_next)
+ if(uleq(name, mp->m_next->m_name))
+ return; /* Don't insert existing name! */
+ mp->m_next = (struct mailname *) malloc(sizeof *mp->m_next);
+ mp = mp->m_next;
+ mp->m_next = 0;
+ mp->m_name = getcpy(name);
+}
+
+
+/* alias implementation below...
+ */
+
+
+
+#define GROUP "/etc/group"
+char *AliasFile = "/usr/local/lib/MailAliases";
+
+char *termptr;
+
+char *
+parse(ptr, buf)
+ register char *ptr;
+ char *buf;
+{
+ register char *cp;
+
+ cp = buf;
+ while(isspace(*ptr) || *ptr == ',' || *ptr == ':')
+ ptr++;
+ while(isalnum(*ptr) || *ptr == '/' || *ptr == '-' ||
+ *ptr == '.' || *ptr == '*')
+ *cp++ = *ptr++;
+ if(cp == buf) {
+ switch(*ptr) {
+ case '<':
+ case '=':
+ *cp++ = *ptr++;
+ }
+ }
+ *cp = 0;
+ if(cp == buf)
+ return 0;
+ termptr = ptr;
+ return buf;
+}
+
+char *
+advance(ptr)
+ register char *ptr;
+{
+ return(termptr);
+}
+
+alias()
+{
+ register char *cp, *pp;
+ register struct mailname *lp;
+ char line[256], pbuf[64];
+ FILE *a;
+
+ if((a = fopen(AliasFile, "r")) == NULL)
+ return;
+ while(fgets(line, sizeof line, a)) {
+ if(line[0] == ';' || line[0] == '\n') /* Comment Line */
+ continue;
+ if((pp = parse(line, pbuf)) == NULL) {
+ oops: fprintf(stderr, "Bad alias file %s\n", AliasFile);
+ fprintf(stderr, "Line: %s", line);
+ done(1);
+ }
+ for(lp = &addrlist; lp->m_next; lp = lp->m_next) {
+ if(aleq(lp->m_next->m_name, pp)) {
+ remove(lp);
+ if(!(cp = advance(line)) ||
+ !(pp = parse(cp, pbuf)))
+ goto oops;
+ switch(*pp) {
+ case '<': /* From file */
+ cp = advance(cp);
+ if((pp = parse(cp, pbuf)) == NULL)
+ goto oops;
+ addfile(pp);
+ break;
+ case '=': /* UNIX group */
+ cp = advance(cp);
+ if((pp = parse(cp, pbuf)) == NULL)
+ goto oops;
+ addgroup(pp);
+ break;
+ case '*': /* ALL Users */
+ addall();
+ break;
+ default: /* Simple list */
+ for(;;) {
+ insert(pp);
+ if(!(cp = advance(line)) ||
+ !(pp = parse(cp, pbuf)))
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+addfile(file)
+ char *file;
+{
+ register char *cp, *pp;
+ char line[128], pbuf[64];
+ FILE *f;
+
+/*** printf("addfile(%s)\n", file); ***/
+ if((f = fopen(file, "r")) == NULL) {
+ fprintf(stderr, "Can't open ");
+ perror(file);
+ done(1);
+ }
+ while(fgets(line, sizeof line, f)) {
+ cp = line;
+ while(pp = parse(cp, pbuf)) {
+ insert(pp);
+ cp = advance(cp);
+ }
+ }
+ fclose(f);
+}
+
+addgroup(group)
+ char *group;
+{
+ register char *cp, *pp;
+ int found = 0;
+ char line[128], pbuf[64], *rindex();
+ FILE *f;
+
+/*** printf("addgroup(%s)\n", group); ***/
+ if((f = fopen(GROUP, "r")) == NULL) {
+ fprintf(stderr, "Can't open ");
+ perror(GROUP);
+ done(1);
+ }
+ while(fgets(line, sizeof line, f)) {
+ pp = parse(line, pbuf);
+ if(strcmp(pp, group) == 0) {
+ cp = rindex(line, ':');
+ while(pp = parse(cp, pbuf)) {
+ insert(pp);
+ cp = advance(cp);
+ }
+ found++;
+ }
+ }
+ if(!found) {
+ fprintf(stderr, "Group: %s non-existent\n", group);
+ done(1);
+ }
+ fclose(f);
+}
+
+addall()
+{
+ register struct shome *h;
+
+/*** printf("addall()\n"); ***/
+ for(h = homes; h; h = h->h_next)
+ if(h->h_uid >= EVERYONE)
+ insert(h->h_name);
+}
+
+remove(mp) /* Remove NEXT from argument node! */
+ register struct mailname *mp;
+{
+ register struct mailname *rp;
+
+ rp = mp->m_next;
+ mp->m_next = rp->m_next;
+ cndfree(rp->m_name);
+ cndfree(rp);
+}
+
+int alarmed;
+
+alarmclock()
+{
+ alarmed++;
+}
+
+extern char **environ;
+char envhome[60] = "HOME=";
+char envname[60] = "NAME=";
+char *envinit[] = {envhome, envname, (char *) 0};
+
+calluserprog(prog, mail, fd, h)
+ char *prog, *mail;
+ int fd;
+ register struct shome *h;
+{
+ register int pid, child, i;
+ int status;
+
+ if(verbose) {
+ printf("Invoking %s ", prog);
+ fflush(stdout);
+ }
+ i = 0;
+ while((child = fork()) == -1)
+ if(++i > 10) {
+ fprintf(stderr, "Can't get a fork to invoke %s!\n",
+ prog);
+ donecd = 1;
+ return;
+ } else
+ sleep(2);
+ if(child == 0) { /* In child... */
+ if(fd != 3)
+ dup2(fd, 3);
+ for(i = 4; i < 15; i++)
+ close(i);
+ strcat(envname, h->h_name);
+ strcat(envhome, h->h_home);
+ environ = envinit;
+ setgid(h->h_gid);
+ setuid(h->h_uid);
+ execlp(prog, prog, tmpfil, mail, h->h_home, 0);
+ perror(prog);
+ done(-1);
+ }
+ signal(SIGALRM, alarmclock);
+ alarmed = 0;
+ alarm(30); /* Give receive proc 30 secs */
+ status = 0;
+ while((pid = wait(&status)) != -1 && pid != child && !alarmed) ;
+ if(alarmed) {
+ kill(0, SIGINT);
+ signal(SIGALRM, alarmclock);
+ alarmed = 0;
+ alarm(30);
+ while((pid = wait(&status)) != -1 && pid != child && !alarmed) ;
+ if(alarmed) {
+ kill(child, SIGKILL);
+ signal(SIGALRM, alarmclock);
+ alarmed = 0;
+ alarm(30);
+ while((pid = wait(&status)) != -1 && pid != child && !alarmed) ;
+ }
+ fprintf(stderr, "Deliver: Killed %s--Took more than 30 seconds!\n",
+ prog);
+ donecd = 1;
+ status = 0;
+ } else
+ alarm(0);
+ if(status) {
+ printf("Deliver: %s error %d from %s on delivery to %s\n",
+ status&0377? "System" : "User",
+ status&0377? status&0377 : status>>8,
+ prog, h->h_name);
+ donecd = 1;
+ }
+ if(pid == -1) {
+ fprintf(stderr, "Deliver: wait on receive process returned -1\n");
+ perror("");
+ donecd = 1;
+ }
+}
+
+aleq(string, aliasent)
+ register char *string, *aliasent;
+{
+ register int c;
+
+ while(c = *string++)
+ if(*aliasent == '*')
+ return 1;
+ else if((c|040) != (*aliasent|040))
+ return(0);
+ else
+ aliasent++;
+ return(*aliasent == 0 | *aliasent == '*');
+}
+
+fcc(file, folder)
+ char *file, *folder;
+{
+ int child, pid, status;
+ char fold[128];
+
+ if(verbose) {
+ printf("Fcc: %s...", folder);
+ fflush(stdout);
+ }
+ while((child = fork()) == -1) sleep(5);
+ if(child == 0) {
+ if(*file != '+')
+ strcpy(fold, "+");
+ strcat(fold, folder);
+ setuid(myuid);
+ execl(fileproc, "file", "-link", "-file", file, fold, 0);
+ exit(-1);
+ } else while((pid = wait(&status)) != -1 && pid != child) ;
+ if(status)
+ fprintf(stderr, "Deliver: Error on fcc to %s\n", folder);
+ else if(verbose)
+ putchar('\n');
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)dist.c 4.1 2/23/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+
+#define NONE 0
+#define NOUSE 0
+
+/* #define TEST 1 */
+
+char *anyl[] = {
+ "no", 0,
+ "yes", 0,
+ "list", 0,
+ 0,
+};
+
+char *anyv[] = {
+ "no", 0,
+ "yes", 0,
+ "verbose", 0,
+ 0,
+};
+
+char *aleqs[] = {
+ "list", 0, /* 0 */
+ "edit [<editor>]", 0, /* 1 */
+ "quit [delete]", 0, /* 2 */
+ "send [verbose]", 0, /* 3 */
+ 0
+};
+
+struct msgs *mp;
+char drft[128];
+char *vec[MAXARGS];
+int inplace; /* preserve links in anno */
+
+struct swit switches[] = {
+ "annotate", 0, /* 0 */
+ "noannotate", 0, /* 1 */
+ "editor editor", 0, /* 2 */
+ "form formfile", 0, /* 3 */
+ "inplace", 0, /* 4 */
+ "noinplace", 0, /* 5 */
+ "help", 4, /* 6 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100], *ed, *form;
+ register int msgnum;
+ register char *cp, **ap;
+ int msgp, anot, curf;
+ int in, out, intr;
+ int pid, wpid, status;
+ char *arguments[50], **argp;
+
+#ifdef NEWS
+ m_news();
+#endif
+ anot = 0; folder = 0; curf = 0; msgp = 0; ed = 0; form = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "dist: -%s unknown\n", cp);
+ goto leave;
+ case 0: anot = 1; continue; /* -annotate */
+ case 1: anot = 0; continue; /* -noannotate */
+ case 2: if(!(ed = *argp++)) { /* -editor */
+ missing: fprintf(stderr, "dist: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 3: if(!(form = *argp++)) /* -form */
+ goto missing;
+ continue;
+ case 4: inplace = 1; continue; /* -inplace */
+ case 5: inplace = 0; continue; /* -noinplace */
+ /* -help */
+ case 6: help("dist [+folder] [msg] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert((cp = msgs[msgnum])))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "dist: Tuna Melt\n"); /* never get here */
+ goto leave;
+ }
+ if(mp->numsel > 1) {
+ fprintf(stderr, "Only one message at a time.\n");
+ goto leave;
+ }
+ if(form) {
+ if((in = open(m_maildir(form), 0)) < 0) {
+ fprintf(stderr, "dist: Can't open form file: %s\n", form);
+ goto leave;
+ }
+ } else if(/***(in = open(m_maildir(distcomps), 0)) < 0 && ***/
+ (in = open(stddcomps, 0)) < 0) {
+ fprintf(stderr, "dist: Can't open default components file!!\n");
+ goto leave;
+ }
+ copy(m_maildir(draft), drft);
+ if((out = open(drft, 0)) >= 0) {
+ if(!fdcompare(in, out)) {
+ cp = concat("\"", drft, "\" exists; Delete? ", 0);
+ while((msgnum = gans(cp, anyl)) == 2)
+ showfile(drft);
+ if(!msgnum)
+ return;
+ }
+ close(out);
+ }
+ if((out = creat(drft, m_gmprot())) < 0) {
+ fprintf(stderr, "Can't create \"%s\"\n", drft);
+ goto leave;
+ }
+ cpydata(in, out);
+ close(in);
+ if((in = open(cp = m_name(mp->lowsel), 0)) < 0) {
+ fprintf(stderr, "Can't open message \"%s\"\n", cp);
+ unlink(drft);
+ goto leave;
+ }
+ cpydata(in, out);
+ close(in);
+ close(out);
+ m_replace(pfolder, folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ if(m_edit(&ed, drft, NOUSE, NONE) < 0)
+ goto leave;
+#ifdef TEST
+ fprintf(stderr, "!! Test Version of SEND Being Run !!\n");
+ fprintf(stderr, " Send verbose !\n\n");
+#endif
+
+ for(;;) {
+ if(!(argp = getans("\nWhat now? ", aleqs)))
+ goto leave;
+ switch(smatch(*argp, aleqs)) {
+ case 0: showfile(drft); /* list */
+ break;
+ case 1: if(*++argp) /* edit */
+ ed = *argp;
+ if(m_edit(&ed, drft, NOUSE, NONE) == -1)
+ goto leave;
+ break;
+ case 2: if(*++argp && *argp[0] == 'd') /* quit */
+ if(unlink(drft) == -1) {
+ fprintf(stderr, "Can't unlink %s ", drft);
+ perror("");
+ }
+ goto leave;
+ case 3: if(*++argp) cp = *argp; else cp = ""; /* send */
+
+ if(!mp->msgflags&READONLY) { /* annotate first */
+ if(anot > 0) {
+ while((pid = fork()) == -1) sleep(5);
+ if(pid) {
+ while(wpid=wait((int *)NULL)!= -1 && wpid!= pid);
+ doano();
+ goto leave;
+ }
+ }
+ }
+ if(!m_send(cp, drft))
+ goto leave;
+ default:fprintf(stderr, "dist: illegal option\n"); /*##*/
+ break;
+ }
+ }
+
+ leave:
+ m_update();
+ done(0);
+}
+
+
+cpydata(in, out)
+{
+ char buf[BUFSIZ];
+ register int i;
+
+ do
+ if((i = read(in, buf, sizeof buf)) > 0)
+ write(out, buf, i);
+ while(i == sizeof buf);
+}
+
+
+doano()
+{
+ register FILE *in;
+ char name[NAMESZ], field[256];
+ register int ind, state;
+ register char *text;
+
+ if(stat(drft, field) != -1) {
+ fprintf(stderr, "%s not sent-- no annotations made.\n", drft);
+ return;
+ }
+ text = copy(drft, field);
+ text[1] = 0;
+ do
+ *text = text[-1];
+ while(--text >= field && *text != '/');
+ *++text =
+#ifdef UCB
+ '#';
+#else
+ ',';
+#endif
+ if((in = fopen(field, "r")) == NULL) {
+ fprintf(stderr, "Can't open %s\n", field);
+ return;
+ }
+ state = FLD;
+ text = 0;
+ for(;;) switch(state = m_getfld(state, name, field, sizeof field, in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(uleq(name, "distribute-to") ||
+ uleq(name, "distribute-cc") == 0) {
+ if(state == FLD) {
+ text = add(name, text);
+ text = add(":", text);
+ }
+ text = add(field, text);
+ }
+ if(state == FLDEOF)
+ goto out;
+ continue;
+ case BODY:
+ case BODYEOF:
+ goto out;
+ default:
+ fprintf(stderr, "Getfld returned %d\n", state);
+ return;
+ }
+
+out:
+ fclose(in);
+ annotate(m_name(mp->lowsel), "Distributed", text, inplace);
+
+
+}
--- /dev/null
+/*
+ * Routine to convert a localtime(3) format date back into
+ * a system format date.
+ *
+ * Hats off to Bob Kridle for the insight that the way to do
+ * this is by binary search of the system date space.
+ */
+
+#include <sys/time.h>
+
+struct tm *localtime();
+
+long
+emitl(dp)
+ struct tm *dp;
+{
+ long conv;
+ register int i, bit;
+ struct tm dcopy;
+
+ dcopy = *dp;
+ dp = &dcopy;
+ conv = 0;
+ for (i = 31; i >= 0; i--) {
+ bit = 1 << i;
+ conv |= bit;
+ if (dcmp(localtime(&conv), dp) > 0)
+ conv &= ~bit;
+ }
+ return(conv);
+}
+
+/*
+ * Compare two localtime dates, return result.
+ */
+
+#define DECIDE(a) \
+ if (dp->a > dp2->a) \
+ return(1); \
+ if (dp->a < dp2->a) \
+ return(-1)
+
+static
+dcmp(dp, dp2)
+ register struct tm *dp, *dp2;
+{
+
+ DECIDE(tm_year);
+ DECIDE(tm_mon);
+ DECIDE(tm_mday);
+ DECIDE(tm_hour);
+ DECIDE(tm_min);
+ DECIDE(tm_sec);
+ return(0);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <dir.h>
+#include <strings.h>
+
+#define NFOLDERS 100
+
+int all, hdrflag, foldp;
+struct msgs *mp;
+char folder[128], *folds[NFOLDERS];
+int msgtot, foldtot, totonly, fshort;
+int fpack;
+struct swit switches[] = {
+ "all", 0, /* 0 */
+ "down", 0, /* 1 */
+ "fast", 0, /* 2 */
+ "nofast", 0, /* 3 */
+ "header", 0, /* 4 */
+ "noheader", 0, /* 5 */
+ "pack", 0, /* 6 */
+ "nopack", 0, /* 7 */
+ "short", -1, /* 8 */
+ "total", 0, /* 9 */
+ "nototal", 0, /*10 */
+ "up", 0, /*11 */
+ "help", 4, /*12 */
+ "debug", 5, /*13 */
+ 0, 0
+};
+
+int debug;
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp, *curm;
+ register int i;
+ char *argfolder;
+ int up, down, j, def_short;
+ char *arguments[50], **argp, **ap;
+ struct stat stbf;
+ struct node *np;
+ extern char _sobuf[];
+ register struct direct *dir;
+ DIR *dirp;
+
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ up = down = 0;
+ argfolder = NULL;
+ curm = 0;
+ if(argv[0][strlen(argv[0])-1] == 's') /* Plural name?? */
+ all++;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "folder: -%s unknown\n", cp);
+ goto leave;
+ case 0: all++; continue; /* -all */
+ case 1: down++; continue; /* -down */
+ case 2: /* -fast */
+ case 3: fshort = 0; continue; /* -nofast */
+ case 4: hdrflag = -1; continue; /* -header */
+ case 5: hdrflag = 0; continue; /* -noheader */
+ case 6: fpack = 1; continue; /* -pack */
+ case 7: fpack = 0; continue; /* -nopack */
+ case 8: fshort = 1; continue; /* -short */
+ case 9: all++; totonly = 1; /* -total */
+ continue;
+ case 10:if(totonly) all--; /* -nototal */
+ totonly =0; continue;
+ case 11:up++; continue; /* -up */
+ /* -help */
+ case 12:help("folder [+folder] [msg] [switches]",
+ switches);
+ goto leave;
+ case 13:debug++; /* -debug */
+ continue;
+ }
+ if(*cp == '+') {
+ if(argfolder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ argfolder = cp + 1;
+ } else if(curm) {
+ fprintf(stderr, "Only one current may be given.\n");
+ goto leave;
+ } else
+ curm = cp;
+ }
+ if(all) {
+ hdrflag = 0;
+ cp = m_maildir("");
+ m_getdefs();
+ for(np = m_defs; np; np = np->n_next) {
+ if(!ssequal("cur-", np->n_name))
+ continue;
+ if(fshort) {
+ def_short++;
+ printf("%s\n", np->n_name+4);
+ } else
+ addfold(np->n_name+4);
+ }
+ if(def_short)
+ putchar('\n');
+ if(fshort) {
+ m_update();
+ fflush(stdout);
+ execl(lsproc, "mh-ls", "-x", cp, 0);
+ fprintf(stderr, "Can't exec: ");
+ perror(lsproc);
+ goto leave;
+ }
+ if(chdir(cp) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(cp);
+ goto leave;
+ }
+ if((cp = m_find(pfolder)) == NULL)
+ *folder = 0;
+ else
+ copy(cp, folder);
+ dirp = opendir(".");
+ (void) readdir(dirp);
+ (void) readdir(dirp);
+ while (dir = readdir(dirp)) {
+ if (stat(dir->d_name, &stbf) < 0 ||
+ (stbf.st_mode & S_IFMT) != S_IFDIR)
+ continue;
+ addfold(dir->d_name);
+ }
+ closedir(dirp);
+ for(i = 0; i < foldp; i++) {
+ pfold(folds[i], 0); fflush(stdout);
+ }
+ if(!totonly)
+ printf("\n\t\t ");
+ printf("TOTAL= %3d message%c in %d Folder%s.\n",
+ msgtot, msgtot!=1? 's':' ',
+ foldtot, foldtot!=1? "s":"");
+ } else {
+ hdrflag++;
+ if(argfolder)
+ cp = copy(argfolder, folder);
+ else
+ cp = copy(m_getfolder(), folder);
+ if(up) {
+ while(cp > folder && *cp != '/') --cp;
+ if(cp > folder)
+ *cp = 0;
+ argfolder = folder;
+ } else if(down) {
+ copy(listname, copy("/", cp));
+ argfolder = folder;
+ }
+ if(pfold(folder, curm) && argfolder)
+ m_replace(pfolder, argfolder);
+ }
+
+ leave:
+ m_update();
+ done(0);
+}
+
+
+addfold(fold)
+char *fold;
+{
+ register int i,j;
+ register char *cp;
+
+ if(foldp >= NFOLDERS) {
+ fprintf(stderr, "More than %d folders!!\n", NFOLDERS);
+ return(1);
+ }
+ cp = getcpy(fold);
+ for(i = 0; i < foldp; i++)
+ if(compare(cp, folds[i]) < 0) {
+ for(j = foldp - 1; j >= i; j--)
+ folds[j+1] = folds[j];
+ foldp++;
+ folds[i] = cp;
+ return(0);
+ }
+ folds[foldp++] = cp;
+ return(0);
+}
+
+
+pfold(fold, curm)
+char *fold;
+{
+ register char *mailfile;
+ register int msgnum, hole;
+ char newmsg[8], oldmsg[8];
+
+ mailfile = m_maildir(fold);
+ if(chdir(mailfile) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(mailfile);
+ return(0);
+ }
+ if(fshort) {
+ printf("%s\n", fold);
+ return(0);
+ }
+ mp = m_gmsg(fold);
+ foldtot++;
+ msgtot += mp->nummsg;
+ if (debug)
+ printf("pfold: %s message flags: 0%o\n", fold, mp->msgflags);
+ if(fpack && (mp->msgflags & READONLY) == 0) {
+ if (debug) {
+ printf("Would normally be packing folder %s\n", fold);
+ return;
+ }
+ for(msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++) {
+ if(mp->msgstats[msgnum]&EXISTS) {
+ if(msgnum != hole) {
+ copy(m_name(hole), newmsg);
+ copy(m_name(msgnum), oldmsg);
+ if(link(oldmsg, newmsg) == -1 ||
+ unlink(oldmsg) == -1) {
+ fprintf(stderr, "Error moving %s to ", oldmsg);
+ perror(newmsg);
+ done(1);
+ }
+ mp->msgstats[hole] = mp->msgstats[msgnum];
+ if(msgnum == mp->lowsel)
+ mp->lowsel = hole;
+ if(msgnum == mp->hghsel)
+ mp->hghsel = hole;
+ }
+ hole++;
+ }
+ }
+ if(mp->nummsg > 0) {
+ mp->lowmsg = 1;
+ mp->hghmsg = hole - 1;
+ }
+ }
+ if(totonly)
+ goto out;
+ if(curm) {
+ if(!m_convert(curm))
+ return(0);
+ if(mp->numsel > 1) {
+ fprintf(stderr, "Can't set current msg to range: %s\n", curm);
+ return(0);
+ }
+ m_setcur(mp->curmsg = mp->hghsel);
+ }
+ if(!hdrflag++)
+ printf("\t\tFolder # of messages ( range ); cur msg (other files)\n");
+ printf("%22s", fold);
+ if(strcmp(folder, fold) == 0)
+ printf("+ ");
+ else
+ printf(" ");
+ if(mp->hghmsg == 0)
+ printf("has no messages");
+ else {
+ printf("has %3d message%s (%3d-%3d)",
+ mp->nummsg, (mp->nummsg==1)?" ":"s",
+ mp->lowmsg, mp->hghmsg);
+ if(mp->curmsg >= mp->lowmsg && mp->curmsg <= mp->hghmsg)
+ printf("; cur=%3s", m_name(mp->curmsg));
+ }
+ if(mp->selist || mp->others) {
+ printf("; (");
+ if(mp->selist) {
+ printf("%s", listname);
+ if(mp->others)
+ printf(", ");
+ }
+ if(mp->others)
+ printf("others");
+ putchar(')');
+ }
+ putchar('.');
+ putchar('\n');
+out:
+ free(mp);
+ mp = 0;
+ return(1);
+}
+
+
+compare(s1, s2)
+char *s1, *s2;
+{
+ register char *c1, *c2;
+ register int i;
+
+ c1 = s1; c2 = s2;
+ while(*c1 || *c2)
+ if(i = *c1++ - *c2++)
+ return(i);
+ return(0);
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)forw.c 4.1 2/23/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+
+#define NONE 0
+#define NOUSE 0
+
+/* #define TEST 1 */
+
+int *vec[MAXARGS];
+struct msgs *mp;
+char drft[128];
+int inplace; /* preserve links in anno */
+
+char *anyl[] = {
+ "no", 0,
+ "yes", 0,
+ "list", 0,
+ 0,
+};
+
+char *anyv[] = {
+ "no", 0,
+ "yes", 0,
+ "verbose", 0,
+ 0,
+};
+
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "annotate", 0, /* 1 */
+ "noannotate", 0, /* 2 */
+ "editor editor", 0, /* 3 */
+ "form formfile", 0, /* 4 */
+ "inplace", 0, /* 5 */
+ "noinplace", 0, /* 6 */
+ "help", 4, /* 7 */
+ 0, 0
+};
+
+char *aleqs[] = {
+ "list", 0, /* 0 */
+ "edit [<editor>]", 0, /* 1 */
+ "quit [delete]", 0, /* 2 */
+ "send [verbose]", 0, /* 3 */
+ 0
+};
+
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100], *ed, *form;
+ register int msgnum;
+ register char *cp, **ap;
+ int msgp, status, anot;
+ int in, out, intr;
+ int pid, wpid, msgcnt;
+ char *arguments[50], **argp;
+ char numbuf[5];
+
+#ifdef NEWS
+ m_news();
+#endif
+ form = 0; anot = 0; folder = 0; msgp = 0; ed = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "forw: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: anot = 1; continue; /* -annotate */
+ case 2: anot = 0; continue; /* -noannotate */
+ case 3: if(!(ed = *argp++)) { /* -editor */
+ missing: fprintf(stderr, "forw: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 4: if(!(form = *argp++)) /* -form */
+ goto missing;
+ continue;
+ case 5: inplace = 1; continue; /* -inplace */
+ case 6: inplace = 0; continue; /* -noinplace */
+ /* -help */
+ case 7: help("forw [+folder] [msgs] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "forw: italian salami.\n"); /* never get here */
+ goto leave;
+ }
+ if(form) {
+ if((in = open(m_maildir(form), 0)) < 0) {
+ fprintf(stderr, "forw: Can't open form file: %s\n", form);
+ goto leave;
+ }
+ } else if((in = open(m_maildir(components), 0)) < 0 &&
+ (in = open(stdcomps, 0)) < 0) {
+ fprintf(stderr, "forw: Can't open default components file!!\n");
+ goto leave;
+ }
+ copy(m_maildir(draft), drft);
+ if((out = open(drft, 0)) >= 0) {
+ if(!fdcompare(in, out)) {
+ cp = concat("\"", drft, "\" exists; Delete? ", 0);
+ while((msgnum = gans(cp, anyl)) == 2)
+ showfile(drft);
+ if(!msgnum)
+ return;
+ }
+ close(out);
+ }
+ if((out = creat(drft, m_gmprot())) < 0) {
+ fprintf(stderr, "Can't create \"%s\"\n", drft);
+ goto leave;
+ }
+ cpydata(in, out);
+ close(in);
+ for(msgcnt = 1, msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED) {
+ if((in = open(cp = m_name(msgnum), 0)) < 0) {
+ fprintf(stderr, "Can't open message \"%s\"\n", cp);
+ unlink(drft);
+ goto leave;
+ }
+ type(out, "\n\n-------");
+ if(msgnum == mp->lowsel) {
+ type(out, " Forwarded Message");
+ if(mp->numsel > 1)
+ type(out, "s");
+ } else {
+ type(out, " Message ");
+ sprintf(numbuf, "%d", msgcnt);
+ type(out, numbuf);
+ }
+ type(out, "\n\n");
+ cpydata(in, out);
+ close(in);
+ msgcnt++;
+ }
+ type(out, "\n\n------- End of Forwarded Message");
+ if(mp->numsel > 1)
+ type(out, "s");
+ type(out, "\n");
+ close(out);
+ m_replace(pfolder, folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ if(m_edit(&ed, drft, NOUSE, NONE) < 0)
+ goto leave;
+
+#ifdef TEST
+ fprintf(stderr, "!! Test Version of SEND Being Run !!\n");
+ fprintf(stderr, " Send verbose !\n\n");
+#endif
+ for(;;) {
+ if(!(argp = getans("\nWhat now? ", aleqs)))
+ goto leave;
+ switch(smatch(*argp, aleqs)) {
+ case 0: showfile(drft); /* list */
+ break;
+ case 1: if(*++argp) /* edit */
+ ed = *argp;
+ if(m_edit(&ed, drft, NOUSE, NONE) == -1)
+ goto leave;
+ break;
+ case 2: if(*++argp && *argp[0] == 'd') /* quit */
+ if(unlink(drft) == -1) {
+ fprintf(stderr, "Can't unlink %s ", drft);
+ perror("");
+ }
+ goto leave;
+ case 3: if(*++argp) cp = *argp; else cp = ""; /* send */
+
+ if(!mp->msgflags&READONLY) { /* annotate first */
+ if(anot > 0) {
+ while((pid = fork()) == -1) sleep(5);
+ if(pid) {
+ while(wpid=wait((int *)NULL)!= -1 && wpid!= pid);
+ doano();
+ goto leave;
+ }
+ }
+ }
+ if(!m_send(cp, drft))
+ goto leave;
+ default:fprintf(stderr, "forw: illegal option\n"); /*##*/
+ break;
+ }
+ }
+
+ leave:
+ m_update();
+ done(0);
+}
+
+
+cpydata(in, out)
+{
+ char buf[BUFSIZ];
+ register int i;
+
+ do
+ if((i = read(in, buf, sizeof buf)) > 0)
+ write(out, buf, i);
+ while(i == sizeof buf);
+}
+
+
+doano()
+{
+ FILE *in;
+ char name[NAMESZ], field[256];
+ register int ind, state;
+ register char *text;
+
+ if(stat(drft, field) != -1) {
+ fprintf(stderr, "%s not sent-- no annotations made.\n", drft);
+ return;
+ }
+ text = copy(drft, field);
+ text[1] = 0;
+ do
+ *text = text[-1];
+ while(--text >= field && *text != '/');
+ *++text =
+#ifdef UCB
+ '#';
+#else
+ ','; /* New backup convention */
+#endif
+ if((in = fopen(field, "r")) == NULL) {
+ fprintf(stderr, "Can't open "); perror(field);
+ return;
+ }
+ state = FLD;
+ text = 0;
+ for(;;) switch(state = m_getfld(state, name, field, sizeof field, in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(uleq(name, "to") || uleq(name, "cc") == 0) {
+ if(state == FLD) {
+ text = add(name, text);
+ text = add(":", text);
+ }
+ text = add(field, text);
+ }
+ if(state == FLDEOF)
+ goto out;
+ continue;
+ case BODY:
+ case BODYEOF:
+ goto out;
+ default:
+ fprintf(stderr, "Getfld returned %d\n", state);
+ return;
+ }
+
+out:
+ fclose(in);
+
+ for(ind = mp->lowsel; ind <= mp->hghsel; ind++)
+ if(mp->msgstats[ind] & SELECTED)
+ annotate(m_name(ind), "Forwarded", text, inplace);
+}
--- /dev/null
+#include <stdio.h>
+#define CCHR 2
+#define CDOT 4
+#define CCL 6
+#define NCCL 8
+#define CDOL 10
+#define CEOF 11
+
+#define STAR 01
+
+#define LBSIZE 1024
+#define ESIZE 256
+
+char ibuf[BUFSIZ];
+char expbuf[ESIZE];
+char linebuf[LBSIZE+1];
+int circf;
+
+char cc[] = {
+ 0000,0001,0002,0003,0004,0005,0006,0007,
+ 0010,0011,0012,0013,0014,0015,0016,0017,
+ 0020,0021,0022,0023,0024,0025,0026,0027,
+ 0030,0031,0032,0033,0034,0035,0036,0037,
+ 0040,0041,0042,0043,0044,0045,0046,0047,
+ 0050,0051,0052,0053,0054,0055,0056,0057,
+ 0060,0061,0062,0063,0064,0065,0066,0067,
+ 0070,0071,0072,0073,0074,0075,0076,0077,
+ 0100,0141,0142,0143,0144,0145,0146,0147,
+ 0150,0151,0152,0153,0154,0155,0156,0157,
+ 0160,0161,0162,0163,0164,0165,0166,0167,
+ 0170,0171,0172,0133,0134,0135,0136,0137,
+ 0140,0141,0142,0143,0144,0145,0146,0147,
+ 0150,0151,0152,0153,0154,0155,0156,0157,
+ 0160,0161,0162,0163,0164,0165,0166,0167,
+ 0170,0171,0172,0173,0174,0175,0176,0177,
+};
+
+
+compile(astr)
+char *astr;
+{
+ register c;
+ register char *ep, *sp;
+ char *lastep;
+ int cclcnt;
+
+ ep = expbuf;
+ sp = astr;
+ if (*sp == '^') {
+ circf++;
+ sp++;
+ }
+ for (;;) {
+ if (ep >= &expbuf[ESIZE])
+ goto cerror;
+ if ((c = *sp++) != '*')
+ lastep = ep;
+ switch (c) {
+
+ case '\0':
+ *ep++ = CEOF;
+ return(1);
+
+ case '.':
+ *ep++ = CDOT;
+ continue;
+
+ case '*':
+ if (lastep==0)
+ goto defchar;
+ *lastep |= STAR;
+ continue;
+
+ case '$':
+ if (*sp != '\0')
+ goto defchar;
+ *ep++ = CDOL;
+ continue;
+
+ case '[':
+ *ep++ = CCL;
+ *ep++ = 0;
+ cclcnt = 1;
+ if ((c = *sp++) == '^') {
+ c = *sp++;
+ ep[-2] = NCCL;
+ }
+ do {
+ *ep++ = c;
+ cclcnt++;
+ if (c=='\0' || ep >= &expbuf[ESIZE])
+ goto cerror;
+ } while ((c = *sp++) != ']');
+ lastep[1] = cclcnt;
+ continue;
+
+ case '\\':
+ if ((c = *sp++) == '\0')
+ goto cerror;
+ defchar:
+ default:
+ *ep++ = CCHR;
+ *ep++ = c;
+ }
+ }
+ cerror:
+ return(0);
+}
+
+
+execute(file)
+char *file;
+{
+ register char *p1, *p2;
+ register c;
+ int f, body, lf;
+ char *ebp, *cbp;
+
+ if ((f = open(file, 0)) < 0) {
+ fprintf(stderr, "Grep: Can't open %s\n", file);
+ return(0);
+ }
+ body = 0;
+ ebp = ibuf;
+ cbp = ibuf;
+ for (;;) {
+ p1 = linebuf;
+ p2 = cbp;
+ lf = 0;
+ for (;;) {
+ if (p2 >= ebp) {
+ if ((c = read(f, ibuf, sizeof ibuf)) <= 0) {
+ close(f);
+ if(lf) break; /* bodyless comp! */
+ return(0);
+ }
+ p2 = ibuf;
+ ebp = ibuf+c;
+ }
+ c = *p2++;
+ if(lf) if(c != ' ' && c != '\t') {
+ --p2;
+ break;
+ } else
+ lf = 0;
+ if (c == '\n')
+ if(body)
+ break;
+ else {
+ if(lf) {
+ body++;
+ break;
+ }
+ lf++;
+ c = ' ';
+ }
+ if(c && p1 < &linebuf[LBSIZE-1])
+ *p1++ = c;
+ }
+ *p1++ = 0;
+ cbp = p2;
+ p1 = linebuf;
+ p2 = expbuf;
+ if (circf) {
+ if (advance(p1, p2))
+ goto found;
+ continue;
+ }
+ /* fast check for first character */
+ if (*p2==CCHR) {
+ c = p2[1];
+ do {
+ if(*p1==c || cc[*p1]==c)
+ if (advance(p1, p2))
+ goto found;
+ } while (*p1++);
+ continue;
+ }
+ /* regular algorithm */
+ do {
+ if (advance(p1, p2))
+ goto found;
+ } while (*p1++);
+ continue;
+ found:
+ close(f);
+ return(1);
+ }
+}
+
+
+advance(alp, aep)
+char *alp, *aep;
+{
+ register char *lp, *ep, *curlp;
+ char *nextep;
+
+ lp = alp;
+ ep = aep;
+ for (;;) switch (*ep++) {
+
+ case CCHR:
+ if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
+ continue;
+ return(0);
+
+ case CDOT:
+ if (*lp++)
+ continue;
+ return(0);
+
+ case CDOL:
+ if (*lp==0)
+ continue;
+ return(0);
+
+ case CEOF:
+ return(1);
+
+ case CCL:
+ if (cclass(ep, *lp++, 1)) {
+ ep += *ep;
+ continue;
+ }
+ return(0);
+
+ case NCCL:
+ if (cclass(ep, *lp++, 0)) {
+ ep += *ep;
+ continue;
+ }
+ return(0);
+
+ case CDOT|STAR:
+ curlp = lp;
+ while (*lp++);
+ goto star;
+
+ case CCHR|STAR:
+ curlp = lp;
+ while (*lp++ == *ep || cc[lp[-1]] == *ep) ;
+ ep++;
+ goto star;
+
+ case CCL|STAR:
+ case NCCL|STAR:
+ curlp = lp;
+ while (cclass(ep, *lp++, ep[-1]==(CCL|STAR)));
+ ep += *ep;
+ goto star;
+
+ star:
+ do {
+ lp--;
+ if (advance(lp, ep))
+ return(1);
+ } while (lp > curlp);
+ return(0);
+
+ default:
+ printf("RE botch\n");
+ return(0);
+ }
+}
+
+
+cclass(aset, ac, af)
+char *aset;
+{
+ register char *set, c;
+ register n;
+
+ set = aset;
+ if ((c = ac) == 0)
+ return(0);
+ n = *set++;
+ while (--n)
+ if (*set++ == c)
+ return(af);
+ return(!af);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <strings.h>
+#include <signal.h>
+
+char *anoyes[]; /* Std no/yes gans array */
+
+extern int errno;
+char scanl[];
+struct msgs *mp;
+FILE *in, *aud;
+struct stat stbuf;
+char *locknode;
+int lockwait; /* Secs to wait for lock-Def in strings/lockdir.c */
+#define LOCKWAIT (lockwait*5) /* If lock is this old, simply ignore it! */
+
+struct swit switches[] = {
+ "audit audit-file", 0, /* 0 */
+ "ms ms-folder", 0, /* 1 */
+ "help", 4, /* 2 */
+ "file mail-file", 0, /* 3 */
+ 0, 0
+};
+
+#ifdef UNIXCOMP
+char unixtmp[] = "/tmp/mhXXXXXX";
+#endif
+
+main(argc, argv)
+char *argv[];
+{
+
+ char *newmail, maildir[128], *folder, *from, *audfile, *srcfile;
+ char mailspace[128];
+ char *myname, *savemail;
+ register char *cp;
+ register int i, msgnum;
+ long now;
+ char **ap;
+ char *arguments[50], **argp;
+ int done();
+ long time();
+ int pid, status, fildes;
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+
+ from = 0; folder = 0; audfile = 0; srcfile = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "inc: -%s unknown\n", cp);
+ goto leave;
+ case 0: if(!(audfile = *argp++)) { /* -audit */
+ missing: fprintf(stderr, "inc: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 1: if(!(from = *argp++)) /* -ms */
+ goto missing;
+ continue;
+ case 2: /* -help */
+ help("inc [+folder] [switches]", switches);
+ goto leave;
+ case 3: /* -file */
+ if (!(srcfile = *argp++))
+ goto missing;
+ continue;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else {
+ fprintf(stderr, "Bad arg: %s\n", argp[-1]);
+ fprintf(stderr, "Usage: inc [+folder] [-ms ms-folder] [-audit audit-file]\n");
+ goto leave;
+ }
+ }
+ if (from && srcfile) {
+ fprintf(stderr, "Only one of \"-ms\" and \"-file\" allowed\n");
+ goto leave;
+ }
+ if(from)
+ newmail = from;
+ else {
+ if((myname = getenv("USER")) == 0) {
+ fprintf(stderr,
+"Environment Variable \"USER\" Must be set to your login name!\n");
+ done(1);
+ }
+ if (srcfile) {
+ newmail = srcfile;
+ goto statit;
+ }
+ newmail = concat(mailboxes, myname, 0);
+ if (stat(newmail, &stbuf) >= 0
+ && (stbuf.st_mode & S_IFMT) == S_IFDIR) {
+ strcpy(mailspace, newmail);
+ newmail = mailspace;
+ strcat(newmail, "/");
+ strcat(newmail, myname);
+ }
+statit:
+ if(stat(newmail, &stbuf) < 0 ||
+ stbuf.st_size == 0) {
+ fprintf(stderr, "No Mail to incorporate.\n");
+ goto leave;
+ }
+ }
+ fildes = -1;
+ if (srcfile)
+ if ((fildes = open(srcfile, 0)) < 0) {
+ perror(srcfile);
+ goto leave;
+ }
+ if(!folder) {
+ folder = defalt;
+ if(from && strcmp(from, "inbox") == 0) {
+ cp = concat("Do you really want to convert from ",
+ from, " into ", folder, "?? ", 0);
+ if(!gans(cp, anoyes))
+ goto leave;
+ cndfree(cp);
+ }
+ }
+ copy(m_maildir(folder), maildir);
+ if(stat(maildir, &stbuf) < 0) {
+ if(errno != ENOENT) {
+ fprintf(stderr, "Error on folder ");
+ perror(maildir);
+ goto leave;
+ }
+ cp = concat("Create folder \"", maildir, "\"? ", 0);
+ if(!gans(cp, anoyes))
+ goto leave;
+ if(!makedir(maildir)) {
+ fprintf(stderr, "Can't create folder \"%s\"\n", maildir);
+ goto leave;
+ }
+ }
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ /* Lock the mail file */
+ if(!from && !srcfile) {
+ signal(SIGINT, done);
+ cp = concat(lockdir, myname, 0);
+ for(i = 0; i < lockwait; i += 2) {
+ if(link(newmail, cp) == -1) {
+ fprintf(stderr, "Mailbox busy...\n");
+ if(i == 0 && stat(newmail, &stbuf) >= 0)
+ if(stbuf.st_ctime + LOCKWAIT < time((long *)0)) {
+ unlink(cp);
+ fprintf(stderr, "Removing lock.\n");
+ continue;
+ }
+ sleep(2);
+ } else {
+ locknode = cp; /* We own the lock now! */
+ break;
+ }
+ }
+ if(i >= lockwait) {
+ fprintf(stderr, "Try again.\n");
+ done(1);
+ }
+ }
+
+#ifdef UNIXCOMP
+ /*
+ * If trying to be compatible with standard
+ * UNIX mailing scheme, call the program unixtomh
+ * to convert the mailbox to some temporary name.
+ */
+
+ mktemp(unixtmp);
+ switch (pid = fork()) {
+ case 0:
+ if (srcfile) {
+ int nout;
+
+ if ((nout = creat(unixtmp, 0600)) < 0) {
+ perror(unixtmp);
+ _exit(1);
+ }
+ close(0);
+ dup(fildes);
+ close(fildes);
+ close(1);
+ dup(nout);
+ close(nout);
+ execl(unixtomh, "unixtomh", 0);
+ perror(unixtomh);
+ _exit(1);
+ }
+ execl(unixtomh, "unixtomh", newmail, unixtmp, 0);
+ perror(unixtomh);
+ _exit(1);
+ break;
+
+ case -1:
+ perror("fork");
+ goto leave;
+
+ default:
+ while (wait(&status) != pid)
+ ;
+ if (status != 0) {
+ fprintf(stderr, "unixtomh failed!?\n");
+ goto leave;
+ }
+ }
+ if (fildes >= 0)
+ close(fildes);
+ savemail = newmail;
+ newmail = unixtmp;
+ if((in = fopen(newmail, "r")) == NULL) {
+ fprintf(stderr, "Can't open "); perror(newmail);
+ goto leave;
+ }
+#else
+ if (srcfile)
+ in = fdopen(fildes, "r");
+ else
+ if((in = fopen(newmail, "r")) == NULL) {
+ fprintf(stderr, "Can't open "); perror(newmail);
+ goto leave;
+ }
+#endif
+
+ if(audfile) {
+ cp = m_maildir(audfile);
+ if((i = stat(cp, &stbuf)) < 0)
+ fprintf(stderr, "Creating Receive-Audit: %s\n", cp);
+ if((aud = fopen(cp, "a")) == NULL) {
+ fprintf(stderr, "Can't append to ");
+ perror(cp);
+ goto leave;
+ } else if(i < 0)
+ chmod(cp, 0600);
+ time(&now);
+ fputs("<<inc>> ", aud);
+ cp = cdate(&now);
+ cp[9] = ' ';
+ fputs(cp, aud);
+ if(from) {
+ fputs(" -ms ", aud);
+ fputs(from, aud);
+ }
+ putc('\n', aud);
+ }
+ printf("Incorporating new mail into %s...\n\n", folder);
+ fflush(stdout);
+ msgnum = mp->hghmsg;
+
+ while((i = scan(in, msgnum+1, msgnum+1, msgnum == mp->hghmsg))) {
+ if(i == -1) {
+ fprintf(stderr, "inc aborted!\n");
+ if(aud)
+ fputs("inc aborted!\n", aud);
+ goto leave;
+ }
+ if(aud)
+ fputs(scanl, aud);
+ fflush(stdout);
+ msgnum++;
+ }
+
+ fclose(in);
+ if(aud)
+ fclose(aud);
+
+#ifdef UNIXCOMP
+ unlink(newmail);
+ newmail = savemail;
+#endif
+
+ if(!from && !srcfile) {
+ if (unlink(newmail) < 0) {
+ if((i = creat(newmail, 0600)) >= 0)
+ close(i);
+ else
+ fprintf(stderr, "Error zeroing %s\n", newmail);
+ }
+ }
+
+ i = msgnum - mp->hghmsg;
+ if(!i)
+ fprintf(stderr, "[No messages incorporated.]\n");
+ else {
+ m_replace(pfolder, folder);
+ m_setcur(mp->hghmsg + 1);
+ }
+leave:
+ m_update();
+ done(0);
+}
+
+
+done(status)
+{
+ if(locknode);
+ unlink(locknode);
+ exit(status);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+char *anoyes[]; /* Std no/yes gans array */
+char *mypath;
+char defpath[128];
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp, *path;
+ register struct node *np;
+ int autof, exitstat;
+ struct stat stbuf;
+ char *geta();
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+ autof = (argc == 2 && strcmp(argv[1], "-auto") == 0);
+ exitstat = 1; /* Assume errors will occur */
+ mypath = getenv("HOME");
+/*** mypath = getpath(getruid()); /* to prevent recursion via m_getdefs */
+ copy(mh_prof, copy(mypath, defpath));
+ if(stat(defpath, &stbuf) != -1) {
+ if(autof)
+ printf("Install-defs invocation error!\n");
+ else
+ printf("You already have an MH profile... use an editor \
+to modify it.\n");
+ goto leave;
+
+ }
+ if(autof || gans("Do you want help? ", anoyes)) {
+printf("\nPrior to using MH, it is necessary to have a file in your login\n");
+printf("directory (%s) named %s which contains information\n",mypath,mh_prof+1);
+printf("to direct certain MH operations. The only item which is required\n");
+printf("is the path to use for all MH folder operations. The suggested MH\n");
+printf("path for you is %s/Mail...\n\n", mypath);
+ }
+ cp = concat(mypath, "/", "Mail", 0);
+ if(stat(cp, &stbuf) != -1) {
+ if((stbuf.st_mode&S_IFMT) == S_IFDIR) {
+ cp = concat("You already have the standard MH directory \"",
+ cp, "\".\nDo you want to use it for MH? ", 0);
+ if(gans(cp, anoyes))
+ path = "Mail";
+ else
+ goto xyz;
+ }
+ } else {
+ cp = concat("Do you want the standard MH path \"", mypath,
+ "/", "Mail\"? ", 0);
+ if(gans(cp, anoyes))
+ path = "Mail";
+ else {
+ xyz: if(gans("Do you want a path below your login directory? ",
+ anoyes)) {
+ printf("What is the path ?? %s/", mypath);
+ path = geta();
+ } else {
+ printf("What is the whole path?? /");
+ path = concat("/", geta(), 0);
+ }
+ }
+ }
+ chdir(mypath);
+ if(chdir(path) == -1) {
+ cp = concat("\"", path, "\" doesn't exist; Create it? ", 0);
+ if(gans(cp, anoyes))
+ if(makedir(path) == 0) {
+ printf("Can't create it!\n");
+ goto leave;
+ }
+ } else
+ printf("[Using existing directory]\n");
+
+ np = m_defs = (struct node *) malloc(sizeof *np);
+ np->n_name = "Path";
+ np->n_field = path;
+ np->n_next = 0;
+ m_replace(pfolder, defalt);
+ exitstat = 0;
+
+leave:
+ m_update();
+ done(exitstat);
+}
+
+
+char *geta()
+{
+ static char line[128];
+ register char *cp;
+ register int c;
+
+ fflush(stdout);
+ cp = line;
+ while((c = getchar()) != EOF) {
+ if(c == '\n') {
+ *cp = 0;
+ return(line);
+ }
+ if(cp < &line[128])
+ *cp++ = c;
+ }
+ done(1);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <signal.h>
+
+#define NUMTOS 10 /* Number of to's & cc's accepted */
+
+char tmpfil[32];
+int exitstat = 1;
+char *subject, *cc, *body;
+
+struct swit switches[] = {
+ "body", 0, /* 0 */
+ "cc", 0, /* 1 */
+ "subject", 0, /* 2 */
+ "help", 4, /* 3 */
+ 0, 0
+};
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ register FILE *out;
+ register int i, cnt;
+ register char *cp;
+ int pid, status, top, ccp, sig(), somebody = 0;
+ char buf[BUFSIZ], *tos[NUMTOS], *ccs[NUMTOS], **argp;
+
+ top = 0;
+ ccp = -1; /* -1 -> collecting TOs */
+ if(argc == 1) { /* Just call inc to read mail */
+ execl("/bin/inc", "inc", 0);
+ execl("/usr/bin/inc", "inc", 0);
+ perror("inc");
+ done(exitstat);
+ }
+ argp = argv + 1;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ done(exitstat);
+ /* unknown */
+ case -1:fprintf(stderr, "send: -%s unknown\n", cp);
+ done(exitstat);
+ /* -body */
+ case 0: if((body = *argp++) == 0) {
+ missing: fprintf(stderr, "Mail: Missing %s arg\n", cp);
+ done(exitstat);
+ }
+ continue;
+ /* -cc */
+ case 1: ccp = 0; /* Now collecting ccs */
+ continue;
+ /* -subject */
+ case 2: if((subject = *argp++) == 0)
+ goto missing;
+ continue;
+ /* -help */
+ case 3: help("mail [switches] users ...",
+ switches);
+ done(0);
+ }
+ else {
+ if(ccp >= 0) { /* If getting ccs..*/
+ if(ccp < NUMTOS)
+ ccs[ccp++] = cp;
+ else {
+ fprintf(stderr, "Mail: Too many ccs\n");
+ done(exitstat);
+ }
+ } else { /* Else, to */
+ if(top < NUMTOS)
+ tos[top++] = cp;
+ else {
+ fprintf(stderr, "Mail: Too many tos\n");
+ done(exitstat);
+ }
+ }
+ }
+ }
+ /* Create a mail temp file */
+ sprintf(tmpfil, "/tmp/%s", makename("mail", ".tmp"));
+ if((out = fopen(tmpfil, "w")) == NULL) {
+ perror(tmpfil);
+ done(exitstat);
+ }
+ signal(SIGINT, sig); /* Clean up if user <del>s out */
+ fprintf(out, "To: "); /* Create to list */
+ for(i = 0; i < top;) {
+ fprintf(out, "%s", tos[i]);
+ if(++i < top)
+ fprintf(out, ", ");
+ }
+ fprintf(out, "\n");
+ if(ccp > 0) {
+ fprintf(out, "Cc: "); /* Create cc list if needed */
+ for(i = 0; i < ccp;) {
+ fprintf(out, "%s", ccs[i]);
+ if(++i < ccp)
+ fprintf(out, ", ");
+ }
+ fprintf(out, "\n");
+ }
+ if(subject) /* Create subject if needed */
+ fprintf(out, "Subject: %s\n", subject);
+
+ fprintf(out, "\n");
+
+ if(body) { /* Use body if I have it, */
+ somebody++;
+ fprintf(out, "%s\n", body);
+ } else { /* Otherwise, get a body */
+ while((cnt = read(0, buf, sizeof buf)) > 0) {
+ somebody++;
+ if(!fwrite(buf, cnt, 1, out)) {
+ perror(tmpfil);
+ sig();
+ }
+ }
+ }
+
+ if(ferror(out)) { /* Check that all wrote well */
+ fprintf(stderr, "Error writing tmp file\n");
+ sig();
+ }
+ fclose(out);
+ if(!somebody) /* If NO body, then don't send */
+ sig(); /* To be compatible with BELL mail */
+ while((i = fork()) == -1) { /* Now, deliver the mail */
+ fprintf(stderr, "Waiting for a fork...\n");
+ sleep(2);
+ }
+ if(i == 0) { /* Call deliverer in child */
+ execl(mh_deliver, mh_deliver, tmpfil, 0);
+ perror(mh_deliver);
+ done(exitstat);
+ }
+ signal(SIGINT, SIG_IGN);
+ while((pid = wait(&status)) != -1 && pid != i) ;
+ if(status) { /* And save mail if delivery failed */
+ signal(SIGINT, SIG_DFL);
+ fprintf(stderr, "Letter saved in dead.letter\n");
+ execl("/bin/mv", "mv", tmpfil, "dead.letter", 0);
+ execl("/usr/bin/mv", "mv", tmpfil, "dead.letter", 0);
+ perror("/bin/mv");
+ done(exitstat);
+ }
+ exitstat = 0;
+ sig();
+}
+
+sig()
+{
+ unlink(tmpfil);
+ done(exitstat);
+}
--- /dev/null
+#define ALL ""
+
+#define MAXARGS 1000 /* Max messages to exec */
+
+#define EXISTS 01 /* Flag bits in msgstats-- Deleted is */
+#define DELETED 02 /* undefined currently */
+#define SELECTED 04 /* Message selected by an arg */
+
+#define READONLY 01 /* No write access to folder */
+#define DEFMOD 01 /* In-core profile has been modified */
+
+/*#define NEWS 1 /* Define for news inclusion */
+
+struct swit {
+ char *sw;
+ int minchars;
+};
+
+/*
+ * m_gmsg() returns this structure. It contains the per folder
+ * information which is obtained from reading the folder directory.
+ */
+
+struct msgs {
+ int hghmsg; /* Highest msg in directory */
+ int nummsg; /* Actual Number of msgs */
+ int lowmsg; /* Lowest msg number */
+ int curmsg; /* Number of current msg if any */
+ int lowsel; /* Lowest selected msg number */
+ int hghsel; /* Highest selected msg number */
+ int numsel; /* Number of msgs selected */
+ char *foldpath; /* Pathname of folder */
+ char selist, /* Folder has a "select" file */
+ msgflags, /* Folder status bits */
+ filler,
+ others; /* Folder has other file(s) */
+ char msgstats[1]; /* Stat bytes for each msg */
+};
+
+ /* m_getfld definitions and return values */
+
+#define NAMESZ 64 /* Limit on component name size */
+#define LENERR -2 /* Name too long error from getfld */
+#define FMTERR -3 /* Message Format error */
+
+ /* m_getfld return codes */
+#define FLD 0 /* Field returned */
+#define FLDPLUS 1 /* Field " with more to come */
+#define FLDEOF 2 /* Field " ending at eom */
+#define BODY 3 /* Body " with more to come */
+#define BODYEOF 4 /* Body " ending at eom */
+#define FILEEOF 5 /* Reached end of input file */
+
+/*
+ * These standard strings are defined in strings.a. They are the
+ * only system-dependent parameters in MH, and thus by redefining
+ * their values and reloading the various modules, MH will run
+ * on any system.
+ */
+
+extern char
+ *components, /* Name of user's component file (in mh dir) */
+ *current, /* Name of current msg file in a folder */
+ *defalt, /* Name of the std folder (inbox) */
+ *distcomps, /* Name of `dist' components file */
+ *draft, /* Name of the normal draft file */
+ *fileproc, /* Path of file program */
+ *foldprot, /* Default folder protection */
+ *hostname, /* Local net host name */
+ *installproc, /* Name of auto-install program path */
+ *listname, /* Default selection list folder name */
+ *lockdir, /* Dir for lock files (Same fs as mailboxes)*/
+ *lsproc, /* Path of the Harvard ls program */
+ *mailboxes, /* Incoming mail directory */
+ *mh_prof, /* Name of users profile file */
+ *mh_deliver, /* Name of deliverer for mh */
+ *mhnews, /* Name of MH news file */
+ *msgprot, /* Default message protection (s.a. 0664) */
+ *pfolder, /* Name of current folder profile entry */
+ *prproc, /* Path of the pr program */
+ *scanproc, /* Path of the scan program */
+ *showproc, /* Path of the type (l) program */
+ *sendproc, /* Path of the send message program */
+ *stdcomps, /* Std comp file if missing user's own */
+ *stddcomps, /* Std dist file if missing user's own */
+ *sysed, /* Path of the std (ned) editor */
+/* Just about every program uses this also */
+ *mypath; /* User's log-on path */
+
+#ifdef UNIXCOMP
+char *unixtomh; /* Path of program to convert UNIX style
+ mailboxes to MH style mailboxes */
+char *Mailprog; /* Path of program to do actual mailing */
+char *localname; /* Name of local machine on local net */
+#endif
+
+/*
+ * node structure used to hold a linked list of the users profile
+ * information taken from logpath/.mh_prof.
+ */
+
+struct node {
+ struct node *n_next;
+ char *n_name,
+ *n_field;
+} *m_defs;
+
+char def_flags;
+
+
+/*
+ * The first char in the mhnews file indicates whether the program
+ * calling m_news() should continue running or halt.
+ */
+
+#define NEWSHALT '!' /* Halt after showing the news */
+#define NEWSCONT ' ' /* Continue (ditto) */
+#define NEWSPAUSE '\001' /* Pause during news output... */
+
+
+/*
+ * Miscellaneous Defines to speed things up
+ */
+
+#define error(str) { fprintf(stderr, "%s\n", str); exit(-1); }
+
+/*
+ * Routine type declarations -- needed by version 7 compiler
+ */
+
+char **brkstring();
+char *m_maildir();
+char *m_find();
+char *m_name();
+char *concat();
+char *getcpy();
+char *trimcpy();
+char *add();
+char *invo_name();
+char **copyip();
+char *getcpy();
+char *m_getfolder();
+struct msgs *m_gmsg();
+char *copy();
+char **getans();
+char *cdate();
+char *makename();
+char *r1bindex();
+
+/*
+ * Routine type declarations -- SHOULD BE GLOBAL
+ */
+char *getenv();
+
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <dir.h>
+#include <strings.h>
+#define max(a,b) (a > b ? a : b)
+
+#define NEWSP "/usr/spool/newnews"
+#define MAXTOPICS 20 /* Enough for a while */
+
+char *mypath;
+int vecp, topicp;
+char *topics[MAXTOPICS+1];
+char *vec[MAXARGS];
+struct msgs *mp;
+int fdisplay, fcheck, fupdate, fsend, freview, fbody; /* flags */
+int frevback;
+int hit;
+
+struct nts {
+ char *t_name;
+ int t_num;
+} nts[MAXTOPICS+1], *check();
+
+struct swit switches[] = {
+ "add", -1, /* 0 */
+ "body", -1, /* 1 */
+ "check", 0, /* 2 */
+ "display", 0, /* 3 */
+ "review [#]", 0, /* 4 */
+ "send topic ...",0, /* 5 */
+ "topics", 0, /* 6 */
+ "update", 0, /* 7 */
+ "help", 4, /* 8 */
+ 0, 0,
+};
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int i;
+ register char *cp, **ap;
+ char *arguments[50], **argp;
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ vecp = 2;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ done(0);
+ /* unknown */
+ case -1:vec[vecp++] = --cp; continue;
+ case 0:
+ case 5: fsend++; continue;
+ case 1: fbody++;
+ vec[vecp++] = --cp; continue;
+ case 2: fcheck++; continue;
+ case 3: fdisplay++; continue;
+ case 4: freview++;
+ if(**argp >= '0' && **argp <= '9')
+ frevback = atoi(*argp++);
+ continue;
+ case 7: fupdate++; continue;
+
+ case 8:
+ help("news [topic ...] [switches] [switches for \"c\" or \"mail\" ]",
+ switches);
+ putchar('\n');
+ case 6:
+ printf("Topic items\n\n"); fflush(stdout);
+ getnts();
+ for(i = 0; nts[i].t_name[0]; i++)
+ printf("%-9s%3d\n", nts[i].t_name,
+ nts[i].t_num);
+ done(0);
+ }
+ else
+ if(vecp == 2)
+ topics[topicp++] = cp;
+ else
+ vec[vecp++] = cp;
+ }
+ getnts();
+ if(fsend) {
+ if(topicp == 0) {
+ fprintf(stderr, "Usage: news -send topic [mail switches]\n");
+ done(1);
+ }
+ for(i = 0; i < topicp; i++)
+ if(check(topics[i]))
+ send(topics[i]);
+ else
+ printf("Unknown topic: %s\n", topics[i]);
+ done(0);
+ }
+ if(!topicp)
+ for(i = 0; nts[i].t_name[0]; i++)
+ disp(nts[i].t_name, 0);
+ else
+ for(i = 0; i < topicp; i++)
+ if(check(topics[i]) == NULL)
+ printf("Topic: %s unknown.\n", topics[i]);
+ else
+ disp(topics[i], 1);
+ if(fcheck) {
+ if(hit)
+ printf(".\n");
+ } else if(!hit && !topicp && !fupdate && !fdisplay)
+ nonews();
+ m_update();
+ done(0);
+}
+
+
+getnts()
+{
+ struct direct *dir;
+ struct stat st;
+ register struct nts *t;
+ register DIR *d;
+ char tbuf[16 + 16];
+
+ t = nts;
+ if((d = opendir(NEWSP)) == 00) {
+ fprintf(stderr, "Can't open ");
+ perror(NEWSP);
+ done(1);
+ }
+ while (dir = readdir(d))
+ if(dir->d_ino && dir->d_name[0] != '.') {
+ t->t_name = (char *)malloc(dir->d_namlen + 1);
+ if (t->t_name == 0)
+ break;
+ strcpy(t->t_name, dir->d_name);
+ t++;
+ }
+ closedir(d);
+ for(t = nts; t->t_name[0]; t++) {
+ sprintf(tbuf, "%s/.%.14s", NEWSP, t->t_name);
+ if(stat(tbuf, &st) != -1)
+ t->t_num = st.st_size;
+ }
+}
+
+struct nts *
+check(topic)
+ char *topic;
+{
+ register struct nts *t;
+
+ for(t = nts; t->t_name[0]; t++)
+ if(strcmp(topic, t->t_name) == 0)
+ return t;
+ return 0;
+}
+
+
+disp(topic, argflg)
+ register char *topic;
+ int argflg;
+{
+ register struct nts *t;
+ register char *cp, *np;
+ register int msgnum;
+ int high;
+ char buf[128];
+
+ if((t = check(topic)) == 0)
+ fprintf(stderr, "HUH?\n");
+ if((cp = m_find(np = concat("news-", topic, 0))) == NULL)
+ cp = "0";
+ high = atoi(cp);
+ if(fcheck) {
+ if(t->t_num > high) {
+ if(!hit++)
+ printf("Unread news in");
+ if(hit > 1)
+ printf(",");
+ printf(" %s", topic);
+ }
+ return;
+ }
+ if(fupdate) {
+ if(t->t_num > high) {
+ m_replace(np, getcpy(m_name(t->t_num)));
+ printf("Skipping %d items in %s.\n",
+ t->t_num - high, topic);
+ }
+ return;
+ }
+ if(freview)
+ if(frevback)
+ msgnum = max(high - frevback, 0);
+ else
+ msgnum = 0;
+ else
+ msgnum = high;
+/*** msgnum = freview? frevback? high - frevback : 0 : high; */
+ if(msgnum >= t->t_num) {
+ if(argflg)
+ printf("%s: no new news.\n", topic);
+ return;
+ }
+ sprintf(buf, "%s/%s", NEWSP, topic);
+ if(chdir(buf) == -1) {
+ perror(buf);
+ return;
+ }
+ vec[1] = showproc;
+ for( ; msgnum < t->t_num;) {
+ cp = m_name(++msgnum);
+ if(hit) {
+ printf("\nPress <return> for %s:%s...", topic, cp);
+ fflush(stdout);
+ read(0, buf, sizeof buf);
+ } else
+ printf("News item %s:%s\n", topic, cp);
+ if(msgnum > high) {
+ m_replace(np, getcpy(cp));
+ m_update();
+ }
+ vec[vecp] = cp;
+ putchar('\n');
+ call(vec + 1);
+ hit = 1;
+ }
+}
+
+
+call(vector)
+ char **vector;
+{
+ register int pid, child;
+ char path[32];
+ int status;
+
+ fflush(stdout);
+ while((child = fork()) == -1) {
+ printf("No forks...\n"); fflush(stdout);
+ sleep(2);
+ }
+ if(child == 0) {
+ execv(vector[0], vector);
+ perror(vector[0]);
+ done(1);
+ }
+ while((pid = wait(&status)) != -1 && pid != child) ;
+ if(pid == -1 || status) {
+ fprintf(stderr, "Abnormal termination from %s\n", vector[0]);
+ done(1);
+ }
+}
+
+char *mailproc;
+
+send(topic)
+ register char *topic;
+{
+ vec[0] = mailproc;
+ vec[1] = concat("news.", topic, 0);
+ if(!fbody)
+ printf("Enter text for %s\n", topic);
+ call(vec);
+ free(vec[1]);
+}
+
+
+char *nons[] = {
+ "No new news",
+ "No news to peruse",
+ "Only old news",
+ "News shortage",
+ "News reporters on strike",
+ "Report your own news",
+ "News presses broken"
+};
+#define NONS (sizeof nons/ sizeof nons[0])
+
+nonews()
+{
+#include <sys/timeb.h>
+ struct timeb tb;
+
+ ftime(&tb);
+ printf("%s.\n", nons[tb.millitm % NONS]);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <strings.h>
+
+int glbtype;
+struct msgs *mp;
+
+struct swit switches[] = {
+ "help", 4, /* 0 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *maildir, *vec[20], *folder, *nfolder;
+ register int msgnum;
+ register char *cp;
+ int next;
+ int vecp;
+ char **ap;
+ char *arguments[50], **argp;
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ next = glbtype;
+ folder = 0; vecp = 2;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:vec[vecp++] = --cp; continue;
+ case 0: if(next > 0) /* -help */
+ help("next [+folder] [switches] [switches for \"type\" ]", switches);
+ else
+ help("prev [+folder] [switches] [switches for \"type\" ]", switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else {
+ fprintf(stderr, "Bad arg: %s\n", cp);
+ fprintf(stderr, "Usage: %s [+folder] [-l.switches]\n",
+ next>0? "next" : "prev");
+ goto leave;
+ }
+ }
+ vec[vecp] = 0;
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!m_convert(next > 0 ? "next" : "prev"))
+ goto leave;
+ m_replace(pfolder, folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ vec[1] = m_name(mp->lowsel);
+ printf("(Message %s:%s)\n", folder, vec[1]);
+ fflush(stdout);
+ vec[0] = "mh-type";
+ m_update();
+ execv(showproc, vec);
+ perror("Can't exec type");
+ leave:
+ m_update();
+ done(0);
+}
--- /dev/null
+int glbtype = 1;
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <strings.h>
+
+#define NFOLD 20 /* Allow 20 folder specs */
+
+char *anoyes[]; /* Std no/yes gans array */
+
+/*
+ * pick [-src folder] [msgs] search [-scan] [-show] [file-op]
+ *
+ * search = -from \
+ * -to \
+ * -cc \
+ * -subject \ pattern
+ * -sub /
+ * -date /
+ * -search /
+ * --component /
+ *
+ * file-op = -file [-preserve] [-link] +folder ...
+ * -keep [-stay] [+folder ...]
+ */
+
+extern int errno;
+int nvecp, foldp;
+char **nvec;
+struct msgs *mp;
+char grep[256], *grepp, *folder, maildir[128];
+int showf, scanf, filef, keepf, linkf, noteold, prsrvf, stayf;
+int grep_lowsel = 5000,
+ grep_hghsel = 0;
+char *delprog;
+
+char _sobuf[BUFSIZ];
+
+struct st_fold {
+ char *f_name;
+ int f_reused;
+ struct msgs *f_mp;
+} folders[NFOLD], *fptr;
+
+struct swit switches[] = {
+ "cc pattern", 0, /* 0 */
+ "date pattern", 0, /* 1 */
+ "from pattern", 0, /* 2 */
+ "search pattern", 0, /* 3 */
+ "subject pattern", 0, /* 4 */
+ "to pattern", 0, /* 5 */
+ "-othercomponent pattern", 15, /* 6 */
+ "all", -3, /* 7 */
+ "file +folder ...", 0, /* 8 */
+ "nofile", 0, /* 9 */
+ "keep [+folder ...]", 0, /* 10 */
+ "nokeep", 0, /* 11 */
+ "link", 0, /* 12 */
+ "nolink", 0, /* 13 */
+ "preserve", 0, /* 14 */
+ "nopreserve", 0, /* 15 */
+ "scan", 0, /* 16 */
+ "noscan", 0, /* 17 */
+ "show", 0, /* 18 */
+ "noshow", 0, /* 19 */
+ "src +folder", 0, /* 20 */
+ "stay", 0, /* 21 */
+ "nostay", 0, /* 22 */
+ "help", 4, /* 23 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *msgs[128], buf[128];
+ register int msgnum;
+ register char *cp;
+ int msgp, i;
+ char **ap;
+ char *arguments[50], **argp, **arrp;
+
+ setbuf(stdout, _sobuf);
+
+#ifdef NEWS
+ m_news();
+#endif
+
+ nvecp = 1;
+ msgp = 0;
+ grepp = grep;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-') {
+ if(*++cp == '-') { /* --component */
+ toomany: if(grepp != grep) {
+ fprintf(stderr, "Only one search string.\n");
+ goto leave;
+ }
+ grepp = copy("^", grepp);
+ grepp = copy(++cp, grepp);
+ grepp = copy(":.*", grepp);
+ goto pattern;
+ }
+ switch(i = smatch(cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "pick: -%s unknown\n", cp);
+ goto leave;
+ /* -component */
+ case 0: case 1: case 2: case 4: case 5:
+ if(grepp != grep)
+ goto toomany;
+ grepp = copy("^", grepp);
+ arrp = brkstring(switches[i].sw, " ", 0);
+ grepp = copy(*arrp, grepp);
+ grepp = copy(":.*", grepp);
+ case 3: /* -search */
+ pattern: grepp = copy(*argp++, grepp);
+ continue;
+ case 6: fprintf(stderr, "pick: can't get here\n");
+ goto leave;
+ /* -all */
+ case 7: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 8: filef = 1; continue; /* -file */
+ case 9: filef = 0; continue; /* -nofile */
+ case 10:keepf = 1; continue; /* -keep */
+ case 11:keepf = 0; continue; /* -nokeep */
+ case 12:linkf = 1; continue; /* -link */
+ case 13:linkf = 0; continue; /* -nolink */
+ case 14:prsrvf = 1; continue; /* -preserve */
+ case 15:prsrvf = 0; continue; /* -nopreserve */
+ case 16:scanf = 1; continue; /* -scan */
+ case 17:scanf = 0; continue; /* -noscan */
+ case 18:showf = 1; continue; /* -show */
+ case 19:showf = 0; continue; /* -noshow */
+ case 21:stayf = 1; continue; /* -stay */
+ case 22:stayf = 0; continue; /* -nostay */
+ case 20:if(folder) { /* -src */
+ fprintf(stderr, "Only one src folder.\n");
+ goto leave;
+ }
+ if(!(folder = *argp++) || *folder == '-') {
+ fprintf(stderr, "pick: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ if(*folder == '+')
+ folder++;
+ continue;
+ /* -help */
+ case 23:help("pick [msgs] [switches]", switches);
+ goto leave;
+ }
+ } else if(*cp == '+') {
+ if(foldp < NFOLD)
+ folders[foldp++].f_name = cp + 1;
+ else {
+ fprintf(stderr, "Only %d folders allowed.\n", NFOLD);
+ goto leave;
+ }
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(grepp == grep) {
+ fprintf(stderr, "No search pattern specified.\n");
+ goto leave;
+ }
+ if(filef && keepf) {
+ fprintf(stderr, "-file and -keep don't go together.\n");
+ goto leave;
+ }
+ if(!scanf && !showf && !filef)
+ keepf++; /* The default is -keep */
+ if(keepf) {
+ prsrvf++; /* -keep forces -preserve */
+ linkf++; /* and -link */
+ }
+ if(!folder)
+ folder = m_getfolder(); /* use cur folder if no -src */
+ copy(m_maildir(folder), maildir);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!foldp) { /* if no +folder given... */
+ if(filef) { /* -file requires one */
+ fprintf(stderr, "-file requires at least one folder arg.\n");
+ goto leave;
+ }
+ if(keepf) { /* use default selection-list name */
+ copy(listname, copy("/", copy(folder, buf)));
+ folders[foldp++].f_name = getcpy(buf);
+ noteold++; /* tell user if existing folder */
+ }
+ } else if(keepf) { /* make folders sub-folders */
+ for(msgnum = 0; msgnum < foldp; msgnum++)
+ if(*(cp = folders[msgnum].f_name) != '.' &&
+ *cp != '/') {
+ copy(cp, copy("/", copy(folder, buf)));
+ folders[msgnum].f_name = getcpy(buf);
+ }
+ noteold++;
+ }
+ if(!msgp)
+ msgs[msgp++] = "first-last";
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "pick: Peanut butter 'n jelly\n");/* never get here */
+ goto leave;
+ }
+ if(!compile(grep)) {
+ fprintf(stderr, "Pattern Error.\n");
+ goto leave;
+ }
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ grepfn(msgnum);
+ if(mp->numsel == 0) {
+ fprintf(stderr, "No messages match specification.\n");
+ goto leave;
+ }
+ mp->lowsel = grep_lowsel;
+ mp->hghsel = grep_hghsel;
+ /* all the exec's */
+ if((((delprog = m_find("delete-prog")) != NULL) &&
+ ((filef || keepf) && !linkf)) ||
+ scanf || showf) {
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "pick: more than %d messages for %s exec\n",
+ MAXARGS-2,
+ scanf ? "scan" : showf ? "show" : delprog);
+ goto leave;
+ }
+ nvec = (char **) malloc(MAXARGS * sizeof nvec[0]);
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ nvec[nvecp++] = getcpy(m_name(msgnum));
+ nvec[nvecp] = 0;
+ }
+ if(keepf || filef)
+ if(opnfolds())
+ goto leave;
+ if(!noteold || foldp > 1)
+ m_replace(pfolder, folder);
+ if(scanf)
+ scanfn(showf|filef|keepf);
+ else {
+ printf("%d hits.\n", mp->numsel); fflush(stdout);
+ }
+ if(showf)
+ showfn(filef|keepf);
+ if(!(filef|keepf))
+ goto leave;
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ if(process(cp = getcpy(m_name(msgnum))))
+ goto leave;
+ else
+ free (cp);
+ if(!linkf)
+ remove();
+ if(noteold) {
+ if(!stayf && foldp == 1) {
+ m_replace(pfolder, cp = folders[0].f_name);
+ printf("[+%s now current]\n", cp); fflush(stdout);
+ }
+ for(fptr = folders; fptr < &folders[foldp]; fptr++)
+ if(!fptr->f_reused) {
+ chdir(m_maildir(fptr->f_name));
+ m_setcur(fptr->f_mp->curmsg);
+ }
+ }
+ leave:
+ m_update();
+}
+
+
+grepfn(msg)
+{
+ if(execute(m_name(msg))) { /* a match */
+ if(msg < grep_lowsel)
+ grep_lowsel = msg;
+ if(msg > grep_hghsel)
+ grep_hghsel = msg;
+ } else {
+ mp->msgstats[msg] &= ~SELECTED; /* clear SELECTED bit */
+ mp->numsel--;
+ }
+}
+
+
+opnfolds()
+{
+ register int i;
+ register char *cp, *ap;
+ char nmaildir[128];
+ struct stat stbuf;
+
+ for(i = 0; i < foldp; i++) {
+ copy(m_maildir(cp = folders[i].f_name), nmaildir);
+ if(stat(nmaildir, &stbuf) < 0) {
+ if(!noteold) {
+ ap = concat("Create folder \"",
+ nmaildir, "\"? ", 0);
+ if(!gans(ap, anoyes))
+ return(1);
+ }
+ if(!makedir(nmaildir)) {
+ fprintf(stderr, "Can't create folder.\n");
+ return(1);
+ }
+ } else if(noteold) {
+ printf("[Folder %s being re-used.]\n", cp);
+ fflush(stdout);
+ folders[i].f_reused++; /* Don't change cur in old fold */
+ }
+ if(chdir(nmaildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(nmaildir);
+ return(1);
+ }
+ if(!(folders[i].f_mp = m_gmsg(folders[i].f_name))) {
+ fprintf(stderr, "Can't read folder %s\n", folders[i].f_name);
+ return(1);
+ }
+ folders[i].f_mp->curmsg = 0;
+ }
+ chdir(maildir); /* return to src folder */
+ return(0);
+}
+
+
+scanfn(forkf)
+{
+ register int pid, i;
+
+ nvec[0] = "mh-scan";
+ if(forkf && (pid = fork())) {
+ if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ done(1);
+ }
+ while(wait((int *)NULL) != pid) ;
+ } else {
+ m_update();
+ fflush(stdout);
+ execv(scanproc, nvec);
+ perror(scanproc);
+ done(1);
+ }
+}
+
+
+showfn(forkf)
+{
+ register int pid, i;
+ int sint, sqit;
+
+ nvec[0] = "c:mh-type";
+ if(forkf) {
+ sint = (int) signal(SIGINT, SIG_IGN);
+ sqit = (int) signal(SIGQUIT, SIG_IGN);
+ }
+ if(forkf && (pid = fork())) {
+ if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ done(1);
+ }
+ while(wait((int *)NULL) != pid) ;
+ signal(SIGINT, sint);
+ signal(SIGQUIT, sqit);
+ } else {
+ m_update();
+ fflush(stdout);
+ execv(showproc, nvec);
+ perror(showproc);
+ done(1);
+ }
+}
+
+
+remove()
+{
+ register int i, j;
+ register char *cp;
+
+ if(delprog != NULL) {
+ nvec[0] = delprog;
+ m_update();
+ fflush(stdout);
+ execv(nvec[0], nvec);
+ fprintf(stderr, "Can't exec deletion-prog--");
+ perror(delprog);
+ } else {
+ for(i= mp->lowsel; i<= mp->hghsel; i++)
+ if(mp->msgstats[i]&SELECTED)
+ if(unlink(cp = m_name(i)) == -1) {
+ fprintf(stderr, "Can't unlink %s:",folder);
+ perror(cp);
+ }
+ }
+}
+
+process(msg)
+char *msg;
+{
+ char newmsg[256], buf[BUFSIZ];
+ register int i;
+ register char *nmsg;
+ register struct st_fold *fp;
+ struct stat stbuf, stbf1;
+ int n, o, linkerr;
+
+ for(fp = folders; fp < &folders[foldp]; fp++) {
+ if(prsrvf)
+ nmsg = msg;
+ else
+ nmsg = m_name(fp->f_mp->hghmsg++ + 1);
+ copy(nmsg, copy("/", copy(m_maildir(fp->f_name), newmsg)));
+ if(link(msg, newmsg) < 0) {
+ linkerr = errno;
+ if(linkerr == EEXIST ||
+ (linkerr == EXDEV && stat(newmsg, &stbuf) != -1)) {
+ if(linkerr != EEXIST || stat(msg, &stbf1) < 0 ||
+ stat(newmsg, &stbuf) < 0 ||
+ stbf1.st_ino != stbuf.st_ino) {
+ fprintf(stderr, "Message %s:%s already exists.\n",
+ fp->f_name, msg);
+ return(1);
+ }
+ continue;
+ }
+ if(linkerr == EXDEV) {
+ if((o = open(msg, 0)) == -1) {
+ fprintf(stderr, "Can't open %s:%s.\n",
+ folder, msg);
+ return(1);
+ }
+ fstat(o, &stbuf);
+ if((n = creat(newmsg, stbuf.st_mode&0777)) == -1) {
+ fprintf(stderr, "Can't create %s:%s.\n",
+ fp->f_name, nmsg);
+ close(o);
+ return(1);
+ }
+ do
+ if((i=read(o, buf, sizeof buf)) < 0 ||
+ write(n, buf, i) == -1) {
+ fprintf(stderr, "Copy error on %s:%s to %s:%s!\n",
+ folder, msg, fp->f_name, nmsg);
+ close(o); close(n);
+ return(1);
+ }
+ while(i == sizeof buf);
+ close(n); close(o);
+ } else {
+ fprintf(stderr, "Error on link %s:%s to %s:",
+ folder, msg, fp->f_name);
+ perror(nmsg);
+ return(1);
+ }
+ }
+ if((i = atoi(nmsg)) < fp->f_mp->curmsg || !fp->f_mp->curmsg)
+ fp->f_mp->curmsg = i;
+cont: ;
+ }
+ return(0);
+}
--- /dev/null
+int glbtype = -1;
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <errno.h>
+#include <sgtty.h>
+#include <signal.h>
+#include <strings.h>
+
+char *mypath;
+extern int errno;
+int wtuser; /* waiting for user input */
+int sigint; /* sensed an interrupt */
+FILE *in, *out;
+struct sgttyb sg;
+struct swit switches[] = {
+ "erase chr", 2, /* 0 */ /* "2" can become "0",since no ed */
+ "kill chr", 0, /* 1 */
+ "help", 4, /* 2 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char tmpfil[32], *drft, name[NAMESZ], field[BUFSIZ];
+ int exitstat;
+ char skill, serase;
+ char *killp, *erasep;
+ register int i, state;
+ register char *cp;
+ char **ap;
+ char *arguments[50], **argp;
+ int sig();
+ int status, pid, wpid, intr;
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+ tmpfil[0] = 0;
+ skill = 0; exitstat = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++)
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto badleave;
+ /* unknown */
+ case -1:fprintf(stderr, "prompter: -%s unknown\n", cp);
+ goto badleave;
+ case 0: if(!(erasep = *argp++)) { /* -erase */
+ missing: fprintf(stderr, "prompter: Missing argument for %s switch\n", argp[-2]);
+ goto badleave;
+ }
+ continue;
+ case 1: if(!(killp= *argp++)) /* -kill */
+ goto missing;
+ continue;
+ /* -help */
+ case 2: help("prompter [switches]",
+ switches);
+ goto badleave;
+ }
+ else
+ drft = cp;
+ if(!drft) {
+ fprintf(stderr, "prompter: missing skeleton\n");
+ goto badleave;
+ }
+ if((in = fopen(drft, "r")) == NULL) {
+ fprintf(stderr, "Can't open %s\n", drft);
+ goto badleave;
+ }
+ copy(makename("prmt", ".tmp"), copy("/tmp/", tmpfil));
+ if((out = fopen(tmpfil, "w")) == NULL) {
+ fprintf(stderr, "Can't create %s\n", tmpfil);
+ goto badleave;
+ }
+ chmod(tmpfil, 0700);
+ signal(SIGINT, sig);
+ gtty(0, &sg);
+ skill = sg.sg_kill;
+ serase = sg.sg_erase;
+ sg.sg_kill = killp ? chrcnv(killp) : skill;
+ sg.sg_erase = erasep ? chrcnv(erasep) : serase;
+/*** stty(0, &sg); ***/
+ ioctl(0, TIOCSETN, &sg);
+ if(killp || erasep) {
+ printf("Erase Char="); chrdisp(sg.sg_erase);
+ printf("; Kill Line="); chrdisp(sg.sg_kill);
+ printf(".\n"); fflush(stdout);
+ }
+ state = FLD;
+ for(;;) switch(state = m_getfld(state,name,field,sizeof field,in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(field[0] != '\n' || field[1] != 0) {
+ printf("%s:%s", name, field);
+ fprintf(out, "%s:%s", name, field);
+ while(state == FLDPLUS) {
+ state=m_getfld(state,name,field,sizeof field,in);
+ printf("%s", field);
+ printf(out, "%s", field);
+ }
+ } else {
+ printf("%s: ", name);
+ fflush(stdout);
+ i = getln(field);
+ if(i == -1)
+ goto badleave;
+ if(i == 0 && (field[0] == '\n' || !field[0]))
+ continue;
+ fprintf(out, "%s:", name);
+ do {
+ if(field[0] != ' ' && field[0] != '\t')
+ putc(' ', out);
+ fputs(field, out);
+ } while(i == 1 && (i = getln(field)) >= 0);
+ if(i == -1)
+ goto badleave;
+ }
+ field[0] = 0;
+ if(state == FLDEOF)
+ goto body;
+ continue;
+
+ case BODY:
+ case BODYEOF:
+ case FILEEOF:
+ body: fputs("--------\n", out);
+ printf("--------\n");
+ if(field[0]) {
+ do {
+ fputs(field, out);
+ if(!sigint)
+ printf("%s", field);
+ } while(state == BODY &&
+ (state=m_getfld(state,name,field,sizeof field,in)));
+ printf("\n--------Enter additional text\n\n");
+ }
+ fflush(stdout);
+ for(;;) {
+ getln(field);
+ if(field[0] == 0)
+ break;
+ fputs(field, out);
+ }
+ goto finish;
+
+ default:
+ fprintf(stderr, "Bad format file!\n");
+ goto badleave;
+ }
+
+
+finish:
+ printf("--------\n"); fflush(stdout);
+ fclose(out);
+ out = fopen(tmpfil, "r");
+ fclose(in);
+ in = fopen(drft, "w"); /* Truncate prior to copy back */
+ do
+ if((i = read(fileno(out), field, sizeof field)) > 0)
+ write(fileno(in), field, i);
+ while(i == sizeof field);
+ goto leave;
+
+badleave:
+ exitstat = 1;
+
+leave:
+ if(in)
+ fclose(in);
+ if(out)
+ fclose(out);
+ if(tmpfil[0])
+ unlink(tmpfil);
+ m_update();
+ if(killp || erasep) {
+ sg.sg_kill = skill;
+ sg.sg_erase = serase;
+/*** stty(0, &sg); ***/
+ ioctl(0, TIOCSETN, &sg);
+ }
+ done(exitstat);
+}
+
+
+getln(buf)
+char *buf;
+{
+ register char *cp;
+ register int c;
+ int stat;
+
+ cp = buf;
+ *cp = 0;
+ wtuser = 1;
+ for(;;) {
+ c = getchar();
+/*** fprintf(stderr,"getchar()=\\%o,errno=%d,EINTR=%d\n",c,errno,EINTR);/***/
+ if(c == EOF)
+ if(errno == EINTR) {
+ stat = -1;
+ goto leave;
+ } else {
+ stat = 0;
+ goto leave;
+ }
+ if(c == '\n') {
+ if(cp[-1] == '\\') {
+ cp[-1] = c;
+ stat = 1;
+ goto leave;
+ }
+ *cp++ = c;
+ *cp = 0;
+ stat = 0;
+ goto leave;
+ }
+ if(cp < buf + 500)
+ *cp++ = c;
+ *cp = 0;
+ }
+ leave: wtuser = 0;
+ return(stat);
+ }
+
+
+sig()
+{
+ signal(SIGINT, sig);
+ if(!wtuser)
+ sigint = 1;
+ return;
+}
+
+
+chrcnv(str)
+char *str;
+{
+ register char *cp;
+ register int c;
+
+ cp = str;
+ if((c = *cp++) != '\\')
+ return(c);
+ c = 0;
+ while(*cp && *cp != '\n') {
+ c *= 8;
+ c += *cp++ - '0';
+ }
+ return c;
+}
+
+
+chrdisp(chr)
+{
+ register int c;
+
+ c = chr;
+ if(c < ' ')
+ printf("<CTRL-%c>", c + '@');
+ else
+ printf("%c", c);
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)refile.c 1.1 5/26/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <strings.h>
+
+#define NFOLD 20 /* Allow 20 folder specs */
+
+/* file [-src folder] [msgs] +folder [+folder ...]
+ *
+ * moves messages from src folder (or current) to other one(s).
+ *
+ * all = 1-999 for a message sequence
+ * -preserve says preserve msg numbers
+ * -link says don't delete old msg
+ */
+
+char *anoyes[]; /* Std no/yes gans array */
+
+int vecp, foldp, prsrvf;
+char **vec, maildir[128], *folder, *file;
+struct msgs *mp;
+
+struct st_fold {
+ char *f_name;
+ struct msgs *f_mp;
+} folders[NFOLD];
+
+char *files[NFOLD + 1]; /* Vec of files to process--starts at 1! */
+int filec = 1;
+char *bellfile = "/usr/bin/file";
+extern int errno;
+char *rindex();
+
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "link", 0, /* 1 */
+ "nolink", 0, /* 2 */
+ "preserve", 0, /* 3 */
+ "nopreserve", 0, /* 4 */
+ "src +folder", 0, /* 5 */
+ "file", 0, /* 6 */
+ "help", 4, /* 7 */
+ 0, 0
+};
+main(argc, argv)
+char *argv[];
+{
+ register int i, msgnum;
+ register char *cp;
+ char *msgs[128];
+ int msgp, linkf;
+ int ismhfile = 0;
+ char **ap;
+ char *arguments[50], **argp;
+ char *pwd(), *pwds;
+
+ /*
+ * Rand has committed the sin of picking a name that already is
+ * used (file). We fix this here since we can tell the difference
+ * between the two (mh file has -'s and +'s always, bell file never
+ * has them.)
+ */
+ for (i=1; i<argc; i++)
+ if (argv[i][0] == '-' || argv[i][0]=='+')
+ ismhfile++;
+ if (!ismhfile) {
+ execv(bellfile, argv);
+ fprintf(stderr, "Cannot find %s\n", bellfile);
+ exit(1);
+ }
+
+#ifdef NEWS
+ m_news();
+#endif
+ folder = 0; msgp = 0; linkf = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-') {
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "file: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: linkf = 1; continue; /* -link */
+ case 2: linkf = 0; continue; /* -nolink */
+ case 3: prsrvf = 1; continue; /* -preserve */
+ case 4: prsrvf = 0; continue; /* -nopreserve */
+ case 5: if(folder) { /* -src */
+ fprintf(stderr, "Only one src folder.\n");
+ goto leave;
+ }
+ if(!(folder = *argp++) || *folder == '-') {
+missing: fprintf(stderr, "file: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ if(*folder == '+')
+ folder++;
+ continue;
+ /* -help */
+ case 6:
+ if(filec >= NFOLD) {
+ fprintf(stderr, "Too many src files.\n");
+ goto leave;
+ }
+ if(!(files[filec++] = *argp) || **argp++ == '-')
+ goto missing;
+ continue;
+
+ case 7: help("file [msgs] [switches] +folder ...",
+ switches);
+ goto leave;
+ }
+ }
+ if(*cp == '+') {
+ if(foldp < NFOLD)
+ folders[foldp++].f_name = cp + 1;
+ else {
+ fprintf(stderr, "Only %d folders allowed.\n", NFOLD);
+ goto leave;
+ }
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!foldp) {
+ fprintf(stderr, "No folder specified.\n");
+fprintf(stderr, "Usage: file [-src folder] [msg ...] [switches] +folder [+folder]\n");
+ goto leave;
+ }
+ if(filec > 1) {
+ if(msgp) {
+ fprintf(stderr, "File: Can't mix files and messages.\n");
+ goto leave;
+ }
+ for(i = 1; i < filec; i++)
+ if(*files[i] != '/') {
+ if(!pwds)
+ pwds = pwd();
+ files[i] = concat(pwds, "/", files[i], 0);
+ }
+ if(opnfolds())
+ goto leave;
+ for(i = 1; i < filec; i++) {
+ if(process(files[i]))
+ goto leave;
+ }
+ if(!linkf) {
+ if((cp = m_find("delete-prog")) != NULL) {
+ files[0] = cp;
+ execvp(cp, files);
+ fprintf(stderr, "Can't exec deletion-prog--");
+ perror(cp);
+ } else for(i = 1; i < filec; i++) {
+ if(unlink(files[i]) == -1) {
+ fprintf(stderr, "Can't unlink ");
+ perror(files[i]);
+ }
+ }
+ }
+ goto leave;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ copy(m_maildir(folder), maildir);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder %s!?\n",folder);
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert((cp = msgs[msgnum])))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "file: ham 'n cheese\n"); /* never get here */
+ goto leave;
+ }
+ m_replace(pfolder, folder);
+ if(mp->hghsel != mp->curmsg && ((mp->numsel != mp->nummsg) || linkf))
+ m_setcur(mp->hghsel);
+ if(opnfolds())
+ goto leave;
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum] & SELECTED)
+ if(process(cp = getcpy(m_name(msgnum))))
+ goto leave;
+ else
+ cndfree(cp);
+ if(!linkf) {
+ if((cp = m_find("delete-prog")) != NULL) {
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "file: more than %d messages for deletion-prog\n",MAXARGS-2);
+ printf("[messages not unlinked]\n");
+ goto leave;
+ }
+ vecp = 1;
+ vec = (char **) calloc(MAXARGS + 2, sizeof *vec);
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ vec[vecp++] = getcpy(m_name(msgnum));
+ vec[vecp] = 0;
+ m_update();
+ fflush(stdout);
+ vec[0] = cp;
+ execv(vec[0], vec);
+ fprintf(stderr, "Can't exec deletion-prog--");
+ perror(cp);
+ } else {
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum] & SELECTED)
+ if(unlink(cp = m_name(msgnum))== -1) {
+ fprintf(stderr, "Can't unlink %s:",folder);
+ perror(cp);
+ }
+ }
+ }
+leave:
+ m_update();
+ done(0);
+}
+
+
+opnfolds()
+{
+ register int i;
+ register char *cp;
+ char nmaildir[128];
+
+ for(i = 0; i < foldp; i++) {
+ copy(m_maildir(folders[i].f_name), nmaildir);
+ if(access(nmaildir, 5) < 0) {
+ cp = concat("Create folder \"", nmaildir, "\"? ", 0);
+ if(!gans(cp, anoyes))
+ goto bad;
+ free(cp);
+ if(!makedir(nmaildir)) {
+ fprintf(stderr, "Can't create folder.\n");
+ goto bad;
+ }
+ }
+ if(chdir(nmaildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(nmaildir);
+ goto bad;
+ }
+ if(!(folders[i].f_mp = m_gmsg())) {
+ fprintf(stderr, "Can't read folder %s\n", folders[i].f_name);
+ goto bad;
+ }
+ }
+ chdir(maildir); /* return to src folder */
+ return(0);
+bad:
+ return(1);
+}
+
+
+process(msg)
+char *msg;
+{
+ char newmsg[256], buf[BUFSIZ];
+ register int i;
+ register char *nmsg;
+ register struct st_fold *fp;
+ struct stat stbuf, stbf1;
+ int n, o, linkerr;
+
+ for(fp = folders; fp < &folders[foldp]; fp++) {
+ if(prsrvf)
+ nmsg = msg;
+ else
+ nmsg = m_name(fp->f_mp->hghmsg++ + 1);
+ copy(nmsg, copy("/", copy(m_maildir(fp->f_name), newmsg)));
+ if(link(msg, newmsg) < 0) {
+ linkerr = errno;
+ if(linkerr == EEXIST ||
+ (linkerr == EXDEV && stat(newmsg, &stbuf) != -1)) {
+ if(linkerr != EEXIST || stat(msg, &stbf1) < 0 ||
+ stat(newmsg, &stbuf) < 0 ||
+ stbf1.st_ino != stbuf.st_ino) {
+ fprintf(stderr, "Message %s:%s already exists.\n",
+ fp->f_name, msg);
+ return(1);
+ }
+ continue;
+ }
+ if(linkerr == EXDEV) {
+ if((o = open(msg, 0)) == -1) {
+ fprintf(stderr, "Can't open %s:%s.\n",
+ folder, msg);
+ return(1);
+ }
+ fstat(o, &stbuf);
+ if((n = creat(newmsg, stbuf.st_mode&0777)) == -1) {
+ fprintf(stderr, "Can't create %s:%s.\n",
+ fp->f_name, nmsg);
+ close(o);
+ return(1);
+ }
+ do
+ if((i=read(o, buf, sizeof buf)) < 0 ||
+ write(n, buf, i) == -1) {
+ fprintf(stderr, "Copy error on %s:%s to %s:%s!\n",
+ folder, msg, fp->f_name, nmsg);
+ close(o); close(n);
+ return(1);
+ }
+ while(i == sizeof buf);
+ close(n); close(o);
+ } else {
+ fprintf(stderr, "Error on link %s:%s to %s:",
+ folder, msg, fp->f_name);
+ perror(nmsg);
+ return(1);
+ }
+ }
+cont: ;
+ }
+ return(0);
+}
+
+
+char *
+pwd()
+{
+ register FILE *pp;
+ static char curpath[128];
+ register int i;
+ FILE *popen();
+
+ if((pp = popen("pwd", "r")) == NULL ||
+ fgets(curpath, sizeof curpath, pp) == NULL ||
+ pclose(pp) != 0) {
+ fprintf(stderr, "Can't find current directory!\n");
+ done(1);
+ }
+ *rindex(curpath, '\n') = 0; /* Zap the lf */
+ return curpath;
+}
--- /dev/null
+#include "mh.h"
+
+char *ltrim(cp)
+char *cp;
+{
+ /* Return pointer to 1st non-blank char in string;
+ * If ptr ==> 0 or ptr ==> '\n'0, return NUL;
+ */
+
+ register char *cp1;
+
+ cp1 = cp;
+ while((*cp1 == ' ') || (*cp1 == '\t')) cp1++;
+ if((*cp1 == 0) || (*cp1 == '\n' && cp1[1] == 0))
+ cp1 = 0;
+ return(cp1);
+}
+
+char *rtrim(cp)
+char *cp;
+{
+ /* trim newline and blanks from the right */
+
+ register char *cp1;
+
+ cp1 = cp+strlen(cp)-1;
+ if(*cp1 == '\n') *cp1 = 0;
+ while(*--cp1 == ' ') ;
+ *++cp1 = 0;
+ return(cp);
+}
+
+char *niceadd(this, that)
+char *this, *that;
+{
+ register char *from, *to;
+
+ if(!(from = ltrim(this))) /* nothing to add */
+ return(that);
+
+ if(to = that)
+ to = add(",\n ", rtrim(to)); /* enuf blanks for "cc: " */
+ return(add(from, to));
+}
+
+#define ADDRLEN (needadr ? addrlen : 0)
+
+char *fix(field, address)
+char *field, *address;
+{
+ /* Appends address to each needy addressee in "field".
+ * Returns pointer to copy of new string. (HUH?)
+ * "field" should never be 0
+ */
+
+ register int len;
+ register char *newp;
+ int addrlen;
+ int needadr;
+ int fieldlen;
+ char *cp;
+
+ addrlen = strlen(address);
+ len = 0;
+ newp = "";
+
+ for(cp = field; ;cp += fieldlen + 1) {
+ needadr = needsaddr(&cp, &fieldlen); /* cp may be changed */
+ if(fieldlen == 0) {
+ cndfree(field);
+ newp = add("\n", newp);
+ return(newp);
+ }
+ if((len + fieldlen + ADDRLEN) > 70) {
+ newp = add(",\n ", newp);
+ len = 4;
+ } else if (*newp) {
+ newp = add(", ", newp);
+ len += 2;
+ }
+ *(cp + fieldlen) = 0;
+ newp = add(cp, newp);
+ if(needadr)
+ newp = add(address, newp);
+ len += fieldlen + ADDRLEN;
+ }
+}
+
+anychar(fchars, field)
+char *fchars, *field;
+{
+ /* Returns 1 if any fancy char appears in "field"
+ * Returns 0 if either "field" is nul or contains no fancy chars
+ */
+
+ register char *fp;
+
+ if(!field)
+ return(0);
+ for(fp = fchars; *fp; fp++)
+ if(r_any(*fp, field))
+ return(1);
+ return(0);
+}
+
+
+r_any(chr,stg)
+char chr, *stg;
+{
+ register char c, *s;
+
+ c = chr;
+ for (s = stg; (*s) && (*s != ',') && (*s != '\n');)
+ if (*s++ == c) return (1);
+ return (0);
+}
+
+char *addr(text)
+char *text;
+{
+ static char buf[128];
+ register char *cp, *bufp;
+ int textseen, blankseen;
+ char *copyaddr();
+
+ textseen = blankseen = 0;
+ bufp = buf;
+ if(!text)
+ return(0);
+ for(cp = text; (*cp == ' ' || *cp == '\t'); cp++);
+ for(;;cp++) {
+ switch(*cp) {
+ default:
+ textseen++;
+ break;
+ case ' ': case '\t':
+ blankseen++;
+ break;
+ case 'a':
+ if(!blankseen || !textseen || !ssequal("at ",cp)){
+ textseen++;
+ break;
+ }
+ bufp = copy(" at ", buf);
+ copyaddr(cp+3, bufp);
+ return(buf);
+ case '@':
+ if(!textseen)
+ return(0);
+ bufp = copy(" @ ", buf);
+ copyaddr(cp+1, bufp);
+ return(buf);
+ case ',': case '\n': case 0:
+ return(0);
+ }
+ }
+}
+
+#define ND1 (*fp) && (*fp != ' ') && (*fp != '\t')
+#define ND2 (*fp != '<') && (*fp != '(') && (*fp != '>') && (*fp != ')')
+#define ND3 (*fp != '\n') && (*fp!= ',') && (*fp != ':')
+#define NOTDELIM ND1 && ND2 && ND3
+
+char *copyaddr(from, to)
+char *from, *to;
+{
+ /* Copies left-trimmed "from" to "to".
+ * Copy terminates on any delimiter.
+ * Returns pointer to NUL terminator in destination string
+ */
+
+ register char *fp, *tp;
+
+ for(fp = from; (*fp == ' ') && (*fp == '\t'); fp++) ;
+ for( ; NOTDELIM; *tp++ = *fp++);
+ *tp = 0;
+ return(tp);
+}
+#define NOTRELEVANT (*cp == ' ' || *cp == '\t' || *cp == '\n'|| *cp == ',')
+
+needsaddr(field, fieldlen)
+char **field;
+int *fieldlen;
+{
+ /* Returns 1 if this field needs an address
+ * Returns 0 if field contains any funny chars or has
+ * an address of the form "xxxx at " or "xxxx[<b>]@"
+ * "field": on input -- addr of pointer to start of field
+ * on output -- val of ptr moved to 1st meaty char
+ * "fieldlen" returns the length of the new field
+ * (it terminates on ',' or '\n' or 0)
+ */
+
+ register char *cp;
+ int textseen, blankseen;
+ int retval;
+ /* find 1st relevant char in field */
+ for(cp = *field; NOTRELEVANT ; cp++);
+
+ *field = cp; /* return it to caller */
+ if(anychar("(<:", cp)) {
+ retval = 0;
+ goto leave;
+ }
+ for(;;cp++) {
+ switch(*cp) {
+ default:
+ textseen++;
+ break;
+ case ' ': case '\t':
+ blankseen++;
+ break;
+ case 'a':
+ if(!blankseen || !textseen || !ssequal("at ",cp)){
+ textseen++;
+ break;
+ }
+ case '@':
+ retval = 0;
+ goto leave;
+ case ',': case '\n': case 0:
+ retval = 1;
+ goto leave;
+
+ }
+ }
+ leave:
+ for(; (*cp) && (*cp != ',') && (*cp != '\n'); cp++) ;
+ *fieldlen = cp- *field;
+ return(retval);
+}
+
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+
+/*#define NEWS 1*/
+
+#define NOUSE 0
+
+/* #define TEST 1 */
+
+char *anyl[] = {
+ "no", 0,
+ "yes", 0,
+ "list", 0,
+ 0
+};
+
+char *aleqs[] = {
+ "list", 0, /* 0 */
+ "edit [<editor>]", 0, /* 1 */
+ "quit [delete]", 0, /* 2 */
+ "send [verbose]", 0, /* 3 */
+ 0
+};
+
+int *vec[MAXARGS], anot;
+int ccme = 1;
+struct msgs *mp;
+char *ed;
+int inplace; /* preserve links in anno */
+
+struct swit switches[] = {
+ "annotate", 0, /* 0 */
+ "noannotate", 0, /* 1 */
+ "ccme", -1, /* 2 */
+ "noccme", -1, /* 3 */
+ "editor editor", 0, /* 4 */
+ "inplace", 0, /* 5 */
+ "noinplace", 0, /* 6 */
+ "help", 4, /* 7 */
+ 0, 0
+};
+
+char *ltrim();
+char *rtrim();
+char *niceadd();
+char *fix();
+char *addr();
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *nfolder, *msg, *maildir;
+ register char *cp, **ap;
+ register int cur;
+ char *arguments[50], **argp;
+
+#ifdef NEWS
+ m_news();
+#endif
+ msg = 0; anot = 0; folder = 0;
+
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "repl: -%s unknown\n", cp);
+ goto leave;
+ case 0: anot = 1; continue; /* -annotate */
+ case 1: anot = 0; continue; /* -noannotate */
+ case 2: ccme = 1; continue; /* -ccme */
+ case 3: ccme = 0; continue; /* -noccme */
+ case 4: if(!(ed = *argp++)) { /* -editor */
+ fprintf(stderr, "repl: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 5: inplace = 1; continue; /* -inplace */
+ case 6: inplace = 0; continue; /* -noinplace */
+ /* -help */
+ case 7: help("repl [+folder] [msg] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else if(msg) {
+ fprintf(stderr, "Only one message per reply.\n");
+ goto leave;
+ } else
+ msg = cp;
+ }
+ if(!msg)
+ msg = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!m_convert(msg))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "repl: pepperoni pizza\n");/* never get here */
+ goto leave;
+ }
+ if(mp->numsel > 1) {
+ fprintf(stderr, "Only one message at a time.\n");
+ goto leave;
+ }
+ m_replace(pfolder, folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ repl(getcpy(m_name(mp->lowsel)));
+ leave:
+ m_update();
+ done(0);
+}
+
+
+repl(msg)
+{
+ register char *cp;
+ register int i,j;
+ register FILE *in;
+ char name[NAMESZ], field[BUFSIZ];
+ char *drft, *msgid, *replto, *from, *cc, *sub, *date, *to;
+ int state, out, status, intr;
+ int pid, wpid;
+ char **argp, *address;
+
+ if((in = fopen(msg, "r")) == NULL) {
+ fprintf(stderr, "Can't open "); perror(msg);
+ return;
+ }
+ drft = m_maildir(draft);
+ if((out = open(drft, 0)) >= 0) {
+ cp = concat("\"", drft, "\" exists; delete? ", 0);
+ while((i = gans(cp, anyl)) == 2)
+ showfile(drft);
+ if(!i)
+ return;
+ free(cp);
+ close(out);
+ }
+ if((out = creat(drft, m_gmprot())) < 0) {
+ fprintf(stderr, "Can't create \"%s\".\n", drft);
+ return;
+ }
+
+ state = FLD;
+ replto = msgid = to = from = cc = sub = date = 0;
+
+ for(;;) {
+
+ switch(state = m_getfld(state, name, field, sizeof field, in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(uleq(name, "from"))
+ from = niceadd(field, from);
+ if(uleq(name, "cc"))
+ cc = niceadd(field, cc);
+ if(uleq(name, "subject"))
+ sub = niceadd(field, sub);
+ if(uleq(name, "date"))
+ date = niceadd(field, date);
+ if(uleq(name, "to"))
+ to = niceadd(field, to);
+ if(uleq(name, "message-id"))
+ msgid = niceadd(field, msgid);
+ if(uleq(name, "reply-to"))
+ replto = niceadd(field, replto);
+ /* if(uleq(name, "sender"))
+ sender = niceadd(field, sender); */
+ if(state == FLDEOF)
+ goto done;
+ break;
+
+ case BODY:
+ case BODYEOF:
+ case FILEEOF:
+ goto done;
+
+ default:
+ fprintf(stderr, "getfld returned %d\n", state);
+ return;
+ }
+
+ }
+
+done:
+
+ /* if(!(address = addr(sender)))
+ if(!(address = addr(from)))
+ address = addr(replto);
+ */
+ /* if(!(address = addr(replto)))
+ address = addr(from);
+ */
+ address = replto ? addr(replto) : addr(from);
+ if(!ccme)
+ to = 0;
+ if(!(from || replto)) {
+ fprintf(stderr, "No one to reply to!!!\n");
+ return;
+ }
+ fclose(in);
+ type(out, "To: "); /* To: */
+ type(out, replto ? replto : from);
+ if(cc || to ) /* cc: */
+ type(out, "cc: ");
+ if(cc) {
+ if(address)
+ cc = fix(cc, address);
+ if(to)
+ rtrim(cc);
+ type(out, cc);
+ }
+ if(to) {
+ if(cc)
+ type(out, ",\n ");
+ if(address)
+ to = fix(to, address);
+ type(out, to);
+ }
+ if(sub) { /* Subject: Re: */
+ type(out, "Subject: ");
+ if(*sub == ' ') sub++;
+ if((sub[0] != 'R' && sub[0] != 'r') ||
+ (sub[1] != 'E' && sub[1] != 'e') ||
+ sub[2] != ':')
+ type(out, "Re: ");
+ type(out, sub);
+ } /* In-reply-to: */
+ if(date) {
+ type(out, "In-reply-to: Your message of ");
+ date[strlen(date)-1] = '.';
+ if(*date == ' ') date++;
+ type(out, date);
+ type(out, "\n");
+ if(msgid) {
+ type(out, " ");
+ if(*msgid == ' ') msgid++;
+ type(out, msgid);
+ }
+ }
+ type(out, "----------\n");
+ close(out);
+ if(m_edit(&ed, drft, NOUSE, msg) < 0)
+ return;
+#ifdef TEST
+ fprintf(stderr, "!! Test Version of SEND Being Run !!\n");
+ fprintf(stderr, " Send verbose !\n\n");
+#endif
+
+ for(;;) {
+ if(!(argp = getans("\nWhat now? ", aleqs))) {
+ unlink("@");
+ return;
+ }
+ switch(smatch(*argp, aleqs)) {
+ case 0: showfile(drft); /* list */
+ break;
+ case 1: if(*++argp) /* edit */
+ ed = *argp;
+ if(m_edit(&ed, drft, NOUSE, msg) == -1)
+ return;
+ break;
+ case 2: if(*++argp && *argp[0] == 'd') /* quit */
+ if(unlink(drft) == -1) {
+ fprintf(stderr, "Can't unlink %s ", drft);
+ perror("");
+ }
+ return;
+ case 3: if(*++argp) cp = *argp; else cp = ""; /* send */
+
+ if(!mp->msgflags&READONLY) { /* annotate first */
+ if(anot > 0) {
+ while((pid = fork()) == -1) sleep(5);
+ if(pid) {
+ while(wpid=wait((int *)NULL)!= -1 && wpid!= pid);
+ if(stat(drft, field) == -1)
+ annotate(msg, "Replied", "", inplace);
+ return;
+ }
+ }
+ }
+ if(!m_send(cp, drft))
+ return;
+ default:fprintf(stderr, "repl: illegal option\n"); /*##*/
+ break;
+ }
+ }
+}
--- /dev/null
+/*
+ * Read up the messages in the named files and rehabilitate them into
+ * UNIX+ style messages on standard output.
+ *
+ * +Unix is a trademark of Bell Laboratories.
+ * The optional -d flag tests the arpa net to unix date format
+ * transformer by reading lines from standard input, modifying them
+ * to unix format, and outputing them on standard output.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+char *index(), *rindex(), *reform();
+long emitl();
+int errs;
+int dateerrs;
+int dflag;
+int lastblank;
+
+main(argc, argv)
+ char **argv;
+{
+ register char *cp, *fname;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: rescue name ...\n");
+ _exit(1);
+ }
+ lastblank = 1;
+ while (--argc) {
+ fname = *++argv;
+ if (strcmp(fname, "-d") == 0) {
+ dflag++;
+ dtest();
+ exit(0);
+ }
+ cp = rindex(fname, '/');
+ if (cp == 0)
+ cp = fname;
+ else
+ cp++;
+ if (strcmp(cp, "cur") == 0)
+ continue;
+ if (strcmp(cp, "select") == 0)
+ continue;
+ if (*cp == ',')
+ continue;
+ while (*cp)
+ if (!isdigit(*cp++)) {
+ fprintf(stderr, "%s: not mh message file\n",
+ fname);
+ goto blog;
+ }
+ fix(fname);
+blog: ;
+ }
+ if (dateerrs)
+ fprintf(stderr, "%d bad date(s) replaced by current date\n",
+ dateerrs);
+ exit(errs);
+}
+
+/*
+ * Fix the named file by putting together a reasonable header
+ * and outputing the stuff onto standard output.
+ */
+fix(name)
+ char name[];
+{
+ register FILE *in;
+ char linebuf[BUFSIZ], from[BUFSIZ], date[BUFSIZ];
+ register int inhead;
+ register char *cp;
+
+ if ((in = fopen(name, "r")) == NULL) {
+ perror(name);
+ errs++;
+ return;
+ }
+ from[0] = date[0] = 0;
+ for (; from[0] == 0 || date[0] == 0;) {
+ if (fgets(linebuf, BUFSIZ, in) == NULL)
+ goto noheader;
+ if (strlen(linebuf) == 1)
+ goto noheader;
+ if (linebuf[0] == '-')
+ goto noheader;
+ if (isfield(linebuf, "from")) {
+ cp = index(linebuf, ':');
+ if (cp == 0)
+ goto noheader;
+ cp++;
+ while (*cp && isspace(*cp))
+ cp++;
+ strcpy(from, cp);
+ continue;
+ }
+ if (isfield(linebuf, "date")) {
+ cp = index(linebuf, ':');
+ if (cp == 0)
+ goto noheader;
+ cp++;
+ while (*cp && isspace(*cp))
+ cp++;
+ strcpy(date, cp);
+ continue;
+ }
+ }
+ /*
+ * Ready to print the from line
+ */
+ zap(from);
+ zap(date);
+ if (!lastblank)
+ printf("\n");
+ printf("From %s %s\n", from, reform(date));
+ lastblank = 0;
+ rewind(in);
+ inhead = 1;
+ while (fgets(linebuf, BUFSIZ, in) != NULL) {
+ if (inhead &&
+ (isfield(linebuf, "from") || isfield(linebuf, "date")))
+ continue;
+ if (strlen(linebuf) == 1)
+ inhead = 0;
+ fputs(linebuf, stdout);
+ lastblank = 0;
+ if (linebuf[0] == '\n' && linebuf[1] == 0)
+ lastblank = 1;
+ }
+ fclose(in);
+ return;
+noheader:
+ fprintf(stderr, "%s: Missing, bad, or incomplete header\n", name);
+ errs++;
+ fclose(in);
+}
+
+/*
+ * Determine if the passed line is a header of the given field name
+ */
+isfield(buf, field)
+ char buf[];
+ char field[];
+{
+ register char *cp, *cp2;
+
+ cp = buf;
+ cp2 = field;
+ while (lower(*cp++) == lower(*cp2++))
+ ;
+ if (*--cp == ':' && *--cp2 == 0)
+ return(1);
+ return(0);
+}
+
+/*
+ * Lower case the given character
+ */
+lower(c)
+ register int c;
+{
+
+ if (isupper(c))
+ return(tolower(c));
+ return(c);
+}
+
+/*
+ * Remove trailing newline from str, if present.
+ */
+zap(str)
+ char str[];
+{
+ register char *cp;
+
+ cp = index(str, '\n');
+ if (cp != 0)
+ *cp = 0;
+}
+
+/*
+ * Reformat the given Arpa net style date
+ * back into a unix ctime(3) date.
+ * Unfortunately, there appears to be NO standard arpa net
+ * date format.
+ */
+
+char *month = "janfebmaraprmayjunjulaugsepoctnovdec";
+
+char *
+reform(date)
+ char date[];
+{
+ static char retdate[35];
+ char dbuf[BUFSIZ];
+ register char *cp, *cp2, *mptr;
+ struct tm d;
+ long x, then;
+
+ cp = date;
+ cp2 = dbuf;
+ while (*cp) {
+ if (*cp == '(') {
+ while (*cp != ')' && *cp)
+ cp++;
+ if (*cp)
+ cp++;
+ goto more;
+ }
+ if (*cp == '\t') {
+ *cp2++ = ' ';
+ cp++;
+ continue;
+ }
+ if (*cp == '-') {
+ *cp2++ = ' ';
+ cp++;
+ continue;
+ }
+ if (isupper(*cp)) {
+ *cp2++ = tolower(*cp++);
+ continue;
+ }
+ *cp2++ = *cp++;
+more: ;
+ }
+ *cp2 = 0;
+ /*
+ * Okie dokie. Now pick off the date part and store
+ * it away. Only possible formats here are:
+ * mm/dd/yy
+ * and
+ * dd monthname year
+ */
+ if (index(dbuf, '/')) {
+ d.tm_mon = atoi(dbuf) - 1;
+ cp = index(dbuf, '/') + 1;
+ d.tm_mday = atoi(cp);
+ if ((cp = index(cp, '/')) == 0)
+ goto baddate;
+ cp++;
+ d.tm_year = atoi(cp);
+ if (d.tm_year > 1900)
+ d.tm_year -= 1900;
+ cp = index(cp, ' ');
+ if (cp == 0)
+ goto baddate;
+ }
+ else {
+ d.tm_mday = atoi(dbuf);
+ cp = index(dbuf, ' ');
+ if (cp == 0)
+ goto baddate;
+ while (*cp && isspace(*cp))
+ cp++;
+ if (*cp == 0)
+ goto baddate;
+ for (mptr = month; *mptr; mptr += 3)
+ if (strncmp(mptr, cp, 3) == 0)
+ break;
+ if (*mptr == 0)
+ goto baddate;
+ d.tm_mon = (mptr - month)/3;
+ cp = index(cp, ' ');
+ if (cp == 0)
+ goto baddate;
+ while (*cp && isspace(*cp))
+ cp++;
+ if (*cp == 0)
+ goto baddate;
+ d.tm_year = atoi(cp);
+ if (d.tm_year > 1900)
+ d.tm_year -= 1900;
+ cp = index(cp, ' ');
+ if (cp == 0)
+ goto baddate;
+ }
+ /*
+ * Got the month part, now fix up the time.
+ * Possibilities are:
+ * hh:mm
+ * hh:mm [am|pm]
+ * hhmm edt
+ * hh:mm:ss edt
+ * Basically, we lose by ignoring time zone.
+ */
+ for (;;) {
+ while (*cp && isspace(*cp))
+ cp++;
+ if (*cp == 0)
+ goto baddate;
+ if (strncmp(cp, "at ", 3) != 0)
+ break;
+ cp += 3;
+ }
+ d.tm_sec = 0;
+ if (index(cp, ':')) {
+ d.tm_hour = atoi(cp);
+ cp = index(cp, ':') + 1;
+ d.tm_min = atoi(cp);
+ if (index(cp, ':')) {
+ cp = index(cp, ':') + 1;
+ d.tm_sec = atoi(cp);
+ }
+ while (*cp && !isspace(*cp))
+ cp++;
+ while (*cp && isspace(*cp))
+ cp++;
+ if (strncmp(cp, "pm", 2) == 0 && d.tm_hour < 12)
+ d.tm_hour += 12;
+ }
+ else {
+ x = atoi(cp);
+ d.tm_hour = x / 100;
+ d.tm_min = x % 100;
+ }
+ then = emitl(&d);
+ strcpy(retdate, ctime(&then));
+ zap(retdate);
+ return(retdate);
+
+baddate:
+ dateerrs++;
+ if (dflag)
+ strcpy(retdate, "************************");
+ else {
+ then = time(0);
+ strcpy(retdate, ctime(&then));
+ zap(retdate);
+ }
+ return(retdate);
+}
+
+/*
+ * Test the arpa net to UNIX date modifier.
+ * Reads lines from standard input, converting them
+ * to unix format, and displaying both on stdout.
+ */
+dtest()
+{
+ char buf[BUFSIZ];
+ register char *cp;
+
+ while (gets(buf)) {
+ cp = reform(buf);
+ printf("\"%s\" \"%s\"\n", buf, cp);
+ }
+}
+
+/*
+ * Routine to convert a localtime(3) format date back into
+ * a system format date.
+ *
+ * Hats off to Bob Kridle for the insight that the way to do
+ * this is by binary search of the system date space.
+ */
+
+struct tm *localtime();
+
+long
+emitl(dp)
+ struct tm *dp;
+{
+ long conv;
+ register int i, bit;
+ struct tm dcopy;
+
+ dcopy = *dp;
+ dp = &dcopy;
+ conv = 0;
+ for (i = 31; i >= 0; i--) {
+ bit = 1 << i;
+ conv |= bit;
+ if (dcmp(localtime(&conv), dp) > 0)
+ conv &= ~bit;
+ }
+ return(conv);
+}
+
+/*
+ * Compare two localtime dates, return result.
+ */
+
+#define DECIDE(a) \
+ if (dp->a > dp2->a) \
+ return(1); \
+ if (dp->a < dp2->a) \
+ return(-1)
+
+dcmp(dp, dp2)
+ register struct tm *dp, *dp2;
+{
+
+ DECIDE(tm_year);
+ DECIDE(tm_mon);
+ DECIDE(tm_mday);
+ DECIDE(tm_hour);
+ DECIDE(tm_min);
+ DECIDE(tm_sec);
+ return(0);
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)rmf.c 1.4 7/7/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <dir.h>
+#include "strings.h"
+
+char *anoyes[]; /* Std no/yes gans array */
+
+int subf;
+
+struct msgs *mp;
+
+struct swit switches[] = {
+ "help", 4, /* 0 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp, **ap;
+ char *folder, buf[128];
+ int i, def_fold;
+ char *arguments[50], **argp;
+
+#ifdef NEWS
+ m_news();
+#endif
+ folder = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "rmf: -%s unknown\n", cp);
+ goto leave;
+ /* -help */
+ case 0: help("rmf [+folder] [switches]", switches);
+ goto leave;
+ }
+ if(*cp == '+')
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ else {
+ fprintf(stderr, "Usage: rmf [+folder]\n");
+ goto leave;
+ }
+ }
+ if(!folder) {
+ folder = m_getfolder();
+ def_fold++;
+ }
+ subf = !((!index(folder, '/')) | (*folder == '/') | (*folder == '.'));
+ if(def_fold && !subf) {
+ cp = concat("Remove folder \"", folder, "\" ?? ", 0);
+ if(!gans(cp, anoyes))
+ goto leave;
+ free(cp);
+ }
+ if(rmfold(folder))
+ goto leave;
+ if(subf) { /* make parent "current" */
+ cp = copy(folder, buf);
+ while(cp > buf && *cp != '/') --cp;
+ if(cp > buf) {
+ *cp = 0;
+ if(strcmp(m_find(pfolder), buf) != 0) {
+ printf("[+%s now current]\n", buf);
+ m_replace(pfolder, buf);
+ }
+ }
+ }
+ leave:
+ m_update();
+ done(0);
+}
+
+rmfold(fold)
+char *fold;
+{
+ register char *maildir;
+ struct direct *ent;
+ int i, leftover, cd;
+ register char *cp, *sp;
+ char nambuf[10];
+ register DIR *dirp;
+
+ leftover = 0;
+ if(!subf && strcmp(m_find(pfolder), fold) == 0) /* make default "current"*/
+ if(strcmp(m_find(pfolder), defalt) != 0) {
+ printf("[+%s now current]\n", defalt);
+ fflush(stdout); /*??*/
+ m_replace(pfolder, defalt);
+ }
+ maildir = m_maildir(fold);
+ if((cd = chdir(maildir)) < 0)
+ goto funnyfold;
+ if(access(".", 2) == -1) {
+ funnyfold: if(!m_delete(concat("cur-", fold, 0)))
+ printf("[Folder %s de-referenced]\n", fold);
+ else
+ fprintf(stderr, "You have no profile entry for the %s folder %s\n",
+ cd < 0 ? "unreadable" : "read-only", fold);
+ return(1);
+ }
+ dirp = opendir(".");
+ ent = readdir(dirp); /* move pointer past "." */
+ ent = readdir(dirp); /* move pointer past ".." */
+ while(ent = readdir(dirp)) {
+ if (ent->d_ino==0) continue;
+ switch (ent->d_name[0]) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '#':
+ case ',':
+ if(unlink(ent->d_name) == -1) {
+ fprintf(stderr, "Can't unlink %s:%s\n", fold,ent->d_name);
+ leftover++;
+ }
+ break;
+ default:
+ if (strcmp(ent->d_name, "cur") == 0 ||
+ strcmp(ent->d_name, "@") == 0) {
+ if(unlink(ent->d_name) == -1) {
+ fprintf(stderr, "Can't unlink %s:%s\n", fold,ent->d_name);
+ leftover++;
+ }
+ } else {
+ fprintf(stderr, "File \"%s/%s\" not deleted!\n", fold, ent->d_name);
+ leftover++;
+ }
+ }
+ }
+ closedir(dirp);
+ chdir(".."); /* Move out of dir to be deleted */
+ if(!leftover && removedir(maildir))
+ return(0);
+ else
+ fprintf(stderr, "Folder %s not removed!\n", fold);
+ return(1);
+}
+
+
+removedir(dir)
+{
+ register int pid, wpid;
+ int status;
+
+ if((pid = fork()) == 0) {
+ m_update();
+ fflush(stdout);
+ execl("/bin/rmdir", "rmdir", dir, 0);
+ execl("/usr/bin/rmdir", "rmdir", dir, 0);
+ fprintf(stderr, "Can't exec rmdir!!?\n");
+ return(0);
+ }
+ if(pid == -1) {
+ fprintf(stderr, "Can't fork\n");
+ return(0);
+ }
+ while((wpid = wait(&status)) != pid && wpid != -1) ;
+ if(status) {
+ fprintf(stderr, "Bad exit status (%o) from rmdir.\n", status);
+ /* return(0); */
+ }
+ return(1);
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)rmm.c 4.1 2/23/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <strings.h>
+
+int vecp;
+char **vec;
+struct msgs *mp;
+
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "help", 4, /* 1 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *nfolder, *maildir, *msgs[100], buf[32];
+ register int msgnum;
+ register char *cp, *sp;
+ int msgp;
+ char **ap;
+ char *arguments[50], **argp;
+
+#ifdef NEWS
+ m_news();
+#endif
+ folder = 0; msgp = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "rmm: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ /* -help */
+ case 1: help("rmm [+folder] [msgs] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "rmm: lasagne 'n sausage\n"); /* never get here */
+ goto leave;
+ }
+ m_replace(pfolder, folder);
+ if((cp = m_find("delete-prog")) == NULL) {
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum] & SELECTED) {
+ sp = getcpy(m_name(msgnum));
+ cp = copy(sp, buf);
+ cp[1] = 0;
+ do
+ *cp = cp[-1];
+ while(--cp >= buf && *cp != '/');
+#ifdef UCB
+ *++cp = '#';
+#else
+ *++cp = ',';
+#endif
+ unlink(buf);
+ if(link(sp, buf) == -1 || unlink(sp) == -1)
+ fprintf(stderr, "Can't rename %s to %s.\n", sp, buf);
+ }
+ } else {
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "rmm: more than %d messages for deletion-prog\n",MAXARGS-2);
+ goto leave;
+ }
+ vec = (char **) calloc(MAXARGS +2, sizeof *vec);
+ vecp = 1;
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ vec[vecp++] = getcpy(m_name(msgnum));
+ vec[vecp] = 0;
+ vec[0] = cp;
+ m_update();
+ fflush(stdout);
+ execv(vec[0], vec);
+ fprintf(stderr, "Can't exec deletion prog--");
+ perror(cp);
+ }
+leave:
+ m_update();
+ done(0);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <strings.h>
+
+int hdrflag = 1;
+int reverse = 0;
+struct msgs *mp;
+
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "ff", 0, /* 1 */
+ "noff", 0, /* 2 */
+ "header", 0, /* 3 */
+ "noheader", 0, /* 4 */
+ "reverse", 0, /* 5 */
+ "help", 4, /* 6 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100];
+ register int msgnum;
+ register char *cp, **ap;
+ int msgp, ff;
+ FILE *in;
+ long now;
+ char *arguments[50], **argp;
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ ff = 0; msgp = 0; folder = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "scan: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: ff = 1; continue; /* -ff */
+ case 2: ff = 0; continue; /* -noff */
+ case 3: hdrflag = 0; continue; /* -header */
+ case 4: hdrflag = 1; continue; /* -noheader */
+ case 5: reverse = 1; continue; /* -reverse */
+ case 6: help("scan [+folder] [msgs] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!msgp)
+ msgs[msgp++] = "first-last";
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "scan: matzo balls.\n"); /* never get here */
+ goto leave;
+ }
+ m_replace(pfolder,folder);
+ for( msgnum = (reverse ? mp->hghsel : mp->lowsel);
+ (reverse ? msgnum >= mp->lowsel : msgnum <= mp->hghsel);
+ (reverse ? msgnum-- : msgnum++)) {
+ if(mp->msgstats[msgnum]&SELECTED) {
+ if((in = fopen(cp = m_name(msgnum), "r")) == NULL)
+ fprintf(stderr, "--Can't open %s\n", cp);
+ else {
+ if(!hdrflag++) {
+ time(&now);
+ cp = cdate(&now);
+ cp[9] = ' '; cp[15] = 0;
+printf("\
+ Folder %-32s%s\n\n\
+ # Date From Subject [<<Body]\n\n", folder, cp);
+ }
+ scan(in, msgnum, 0, msgnum == mp->curmsg);
+ fclose(in);
+ if(stdout->_cnt < 80)
+ fflush(stdout);
+ }
+ }
+ }
+ if(ff)
+ putchar('\014');
+leave:
+ m_update();
+ done(0);
+}
+
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+#define _FROM 1
+#define _NOTFROM 0
+
+
+#define FROM 13 /* Start of From field */
+#define SFROM 16 /* Length of " " */
+#define DATE 5 /* Start of Date field */
+#define SDATE 7 /* Length */
+#define SUBJ 31 /* Start of Subject field */
+#define SSUBJ (79-SUBJ) /* Size of Subject field */
+#define BSUBJ 20 /* Room needed in Sub field to */
+ /* add stuff from the body */
+#define MSGN 0 /* Start of msg name field */
+#define SMSGN 3 /* Length */
+#define FLGS 3 /* Start of flags field */
+#define SFLGS 2 /* Width of flag field */
+
+FILE *scnout;
+char scanl[82];
+int local;
+int hostseen;
+char *frmtok();
+
+scan(inb, innum, outnum, curflg)
+struct iobuf *inb;
+int outnum;
+{
+
+ char buf[BUFSIZ], name[NAMESZ], tobuf[32], frombuf[32];
+ register char *cp, **tok1;
+ int state, subsz, first, compnum;
+ static char *myname;
+
+ local = 0; hostseen = 0;
+ if(!myname)
+ myname = getenv("USER");
+ tobuf[0] = 0; frombuf[0] = 0;
+ first = 0;
+ state = FLD;
+ compnum = 1;
+
+ for(;;) {
+
+ state = m_getfld(state, name, buf, sizeof buf, inb);
+ if(!first++ && state != FILEEOF) { /*##*/
+ if(outnum) {
+ if((scnout = fopen(cp = m_name(outnum), "w")) == NULL) {
+ fprintf(stderr, "Error creating msg ");
+ perror(cp); done(-1);
+ }
+ chmod(cp, m_gmprot());
+ }
+ sfill(scanl, sizeof scanl);
+ scanl[sizeof scanl - 1] = 0;
+ subsz = 0;
+ tobuf[0] = 0;
+ }
+
+ switch(state) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ compnum++;
+ if(uleq(name, "from"))
+ frombuf[
+ cpyfrm(buf,frombuf,sizeof frombuf,_FROM)]=0;
+ else if(uleq(name, "date"))
+ cpydat(buf, scanl+DATE, SDATE);
+ else if(uleq(name, "subject") && scanl[SUBJ] == ' ')
+ subsz = cpy(buf, scanl+SUBJ, SSUBJ);
+ else if(uleq(name, "to") && !tobuf[0])
+ tobuf[
+ cpyfrm(buf,tobuf,sizeof tobuf-1,_NOTFROM)]=0;
+ else if(uleq(name, "replied"))
+ cpy("-", scanl+FLGS+1, 1);
+ put(name, buf, scnout);
+ while(state == FLDPLUS) {
+ state=m_getfld(state,name,buf,sizeof buf,inb);
+ if(scnout)
+ fputs(buf, scnout);
+ }
+ if(state == FLDEOF)
+ goto putscan;
+ continue;
+
+ case BODY:
+ case BODYEOF:
+ compnum = -1;
+ if(buf[0] && subsz < SSUBJ - BSUBJ) {
+ scanl[SUBJ+subsz+1] = '<';
+ scanl[SUBJ+subsz+2] = '<';
+ cpy(buf, scanl+SUBJ+subsz+3, SSUBJ-subsz-3);
+ subsz = SSUBJ;
+ }
+ if(buf[0] && scnout) {
+ putc('\n', scnout);
+ fputs(buf, scnout);
+ if(ferror(scnout)) {
+ fprintf(stderr, "Write error on ");
+ perror(m_name(outnum));done(-1);
+ }
+ }
+ body: while(state == BODY) {
+ state=m_getfld(state,name,buf,sizeof buf,inb);
+ if(scnout)
+ fputs(buf, scnout);
+ }
+ if(state == BODYEOF) {
+ putscan: cpymsgn(m_name(innum), scanl+MSGN, SMSGN);
+ tok1= brkstring(getcpy(frombuf), " ", "\n");
+ if(!frombuf[0] || uleq(frombuf, myname) ||
+ (local && uleq(*tok1, myname))) {
+ cpy("To:", scanl+FROM, 3);
+ cpy(tobuf, scanl+FROM+3, SFROM-3);
+ } else
+ cpy(frombuf, scanl+FROM, SFROM);
+ if(curflg)
+ cpy("+", scanl+FLGS, SFLGS);
+ trim(scanl);
+ fputs(scanl, stdout);
+
+ if(scnout) {
+ fflush(scnout);
+ if(ferror(scnout)) {
+ perror("Write error on ");
+ perror(m_name(outnum));
+ done(-1);
+ }
+ fclose(scnout);
+ scnout = NULL;
+ }
+ return(1);
+ }
+ break;
+
+ case LENERR:
+ case FMTERR:
+ fprintf(stderr, "??Message Format Error ");
+ fprintf(stderr, "(Message %d) ", outnum ? outnum :innum);/*##*/
+ if(compnum < 0) fprintf(stderr, "in the Body.\n");
+ else fprintf(stderr, "in Component #%d.\n", compnum);
+ fprintf(stderr, "-----------------------------------------");
+ fprintf(stderr, "-------------------------------------\n");
+ goto badret;
+ default:
+ fprintf(stderr, "Getfld returned %d\n", state);
+
+
+ badret: if(outnum) {
+ fputs("\n\nBAD MSG:\n", scnout);
+ if(compnum < 0)
+ fputs(buf, scnout);
+ else
+ fputs(name, scnout);
+ /*** ungetc(inb); ***/
+ state = BODY;
+ goto body;
+
+ }
+ if(scnout)
+ fflush(scnout);
+ return(-1);
+ case FILEEOF:
+ return(0);
+
+ }
+
+ }
+}
+
+
+trim(str)
+char *str;
+{
+ register char *cp;
+
+ cp = str;
+ while(*cp) cp++;
+ while(*--cp == ' ') ;
+ cp++;
+ *cp++ = '\n';
+ *cp++ = 0;
+}
+
+sfill(str, cnt)
+char *str;
+{
+ register char *cp;
+ register int i;
+
+ cp = str; i = cnt;
+ do
+ *cp++ = ' ';
+ while(--i);
+}
+
+
+put(name, buf, ip)
+register FILE *ip;
+{
+ if(ip) {
+ fputs(name, ip);
+ putc(':', ip);
+ fputs(buf, ip);
+ if(ferror(ip)) { perror("Write error");done(-1);}
+ }
+}
+
+
+cpy(from, to, cnt)
+register char *from, *to;
+register int cnt;
+{
+ register int c;
+ char *sfrom;
+
+ sfrom = from;
+ while(*from == ' ' || *from == '\t' || *from == '\n')
+ from++;
+ while(cnt--)
+ if(c = *from) {
+ if(c == '\t' || c == ' ' || c == '\n') {
+ *to++ = ' ';
+ do
+ from++;
+ while((c= *from)==' '||c=='\t'||c=='\n');
+ continue;
+ } else
+ *to++ = c;
+ from++;
+ } else
+ break;
+ return(from - sfrom - 1);
+}
+
+int *localtime();
+char *findmonth();
+
+cpydat(sfrom, sto, cnt)
+char *sfrom, *sto;
+{
+ register char *from, *cp;
+ register int c;
+ static int *locvec;
+ long now;
+ char *to;
+
+ if(!locvec) {
+ time(&now);
+ locvec = localtime(&now);
+ }
+ to = sto;
+ for(from = sfrom; (c = *from) < '0' || c > '9'; from++)
+ if(!c)
+ return;
+ c = cnt;
+ for(cp = from; (*cp >= '0' && *cp <= '9') || *cp == ' '; cp++);
+ if(cp = findmonth(cp)) {
+ if(!cp[1]) {
+ *to++ = ' ';
+ c--;
+ }
+ while(*cp && c--)
+ *to++ = *cp++;
+ c--; *to++ = '/';
+ if(from[1] == ' ') {
+ *to++ = ' ';
+ c--;
+ }
+ while(*from >= '0' && *from <= '9' && c--)
+ *to++ = *from++;
+ if(c >= 2) {
+ while(*from < '0' || *from > '9') from++;
+ if(((c = atoi(from)) > 1970 && c-1900 < locvec[5])
+ || c < locvec[5]) {
+ *to++ = '/';
+ *to++ = (c < 100) ? (c - 70 + '0')
+ : (c - 1970 + '0');
+ }
+ }
+ return;
+ }
+ if(from[1] == ' ') {
+ *to++ = ' ';
+ c--;
+ }
+ while(*from && c--)
+ *to++ = *from++;
+}
+
+
+char *fromp, fromdlm, pfromdlm;
+
+cpyfrm(sfrom, sto, cnt, fromcall)
+char *sfrom, *sto;
+{
+ register char *to, *cp;
+ register int c;
+
+ fromdlm = ' ';
+ fromp = sfrom; to = sto;
+ cp = frmtok();
+ do
+ if(c = *cp++)
+ *to++ = c;
+ else
+ break;
+ while(--cnt);
+ for(;;) {
+ if(cnt < 3) break;
+ if(*(cp = frmtok()) == 0) break;
+ if(*cp == '@' || uleq(cp, "at")) {
+ cp = frmtok();
+ if(uleq(cp, "berkeley")) {
+ /* if the first "From:" host is local */
+ if(fromcall && !hostseen++)
+ local++;
+ } else {
+ *to++ = '@';
+ cnt--;
+ do
+ if(c = *cp++)
+ *to++ = c;
+ else
+ break;
+ while(--cnt);
+ }
+ } else if(cnt > 4) {
+ cnt--; *to++ = pfromdlm;
+ do
+ if(c = *cp++)
+ *to++ = c;
+ else
+ break;
+ while(--cnt);
+ }
+ }
+ if(fromcall)
+ hostseen++;
+ return(to - sto);
+}
+
+
+char *frmtok()
+{
+ static char tokbuf[64];
+ register char *cp;
+ register int c;
+
+ pfromdlm = fromdlm;
+ cp = tokbuf; *cp = 0;
+ while(c = *fromp++) {
+ if(c == '\t')
+ c = ' ';
+ if(c == ' ' && cp == tokbuf)
+ continue;
+ if(c == ' ' || c == '\n' || c == ',')
+ break;
+ *cp++ = c;
+ *cp = 0;
+ if(c == '@' || *fromp == '@' || cp == &tokbuf[63])
+ break;
+ }
+ fromdlm = c;
+ return(tokbuf);
+}
+
+
+/* num specific! */
+
+cpymsgn(msgnam, addr, len)
+char *msgnam, *addr;
+{
+ register char *cp, *sp;
+
+ sp = msgnam;
+ cp = addr + (len - strlen(sp));
+ while(*sp)
+ *cp++ = *sp++;
+}
+
+char *monthtab[] = {
+ "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec",
+};
+
+char *findmonth(str)
+char *str;
+{
+ register char *cp, *sp;
+ register int i;
+ static char buf[4];
+ char *locv();
+
+ for(cp=str, sp=buf; (*sp++ = *cp++) && sp < &buf[3] && *cp != ' '; );
+ *sp = 0;
+ for(i = 0; i < 12; i++)
+ if(uleq(buf, monthtab[i])) {
+ sprintf(buf, "%2d", i+1);
+ return buf;
+ }
+ return(0);
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)send.c 4.2 2/23/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <strings.h>
+#include <signal.h>
+
+char *anoyes[]; /* Std no/yes gans array */
+
+char *vec[20];
+int vecp;
+
+struct swit switches[] = {
+ "debug", -1, /* 0 */
+ "draft", 0, /* 1 */
+ "format", 0, /* 2 */
+ "noformat", 0, /* 3 */
+ "msgid", 0, /* 4 */
+ "nomsgid", 0, /* 5 */
+ "verbose", 0, /* 6 */
+ "noverbose", 0, /* 7 */
+ "help", 4, /* 8 */
+ 0, 0
+};
+
+int debug;
+
+main(argc, argv)
+char *argv[];
+{
+ register char *drft, *cp;
+ register int i;
+ int status, pid;
+ struct stat stbuf;
+ char **ap;
+ char *arguments[50], **argp;
+
+#ifdef NEWS
+ m_news();
+#endif
+ drft = 0;
+ vec[vecp++] = "mh_deliver";
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "send: -%s unknown\n", cp);
+ goto leave;
+ /* -draft */
+ case 1: vec[vecp++] = drft = m_maildir(draft);
+ continue;
+ case 0: debug++;
+ case 2: case 3: case 4:
+ case 5: case 6: case 7:
+ vec[vecp++] = --cp;
+ continue;
+ case 8: help("send [file] [switches]",
+ switches);
+ goto leave;
+ }
+ if(drft) {
+ fprintf(stderr, "Send: Only one message at a time.\n");
+ done(1);
+ }
+ vec[vecp++] = drft = cp;
+ }
+ if(!drft) {
+ drft = m_maildir(draft);
+ if(stat(drft, &stbuf) == -1) {
+ fprintf(stderr, "Draft file: %s doesn't exist.\n", drft);
+ done(1);
+ }
+ cp = concat("Use \"", drft, "\"? ", 0);
+ if(!gans(cp, anoyes))
+ done(0);
+ vec[vecp++] = drft;
+ } else {
+ if(stat(drft, &stbuf) == -1) {
+ fprintf(stderr, "Draft file: %s doesn't exist.\n", drft);
+ done(1);
+ }
+ }
+ m_update();
+ vec[vecp] = 0;
+
+ while((pid = fork()) == -1) {
+ fprintf("Waiting for a fork\n");
+ sleep(2);
+ }
+ if(pid == 0) {
+ execv(mh_deliver, vec);
+ perror(mh_deliver);
+ done(1);
+ }
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ while((i = wait(&status)) != -1 && i != pid) ;
+ if(status == 0 && !debug)
+ backup(drft);
+
+leave: ;
+/*** m_update(); ***/
+}
+
+
+backup(file)
+char *file;
+{
+ char buf[128];
+ register char *cp;
+ extern char *rindex();
+
+ buf[0] = 0;
+ if(cp = rindex(file, '/'))
+ sprintf(buf, "%.*s", (++cp)-file, file);
+ else
+ cp = file;
+#ifdef UCB
+ strcat(buf, "#");
+#else
+ strcat(buf, ",");
+#endif
+ strcat(buf, cp);
+ unlink(buf);
+ if(link(file, buf) < 0 || unlink(file) < 0) {
+ fprintf(stderr, "Send: Backup rename failure ");
+ perror(buf);
+ done(1);
+ }
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <strings.h>
+
+int vecp;
+char *vec[MAXARGS];
+struct msgs *mp;
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "draft", 2, /* 1 */
+ "pr", 2, /* 2 */
+ "nopr", 2, /* 3 */
+ "help", 4, /* 4 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100];
+ register int msgnum;
+ register char *cp, **ap;
+ int msgp, all, drft, pr;
+ char *arguments[50], **argp;
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ folder = (char *) 0;
+ pr = all = msgp = 0;
+ vecp = 1;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:vec[vecp++] = --cp; continue;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: drft = 1; continue; /* -draft */
+ case 2: pr = 1; continue; /* -pr */
+ case 3: pr = 0; vecp = 1; continue;/* -nopr */
+ case 4: /* -help */
+ help("show [+folder] [msgs] [switches] [switches for \"type\" or \"pr\" ]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(drft)
+ maildir = m_maildir("");
+ else {
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ }
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(drft) {
+ vec[vecp++] = draft;
+ goto doit;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(msgp)
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "show: potato pancakes.\n"); /* never get here */
+ goto leave;
+ }
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "show: more than %d messages for show-exec\n", MAXARGS-2);
+ goto leave;
+ }
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ vec[vecp++] = getcpy(m_name(msgnum));
+ m_replace(pfolder, folder);
+ if(mp->hghsel != mp->curmsg)
+ m_setcur(mp->hghsel);
+ if(vecp == 2 ) {
+ printf("(Message %s:%s)\n", folder, vec[1]);
+ }
+doit: m_update();
+ fflush(stdout);
+ vec[vecp] = 0;
+ if(!pr) {
+ vec[0] = "c:mh-type";
+ execv(showproc, vec);
+ } else {
+ vec[0] = "mh-pr";
+ execv(prproc, vec);
+ }
+ perror(pr ? prproc : showproc);
+ leave:
+ m_update();
+ done(0);
+}
+
+
--- /dev/null
+/*
+ * This file gives extern declarations to all the strings
+ * that we might ever reference.
+ *
+ * I don't know if this what strings.h is supposed to be,
+ * but this is as good a first guess as I can handle.
+ */
+
+extern char *anoyes[];
+extern char *components;
+extern char *current;
+extern char *defalt;
+extern char *distcomps;
+extern char *draft;
+extern char *fileproc;
+extern char *foldprot;
+extern char *hostname;
+extern char *installproc;
+extern char *listname;
+extern char *lockdir;
+extern int lockwait;
+extern char *lsproc;
+extern char *mailboxes;
+extern char *mailproc;
+extern char *mh_deliver;
+extern char *mh_prof;
+extern char *mhnews;
+extern char *msgprot;
+extern char *pfolder;
+extern char *prproc;
+extern char *scanproc;
+extern char *sendproc;
+extern char *showproc;
+extern char *stdcomps;
+extern char *stddcomps;
+extern char *sysed;
+
+#ifdef UNIXCOMP
+extern char *unixtomh;
+extern char *Mailprog;
+extern char *localname;
+#endif
--- /dev/null
+#
+
+/*
+ * This program copies the mail file in standard unix format
+ * given as $1 to the file $2 in Rand Message Handler format.
+ * The change made is to bracket each message with a line
+ * containing 4 control-A's and to split the From line into
+ * a From: field and a Date: field, with the date in Arpanet
+ * standard format.
+ *
+ * This program is designed to be called from the rand mh program
+ * ``inc''
+ *
+ * Set SENDMAIL if you are running sendmail -- this guarantees that
+ * From: and Date: lines will appear already, and will put the info
+ * in the UNIX-From line into a Received-From: field.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <ctype.h>
+
+
+struct headline {
+ char *l_from; /* The name of the sender */
+ char *l_tty; /* His tty string (if any) */
+ char *l_date; /* The entire date string */
+};
+
+char *savestr(), *copyin(), *copy(), *nextword(), *calloc();
+char *index();
+
+#define NOSTR ((char *) 0)
+#define UUCP /* Undo strange uucp naming */
+
+main(argc, argv)
+ char **argv;
+{
+ char linebuf[BUFSIZ];
+ register int maybe;
+ register FILE *inf, *outf;
+ int inhdr, infld;
+
+ if (argc > 3) {
+ fprintf(stderr, "Usage: unixtomh name1 name2\n");
+ exit(1);
+ }
+ outf = inf = NULL;
+ if (argc < 3)
+ outf = stdout;
+ if (argc < 2)
+ inf = stdin;
+ if (inf == NULL && (inf = fopen(argv[1], "r")) == NULL) {
+ perror(argv[1]);
+ exit(1);
+ }
+ if (outf == NULL && (outf = fopen(argv[2], "w")) == NULL) {
+ perror(argv[2]);
+ exit(1);
+ }
+ maybe = 1;
+ inhdr = 0;
+ infld = 0;
+ while (nullgets(linebuf, BUFSIZ, inf) > 0) {
+ if (maybe && ishead(linebuf)) {
+ fputs("\1\1\1\1\n", outf);
+ inhdr++;
+ dohead(linebuf, inf, outf);
+ continue;
+ }
+ if (strlen(linebuf) == 0) {
+ maybe = 1;
+ inhdr = 0;
+ infld = 0;
+ putc('\n', outf);
+ continue;
+ }
+ else
+ maybe = 0;
+#ifndef SENDMAIL
+ if (inhdr && strncmp(linebuf, "Date: ", 6) == 0)
+ continue;
+ if (inhdr && strncmp(linebuf, "From: ", 6) == 0)
+ continue;
+#endif SENDMAIL
+ if (infld && isspace(linebuf[0])) {
+ fputs(linebuf, outf);
+ putc('\n', outf);
+ continue;
+ }
+ if (inhdr && !isspace(linebuf[0])) {
+ char *colp, *sp;
+
+ colp = index(linebuf, ':');
+ sp = index(linebuf, ' ');
+ if (colp == NOSTR || sp == NOSTR || sp < colp) {
+ putc('\n', outf);
+ inhdr = 0;
+ }
+ else
+ infld = 1;
+ }
+ fputs(linebuf, outf);
+ putc('\n', outf);
+ }
+ fputs("\1\1\1\1\n", outf);
+ fflush(outf);
+ if (ferror(outf)) {
+ fprintf(stderr, "unixtomh: write: ");
+ perror(argv[2]);
+ exit(1);
+ }
+ exit(0);
+}
+
+/*
+ * Get a line from the given file descriptor, don't return the
+ * terminating newline.
+ */
+
+nullgets(linebuf, sz, file)
+ char linebuf[];
+ register FILE *file;
+{
+ register char *cp;
+ register int c, cnt;
+
+ cp = linebuf;
+ cnt = sz;
+ do {
+ if (--cnt <= 0) {
+ *cp = 0;
+ return(1);
+ }
+ c = getc(file);
+ *cp++ = c;
+ } while (c != EOF && c != '\n');
+ if (c == EOF && cp == linebuf+1)
+ return(0);
+ *--cp = 0;
+ return(1);
+}
+
+/*
+ * Output the fields extracted from the From line --
+ * From: and Date: Untangle UUCP stuff if appropriate.
+ */
+
+dohead(line, infile, outfile)
+ char line[];
+ register FILE *infile, *outfile;
+{
+ register char *cp;
+ struct headline hl;
+ char parbuf[BUFSIZ];
+#ifdef UUCP
+ char *word();
+ char namebuf[BUFSIZ];
+ char linebuf[BUFSIZ];
+ int first;
+ long curoff;
+#endif UUCP
+
+ parse(line, &hl, parbuf);
+#ifndef SENDMAIL
+ putdate(hl.l_date, outfile);
+#endif SENDMAIL
+#ifdef UUCP
+ if (strcmp(hl.l_from, "uucp") == 0) {
+ strcpy(namebuf, "");
+ first = 1;
+ for (;;) {
+ curoff = ftell(infile);
+ if (fgets(linebuf, BUFSIZ, infile) == NULL)
+ break;
+ if (strcmp(word(1, linebuf), ">From") != 0)
+ break;
+ if (strcmp(word(-3, linebuf), "remote") != 0)
+ break;
+ if (strcmp(word(-2, linebuf), "from") != 0)
+ break;
+ if (first) {
+ strcpy(namebuf, word(-1, linebuf));
+ strcat(namebuf, "!");
+ strcat(namebuf, word(2, linebuf));
+ first = 0;
+ }
+ else {
+ strcpy(rindex(namebuf, '!')+1,
+ word(-1, linebuf));
+ strcat(namebuf, "!");
+ strcat(namebuf, word(2, linebuf));
+ }
+ }
+ fseek(infile, curoff, 0);
+#ifdef SENDMAIL
+ if (!first)
+ fprintf(outfile, "Return-Path: <%s>\n", namebuf);
+#else SENDMAIL
+ if (first)
+ fprintf(outfile, "From: uucp\n");
+ else
+ fprintf(outfile, "From: %s\n", namebuf);
+#endif SENDMAIL
+ return;
+ }
+#endif UUCP
+#ifdef SENDMAIL
+ if (hl.l_from[0] == '<')
+ fprintf(outfile, "Return-Path: %s\n", hl.l_from);
+ else
+ fprintf(outfile, "Return-Path: <%s>\n", hl.l_from);
+#else SENDMAIL
+ fprintf(outfile, "From: %s\n", hl.l_from);
+#endif SENDMAIL
+}
+
+#ifdef UUCP
+
+/*
+ * Return liberal word i from the given string.
+ * The words are numbered 1, 2, 3, . . . from the left
+ * and -1, -2, . . . from the right.
+ */
+
+char *
+word(index, str)
+ char str[];
+{
+ register char *cp;
+ char *secbuf;
+ register int c;
+ static char retbuf[100];
+ char *gword();
+
+ cp = str;
+ if ((c = index) > 0) {
+ while (c-- > 0)
+ cp = gword(cp, retbuf);
+ return(retbuf);
+ }
+ if (c == 0)
+ return("");
+ secbuf = (char *) malloc(strlen(str) + 1);
+ strcpy(secbuf, str);
+ rev(secbuf);
+ cp = word(-index, secbuf);
+ rev(cp);
+ return(cp);
+}
+
+/*
+ * Skip leading blanks in the string, return
+ * first liberal word collected.
+ */
+
+char *
+gword(cp, buf)
+ register char *cp;
+ char buf[];
+{
+ register char *cp2;
+
+ cp2 = buf;
+ while (*cp && any(*cp, " \t\n"))
+ cp++;
+ while (*cp && !any(*cp, " \t\n"))
+ *cp2++ = *cp++;
+ *cp2 = 0;
+ return(cp);
+}
+
+/*
+ * Reverse the characters in the string in place
+ */
+
+rev(str)
+ char str[];
+{
+ register char *cpl, *cpr;
+ register int s;
+
+ s = strlen(str);
+ cpl = str;
+ cpr = &str[s-1];
+ while (cpl < cpr) {
+ s = *cpl;
+ *cpl++ = *cpr;
+ *cpr-- = s;
+ }
+}
+#endif UUCP
+
+/*
+ * Save a string in dynamic space.
+ * This little goodie is needed for
+ * a headline detector in head.c
+ */
+
+char *
+savestr(str)
+ char str[];
+{
+ register char *top;
+
+ top = calloc(strlen(str) + 1, 1);
+ if (top == NOSTR) {
+ fprintf(stderr, "unixtomh: Ran out of memory\n");
+ exit(1);
+ }
+ copy(str, top);
+ return(top);
+}
+
+/*
+ * See if the passed line buffer is a mail header.
+ * Return true if yes. Note the extreme pains to
+ * accomodate all funny formats.
+ */
+
+ishead(linebuf)
+ char linebuf[];
+{
+ register char *cp;
+ struct headline hl;
+ char parbuf[BUFSIZ];
+
+ cp = linebuf;
+ if (!isname("From ", cp, 5))
+ return(0);
+ parse(cp, &hl, parbuf);
+ if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
+ fail(linebuf, "No from or date field");
+ return(0);
+ }
+ if (!isdate(hl.l_date)) {
+ fail(linebuf, "Date field not legal date");
+ return(0);
+ }
+
+ /*
+ * I guess we got it!
+ */
+
+ return(1);
+}
+
+fail(linebuf, reason)
+ char linebuf[], reason[];
+{
+ return;
+}
+
+/*
+ * Split a headline into its useful components.
+ * Copy the line into dynamic string space, then set
+ * pointers into the copied line in the passed headline
+ * structure. Actually, it scans.
+ */
+
+parse(line, hl, pbuf)
+ char line[], pbuf[];
+ struct headline *hl;
+{
+ register char *cp, *dp;
+ char *sp;
+ char word[BUFSIZ];
+
+ hl->l_from = NOSTR;
+ hl->l_tty = NOSTR;
+ hl->l_date = NOSTR;
+ cp = line;
+ sp = pbuf;
+
+ /*
+ * Skip the first "word" of the line, which should be "From"
+ * anyway.
+ */
+
+ cp = nextword(cp, word);
+ dp = nextword(cp, word);
+ if (word[0] != 0)
+ hl->l_from = copyin(word, &sp);
+ if (isname(dp, "tty", 3)) {
+ cp = nextword(dp, word);
+ hl->l_tty = copyin(word, &sp);
+ if (cp != NOSTR)
+ hl->l_date = copyin(cp, &sp);
+ }
+ else
+ if (dp != NOSTR)
+ hl->l_date = copyin(dp, &sp);
+}
+
+/*
+ * Copy the string on the left into the string on the right
+ * and bump the right (reference) string pointer by the length.
+ * Thus, dynamically allocate space in the right string, copying
+ * the left string into it.
+ */
+
+char *
+copyin(src, space)
+ char src[];
+ char **space;
+{
+ register char *cp, *top;
+ register int s;
+
+ s = strlen(src);
+ cp = *space;
+ top = cp;
+ strcpy(cp, src);
+ cp += s + 1;
+ *space = cp;
+ return(top);
+}
+
+/*
+ * See if the two passed strings agree in the first n characters.
+ * Return true if they do, gnu.
+ */
+
+isname(as1, as2, acount)
+ char *as1, *as2;
+{
+ register char *s1, *s2;
+ register count;
+
+ s1 = as1;
+ s2 = as2;
+ count = acount;
+ if (count > 0)
+ do
+ if (*s1++ != *s2++)
+ return(0);
+ while (--count);
+ return(1);
+}
+
+/*
+ * Test to see if the passed string is a ctime(3) generated
+ * date string as documented in the manual. The template
+ * below is used as the criterion of correctness.
+ * Also, we check for a possible trailing time zone using
+ * the auxtype template.
+ */
+
+#define L 1 /* A lower case char */
+#define S 2 /* A space */
+#define D 3 /* A digit */
+#define O 4 /* An optional digit or space */
+#define C 5 /* A colon */
+#define N 6 /* A new line */
+#define U 7 /* An upper case char */
+
+char ctypes[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,D,D,D,D,0};
+char tmztypes[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,U,U,U,S,D,D,D,D,0};
+
+isdate(date)
+ char date[];
+{
+ register char *cp;
+
+ cp = date;
+ if (cmatch(cp, ctypes))
+ return(1);
+ return(cmatch(cp, tmztypes));
+}
+
+/*
+ * Match the given string against the given template.
+ * Return 1 if they match, 0 if they don't
+ */
+
+cmatch(str, temp)
+ char str[], temp[];
+{
+ register char *cp, *tp;
+ register int c;
+
+ cp = str;
+ tp = temp;
+ while (*cp != '\0' && *tp != 0) {
+ c = *cp++;
+ switch (*tp++) {
+ case L:
+ if (!islower(c))
+ return(0);
+ break;
+
+ case S:
+ if (c != ' ')
+ return(0);
+ break;
+
+ case D:
+ if (!isdigit(c))
+ return(0);
+ break;
+
+ case O:
+ if (c != ' ' && !isdigit(c))
+ return(0);
+ break;
+
+ case C:
+ if (c != ':')
+ return(0);
+ break;
+
+ case N:
+ if (c != '\n')
+ return(0);
+ break;
+
+ case U:
+ if (!isupper(c))
+ return(0);
+ break;
+ }
+ }
+ if (*cp != '\0' || *tp != 0)
+ return(0);
+ return(1);
+}
+
+/*
+ * Collect a liberal (space, tab delimited) word into the word buffer
+ * passed. Also, return a pointer to the next word following that,
+ * or NOSTR if none follow.
+ */
+
+char *
+nextword(wp, wbuf)
+ char wp[], wbuf[];
+{
+ register char *cp, *cp2;
+
+ if ((cp = wp) == NOSTR) {
+ copy("", wbuf);
+ return(NOSTR);
+ }
+ cp2 = wbuf;
+ while (!any(*cp, " \t") && *cp != '\0')
+ *cp2++ = *cp++;
+ *cp2 = '\0';
+ while (any(*cp, " \t"))
+ cp++;
+ if (*cp == '\0')
+ return(NOSTR);
+ return(cp);
+}
+
+/*
+ * Copy str1 to str2, return pointer to null in str2.
+ */
+
+char *
+copy(str1, str2)
+ char *str1, *str2;
+{
+ register char *s1, *s2;
+
+ s1 = str1;
+ s2 = str2;
+ while (*s1)
+ *s2++ = *s1++;
+ *s2 = 0;
+ return(s2);
+}
+
+/*
+ * Is ch any of the characters in str?
+ */
+
+any(ch, str)
+ char *str;
+{
+ register char *f;
+ register c;
+
+ f = str;
+ c = ch;
+ while (*f)
+ if (c == *f++)
+ return(1);
+ return(0);
+}
+
+/*
+ * Convert lower case letters to upper case.
+ */
+
+raise(c)
+ register int c;
+{
+ if (c >= 'a' && c <= 'z')
+ c += 'A' - 'a';
+ return(c);
+}
--- /dev/null
+ register char *cp;
+ register int i,j;
+ register FILE *in;
+ char name[NAMESZ], field[BUFSIZ];
+ char *drft, *msgid, *replto, *from, *cc, *sub, *date, *to;
+ int state, out, status, intr;
+ int pid, wpid;
+ char **argp, *address;
+ char ackfile[10];
+ char buf[BUFSIZ];
--- /dev/null
+The Alias file for mail delivery is the file
+
+ /etc/MailAliases
+
+Each line of the alias file has the format:
+
+match : alias
+
+Where:
+
+ alias := simple-list
+ | "<" alias-file
+ | "=" UNIX-group
+ | "*"
+
+ simple-list := simple-name
+ | simple-list, simple-name
+
+Alias-file is a fully qualified UNIX file name. UNIX-group is a
+group name from /etc/group. A simple-name is a local user login
+name, including only alphanumerics, `.' and `-'. Throughout this
+file case is ignored, except for alias-file.
+
+In match, a trailing * on a name will match anything. (See example
+below.)
+
+The procedure for mail aliasing is:
+
+1) Build a list of all addresses from the message to be
+ delivered, eliminating duplicates.
+
+2) For each line in the alias file, compare "match" against all
+ of the existing addresses. If a match, remove the matched
+ name from the address list, and add each new alias name to the
+ address list if it is not already on the list.
+
+Since the alias file is read line by line, forward references
+work, but backward references are not recognized, thus, there is
+no recursion.
+
+E.g.:
+
+Borden: bruce
+Bruce: bsb
+Wharman: mike
+ASRL: bsb, mike, obrien, giarla
+UNIX-committee: < /usr/people/unix-committee
+System: = sys
+Everyone: *
+news.*: news
+ ...
+
+In the "unix-committee" example, the file "/usr/people/unix-
+committee" contains one simple-name, or a list of comma separated
+simple-names. A new-line will be treated as a blank in this
+file, s.a.
+
+ foo, fie,
+ fum, fiddle
+
+In the "system" case, the names from the group "sys" will be used
+as the expanded name list.
+
+In the "news.*" case, all names of the form "news.<anything>" will
+be mapped to "news". This is used for the MH news facility.
+
+Bruce Borden October 1979
--- /dev/null
+vgrind aliascheck.c annotate.c comp.c deliver.c dist.c emitl.c\
+ errno.h file.c folder.c forw.c grep.c inc.c install-mh.c\
+ mail.c mh.h news.c next.c nexthdr.c pick.c prevhdr.c\
+ prompter.c replsubs.c reply.c rescue.c rmf.c rmm.c scan.c\
+ scansub.c send.c show.c strings.h strings/Mailprog.c strings/anoyes.c\
+ strings/components.c strings/current.c strings/defalt.c\
+ strings/distcomps.c strings/draft.c strings/fileproc.c\
+ strings/foldprot.c strings/hostname.c strings/installproc.c\
+ strings/listname.c strings/localname.c strings/lockdir.c\
+ strings/lsproc.c strings/mailboxes.c strings/mailproc.c\
+ strings/mh_defs.c strings/mh_deliver.c strings/mh_prof.c\
+ strings/mhnews.c strings/msgprot.c strings/pfolder.c\
+ strings/prproc.c strings/scanproc.c strings/sendproc.c\
+ strings/showproc.c strings/stdcomps.c strings/stddcomps.c\
+ strings/strings.h strings/sysed.c strings/unixtomh.c\
+ subs/add.c subs/ambigsw.c subs/atooi.c subs/brkstring.c\
+ subs/cdate.c subs/cndfree.c subs/concat.c subs/copy.c subs/copyip.c\
+ subs/cputc.c subs/crpbrkstring.c subs/done.c subs/fdcompare.c\
+ subs/gans.c subs/getans.c subs/getcpy.c subs/help.c subs/invo_name.c\
+ subs/locv.c subs/m_convert.c subs/m_delete.c subs/m_edit.c\
+ subs/m_find.c subs/m_getdefs.c subs/m_getfld.c subs/m_getfolder.c\
+ subs/m_gmprot.c subs/m_gmsg.c subs/m_maildir.c subs/m_name.c\
+ subs/m_replace.c subs/m_send.c subs/m_setcur.c subs/m_update.c\
+ subs/makedir.c subs/makename.c subs/mh.h subs/peekc.c\
+ subs/pr_array.c subs/printsw.c subs/putdate.c subs/r1bindex.c\
+ subs/showfile.c subs/smatch.c subs/ssequal.c subs/trimcpy.c\
+ subs/type.c subs/uleq.c support/l.c unixtomh.c vars.c
--- /dev/null
+ HOW TO GENERATE AN MH
+
+ASSUMPTIONS/RESTRICTIONS:
+
+ All of the code is written for Version 7 C, and assumes
+the existence of appropriate Version 7 /usr/include files. It
+also uses the Version 7 stdio package, which is somewhat
+different than the Phototypesetter stdio!
+
+ There is moderate usage of Version 7 UNIX features,
+including:
+
+ ftime() system call
+ execlp() & execvp() environment exec calls
+ getenv() environment access
+
+also, login has to be changed to add the environment entry
+"USER=name". This is used during scan listings to see if the
+message "From" should be replaced by "To:name". This string is
+NOT used to determine the "From: name" stamp on outgoing mail.
+
+ All of these usages ARE replaceable by subroutines which
+do the same thing, only slower. That is, a line of the form:
+
+ homedir = getenv("HOME");
+
+should be replaced by something like:
+
+ homedir = gethome();
+
+and the routine gethome() written to return the home directory by
+looking through /etc/passwd for the line matching the process'
+getuid(). This goes for the environment variable "USER" as well.
+
+The routines execlp() & execvp() are simply fancy exec's, which
+use the "PATH" environment variable to determine the search path
+by which to find the executable image. They can be replaced by
+routines which use a default search list. They also call a shell
+to execute the file in the same way the shell handles shell
+scripts.
+
+
+
+PROCEDURE:
+
+
+1) Read the MH directory tree onto a file system.
+
+2) Examine all of the files in directory strings. These are the
+ names and paths of all of the programs MH calls upon. Change
+ them to suit your installation. Most of the files contain
+ short descriptions of what the strings are.
+
+3) In the top level directory, utter:
+
+ make strings.a subs.a all
+
+ This will make both of the libraries: strings.a and subs.a,
+ and ALL of the executable modules.
+
+4) AS SU:
+
+ make onceonly This renames conflicting bell
+ programs, and makes requisite
+ directories.
+
+ make install This puts all of the programs
+ into appropriate directories.
+
+That's it. Take a close look at the Makefile--it does LOTS of
+work. If you don't want to install everything in standard
+places, run "make install" with the variables MHDIR=newdir and
+BINDIR=newdir pointing wherever you wish. If you do this, you
+probably have to change some of the path names in the strings
+files. For most of them, you can get away with adding profile
+entries to change where the default paths are sought.
+
+If you don't have `make':
+
+ You'll have to use the make file as a template for commands
+ to give by hand. Basically each section of the make file
+ defines the sequence of shell commands needed to create the
+ object before the `:'. The list immediately after the `:'
+ specifies the dependencies for the object--that is, those
+ objects which either must be made first, or those modules
+ that if they've changed, the object must be rebuilt. The
+ following lines (up to the next object) are simply shell
+ commands to be executed. Make knows how to create .o's from
+ .c's, and the "CFLAGS= -O" at the beginning tells it to
+ include optimization when it does a c compile.
+
+If you don't have stdio (i.e. some version 7 C compiler):
+
+ Punt. I recently converted the whole package from the old
+ getc/putc/iobuf subroutines--including lots of upgrades/
+ improvements, it took me about a week. Expect it to take a
+ couple of weeks for someone good to convert back.
+ Basically, convert the subroutines, then once you've
+ converted one module (start with show or comp), you'll find
+ all the rest VERY similar. Some day I may split out all of
+ the system dependencies, but don't hold your breath.
+
+
+
+As a last resort:
+
+ Feel free to call me, but please don't expect me to spend
+hours helping. Collect your questions/problems, and get in touch
+and I'll see what I can do. I can be reached:
+
+ via ARPANET: Borden at Rand-UNIX
+
+ Mail: The Rand Corporation
+ 1700 Main Street
+ Santa Monica, CA 90406
+
+ Phone: (213) 399-0568 x 7463
+
+
+
+Bruce Borden
+October, 1979
--- /dev/null
+This file contains some notes on features/bugs/etc which are
+not documented in the "MH User's Manual", as well as some notes
+on future directions. See MHgenerate for more info. Some of
+these notes assume VAX/V7 UNIX--as noted by {V/V7}.
+
+0) Directories:
+ support contains files which get copied to /etc/mh, as
+ well as some miscellaneous Rand support programs
+ subs contains support subroutines--built into subs.a
+ strings contains c files which define all of the default
+ names and paths used by the package->strings.a
+ Extras old and un-supported code--much of it not
+ converted to V7. Look at libg/libh for help in
+ getting around V7 features.
+ DOC contains the MH User's Manual document in nroff/
+ troff form. This requires the Phototypesetter or
+ V7 version of nroff/troff, AND the Berkeley -me
+ macros.
+
+1) Undocumented Feature: The paths to the various programs which
+ MH exec's are kept in variables named something like "lsproc".
+ (See the strings directory.) While reading in the user's
+ profile, (m_getdefs()) a component matching one of these exec
+ path names, will cause the default string to be replaced by
+ the profile entry argument. Thus, the profile entry "lsproc:
+ /usr/foo/bin/newls" will cause all MH programs using "lsproc"
+ to get a new ls. At least for now, there is no way to specify
+ switches. This mapping is arranged by the "procs" structure
+ in m_getdefs.c--keep it up to date if new exec procs are
+ added.
+
+2) Collision: Take a close look at the "onceonly" entry of the
+ Makefile. Bell already has a program named `file', which the
+ makefile will rename to `filetype', which is what it tries to
+ indicate. If you really want to, you might rename the MH
+ command `file', but I have yet to hear of an even vaguely
+ reasonable alternative.
+
+3) Different Approach: Using the Berkeley C shell (csh),
+ "multiple links to the same file with different profile
+ entries" is better served with aliases.
+
+4) Collision: {V/V7} BELL mail cannot co-exist with MH--IF THEY
+ SHARE THE SAME MAILBOXES, otherwise they co-exist fine! If
+ you use the standard (VAX) mail directory /usr/spool/mail for
+ MH, you should also install the MH version of the mail
+ program. It is much nicer, and integrates with MH cleanly.
+ The advantage of using /usr/spool/mail is that login will
+ notify of new mail.
+
+5) Feature: If you add a line like:
+
+ 30 1 * * * /etc/mh/aliascheck -mail bsb
+
+ to crontab, then every morning at 1:30 AM, the alias file will
+ be checked against the /etc/passwd file to see that
+ inconsistencies haven't been introduced. In particular, a
+ line in the alias file may be "tom: jones" (because Tom Jones
+ likes to be called Tom), but if tom is also a valid user name,
+ tom will no longer receive any mail! This program also prints
+ any mail drops in /usr/spool/mail which don't belong to a
+ valid user (i.e. a deleted or renamed user id).
+
+ "Aliascheck -mail name" will check the consistency and mail
+ the specified user a short status message.
+
+ This program also checks to see if there are any users who do
+ not belong to any group, or any user in a group which is missing
+ from the passwd file. This latter is an inconsistency on all
+ systems, whereas the former is not required except at Rand, and
+ won't be compiled without the "-DRAND" cc flag in the makefile.
+
+6) Hidden Feature: At the request of some of the Rand staff,
+ there is the ability to invoke a user-specified deletion-
+ program to implement message deletion, rather than getting the
+ default comma renaming convention (see next item). If a
+ user's profile contains the line: "Delete-prog: path", the
+ specified path will be called with a list of files needing
+ deletion. All this code works...
+
+7) Feature: When a message (draft or in a folder) is "removed",
+ it is really renamed with a leading comma. E.g. foo -> ,foo.
+ At Rand we have a program called the midnight skulker which
+ goes through the whole system and removes all backup (starting
+ with comma), a.out, and core files. This backup convention
+ gives users a chance to undo spurious removes, at least all
+ day. You may want to replace these renames with a simple
+ unlink(), or each user may get this effect by specifying
+ "Delete-prog: /bin/rm" in his/her profile.
+
+8) Feature: NEWS. The news facility is undocumented in the MH
+ manual, because it is a very new addition to the package. SO,
+ here it is...
+
+ The directory /usr/news should be created--it will
+ contain the folders for news topics, and various support
+ files. The news items are strictly MH folders, and users
+ can utilize all of the MH commands on them. The news
+ program is similar to "show", but it shows `unseen' news
+ as the default, keeping a separate entry in the users
+ profile for each news topic indicating the highest item
+ the user has seen. These entries look like
+ "news-<topic>: highest-seen".
+
+ Rather than read through the news folders to determine
+ the number of entries, a file with name .<topic> (i.e.
+ period followed by the topic name) is kept with length
+ equal to highest message number. Thus, to determine if a
+ user hasn't seen some news, the news directory
+ (/usr/news) is read, and for each non-period beginning
+ file (i.e. each folder), stat the associated period
+ beginning file, and compare its length with the users
+ profile news entry for the same name. If the user has no
+ entry, or it is less than the length of the period-file,
+ then show him the remainder of the news in each such
+ topic.
+
+ The program `l' is used to display each message, and the
+ highest item profile entry is updated prior to each
+ individual message displayed, so <del> will leave the
+ user's profile in the proper state for the next news
+ request.
+
+ Add a user to the system called news, with home directory
+ /usr/news and add the line:
+
+ news.*: news
+
+ to /etc/MailAlias. Thus, to add news to a topic, it is
+ only necessary to mail to news.topic, and it will happen.
+ To make the automatic filing into folders happen, copy
+ the file support/news-mh_receiv to /usr/news/.mh_receive.
+ This is a shell script which will get invoked whenever
+ mail is sent to the user news (see next "undocumented
+ feature").
+
+ Problems: I have yet to write the program which packs
+ news folders. Items can be readily removed (as long as
+ they are not the last item in the folder), but if the
+ folder is packed (after some months/years the item
+ numbers will reach the 999 limit), it is necessary to go
+ through everyones .mh_profile files and reset the
+ highest-seen numbers. Not hard to write, I just haven't
+ done it yet. Also, the receive shell script should be
+ recoded in C to speed it up considerably.
+
+9) Undocumented Feature: If a user has an executable program or
+ shell script named ".mh_receive" in his home directory, then
+ it will be executed by the mail deliverer RATHER than
+ appending mail items to the user's mail file
+ (/usr/spool/mail/name). This program will be called with:
+
+ execlp(prog, prog, tmpfil, mail, home, 0);
+
+ where prog is the receive program, tmpfil is a file in
+ /usr/tmp which is the mail to be received, mail is the path of
+ the user's mail drop (/usr/spool/mail/name), and home is the
+ $HOME directory of the user. File descriptor 3 will have
+ tmpfil opened on it read only. These are all the RECEIVER'S
+ parameters, not the sender's. Also, the environment is set up
+ with appropriate values for HOME and USER.
+
+ Eventually, the goal is to have received mail LINKED into
+ user's inbox folders, rather than appended to their mailboxes.
+ This will facilitate the sending of mail to large distribution
+ lists (Rand is always tight on space!) Have a look at the news
+ .mh_receive file for an example of this facility.
+
+ Warning: appropriate interlocks are implemented in "deliver"
+ to prevent collisions when it appends to mailboxes, but it is
+ up to the users's .mh_receive program to provide its own
+ interlocks!
+
+
+
+
+Bruce Borden
+February 1980
--- /dev/null
+manual:
+ itroff -me titlepage mh.me
--- /dev/null
+.de $c \" Major Heading printer
+.ce
+.b "\\s12\\n+(ch.\\ \\$1\\s0" \" 12 Point Bold Header
+.(x
+
+\ \ \ \\n(ch.\\ \\ \\$1
+.)x
+.sp 45p \" 45 point space or about 1/2 inch
+..
+\".nr xs .15v \" Put index entries closer together
+.(x
+
+Section
+.)x _
+.de $0 \" Sub-Heading macro called AFTER printing the heading
+.(x
+.sp .3v
+.ti .5i
+\\$1
+.)x
+..
+.de $s \" Macro to print footnote separator
+\"\l'2i' \" No line drawn
+.if n \
+. sp 1.3 \" But extra space to make up for it.
+..
+.fc ^ ~ \" The characters ^ and ~ CANNOT BE USED
+\" throughout this document except as field
+\" delimiter & pad indicator!
+.he ''-%-''
+.ll 32P \" 32 Picas or about 5+1/3 inch Line Length
+.if n .ll 72m \" Use 72 ems for nroff
+.nr ss 30p \" 30 point space before section titles
+.nr fm 5v \" Rand likes bigger than normal [3v] bottom margins
+.nr bm 7v \" ditto
+.ds . \\fB.\\fP\\h'-(1m/3)' \" Bold period to stand out.
+.ds << <\\h!-(\\w'<'/2)!<
+.ds >> >\\h!-(\\w'>'/2)!>
+.ds ** \v'-3p'\s+1*\s0\v'+3p'
+.++ C
+.+c INTRODUCTION
+.pp
+Although people can travel cross-country in hours and can
+reach others by telephone in seconds, communications still depend
+heavily upon paper, most of which is distributed through the mails.
+.pp
+There are several major reasons for this continued dependence on
+written documents.
+First, a written document may be proofread
+and corrected prior to its distribution, giving the author
+complete control over his words.
+Thus, a written document is
+better than a telephone conversation in this respect.
+Second,
+a carefully written document is far less likely to be
+misinterpreted or poorly translated than a phone conversation.
+Third, a signature offers reasonable verification of authorship,
+which cannot be provided with media such as telegrams.
+.pp
+However, the need for
+.u fast ,
+accurate, and reproducible document distribution is
+obvious.
+One solution in widespread use is the telefax.
+Another
+that is rapidly gaining popularity is electronic mail.
+Electronic mail is similar to telefax in that the data to be sent
+are digitized, transmitted via phone lines, and
+turned back into a document at the receiver.
+The advantage of
+electronic mail is in its compression factor.
+Whereas a telefax
+must scan a page in very fine lines and send all of the black and
+white information, electronic mail assigns characters fixed
+codes which can be transmitted as a few bits of information.
+Telefax presently has the advantage of being able to transmit an
+arbitrary page, including pictures, but electronic mail is
+beginning to deal with this problem.
+Electronic mail also integrates well
+with current directions in office automation, allowing documents
+prepared with sophisticated equipment at one site to be quickly
+transferred and printed at another site.
+.pp
+Currently, most electronic mail is intraorganizational,
+with mail transfer remaining within one computer.
+As computer
+networking becomes more common, however, it is becoming more feasible to
+communicate with anyone whose computer can be linked to your
+own via a network.
+.pp
+The pioneering efforts on general-purpose electronic mail
+were by organizations using the Defense Department's ARPANET.[1]
+The capability to send messages between computers existed before
+the ARPANET was developed, but it was used only in limited ways.
+With the advent of the
+ARPANET, tools began to be developed which made it convenient for
+individuals or organizations to distribute messages
+over broad geographic areas, using
+diverse computer facilities.
+The interest and activity in
+message systems has now reached such proportions that steps
+have been taken within the DoD to coordinate and
+unify the development of military message systems.
+The use of electronic mail is expected to increase
+dramatically in the next few years.
+The utility of such systems
+in the command and control and intelligence environments is
+clear, and applications in these areas will probably lead the
+way.
+As the costs for sending and handling electronic messags
+continue their rapid decrease, such uses can be
+expected to spread rapidly into other areas and, of course, will
+not be limited to the DoD.
+.pp
+A message system provides tools that help users (individuals
+or organizations) deal with messages in various ways.
+Messages
+must be composed, sent, received, stored, retrieved,
+forwarded, and replied to.
+Today's best interactive computer
+systems provide a variety of word-processing and information
+handling capabilities.
+The message handling facilities should be
+well integrated with the rest of the system, so as to be a
+graceful extension of overall system capability.
+.pp
+The message system described in this report, MH, provides most of the
+features that can be found in other message systems and also
+incorporates some new ones.
+It has been built on the UNIX time-sharing
+system,[2] a popular operating system for the DEC PDP-11
+and VAX classes of computers.
+A \*(lqsecure\*(rq operating
+system similar to UNIX is currently being developed,[3]
+and that system will also run MH.
+.pp
+This report provides a complete description of MH and
+thus may serve as a user's manual, although parts of the report
+will be of interest to non-users as well.
+Sections 2 and 3, the
+Overview and Tutorial, present the key
+ideas of MH and will give those not familiar with message systems
+an idea of what such systems are like.
+.pp
+MH consists of a set of commands which use some special
+files and conventions.
+Section 4 covers the information
+a user needs to know in addition to the
+commands.
+The final section, Sec. 5, describes each of
+the MH commands in detail.
+A summary of the commands is given in
+Appendix A, and Appendixes B and C describe the ARPANET
+conventions for messages (we expect that many users of MH
+will be using the ARPANET) and the formal syntax of such
+messages, respectively.
+Finally, Appendix D provides
+an illustration of how MH commands may be used in
+conjunction with other UNIX facilities.
+.pp
+A novel approach has been taken in the design of MH.
+The
+design concept will be reported in detail in a forthcoming Rand
+report, but it can be described briefly as follows.
+Instead of creating a large subsystem that appears as a single
+command to the user, (such as MS[4])
+MH is a collection of separate commands
+which are run as separate programs.
+The file and directory
+system of UNIX are used directly.
+Messages are stored as
+individual files (datasets), and collections of them are grouped
+into directories.
+In contrast, most other message systems store
+messages in a complicated data structure within a monolithic
+file.
+With the MH approach, UNIX commands can be
+interleaved with commands invoking the functions of the message
+handler.
+Conversely, existing UNIX commands
+can be used in connection with messages.
+For
+example, all the usual UNIX editing, text-formatting, and printing
+facilities can be applied directly to individual messages.
+MH,
+therefore, consists of a relatively small amount of new code; it
+makes extensive use of other UNIX software to provide the
+capabilities found in other message systems.
+.+c OVERVIEW
+.pp
+There are three main aspects of MH: the way messages are
+stored (the message database), the user's profile (which directs
+how certain actions of the message handler take place), and the
+commands for dealing with messages.
+.pp
+Under MH, each message is stored as a separate file.
+A user
+can take any action with a message that he could with an ordinary
+file in UNIX.
+A UNIX directory in which messages are stored is
+called a folder.
+Each folder contains some standard entries to support
+the message-handling functions.
+The messages in a folder have numerical
+names.
+These folders (directories)
+are entries in a particular directory path, described in
+the user profile, through which MH can find message folders.
+Using the UNIX \*(lqlink\*(rq facility, it is possible for one copy of a
+message to be \*(lqfiled\*(rq in more than one folder, providing a
+message index facility.
+Also, using the UNIX tree-structured
+file system, it is possible to have a folder within a folder.
+This two-level organization provides a \*(lqselection-list\*(rq
+facility, with the full power of the MH commands available on
+selected sublists of messages.
+.pp
+Each user of MH has a user profile, a file in his $HOME (initial
+login)
+directory called \*(lq\*.mh\(ruprofile\*(rq.
+This profile contains several
+pieces of information used by the MH commands: a
+path name to the directory that contains the message folders,
+information concerning which folder the user last referenced (the
+\*(lqcurrent\*(rq folder), and parameters that tailor MH commands
+to the individual user's requirements.
+It also contains
+most of the necessary state information concerning how
+the user is dealing with his messages, enabling MH to be
+implemented as a set of individual UNIX commands, in contrast to the
+usual approach of a monolithic subsystem.
+.pp
+In MH, incoming mail is appended
+to the end of a file called \*.mail in a user's $HOME
+directory.
+The user adds the new messages to his collection of MH messages
+by invoking the command
+.i inc .
+.i Inc
+(incorporate) adds the new
+messages to a folder called \*(lqinbox\*(rq, assigning them names which
+are consecutive integers starting with the next highest integer
+available in inbox.
+.i Inc
+also produces a
+.i scan
+summary of
+the messages thus incorporated.
+.pp
+There are four commands for examining the messages in a
+folder:
+.i show ,
+.i prev ,
+.i next ,
+and
+.i scan .
+.i Show
+displays a
+message in a folder,
+.i prev
+displays the message preceding the
+current message, and
+.i next
+displays the message following the
+current message.
+.i Scan
+summarizes the messages in a folder,
+producing one line per message, showing who the message is from,
+the date, the subject, etc.
+.pp
+The user may move a message from one folder to another with
+the command
+.i file .
+Messages may be removed from a folder
+by means of the command
+.i rmm .
+In addition, a user may query
+what the current folder is and may specify that a new folder
+become the current folder, through the command
+.i folder .
+.pp
+A set of messages based on content may be selected by
+use of the command
+.i pick .
+This command searches through
+messages in a folder and selects those that match a given
+criterion.
+A subfolder is created within the original folder,
+containing links to all the messages that satisfy the selection
+criteria.
+.pp
+A message folder (or subfolder) may be removed by means of
+the command
+.i rmf .
+.pp
+There are five commands enabling the user to create new
+messages and send them:
+.i comp ,
+.i dist ,
+.i forw ,
+.i repl ,
+and
+.i send .
+.i Comp
+provides the facility for the user to compose a
+new message;
+.i dist
+redistributes mail to additional addressees;
+.i forw
+enables the user to forward messages; and
+.i repl
+facilitates the generation of a reply to an incoming message.
+If
+a message is not sent directly by one of these commands, it may
+be sent at a later time using the command
+.i send .
+.pp
+All of the elements summarized above
+are described in more detail in the following sections.
+Many of the
+normal facilities of UNIX provide additional capabilities for
+dealing with messages in various ways.
+For example, it is
+possible to print messages
+on the line-printer without requiring any additional code within
+MH.
+Using standard UNIX facilities, any terminal output can be
+redirected to a file for repeated or future viewing.
+In general,
+the flexibility and capabilities of the UNIX interface with the
+user are preserved as a result of the integration of MH into the UNIX
+structure.
+.+c TUTORIAL
+.pp
+This tutorial provides a brief introduction to the MH commands.
+It should be sufficient
+to allow the user to read his mail, do some simple manipulations of
+it, and create and send messages.
+.pp
+A message has two major pieces: the
+header and the body.
+The body consists of the text of the message
+(whatever you care to type in).
+It follows the header and is separated from
+it by an empty line.
+(When you compose a message, the form that appears
+on your terminal shows a line of dashes after the header.
+This is for
+convenience and is replaced by an empty line when the message is
+sent.) The header is composed of several components, including the
+subject of the message and the person to whom it is addressed.
+Each component starts with a name
+and a colon; components must not start with a blank.
+The text of the
+component may take more than one line, but each continuation line must
+start with a blank.
+Messages typically have \*(lqto:\*(rq, \*(lqcc:\*(rq, and
+\*(lqsubject:\*(rq components.
+When composing a message, you should include
+the \*(lqto:\*(rq and \*(lqsubject:\*(rq components; the \*(lqcc:\*(rq (for people
+you want to send copies to) is not necessary.
+.pp
+The basic MH commands are
+.i inc ,
+.i scan ,
+.i show ,
+.i next ,
+.i prev ,
+.i rmm ,
+.i comp ,
+and
+.i repl .
+These are described below.
+
+.i inc
+.pp
+When you get the message \*(lqYou have mail\*(rq, type the command
+.i inc .
+You will get a \*(lqscan listing\*(rq such as:
+
+.nf
+.if t .ta .4i 1.0i 2i
+.if n .ta .4i 1.2i 3i
+^7+~^^\07/13~^^Cas~^revival of measurement work
+^8~^^10/\09~^^Norm~^NBS people and publications
+^9~^^11/26~^^To:norm~^question \*(<<Are there any functions
+.re
+.fi
+.pp
+This shows the messages you received since the last time you
+executed this command (
+.i inc
+adds these new messages to
+your inbox folder).
+You can see this list again, plus a list of any
+other messages you have, by using the
+.i scan
+command.
+
+.i scan
+.pp
+The scan listing shows the message number, followed by the
+date and the sender.
+(If you are the sender, the addressee in the \*(lqto:\*(rq
+component is displayed.
+You may send yourself a message by including
+your name among the \*(lqto:\*(rq or \*(lqcc:\*(rq addressees.)
+It also shows the message's subject; if
+the subject is short, the first part of the body of the message is
+included after the characters \*(<<.
+
+.ne 5
+.i show
+.pp
+This command shows the current message, that is,
+the first one of the new messages after an
+.i inc .
+If the message is not
+specified by name (number), it is
+generally the last message referred to by an MH command.
+For example,
+
+.ta 1i
+.ti .5i
+^\fIshow\fP\05~^will show message 5.
+.pp
+You can use the show command to copy a message or print a
+message.
+
+.(b L
+.in .5i
+.if t .ta 1i
+.if n .ta 1.5i
+^\fIshow\fR\0>\0\fIx\fR~^will copy the message to file x.
+.br
+^\fIshow\fR\0|\0\fIprint\fR~^will print the message, using the \fIprint\fR command.
+.br
+^\fInext\fR~^will show the message that follows the current message.
+.br
+^\fIprev\fR~^will show the message previous to the current message.
+.br
+^\fIrmm\fR~^will remove the current message.
+.br
+^\fIrmm\03\fR~^will remove message 3.
+.)b
+
+.ne 5
+.i comp
+.pp
+The
+.i comp
+command puts you in the editor to write or edit a message.
+Fill in or
+delete the \*(lqto:\*(rq, \*(lqcc:\*(rq, and \*(lqsubject:\*(rq fields, as appropriate, and
+type the body of the message.
+Then
+exit normally from the editor.
+You will be asked
+\*(lqWhat now?\*(rq.
+Type a carriage return to see the options.
+Typing \fBsend\fR
+will cause the message to be sent; typing \fBquit\fR will cause an exit
+from
+.i comp ,
+with the message draft saved.
+.pp
+If you quit without sending the message, it will be saved in a file
+called /usr/<name>/Mail/draft (where /usr/<name> is your $HOME directory).
+You can edit this file and send the message later, using the
+.i send
+command.
+
+.ne 4
+.i "comp\0\-editor\0prompter"
+.pp
+This command uses a different editor and is useful for preparing
+\*(lqquick and dirty\*(rq messages.
+It prompts you for each component of the
+header.
+Type the information for that component, or type a carriage
+return to omit the component.
+After that, type the body of the
+message.
+Backspacing is the only form of editing allowed with this editor.
+When the body is complete, type a carriage return followed by <CTRL-D>
+(<OPEN> on Ann Arbor terminals).
+This completes the initial preparation of the message; from then on, use
+the same procedures as with
+.i comp
+(above).
+
+.ne 5
+.i repl
+.br
+.i "repl\0n"
+.pp
+This command makes up an initial message form with a header
+that is appropriate for
+replying to an existing message.
+The message being answered is the
+current message if no message number is mentioned, or n if a number
+is specified.
+After the header is completed, you can finish the message as in
+.i comp
+(above).
+.pp
+This is enough information to get you going using MH.
+There are more commands,
+and the commands described here have more features.
+Subsequent sections
+explain MH in complete detail.
+The system is quite powerful if you
+want to use its sophisticated features, but the foregoing commands
+suffice for sending and receiving messages.
+.pp
+There are numerous additional capabilities you may wish to explore.
+For example, the
+.i pick
+command will select a subset of messages
+based on specified criteria such as sender or subject.
+Groups of
+messages may be designated, as described in Sec. V, under \*(lqMessage
+Naming\*(rq.
+The file \*(lq\*.mh\(ruprofile\*(rq can be used to tailor your use of
+the message system to your needs and preferences, as described in Sec. V,
+under \*(lqThe User Profile\*(rq.
+In general, you may
+learn additional features of the system selectively, according to your
+requirements,
+by studying the relevant sections of this manual.
+There is no need to
+learn all the details of the system at once.
+.+c "DETAILED DESCRIPTION"
+.pp
+This section describes the MH system in detail, including the components
+of the user profile, the conventions for message naming, and some of
+the other MH conventions.
+Readers who are
+generally familiar with computer systems will be able to follow
+the principal ideas, although some details may be meaningful only to
+those familiar with UNIX.
+.uh "THE USER PROFILE"
+.pp
+The first time an MH command is issued by a new user, the system
+prompts for a \*(lqpath\*(rq and creates an MH \*(lqprofile\*(rq.
+.pp
+Each MH user has a profile which contains current
+state information for the MH package and, optionally, tailoring
+information for each individual program.
+When a folder becomes
+the current folder, it is recorded in the user's profile.
+Other profile entries control the MH path (where folders and
+special files are kept), folder and message protections, editor
+selection, and default arguments for each MH program.
+.pp
+The MH profile is stored in the file \*(lq\*.mh\(ruprofile\*(rq in the
+user's $HOME directory.
+It has the format of a message without
+any body.
+That is, each profile entry is on one line, with a
+keyword followed by a colon (:) followed by text particular to
+the keyword.
+.br
+\(rh\ \ \&
+.i "This file must not have blank lines."
+.br
+The keywords
+may have any combination of upper and lower case.
+(See Appendix
+B for a description of message formats.)
+.pp
+For the average MH user, the only profile entry of
+importance is \*(lqPath\*(rq.
+Path specifies a directory in which MH
+folders and certain files such as \*(lqdraft\*(rq are found.
+The
+argument to this keyword must be a legal UNIX path that names an
+existing directory.
+If this path is unrooted (i.e., does not
+begin with a \fB/\fR), it will be presumed to start from the
+user's $HOME directory.
+All folder and message references within
+MH will relate to this path unless full path names are used.
+.pp
+Message protection defaults to 664, and folder protection to
+751.
+These may be changed by profile entries \*(lqMsg-Protect\*(rq
+and \*(lqFolder-Protect\*(rq, respectively.
+The argument to these
+keywords is an octal number which is used as the UNIX file mode.\**
+.(f
+\**See
+.i chmod (I)
+in the
+.i "UNIX Programmer's Manual" .[5]
+.)f
+.pp
+When an MH program starts running, it looks through the
+user's profile for an entry with a keyword matching the program's
+name.
+For example, when
+.i comp
+is run, it looks for a \*(lqcomp\*(rq
+profile entry.
+If one is found, the text of the profile entry is
+used as the default switch setting until all defaults are overridden
+by explicit switches passed to the program as arguments.
+Thus the profile
+entry \*(lqcomp:\0\-form\0standard.list\*(rq would direct
+.i comp
+to use the
+file \*(lqstandard.list\*(rq as the message skeleton.
+If an explicit
+form switch is given to the
+.i comp
+command, it will override the
+switch obtained from the profile.
+.pp
+In UNIX, a program may exist under several names, either by
+linking or aliasing.
+The actual invocation name is used by an MH
+program when scanning for its profile defaults.
+Thus, each MH program
+may have several names by which it can be invoked, and each name
+may have a different set of default switches.
+For example, if
+.i comp
+is invoked by the name
+.i icomp ,
+the profile entry
+\*(lqicomp\*(rq will control the default switches for this invocation of
+the
+.i comp
+program.
+This provides a powerful
+definitional facility for commonly used switch settings.
+.pp
+The default editor
+for editing within
+.i comp ,
+.i repl ,
+.i forw ,
+and
+.i dist ,
+is \*(lq/bin/ned\*(rq.\**
+.(f
+\**See Ref. 6 for a description of
+the NED text editor.
+.)f
+A different editor may be used by specifying
+the profile entry
+\*(lqEditor: \*(rq.
+The argument to \*(lqEditor\*(rq is the name of an
+executable program or shell command file which can be found via
+the user's $PATH defined search path, excluding the current
+directory.
+The \*(lqEditor:\*(rq profile specification
+may in turn be overridden by a \*(lq\-editor\0<editor>\*(rq
+profile switch associated with
+.i comp ,
+.i repl ,
+.i forw ,
+or
+.i dist .
+Finally, an explicit editor switch specified with any
+of these four commands will have ultimate precedence.
+.pp
+During message composition, more than one editor may be
+used.
+For example, one editor (such as
+.i prompter )
+may be used
+initially, and a second editor may be invoked later to revise
+the message being composed
+(see the discussion of
+.i comp
+in Section 5 for details).
+A profile entry \*(lq<lasteditor>\-next:\0<editor>\*(rq specifies the name of
+the editor to be used after a particular editor.
+Thus \*(lqcomp:\0\-e\0prompter\*(rq
+causes the initial text to be collected by
+.i prompter ,
+and the profile entry \*(lqprompter\-next:\0ed\*(rq names ed as the
+editor to be invoked for the next round of editing.
+.pp
+Some of the MH commands, such as
+.i show ,
+can be used on
+message folders owned by others, if those folders are readable.
+However,
+you cannot write in someone else's folder.
+All the MH command
+actions not requiring write permission may be used with
+a \*(lqread-only\*(rq folder.
+In a writable folder, a file named
+\*(lqcur\*(rq is used to contain its current message name.
+For read-only folders, the current message name is
+stored in the user's profile.
+.pp
+Table 1 lists examples of the currently defined profile
+entries, typical arguments, and the programs that reference the
+entries.
+.in .9i
+.ll -.9i
+.ta 2.3i
+.sp 30p
+.ce
+Table 1
+.sp 8p
+.ce
+P\s-2ROFILE\s0 C\s-2OMPONENTS\s0
+.hl \" ~12p preceding + 1v (12p) after
+.nf
+^^MH Programs that
+^Keyword and Argument~^\ Use Component\h'|\n(.lu-.9i'\v'4p'\l'|0'\v'-4p' \" \l'..' does underlining
+.sp
+^Path:\0Mail~^All
+^Current-Folder:\0inbox~^Most
+^Editor:\0/bin/ed~^\fIcomp, dist, forw, repl\fR
+^Msg\-Protect:\0644~^\fIinc\fR
+^Folder\-Protect:\0711~^\fIfile, inc, pick\fR
+^<program>:\0default switches~^All
+^cur\-<read-onlyfolder>:\0172~^Most
+^prompter\-next:\0ed~^\fIcomp, dist, forw, repl\fR
+.hl
+.ll +.9i
+.in 0
+.fi
+.pp
+Path
+.u should
+be present.
+Folder is maintained
+automatically by many MH commands (see the \*(lqContext\*(rq sections of
+the individual commands in Sec. V).
+All other entries are optional,
+defaulting to the values described above.
+.uh "MESSAGE NAMING"
+.pp
+Messages may be referred to explicitly or implicitly when
+using MH commands.
+A formal syntax of message names is given in Appendix C, but the
+following description should be sufficient for most MH users.
+Some details of message naming that apply only to certain
+commands are included in the description of those
+commands.
+.pp
+Most of the MH commands accept arguments specifying one or
+more folders, and one or more messages to operate on.
+The use of
+the word \*(lqmsg\*(rq as an argument to a command means that exactly one
+message name may be specified.
+A message name may be a number,
+such as 1, 33, or 234, or it may be
+one of the \*(lqreserved\*(rq message names:
+first, last, prev, next, and cur.
+(As a shorthand, a
+period (\*.) is equivalent to cur.)
+The meanings of these names
+are straightforward: \*(lqfirst\*(rq is the first message in the
+folder; \*(lqlast\*(rq is the last
+message in the folder; \*(lqprev\*(rq is the
+message numerically previous to the current message; \*(lqnext\*(rq
+is the message numerically following the current message; \*(lqcur\*(rq
+(or \*(lq\*.\*(rq) is the current message in the folder.
+.pp
+The default in commands that take a \*(lqmsg\*(rq argument is
+always \*(lqcur\*(rq.
+.pp
+The word \*(lqmsgs\*(rq indicates that several messages may be
+specified.
+Such a specification consists of several message
+designations separated by spaces.
+A message designation is
+either a message name or a message range.
+A message range is a
+specification of the form name1\-name2 or name1:n, where name1 and
+name2 are message names and n is an integer.
+The first form
+designates all the messages from name1 to name2 inclusive; this
+must be a non-empty range.
+The second form specifies up to n
+messages, starting with name1 if name1 is a number, or first,
+cur, or next, and ending with name1 if name1 is last or
+prev.
+This interpretation of n is overridden if n is preceded
+by a plus sign or a minus sign;
++n always means up to n messages starting with
+name1, and \-n always means up to n messages ending with name1.
+Repeated specifications of the same message have the same effect
+as a single specification of
+the message.
+Examples of
+specifications are:
+
+.(b
+1 5 7\-11 22
+first 6 8 next
+first\-10
+last:5
+.)b
+.pp
+The message name \*(lqall\*(rq is a shorthand for \*(lqfirst\-last\*(rq,
+indicating all of the messages in the folder.
+.pp
+The limit on the number of messages in an expanded message
+list is generally 999\*-the maximum number of messages in a
+folder.
+However, the
+.i show
+command and the
+commands `\fIpick\0\-scan\fR' and `\fIpick\0\-show\fR'
+are constrained to have argument lists
+that are no more than 512 characters long.
+(Under Version 7 UNIX this limit is 4096.)
+.pp
+In commands that accept \*(lqmsgs\*(rq arguments, the default is
+either cur or all, depending on which makes more sense.
+.pp
+In all of the MH commands, a plus sign preceding an argument
+indicates a folder name.
+Thus, \*(lq+inbox\*(rq is the name of the
+user's standard inbox.
+If an explicit folder argument is given
+to an MH command, it will become the current folder (that is,
+the \*(lqCurrent-Folder:\*(rq entry
+in \*(lq\*.mh\(ruprofile\*(rq will be changed to this
+folder).
+In the case of the
+.i file
+and
+.i pick
+commands, which
+can have multiple output folders, a new source folder (other than
+the default current folder) is specified by \*(lq\-src\0+folder\*(rq.
+.uh "OTHER MH CONVENTIONS"
+.pp
+One very powerful feature of MH is that the MH commands may
+be issued from any current directory, and the proper path to
+the appropriate folder(s) will be taken from the user's profile.
+If the MH path is not appropriate for a specific folder or file,
+the automatic prepending of the MH path can be avoided by
+beginning a folder or file name with \fB/\fR.
+Thus any specific full
+path may be specified.
+.pp
+Arguments to the various programs may be given in any order,
+with the exception of a few switches whose arguments must follow
+immediately, such as \*(lq\-src\0+folder\*(rq for \fIpick\fR and \fIfile\fR.
+.pp
+Whenever an MH command prompts the user, the valid options
+will be listed in response to a <RETURN>.
+(The first of the
+listed options is the default if end-of-file is encountered, such
+as from a command file.) A valid response is any \fIunique\fR
+abbreviation of one of the listed options.
+.pp
+Standard UNIX documentation conventions are used in this report
+to describe MH command syntax.
+Arguments enclosed in brackets
+([ ]) are optional; exactly one of the arguments enclosed
+within braces ({ }) must be specified, and all other
+arguments are required.
+The use of ellipsis dots (...) indicates
+zero or more repetitions of the previous item.
+For example,
+\*(lq+folder ...\*(rq would indicate that one or more \*(lq+folder\*(rq arguments
+is required and \*(lq[+folder ...]\*(rq indicates that 0 or more
+\*(lq+folder\*(rq arguments may be given.
+.pp
+MH departs from UNIX standards by using switches that consist of
+more than one character, e.g. \*(lq\-header\*(rq.
+To minimize typing,
+only a unique abbreviation of a switch need be typed; thus, for
+\*(lq\-header\*(rq, \*(lq\-hea\*(rq is probably sufficient, depending on the
+other switches the command accepts.
+Each MH program
+accepts the switch \*(lq\-help\*(rq (which \fImust\fR be spelled out fully)
+and produces a syntax description and a list of switches.
+In the
+list of switches, parentheses indicate required characters.
+For example, all \*(lq\-help\*(rq switches will appear as \*(lq\-(help)\*(rq,
+indicating that no abbreviation is accepted.
+.pp
+Many MH switches have both on and off forms, such as
+\*(lq\-format\*(rq and \*(lq\-noformat\*(rq.
+In many of the descriptions in Sec. V,
+only one form is defined; the other form, often used to
+nullify profile switch settings, is assumed to be the opposite.
+.br
+.bp
+.uh "MH COMMANDS"
+.pp
+The MH package comprises 16 programs:
+
+.nf
+.in .5i
+.ta 1.5i
+^comp~^Compose a message
+^dist~^Redistribute a message
+^file~^Move messages between folders
+^folder~^Select/list status of folders
+^forw~^Forward a message
+^inc~^Incorporate new mail
+^next~^Show the next message
+^pick~^Select a set of messages by context
+^prev~^Show the previous message
+^prompter~^Prompting editor front end for composing messages
+^repl~^Reply to a message
+^rmf~^Remove a folder
+^rmm~^Remove messages
+^scan~^Produce a scan listing of selected messages
+^send~^Send a previously composed message
+^show~^Show messages
+.fi
+.re
+.pp
+These programs are described below.
+The form of the descriptions
+conforms to the standard
+form for the description of UNIX commands.
+.if t \{
+.ll 6.5i
+.lt 6.5i
+\}
+.fo '7th Edition'UNIX/32V(Rand)''
+.de SC
+.he '\\$1(1)'-%-'\\$1(1)'
+.bp
+.(x
+.ti .8i
+\\$1
+.)x
+..
+.de NA
+.b \\s-2NAME\\s0
+.ti .5i
+..
+.de SY
+.sp
+.b \\s-2SYNOPSIS\\s0
+.in 1i
+.ti .5i
+.na
+..
+.de DE
+.ad
+.sp
+.in 0
+.b \\s-2DESCRIPTION\\s0
+.sp
+.fi
+.in .5i
+..
+.de Fi
+.(b L
+.ti 0
+.b \\s-2Files\\s0
+.ta 2i
+..
+.de Pr
+.)b
+.(b L F
+.in 2.5i
+.ti 0
+.b "\\s-2Profile Components\\s0"
+.ti .5i
+..
+.de Ps
+.ti .5i
+..
+.de De
+.)b
+.(b L
+.in .5i
+.ti 0
+.b \\s-2Defaults\\s0
+..
+.de Co
+.)b
+.(b L F
+.ti 0
+.b \\s-2Context\\s0
+.br
+..
+.de En
+.)b
+.in 0
+..
+.SC COMP
+.NA
+comp \- compose a message
+
+.SY
+comp \%[\-editor\ editor] \%[\-form\ formfile] \%[file] \%[\-use]
+\%[\-nouse] \%[\-help]
+
+.DE
+\fIComp\fP is used to create a new message to be mailed.
+If
+\fIfile\fP is not specified, the file named \*(lqdraft\*(rq in the user's MH
+directory will be used.
+\fIComp\fR copies a message form to
+the file being composed and then invokes an editor on the
+file.
+The default editor is /bin/ned, which may be overridden with
+the `\-editor' switch or with a profile entry \*(lqEditor:\*(rq.
+(See Ref. 5 for a
+description of the NED text editing system.)
+The default
+message form contains the following elements:
+
+ To:
+ cc:
+ Subject:
+ ----------
+
+If the file named \*(lqcomponents\*(rq exists in the user's MH directory,
+it will be used instead of this form.
+If `\-form
+formfile' is specified, the specified formfile (from the MH
+directory) will be used as the skeleton.
+The line of dashes
+or a blank line must be left between the header and the
+body of the message for the message to be identified properly when it is
+sent (see \fIsend;\fR).
+The switch `\-use' directs \fIcomp\fR to
+continue editing an already started message.
+That is, if a
+\fIcomp\fR (or \fIdist\fR, \fIrepl\fR, or \fIforw\fR) is terminated without
+sending the message, the message can be edited again via
+\*(lqcomp \-use\*(rq.
+
+If the specified file (or draft) already exists, \fIcomp\fR will ask
+if you want to delete it before continuing.
+A reply of \fBNo\fR will abort the
+\fIcomp\fR, \fByes\fR will replace the existing draft with a blank
+skeleton, \fBlist\fR will display the draft, and \fBuse\fR will use it
+for further composition.
+
+Upon exiting from the editor, \fIcomp\fR will ask \*(lqWhat now?\*(rq.
+The valid
+responses are \fBlist\fR, to list the draft on the terminal; \fBquit\fR, to
+terminate the session and preserve the draft; \fBquit delete\fR, to terminate,
+then delete the draft; \fBsend\fR, to send the message; \fBsend verbose\fR, to
+cause the delivery process to be monitored; \fBedit <editor>\fR, to invoke
+<editor> for further editing; and \fBedit\fR, to re-edit using the
+same editor that was used on the preceding round unless a profile
+entry \*(lq<lasteditor>\-next: <editor>\*(rq names an alternative editor.
+
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`file' defaults to draft
+`\-editor' defaults to /bin/ned
+`\-nouse'
+.Co
+\fIComp\fR does not affect either the current folder or the current message.
+.En
+.SC DIST
+.NA
+dist \- redistribute a message to additional addresses
+.SY
+dist \%[+folder] \%[msg] \%[\-form\ formfile] \%[\-editor\ editor]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+.DE
+\fIDist\fR is similar to \fIforw\fR.
+It prepares the specified
+message for redistribution to addresses that (presumably) are
+not on the original address list.
+The file \*(lqdistcomps\*(rq in the
+user's MH directory, or a standard form, or the file specified by
+`\-form formfile' will be used as the blank components file to
+be prepended to the message being distributed.
+The standard form
+has the components \*(lqDistribute-to:\*(rq and \*(lqDistribute-cc:\*(rq.
+When
+the message is sent, \*(lqDistribution-Date:\0date\*(rq,
+\*(lqDistribution-From:\0name\*(rq, and
+\*(lqDistribution-Id:\0id\*(rq (if `\-msgid' is
+specified to \fIsend\fR;) will be prepended to the outgoing message.
+Only those addresses in \*(lqDistribute-To\*(rq, \*(lqDistribute-cc\*(rq, and
+\*(lqDistribute-Bcc\*(rq will be sent.
+Also, a \*(lqDistribute-Fcc:\0folder\*(rq
+will be honored (see \fIsend;\fR).
+
+\fISend\fR recognizes a message as a redistribution message by the
+existence of the field \*(lqDistribute-To:\*(rq, so don't try to
+redistribute a message with only a \*(lqDistribute-cc:\*(rq.
+
+If the `\-annotate' switch is given, each message being
+distributed will be annotated with the lines:
+
+ Distributed:\0\*(<<date\*(>>
+ Distributed:\0Distribute-to: names
+
+where each \*(lqto\*(rq list contains as many lines as required.
+This annotation
+will be done only if the message is sent directly from \fIdist\fR.
+If the
+message is not sent immediately from \fIdist\fR (i.e., if it is sent later
+via \fIsend;\fR),
+\*(lqcomp \-use\*(rq may be used to re-edit and send the constructed message, but
+the annotations won't take place.
+The '\-inplace' switch causes annotation to
+be done in place in order to preserve links to the annotated message.
+
+See \fIcomp\fR for a description of the `\-editor' switch and for options
+upon exiting from the editor.
+
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`+folder' defaults to the current folder
+`msg' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a +folder is specified, it will become the current
+folder, and the current message will be set to the message
+being redistributed.
+.En
+.SC FILE
+.NA
+file \- file message(s) in (an)other folder(s)
+.SY
+file \%[\-src\ +folder] \%[msgs] \%[\-link] \%[\-preserve] \%+folder\ ...
+\%[\-nolink] \%[\-nopreserve]
+\%[\-file\ file] \%[\-nofile] \%[\-help]
+.DE
+\fIFile\fR moves (\fImv\fR(I)) or links (\fIln\fR(I)) messages from a
+source folder into one or more destination folders.
+If you think
+of a message as a sheet of paper, this operation is not
+unlike filing the sheet of paper (or copies) in file cabinet
+folders.
+When a message is filed, it is linked into the
+destination folder(s) if possible, and is copied otherwise.
+As long
+as the destination folders are all on the same file system, multiple filing
+causes little storage overhead.
+This facility provides a good way to cross-file or multiply-index
+messages.
+For example, if a message is received from Jones about
+the ARPA Map Project, the command
+
+ file\0cur\0+jones\0+Map
+
+would allow the message to be found in either of the two
+folders `jones' or `Map'.
+
+The option `\-file file' directs \fIfile\fR to use the specified
+file as the source message to be filed, rather than a message from
+a folder.
+
+If a destination folder doesn't exist, \fIfile\fR will ask if you
+want to create one.
+A negative response will abort the file
+operation.
+
+`\-link' preserves the source folder copy of the message
+(i.e., it does a \fIln\fR(I) rather than a \fImv\fR(I)), whereas,
+`\-nolink' deletes the \*(lqfiled\*(rq messages from the source
+folder.
+Normally, when a message is filed, it is assigned the
+next highest number available in each of the destination folders.
+Use of the `\-preserve' switch will override this message
+\*(lqrenaming\*(rq, but name conflicts may occur, so
+use this switch cautiously.
+(See \fIpick\fR for more details on
+message numbering.)
+
+If `\-link' is not specified (or `\-nolink' is specified),
+the filed messages will be removed (unlink(II)) from the
+source folder.
+
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.Ps
+^Folder\-Protect:~^To set mode when creating a new folder
+.De
+`\-src +folder' defaults to the current folder
+`msgs' defaults to cur
+`\-nolink'
+`\-nopreserve'
+`\-nofile'
+.Co
+If `\-src +folder' is given, it will become the
+current folder for future MH commands.
+If neither `\-link' nor
+`all' are specified, the current message in the source
+folder will be set to the last message specified; otherwise, the
+current message won't be changed.
+.En
+.SC FOLDER
+.NA
+folder \- set/list current folder/message
+.SY
+folder \%[+folder] \%[msg] \%[\-all] \%[\-fast] \%[\-nofast] \%[\-up] \%[\-down]
+\%[\-header] \%[\-noheader] \%[\-total] \%[\-nototal] \%[\-pack] \%[\-nopack]
+\%[\-help]
+
+.ti .5i
+folders <equivalent to 'folder \-all'>
+.DE
+Since the MH environment is the shell, it is easy to lose
+track of the current folder from day to day.
+\fIFolder\fR will
+list the current folder, the number of messages in it, the
+range of the messages (low-high), and the current message within
+the folder, and will flag a selection list or extra files if they
+exist.
+An example of the output is:
+
+ inbox+ has 16 messages ( 3\- 22); cur= 5.
+
+If a `+folder' and/or `msg' are specified, they will
+become the current folder and/or message.
+An `\-all' switch
+will produce a line for each folder in the user's MH directory,
+sorted alphabetically.
+These folders are preceded by the read-only
+folders, which occur as \*.mh\(ruprofile \*(lqcur\-\*(rq entries.
+For example,
+
+.nf
+.ta 1.5i 2.1i 2.7i 3.5i
+^~Folder\ \ ^^~#\ of\ ^^messages~^^(~\ range\~ );\ ^cur msg (other files)
+^~/fsd/rs/m/tacc\ \ ^^has~35\ ^^messages~^^(~1\-\035);\ ^cur=\ 23.
+^~/rnd/phyl/Mail/EP\ \ ^^has~82\ ^^messages~^^(~1\-108);\ ^cur=\ 82.
+^~f\&f\ \ ^^has~4\ ^^messages~^^(~1\-\0\04);\ ^cur=\ \01.
+^~inbox+\ ^^has~16\ ^^messages~^^(~3\-\022);\ ^cur=\ \05.
+^~mh\ \ ^^has~76\ ^^messages~^^(~1\-\076);\ ^cur=\ 70.
+^~notes\ \ ^^has~2\ ^^messages~^^(~1\-\0\02);\ ^cur=\ \01.
+^~ucom\ \ ^^has~124\ ^^messages~^^(~1\-124);\ ^cur=\ \06; (select).
+
+^^^~TOTAL=\0339\ ^messages\0in\0\07\0Folders.
+.re
+.fi
+
+The \*(lq+\*(rq after inbox indicates that it is the current folder.
+The \*(lq(select)\*(rq indicates that the folder ucom has a selection
+list produced by \fIpick\fR.
+If \*(lqothers\*(rq had appeared in parentheses at
+the right of a line, it would indicate that there are files in
+the folder directory that don't belong under the MH file naming
+scheme.
+
+The header is output if either an `\-all' or a `\-header' switch
+is specified; it is suppressed by `\-noheader'.
+Also, if \fIfolder\fR
+is invoked by a name ending with \*(lqs\*(rq (e.g., \fIfolders\fR),
+`\-all' is assumed.
+A `\-total' switch will produce only the
+summary line.
+
+If `\-fast' is given, only the folder name (or names in the
+case of `\-all') will be listed.
+(This is faster because the
+folders need not be read.)
+
+The switches `\-up' and `\-down' change the folder to be the
+one above or below the current folder.
+That is, \*(lqfolder \-down\*(rq
+will set the folder to \*(lq<current\-folder>/select\*(rq, and if the
+current folder is a selection-list folder, \*(lqfolder \-up\*(rq will
+set the current folder to the parent of the selection-list.
+(See \fIpick\fR for details on selection-lists.)
+
+The `\-pack' switch will compress the message names in a folder, removing
+holes in message numbering.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^/bin/ls~^To fast-list the folders
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to the current folder
+`msg' defaults to none
+`\-nofast'
+`\-noheader'
+`\-nototal'
+`\-nopack'
+.Co
+If `+folder' and/or `msg' are given, they will become the
+current folder and/or message.
+.En
+.SC FORW
+.NA
+forw \- forward messages
+.SY
+forw \%[+folder] \%[msgs] \%[\-editor\ editor] \%[\-form\ formfile]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+.DE
+\fIForw\fR may be used to prepare a message containing other
+messages.
+It constructs the new message from the components file
+or `\-form formfile' (see \fIcomp\fR), with a body composed of the
+message(s) to be forwarded.
+An editor is invoked as in \fIcomp\fR,
+and after editing is complete, the user is prompted before the message
+is sent.
+
+If the `\-annotate' switch is given, each message being
+forwarded will be annotated with the lines
+
+ Forwarded: \*(<<date\*(>>
+ Forwarded: To: names
+ Forwarded: cc: names
+
+where each \*(lqTo:\*(rq and \*(lqcc:\*(rq list contains as many lines as required.
+This annotation will be done only if the message is sent directly
+from \fIforw\fR.
+If the message is not sent immediately from \fIforw\fR,
+\*(lqcomp \-use\*(rq may be used in a later session to re-edit and send
+the constructed message, but the annotations won't take place.
+The `\-inplace' switch permits annotating a message in place in
+order to preserve its links.
+
+See \fIcomp\fR for a description of the `\-editor' switch.
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^Current-Folder:~^To find the default current folder
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`+folder' defaults to the current folder
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a +folder is specified, it will become
+the current folder, and the current message will be set to
+the first message being forwarded.
+.En
+.SC INC
+.NA
+inc \- incorporate new mail
+.SY
+inc \%[+folder] \%[\-audit\ audit-file] \%[\-help]
+.DE
+\fIInc\fR incorporates mail from the user's incoming mail drop
+(\*.mail) into an MH folder.
+If `+folder' isn't specified,
+the folder named \*(lqinbox\*(rq in the user's MH directory will be used.
+The
+new messages being incorporated are assigned numbers starting
+with the next highest number in the folder.
+If the specified (or
+default) folder doesn't exist, the user will be queried prior to
+its creation.
+As the messages are processed, a \fIscan\fR listing
+of the new mail is produced.
+
+If the user's profile contains a \*(lqMsg\-Protect: nnn\*(rq entry, it
+will be used as the protection on the newly created messages,
+otherwise the MH default of 664 will be used.
+During all
+operations on messages, this initially assigned protection will
+be preserved for each message, so \fIchmod\fR(I) may be used to set a
+protection on an individual message, and its protection will be
+preserved thereafter.
+
+If the switch `\-audit audit-file' is specified (usually as a
+default switch in the profile), then \fIinc\fR will append a header
+line and a line per message to the end of the specified
+audit-file with the format:
+
+.nf
+.ti 1i
+\*(<<inc\*(>> date
+.ti 1.5i
+<scan line for first message>
+.ti 1.5i
+<scan line for second message>
+.ti 2.5i
+<etc.>
+.fi
+
+This is useful for keeping track of volume and source of incoming
+mail.
+Eventually, \fIrepl\fR, \fIforw\fR, \fIcomp\fR, and \fIdist\fR may also
+produce audits to this (or another) file, perhaps with
+\*(lqMessage-Id:\*(rq information to keep an exact correspondence history.
+\*(lqAudit-file\*(rq will be in the user's MH directory unless a full
+path is specified.
+
+\fIInc\fR will incorporate even illegally formatted messages into the
+user's MH folder, inserting a blank line prior to the offending
+component and printing a comment identifying the bad message.
+
+In all cases, the \*.mail file will be zeroed.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^$HOME/\*.mail~^The user's mail drop
+^<mh-dir>/audit-file~^Audit trace file (optional)
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Folder\-Protect:~^For protection on new folders
+.Ps
+^Msg\-Protect:~^For protection on new messages
+.De
+`+folder' defaults to \*(lqinbox\*(rq
+.Co
+The folder into which the message is
+being incorporated will become the
+current folder, and the first message incorporated will be the
+current message.
+This leaves the context ready for a \fIshow\fR
+of the first new message.
+.En
+.SC NEXT
+.NA
+next \- show the next message
+.SY
+next \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+.DE
+\fINext\fR performs a \fIshow\fR on the next message in the
+specified (or current) folder.
+Like \fIshow\fR, it passes any
+switches on to the program \fIl\fR, which is called to list the
+message.
+This command is exactly equivalent to \*(lqshow next\*(rq.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+.Co
+If a folder is specified, it will become the current folder, and the
+message that is shown (i.e., the next message in sequence)
+will become the current message.
+.En
+.SC PICK
+.NA
+pick \- select messages by content
+.SY
+.ta .4i 1.8i
+.nf
+.in .5i
+^pick~^^\0\-cc~^ \%[\-src\ +folder] \%[msgs] \%[\-help] \%[\-scan] \%[\-noscan]
+^^^\0\-date~^ \%[\-show] \%[\-noshow] \%[\-nofile] \%[\-nokeep]
+^^^\0\-from~^
+^^^\s+2\b'\(lt\(bv\(bv\(lk\(bv\(bv\(lb'\s0 \-search~\s+2\b'\(rt\(bv\(bv\(rk\(bv\(bv\(rb'\s0^ pattern
+^^^\0\-subject~^
+^^^\0\-to~^ \%[\-file \%[\-preserve] \%[\-link] \%+folder\ ... \%[\-nopreserve] \%[\-nolink] ]
+^^^\0\-\-component~^ \%[\-keep \%[\-stay] \%[\-nostay] \%[+folder\ ...]\ ]
+.fi
+
+.re
+.ti .5i
+typically:
+.in 1i
+pick\0\-from\0jones\0\-scan
+.br
+pick\0\-to\0holloway
+.br
+pick\0\-subject\0ned\0\-scan\0\-keep
+.DE
+\fIPick\fR searches messages within a folder for the specified
+contents, then performs several operations on the selected
+messages.
+
+A modified \fIgrep\fR(I) is used to perform the searching, so the
+full regular expression (see \fIed\fR(I)) facility is available
+within `pattern'.
+With `\-search', pattern is used directly,
+and with the others, the grep pattern constructed is:
+
+.ti +.5i
+\*(lq^component:\*.\*(**pattern\*(rq
+
+This means that the pattern specified for a `\-search' will be
+found everywhere in the message, including the header and the body,
+while the other search requests are limited to the single
+specified component.
+The expression `\-\-component pattern'
+is a shorthand for
+specifying `\-search \*(lqcomponent:\*.\*(**pattern\*(rq\ '; it is used to pick
+a component not in the set [cc date from subject to].
+An
+example is \*(lqpick \-\-reply\-to pooh \-show\*(rq.
+
+Searching is performed on a per-line basis.
+Within the header of
+the message, each component is treated as one long line, but in
+the body, each line is separate.
+Lower-case letters in the
+search pattern will match either lower or upper case in the
+message, while upper case will match only upper case.
+
+Once the search has been performed, the selected messages
+are scanned (see \fIscan\fR) if the `\-scan' switch is given, and
+then they are shown (see \fIshow\fR) if the `\-show' switch is
+given.
+After these two operations, the file operations (if
+requested) are performed.
+
+The `\-file' switch operates exactly like the \fIfile\fR command, with the
+same meaning for the `\-preserve' and `\-link' switches.
+
+The `\-keep' switch is similar to `\-file', but it produces a folder that
+is a subfolder of the folder being searched and defines it as
+the current folder (unless the `\-stay' flag is used).
+This
+subfolder contains the messages which matched the search
+criteria.
+All of the MH commands may be used with the sub-folder
+as the current folder.
+This gives the user considerable power
+in dealing with subsets of messages in a folder.
+
+The messages in a folder produced by `\-keep' will always have the
+same numbers as they have in the source folder (i.e., the
+`\-preserve' switch is automatic).
+This way, the message
+numbers are consistent with the folder from which the messages
+were selected.
+Messages are not removed from the source folder
+(i.e., the `\-link' switch is assumed).
+If a `+folder' is not
+specified, the standard name \*(lqselect\*(rq will be used.
+(This is the
+meaning of \*(lq(select)\*(rq when it appears in the output of the
+\fIfolder\fR command.) If `+folder' arguments are given to
+`\-keep', they will be used rather than \*(lqselect\*(rq for the names
+of the subfolders.
+This allows for several subfolders to be
+maintained concurrently.
+
+When a `\-keep' is performed, the subfolder becomes the current folder.
+This can be overridden by use
+of the `\-stay' switch.
+
+Here's an example:
+
+.nf
+\01 % folder +inbox
+\02 inbox+ has 16 messages ( 3\- 22); cur= 3.
+\03 % pick \-from dcrocker
+\04 6 hits.
+\05 [+inbox/select now current]
+\06 % folder
+\07 inbox/select+ has \06 messages ( 3\- 16); cur= 3.
+\08 % scan
+.ds p \\h'\\w'+'u'
+\09 \03+ 6/20 Dcrocker Re: ned file update issue...
+10 \06\*p 6/23 Dcrocker removal of files from /tm...
+11 \08\*p 6/27 Dcrocker Problems with the new ned...
+12 13\*p 6/28 d\h'\w'D'u-\w'd'u'crocker newest nned \*(<<I would ap...
+13 15\*p 7/\05 Dcrocker nned \*(<<Last week I asked...
+14 16\*p 7/\05 d\h'\w'D'u-\w'd'u'crocker message id format \*(<<I re...
+15 % show all | print
+16 [produce a full listing of this set of messages on the line printer.]
+17 % folder \-up
+18 inbox+ has 16 messages ( 3\- 22); cur= 3; (select).
+19 % folder \-down
+20 inbox/select+ has 6 messages ( 3\- 16); cur= 3.
+21 % rmf
+22 [+inbox now current]
+23 % folder
+24 inbox+ has 16 messages ( 3\- 22); cur= 3.
+.fi
+
+This is a rather lengthy example, but it shows the power of the
+MH package.
+In item 1, the current folder is set to inbox.
+In 3,
+all of the messages from dcrocker are found in inbox and linked
+into the folder \*(lqinbox/select\*(rq.
+(Since no action switch is
+specified, `\-keep' is assumed.) Items 6 and 7 show that this
+subfolder is now the current folder.
+Items 8 through 14 are a
+\fIscan\fR of the selected messages (note that they are all from dcrocker
+and are all in upper and lower case).
+Item 15 lists all of the messages to
+the high-speed printer.
+Item 17 directs \fIfolder\fR to set the
+current folder to the parent of the selection-list folder, which
+is now current.
+Item 18 shows that this has been done.
+Item 19 resets
+the current folder to the selection list, and 21 removes the
+selection-list folder and resets the current folder to the
+parent folder, as shown in 22 and 23.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Folder\-Protect:~^For protection on new folders
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`\-src +folder' defaults to current
+`msgs' defaults to all
+.fi
+`\-keep +select' is the default if no `\-scan', `\-show', or `\-file' is specified
+.Co
+If a `\-src +folder' is specified, it will
+become the current folder, unless a `\-keep' with 0 or 1
+folder arguments makes the selection-list subfolder the
+current folder.
+Each selection-list folder will have its
+current message set to the first of the messages linked into
+it unless the selection list already existed, in which case the
+current message won't be changed.
+.En
+.SC PREV
+.NA
+prev \- show the previous message
+.SY
+prev \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+.DE
+\fIPrev\fR performs a \fIshow\fR on the previous message in the specified
+(or current) folder.
+Like \fIshow\fR, it passes any switches on to the
+program \fIl\fR, which is called to list the message.
+This command
+is exactly equivalent to \*(lqshow prev\*(rq.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+.Co
+If a folder is specified, it will become current, and the
+message that is shown (i.e., the previous message in sequence)
+will become the current message.
+.En
+.SC PROMPTER
+.NA
+prompter \- prompting editor front end
+.SY
+This program is not called directly but takes the place
+of an editor and acts as an editor front end.
+
+.ti .5i
+prompter \%[\-erase\ chr] \%[\-kill\ chr] \%[\-help]
+.DE
+\fIPrompter\fR is an editor which allows rapid composition of
+messages.
+It is particularly useful to network and low-speed
+(less than 2400 baud) users of MH.
+It is an MH program in that
+it can have its own profile entry with switches, but it can't
+be invoked directly as all other MH commands can; it is an editor
+in that it is invoked by an \*(lq\-editor prompter\*(rq switch or by the
+profile entry \*(lqEditor: prompter\*(rq, but functionally it is merely
+a text-collector and not a true editor.
+
+\fIPrompter\fR expects to be called from \fIcomp\fR, \fIrepl\fR, \fIdist\fR, or
+\fIforw\fR, with a draft file as an argument.
+For example, \*(lqcomp
+\-editor prompter\*(rq will call \fIprompter\fR with the file \*(lqdraft\*(rq already set
+up with blank components.
+For each blank component it finds in
+the draft, it prompts the user and accepts a response.
+A
+<RETURN> will cause the whole component to be left out.
+A \*(lq\\\*(rq
+preceding a <RETURN> will continue the response on the next line,
+allowing for multiline components.
+
+Any component that is non-blank will be copied and echoed to the
+terminal.
+
+The start of the message body is prompted by a line of
+dashes.
+If the body is non-blank, the prompt is
+\*(lq--------Enter additional text\*(rq.
+Message-body typing is terminated with
+a <CTRL-D> (or <OPEN>).
+Control is returned to the calling
+program, where the user is asked \*(lqWhat now?\*(rq.
+See \fIcomp\fR for
+the valid options.
+
+The line editing characters for kill and erase may be
+specified by the user via the arguments \*(lq\-kill chr\*(rq and \*(lq\-erase
+chr\*(rq, where chr may be a character; or \*(lq\\nnn\*(rq, where nnn is the
+octal value for the character.
+(Again, these may come from the
+default switches specified in the user's profile.)
+
+A <DEL> during message-body typing is equivalent to
+<CTRL-D> for compatibility with NED.
+A <DEL> during
+component typing will abort the command that invoked
+\fIprompter\fR.
+.Fi
+None
+.Pr
+^prompter-next:~^To name the editor to be used on exit from \fIprompter\fR
+.De
+.Co
+None
+.En
+.SC REPL
+.NA
+repl \- reply to a message
+.SY
+repl \%[+folder] \%[msg] \%[\-editor\ editor] \%[\-inplace] \%[\-annotate]
+\%[\-help] \%[\-noinplace]
+\%[\-noannotate]
+.DE
+\fIRepl\fR aids a user in producing a reply to an existing
+message.
+In its simplest form (with no arguments), it will set up
+a message-form skeleton in reply to the current message in the
+current folder, invoke the editor, and send the composed
+message if so directed.
+The composed message is constructed as
+follows:
+
+.nf
+.in 1i
+To: <Reply-To> or <From>
+cc: <cc>, <To>
+Subject: Re: <Subject>
+In-reply-to: Your message of <Date>
+.ti +\w'In-reply-to: 'u
+<Message-Id>
+.in .5i
+.fi
+
+where field names enclosed in angle brackets (< >) indicate the
+contents of the named field from the message to which the reply
+is being made.
+Once the skeleton is constructed, an editor is
+invoked (as in \fIcomp\fR, \fIdist\fR, and \fIforw\fR).
+While in the editor,
+the message being replied to is available through a link named
+\*(lq@\*(rq.
+In NED, this means the replied-to message may be \*(lqused\*(rq
+with \*(lquse @\*(rq, or put in a window by \*(lqwindow @\*(rq.
+
+As in \fIcomp\fR, \fIdist\fR, and \fIforw\fR, the user will be queried
+before the message is sent.
+If `\-annotate' is
+specified, the replied-to message will be annotated with the
+single line
+
+.ti +.5i
+Replied: \*(<<Date\*(>>.
+
+The command
+\*(lqcomp \-use\*(rq may be used to pick up interrupted editing, as in
+\fIdist\fR and \fIforw\fR; the `\-inplace' switch annotates the message in place,
+so that all folders with links to it will see the annotation.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The constructed message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a `+folder' is specified, it will become the current
+folder, and the current message will be set to the replied-to
+message.
+.sp 2
+.En
+.SC RMF
+.NA
+rmf \- remove folder
+.SY
+rmf \%[+folder] \%[\-help]
+.DE
+\fIRmf\fR removes all of the files (messages) within the specified
+(or default) folder, and then removes the directory (folder).
+If
+there are any files within the folder which are not a part of MH,
+they will \fInot\fR be removed, and an error will be produced.
+If the
+folder is given explicitly or the current folder is a
+subfolder (i.e., a selection list from \fIpick\fR), it will be
+removed without confirmation.
+If no argument is specified and
+the current folder is not a selection-list folder, the
+user will be asked for confirmation.
+
+\fIRmf\fR irreversibly deletes messages that don't have other links,
+so use it with caution.
+
+If the folder being removed is a subfolder, the parent
+folder will become the new current folder, and \fIrmf\fR will
+produce a message telling the user this has happened.
+This
+provides an easy mechanism for selecting a set of messages,
+operating on the list, then removing the list and returning to
+the current folder from which the list was extracted.
+(See the
+example under \fIpick\fR.)
+
+The files that \fIrmf\fR will delete are cur, any file beginning
+with a comma, and files with purely numeric names.
+All others
+will produce error messages.
+
+\fIRmf\fR of a read-only folder will delete the \*(lqcur\-\*(rq entry from the
+profile without affecting the folder itself.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current, usually with confirmation
+.Co
+\fIRmf\fR will set the current folder to the parent folder if a
+subfolder is removed; or if the current folder is removed,
+it will make \*(lqinbox\*(rq current.
+Otherwise, it doesn't change the
+current folder or message.
+.En
+.SC RMM
+.NA
+rmm \- remove messages
+.SY
+rmm \%[+folder] \%[msgs] \%[\-help]
+.DE
+\fIRmm\fR removes the specified messages by renaming the message
+files with preceding commas.
+(This is the Rand-UNIX backup file
+convention.)
+
+The current message is not changed by \fIrmm\fR, so a \fInext\fR will
+advance to the next message in the folder as expected.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+.Co
+If a folder is given, it will become current.
+.En
+.SC SCAN
+.NA
+scan \- produce a one-line-per-message scan listing
+.SY
+scan \%[+folder] \%[msgs] \%[\-f\&f] \%[\-header] \%[\-help]
+\%[\-nof\&f] \%[\-noheader]
+.DE
+\fIScan\fR produces a one-line-per-message listing of the specified
+messages.
+Each \fIscan\fR line contains the message number (name),
+the date, the \*(lqFrom\*(rq field, the \*(lqSubject\*(rq field, and, if room
+allows, some of the body of the message.
+For example:
+
+.nf
+.ta .5i 1.2i 2.6i
+^ #~^^Date~^^ From~^Subject\ \ \ \ \[\*(<<Body]
+^15+~^^7/\05~^^Dcrocker~^nned \*(<<Last week I asked some of
+^16\ \-~^^7/\05~^^dcrocker~^message id format \*(<<I recommend
+^18~^^7/\06~^^Obrien~^Re: Exit status from mkdir
+^19~^^7/\07~^^Obrien~^"scan" listing format in MH
+.re
+.fi
+
+The `+' on message 15 indicates that it is the current message.
+The `\-' on message 16 indicates that it has been
+replied to, as indicated by a \*(lqReplied:\*(rq component produced by
+an `\-annotate' switch to the \fIrepl\fR command.
+
+If there is sufficient room left on the \fIscan\fR line after the
+subject, the line will be filled with text from the body,
+preceded by \*(<<.
+\fIScan\fR actually reads each of the specified
+messages and parses them to extract the desired fields.
+During parsing, appropriate error messages will be produced if
+there are format errors in any of the messages.
+
+The `\-header' switch produces a header line prior to the \fIscan\fR
+listing, and the `\-f\&f' switch will cause a form feed to be
+output at the end of the \fIscan\fR listing.
+See Appendix D.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+Defaults:
+`+folder' defaults to current
+`msgs' defaults to all
+`\-nof\&f'
+`\-noheader'
+.Co
+If a folder is given, it will become current.
+The current
+message is unaffected.
+.En
+.SC SEND
+.NA
+send \- send a message
+.SY
+send \%[file] \%[\-draft] \%[\-verbose] \%[\-format] \%[\-msgid]
+\%[\-help] \%[\-noverbose] \%[\-noformat] \%[\-nomsgid]
+.DE
+\fISend\fR will cause the specified file (default <mh-dir>/draft) to
+be delivered to each of the addresses in the \*(lqTo:\*(rq, \*(lqcc:\*(rq, and \*(lqBcc:\*(rq
+fields of the message.
+If `\-verbose' is specified, \fIsend;\fR
+will monitor the delivery of local and net mail.
+\fISend\fR with no
+argument will query whether the draft is the intended file, whereas
+`\-draft' will suppress this question.
+Once the message has
+been mailed (or queued) successfully, the file will be renamed
+with a leading comma, which allows it to be retreived until the
+next draft message is sent.
+If there are errors in the
+formatting of the message, \fIsend;\fR will abort with a (hopefully)
+helpful error message.
+
+If a \*(lqBcc:\*(rq field is encountered, its addresses will be used for
+delivery, but the \*(lqBcc:\*(rq field itself will be deleted from all
+copies of the outgoing message.
+
+Prior to sending the message, the fields \*(lqFrom: user\*(rq, and
+\*(lqDate: now\*(rq will be prepended to the message.
+If `\-msgid' is
+specified, then a \*(lqMessage-Id:\*(rq field will also be added to the
+message.
+If the message already contains a \*(lqFrom:\*(rq field, then a
+\*(lqSender: user\*(rq field will be added instead.
+(An already existing
+\*(lqSender:\*(rq field will be deleted from the message.)
+
+If the user doesn't specify `\-noformat', each of the entries in
+the \*(lqTo:\*(rq and \*(lqcc:\*(rq fields will be replaced with \*(lqstandard\*(rq format
+entries.
+This standard format is designed to be usable by all
+of the message handlers on the various systems around the
+ARPANET.
+
+If an \*(lqFcc: folder\*(rq is encountered, the message will be copied
+to the specified folder in the format in which it will appear to any
+receivers of the message.
+That is, it will have the prepended
+fields and field reformatting.
+
+If a \*(lqDistribute-To:\*(rq field is encountered, the message
+is handled as a redistribution message (see \fIdist\fR for
+details), with \*(lqDistribution-Date: now\*(rq and \*(lqDistribution-From: user\*(rq
+added.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.De
+`file' defaults to draft
+`\-noverbose'
+`\-format'
+`\-nomsgid'
+.Co
+\fISend\fR has no effect on the current message or folder.
+.En
+.SC SHOW
+.NA
+show \- show (list) messages
+.SY
+show \%[+folder] \%[msgs] \%[\-pr] \%[\-nopr] \%[\-draft] \%[\-help]
+\%[\fIl\fR\ or\ \fIpr\fR\ switches]
+.DE
+\fIShow\fR lists each of the specified messages to the standard
+output (typically, the terminal).
+The messages are listed exactly
+as they are, with no reformatting.
+A program called \fIl\fR is
+invoked to do the listing, and any switches not recognized by
+\fIshow\fR are passed along to \fIl\fR.
+
+If no \*(lqmsgs\*(rq are specified, the current message is used.
+If
+more than one message is specified, \fIl\fR will prompt for a
+<return> prior to listing each message.
+
+\fIl\fR will list each message, a page at a time.
+When the end of
+page is reached, \fIl\fR will ring the bell and wait for a <RETURN>
+or <CTRL-D>.
+If a <return> is entered, \fIl\fR will clear the
+screen before listing the next page, whereas <CTRL-D> will not.
+The switches to \fIl\fR are
+`\-p#' to indicate the page length in lines, and `\-w#' to
+indicate the width of the page in characters.
+
+If the standard output is not a terminal, no queries are made,
+and each file is listed with a one-line header and two lines of
+separation.
+
+If `\-pr' is specified, then \fIpr\fR(I) will be invoked rather than
+\fIl\fR, and the switches (other than `\-draft') will be passed
+along.
+\*(lqShow \-draft\*(rq will list the file <mh-dir>/draft if it
+exists.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^/bin/l~^Screen-at-a-time list program
+^/bin/pr~^\fIpr\fR(I)
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-nopr'
+.Co
+If a folder is given, it will become the current message.
+The last message
+listed will become the current message.
+.En
+\"
+\" On to the Appendices
+\"
+.fo ''-%-''
+.he ''''
+.(x
+.sp
+Appendix
+.)x _
+.de $c \" Major Heading printer
+.ce
+Appendix \\n+(ch
+.sp 2p
+.ce
+.b "\\s12\\$1\\s0" \" 12 Point Bold Header
+.(x
+\ \ \ \\n(ch.\\ \\ \\$2
+.)x
+.sp 45p \" 45 points or about 1/2 inch
+..
+.++ A
+.bp
+.$c "COMMAND SUMMARY\\**" "Command Summary"
+.(f
+\**All commands accept a \-help switch.
+.)f
+.in 1i
+.na
+.ti .5i
+comp \%[\-editor\ editor] \%[\-form\ formfile] \%[file] \%[\-use]
+\%[\-nouse] \%[\-help]
+
+.ti .5i
+dist \%[+folder] \%[msg] \%[\-form\ formfile] \%[\-editor\ editor]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+
+.ti .5i
+file \%[\-src\ +folder] \%[msgs] \%[\-link] \%[\-preserve] \%+folder\ ...
+\%[\-nolink] \%[\-nopreserve]
+\%[\-file\ file] \%[\-nofile] \%[\-help]
+
+.ti .5i
+folder \%[+folder] \%[msg] \%[\-all] \%[\-fast] \%[\-nofast] \%[\-up] \%[\-down]
+\%[\-header] \%[\-noheader] \%[\-total] \%[\-nototal] \%[\-pack] \%[\-nopack]
+\%[\-help]
+
+.ti .5i
+forw \%[+folder] \%[msgs] \%[\-editor\ editor] \%[\-form\ formfile]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+
+.ti .5i
+inc \%[+folder] \%[\-audit\ audit-file] \%[\-help]
+
+.ti .5i
+next \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+
+.ta .4i 1.8i
+.nf
+.in .5i
+^pick~^^\0\-cc~^ \%[\-src\ +folder] \%[msgs] \%[\-help] \%[\-scan] \%[\-noscan]
+^^^\0\-date~^ \%[\-show] \%[\-noshow] \%[\-nofile] \%[\-nokeep]
+^^^\0\-from~^
+^^^\s+2\b'\(lt\(bv\(bv\(lk\(bv\(bv\(lb'\s0 \-search~\s+2\b'\(rt\(bv\(bv\(rk\(bv\(bv\(rb'\s0^ pattern
+^^^\0\-subject~^
+^^^\0\-to~^ \%[\-file \%[\-preserve] \%[\-link] \%+folder\ ... \%[\-nopreserve] \%[\-nolink] ]
+^^^\0\-\-component~^ \%[\-keep \%[\-stay] \%[\-nostay] \%[+folder\ ...]\ ]
+.fi
+.re
+
+.ti .5i
+prev \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+
+.ti .5i
+prompter \%[\-erase\ chr] \%[\-kill\ chr] \%[\-help]
+
+.ti .5i
+repl \%[+folder] \%[msg] \%[\-editor\ editor] \%[\-inplace] \%[\-annotate]
+\%[\-help] \%[\-noinplace]
+\%[\-noannotate]
+
+.ti .5i
+rmf \%[+folder] \%[\-help]
+
+.ti .5i
+rmm \%[+folder] \%[msgs] \%[\-help]
+
+.ti .5i
+scan \%[+folder] \%[msgs] \%[\-f\&f] \%[\-header] \%[\-help]
+\%[\-nof\&f] \%[\-noheader]
+
+.ti .5i
+send \%[file] \%[\-draft] \%[\-verbose] \%[\-format] \%[\-msgid]
+\%[\-help] \%[\-noverbose] \%[\-noformat] \%[\-nomsgid]
+
+.ti .5i
+show \%[+folder] \%[msgs] \%[\-pr] \%[\-nopr] \%[\-draft] \%[\-help]
+\%[\fIl\fR\ or\ \fIpr\fR\ switches]
+.ad
+.in 0
+\".+c "MESSAGE FORMAT" "Message Format"
+.if t \{
+.ll 32P
+.lt 32P
+\}
+.bp
+.$c "MESSAGE FORMAT" "Message Format"
+.pp
+This section paraphrases the format of ARPANET text messages
+given in Ref. 6.
+
+.lp
+ASSUMPTIONS
+.np
+Messages
+are expected to consist of lines of text.
+Graphics and binary data are not handled.
+.np
+No data compression is accepted.
+All text is clear
+ASCII 7-bit data.
+
+.lp
+LAYOUT
+.lp
+A general \*(lqmemo\*(rq framework is used.
+A message consists of a
+block of information in a rigid format, followed by general
+text with no specified format.
+The rigidly formatted first
+part of a message is called the header, and the free-format
+portion is called the body.
+The header must always
+exist, but the body is optional.
+
+.lp
+THE HEADER
+.lp
+Each header item can be viewed as a single logical line of ASCII
+characters.
+If the text of a header item extends across several
+real lines, the continuation lines are indicated by leading
+spaces or tabs.
+.lp
+Each header item is called a component and is composed of a
+keyword or name, along with associated text.
+The keyword begins at the
+left margin, may contain spaces or tabs, may not exceed 63
+characters, and is terminated by a colon (:).
+Certain
+components (as identified by their keywords) must follow rigidly
+defined formats in their text portions.
+.lp
+The text for most formatted components (e.g., \*(lqDate:\*(rq and \*(lqMessage-Id:\*(rq)
+is produced automatically.
+The only ones entered by the
+user are address fields such as \*(lqTo:\*(rq, \*(lqcc:\*(rq, etc.
+ARPA addresses
+are assigned mailbox names and host computer specifications.
+The
+rough format is \*(lqmailbox at host\*(rq, such as \*(lqBorden at Rand-Unix\*(rq.
+Multiple addresses are separated by commas.
+A missing host is
+assumed to be the local host.
+
+.ne 10
+.lp
+THE BODY
+.lp
+A blank line signals that all following text up to the end of the file
+is the body.
+(A blank line is defined as a pair of
+<end-of-line> characters with \fIno\fR characters in between.)
+No formatting is expected or enforced within the body.
+.lp
+Within MH, a line consisting of dashes is accepted
+as the header delimiter.
+This is a cosmetic feature applying
+only to locally composed mail.
+.bp
+.$c "MESSAGE NAME BNF" "Message Name BNF"
+
+.ta 1.2i 1.8i 3.2i
+.nf
+.in 1i
+^msgs~^^:=~^^msgspec~^|
+^^^^msgs msgspec
+
+^msgspec~^^:=~^^msg~^|
+^^^^^msg-range~^|
+^^^^msg-sequence
+
+^msg~^^:=~^^msg-name~^|
+^^^^<number>^
+
+^msg-name~^^:=~^^\*(lqfirst\*(rq~^|
+^^^^^\*(lqlast\*(rq~^|
+^^^^^\*(lqcur\*(rq~^|
+^^^^^\*(lq\*.\*(rq~^|
+^^^^^\*(lqnext\*(rq~^|
+^^^^\*(lqprev\*(rq
+
+^msg-range~^^:=~^^msg\*(lq-\*(rqmsg~^|
+^^^^^\*(lqall\*(rq
+
+^msg-sequence~^^:=~^msg\*(lq:\*(rqsigned-number
+
+^signed-number~^^:=~^^\*(lq+\*(rq<number>~^|
+^^^^^\*(lq\--\*(rq<number>~^|
+^^^^<number>
+.re \" Reset Tabs
+.fi
+.sp
+.pp
+Where <number> is a decimal number in the range 1 to 999.
+.pp
+Msg-range specifies all of the messages in the given range
+and must not be empty.
+.pp
+Msg-sequence specifies up to <number> of messages, beginning
+with \*(lqmsg\*(rq (in the case of first, cur, next, or <number>),
+or ending with \*(lqmsg\*(rq (in the case of prev or last).
++<number> forces \*(lqstarting with msg\*(rq, and \-<number> forces
+\*(lqending with number\*(rq.
+In all cases, \*(lqmsg\*(rq must exist.
+.bp
+.$c "EXAMPLE OF SHELL COMMANDS" "Example of Shell Commands"
+.pp
+UNIX commands may be mixed with MH commands to obtain additional
+functions.
+These may be prepared as files (known as
+shell command files or
+shell scripts).
+The following example is a useful function that
+illustrate the possibilities.
+Other functions, such as copying,
+deleting, renaming, etc., can be achieved in a similar fashion.
+
+HARDCOPY
+.pp
+The command:
+
+.ti +.5i
+(scan\0\-f\&f\0\-header;\0show\0all\0\-pr\0\-f)\0|\0print
+
+produces a scan listing of the current folder, followed by a
+form feed, followed by a formatted listing of all messages
+in the folder, one per page.
+Omitting \*(lq\-pr\0\-f\*(rq will cause the
+messages to be concatenated, separated by a one-line header
+and two blank lines.
+.pp
+You can create variations on this theme, using \fIpick\fR.
+.re
+.fi
+.in 0
+.bp
+.ce
+.b \\s12REFERENCES\\s0
+.(x
+.sp
+REFERENCES
+.)x
+.sp 3
+.in .4i
+.ti 0
+1. Crocker, D. H., J. J. Vittal, K. T. Pogran, and D. A. Henderson, Jr.,
+\*(lqStandard for the Format of ARPA Network Test Messages,\*(rq \fIArpanet Request
+for Comments\fR, No. 733, Network Information Center 41952, Augmentation
+Research Center, Stanford Research Institute,
+November 1977.
+
+.ti 0
+2. Thompson, K., and D. M. Ritchie, \*(lqThe UNIX Time-sharing System,\*(rq
+\fICommunications of the ACM\fR, Vol. 17, July 1974, pp. 365-375.
+
+.ti 0
+3. McCauley, E. J., and P. J. Drongowski, \*(lqKSOS\-The Design of a Secure
+Operating System,\*(rq \fIAFIPS Conference Proceedings\fR,
+National Computer Conference,
+Vol. 48, 1979, pp. 345-353.
+
+.ti 0
+4. Crocker, David H., \fIFramework and Functions of the \*(lqMS\*(rq Personal
+Message System\fR, The Rand Corporation, R-2134-ARPA, December 1977.
+
+.ti 0
+5. Thompson, K., and D. M. Ritchie, \fIUNIX Programmer's Manual\fR, 6th ed.,
+Western Electric Company, May 1975 (available only to UNIX licensees).
+
+.ti 0
+6. Bilofsky, Walter, \fIThe CRT Text Editor NED\-Introduction and
+Reference Manual\fR, The Rand Corporation, R-2176-ARPA, December 1977.
+.bp 3
+.de $c
+.ce
+.b "\\s12\\$1\\s0" \" 12 Point Bold Header
+.(x y
+.sp
+\\$1
+.)x
+.sp 3
+..
+.pn 3
+.++ P
+.fo ''''
+.he ''-%-''
+.+c PREFACE
+.pp
+This report describes a system for dealing with messages transmitted on a
+computer. Such messages might originate with other users of the same
+computer or might come from an outside source through a network to which the user's
+computer is connected. Such computer-based message systems are
+becoming increasingly widely used, both within and outside the Department
+of Defense.
+.pp
+The message handling system MH was developed for two reasons.
+One was to investigate some
+research ideas concerning how a message system might take advantage of
+the architecture of the UNIX time-sharing operating system for
+Digital Equipment Corporation PDP-11 and VAX computers, and the special
+features of UNIX's command-level interface with the user (the
+\*(lqshell\*(rq). The other reason was to provide a better and more
+adaptable base than that of conventional designs
+on which to build a command and control message system.
+The effort has succeeded in both
+regards, although this report mainly describes the message system itself
+and how it fits in with UNIX. The main research results are being
+described and analyzed in a forthcoming Rand report.
+The system is currently being used as part
+of a tactical command and control \*(lqlaboratory,\*(rq which is also being described
+in a separate report.
+.pp
+The present report should be of interest to three groups of readers. First,
+it is a complete reference manual for the users of MH (although
+users outside of Rand must take into
+account differences from the local Rand operating system). Second, it should be
+of interest to those who have a general knowledge of computer-based
+message systems, both in civilian and military applications. Finally,
+it should be of interest to those who build large subsystems that
+interface with users, since it illustrates a new approach to such
+interfaces.
+.pp
+The MH system was developed by the first
+author, using an approach suggested by the other two authors.
+Valuable assistance was provided by Phyllis Kantar in the later
+stages of the system's implementation.
+Several colleagues
+contributed to the ideas included in this system, particularly
+Robert Anderson and David Crocker.
+In addition, valuable experience
+in message systems, and a valuable source of ideas, was available
+to us in the form of a previous message system for UNIX called
+MS, designed at Rand by David Crocker.
+.pp
+This report was prepared as part of the Rand project entitled \*(lqData
+Automation Research\*(rq, sponsored by Project AIR FORCE.
+.pn 5
+.+c SUMMARY
+.pp
+Electronic communication of text messages is becoming
+commonplace. Computer-based message systems\-software
+packages that provide tools for dealing with messages\-are used in many
+contexts. In particular, message systems are becoming
+increasingly important in command and control and intelligence
+applications.
+.pp
+This report describes a message handling system called MH.
+This system provides the user
+with tools to compose, send, receive, store, retrieve, forward, and
+reply to messages. MH has been built on the UNIX time-sharing system,
+a popular operating system developed for the DEC PDP-11 and VAX classes of
+computers.
+.pp
+A complete description of MH is given for users of
+the system. For those who do not intend to use the system, this description
+gives a general idea of what a message system is like. The system involves
+some new ideas about how large subsystems can be constructed. These design
+concepts and a comparison of MH with other message systems
+will be published in a forthcoming Rand report.
+.pp
+The interesting and unusual features of MH include the
+following: The user command interface to MH is the UNIX \*(lqshell\*(rq
+(the standard UNIX command interpreter). Each separable
+component of message handling, such as message composition or
+message display, is a separate command. Each program is driven from
+and updates a private user environment, which is stored as a file
+between program invocations. This private environment also contains
+information to \*(lqcustom tailor\*(rq MH to the individual's tastes. MH
+stores each message as a separate file under UNIX, and it utilizes the
+tree-structured UNIX file system to organize groups of files within
+separate directories or \*(lqfolders.\*(rq All of the UNIX facilities
+for dealing with files and directories, such as
+renaming, copying, deleting, cataloging, off-line printing, etc., are
+applicable to messages and directories of messages (folders). Thus,
+important capabilities needed in a message system are available in MH without
+the need (often seen in other message systems) for code that
+duplicates the facilities of the supporting operating system.
+It also allows users familiar with the shell to use MH with minimal
+effort.
+.he ''''
+.fo ''''
+.bp
+.ce
+.b \\s12CONTENTS\\s0
+.sp 3
+.xp y
+.xp x
+
+.bp \" Spare numbers for cut and paste work!
+.ft B
+
+1 1 1 1 1 1 1 1
+
+1 1 1 1 1 1 1 1
+
+1 1 1 1 1 1 1 1
+
+1 1 1 1 1 1 1 1
+
+2 2 2 2 2 2 2 2
+
+2 2 2 2 2 2 2 2
+
+2 2 2 2 2 2 2 2
+
+3 3 3 3 3 3 3 3
+
+3 3 3 3 3 3 3 3
--- /dev/null
+.(l C
+.sp 1i
+.sz +8
+.b
+MH
+.sp 0.4i
+.sz -4
+.r
+A Mail Handling System
+.sp 0.2i
+for \s-1UNIX\s+1
+.sz -4
+.sp 1i
+October, 1979
+
+Bruce Borden
+.sp 1i
+The Rand Corporation
+1700 Main Street
+Santa Monica, CA 90406
+
+(213) 399-0568 x 7463
+.)l
--- /dev/null
+DEST = $(DESTDIR)/usr/man/mann
+
+MAKEFILE = Makefile
+
+PRINT = vtroff
+
+SRCS = comp.1 \
+ dist.1 \
+ file.1 \
+ folder.1 \
+ forw.1 \
+ inc.1 \
+ next.1 \
+ pick.1 \
+ prev.1 \
+ prompter.1 \
+ repl.1 \
+ rmf.1 \
+ rmm.1 \
+ scan.1 \
+ send.1 \
+ show.1
+
+all:;
+
+clean:;
+
+depend:; @mkmf -f $(MAKEFILE)
+
+cp:; @echo Installing $(SRCS) in $(DEST)
+ @for i in $(SRCS); do cp $$i $(DEST)/`basename $$i .1`.n; done
+
+print: $(SRCS)
+ @$(PRINT) -man $?
+ @touch print
+
+update:;
--- /dev/null
+.TH COMP 1 "3 August 1983"
+.UC 4
+.SH NAME
+comp \- compose a message
+.SH SYNOPSIS
+.B comp
+[ \-editor editor ] [ \-form formfile ] [ file ] [ \-use ]
+[ \-nouse ] [ \-help ]
+.SH DESCRIPTION
+\fIComp\fP is used to create a new message to be mailed.
+If
+\fIfile\fP is not specified, the file named \*(lqdraft\*(rq in the user's MH
+directory will be used.
+\fIComp\fR copies a message form to
+the file being composed and then invokes an editor on the
+file.
+The default editor is /bin/ned, which may be overridden with
+the `\-editor' switch or with a profile entry \*(lqEditor:\*(rq.
+The default message form contains the following elements:
+.nf
+
+ To:
+ cc:
+ Subject:
+ ----------
+
+.fi
+If the file named \*(lqcomponents\*(rq exists in the user's MH directory,
+it will be used instead of this form.
+If `\-form formfile' is specified, the specified formfile (from the MH
+directory) will be used as the skeleton.
+The line of dashes
+or a blank line must be left between the header and the
+body of the message for the message to be identified properly when it is
+sent (see
+.IR send (1)).
+The switch `\-use' directs \fIcomp\fR to
+continue editing an already started message.
+That is, if a
+\fIcomp\fR (or \fIdist\fR, \fIrepl\fR, or \fIforw\fR) is terminated without
+sending the message, the message can be edited again via
+\*(lqcomp \-use\*(rq.
+.PP
+If the specified file (or draft) already exists, \fIcomp\fR will ask
+if you want to delete it before continuing.
+A reply of \fBNo\fR will abort the
+\fIcomp\fR, \fByes\fR will replace the existing draft with a blank
+skeleton, \fBlist\fR will display the draft, and \fBuse\fR will use it
+for further composition.
+.PP
+Upon exiting from the editor, \fIcomp\fR will ask \*(lqWhat now?\*(rq.
+The valid
+responses are \fBlist\fR, to list the draft on the terminal; \fBquit\fR, to
+terminate the session and preserve the draft; \fBquit delete\fR, to terminate,
+then delete the draft; \fBsend\fR, to send the message; \fBsend verbose\fR, to
+cause the delivery process to be monitored; \fBedit <editor>\fR, to invoke
+<editor> for further editing; and \fBedit\fR, to re-edit using the
+same editor that was used on the preceding round unless a profile
+entry \*(lq<lasteditor>\-next: <editor>\*(rq names an alternative editor.
+.PP
+\fIComp\fR does not affect either the current folder or the current message.
+.SH FILES
+.nf
+.ta \w'or <mh-dir>/components 'u
+/etc/mh/components The message skeleton
+or <mh-dir>/components Rather than the standard skeleton
+$HOME/\*.mh_profile The user profile
+<mh-dir>/draft The default message file
+/usr/new/send To send the composed message
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'<lasteditor>\-next: 'u
+Path: To determine the user's MH directory
+Editor: To override the use of /bin/ned as the default editor
+<lasteditor>\-next: editor to be used after exit from <lasteditor>
+.SH DEFAULTS
+.nf
+`file' defaults to draft
+`\-editor' defaults to /bin/ned
+`\-nouse'
+.fi
--- /dev/null
+.TH DIST 1 "3 August 1983"
+.UC 4
+.SH NAME
+dist \- redistribute a message to additional addresses
+.SH SYNOPSIS
+.B dist
+[ +folder ] [ msg ] [ \-form formfile ] [ \-editor editor ]
+[ \-annotate ] [ \-noannotate ]
+[ \-inplace ] [ \-noinplace ] [ \-help ]
+.SH DESCRIPTION
+\fIDist\fR is similar to \fIforw\fR.
+It prepares the specified
+message for redistribution to addresses that (presumably) are
+not on the original address list.
+The file \*(lqdistcomps\*(rq in the
+user's MH directory, or a standard form, or the file specified by
+`\-form formfile' will be used as the blank components file to
+be prepended to the message being distributed.
+The standard form
+has the components \*(lqDistribute-to:\*(rq and \*(lqDistribute-cc:\*(rq.
+When
+the message is sent, \*(lqDistribution-Date:\0date\*(rq,
+\*(lqDistribution-From:\0name\*(rq, and
+\*(lqDistribution-Id:\0id\*(rq (if `\-msgid' is
+specified to \fIsend\fR;) will be prepended to the outgoing message.
+Only those addresses in \*(lqDistribute-To\*(rq, \*(lqDistribute-cc\*(rq, and
+\*(lqDistribute-Bcc\*(rq will be sent.
+Also, a \*(lqDistribute-Fcc:\0folder\*(rq
+will be honored (see \fIsend;\fR).
+.PP
+\fISend\fR recognizes a message as a redistribution message by the
+existence of the field \*(lqDistribute-To:\*(rq, so don't try to
+redistribute a message with only a \*(lqDistribute-cc:\*(rq.
+.PP
+If the `\-annotate' switch is given, each message being
+distributed will be annotated with the lines:
+.nf
+
+ Distributed:\0\*(<<date\*(>>
+ Distributed:\0Distribute-to: names
+
+.fi
+where each \*(lqto\*(rq list contains as many lines as required.
+This annotation
+will be done only if the message is sent directly from \fIdist\fR.
+If the
+message is not sent immediately from \fIdist\fR (i.e., if it is sent later
+via \fIsend;\fR),
+\*(lqcomp \-use\*(rq may be used to re-edit and send the constructed message,
+but the annotations won't take place.
+The '\-inplace' switch causes annotation to
+be done in place in order to preserve links to the annotated message.
+.PP
+See \fIcomp\fR for a description of the `\-editor' switch and for options
+upon exiting from the editor.
+.PP
+If a +folder is specified, it will become the current
+folder, and the current message will be set to the message
+being redistributed.
+.SH FILES
+.nf
+.ta \w'or <mh-dir>/components 'u
+/etc/mh/components The message skeleton
+or <mh-dir>/components Rather than the standard skeleton
+$HOME/\*.mh\(ruprofile The user profile
+<mh-dir>/draft The default message file
+/usr/bin/send To send the composed message
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'<lasteditor>\-next: 'u
+Path: To determine the user's MH directory
+Editor: To override the use of /bin/ned as the default editor
+<lasteditor>\-next: editor to be used after exit from <lasteditor>
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to the current folder
+`msg' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.fi
--- /dev/null
+.TH FILE 1 "3 August 1983"
+.UC 4
+.SH NAME
+file \- file message(s) in (an)other folder(s)
+.SH SYNOPSIS
+file [ \-src +folder ] [ msgs ] [ \-link ] [ \-preserve ] +folder ...
+[ \-nolink] [ \-nopreserve ]
+[ \-file file ] [ \-nofile ] [ \-help ]
+.SH DESCRIPTION
+\fIFile\fR moves (\fImv\fR(1)) or links (\fIln\fR(1)) messages from a
+source folder into one or more destination folders.
+If you think
+of a message as a sheet of paper, this operation is not
+unlike filing the sheet of paper (or copies) in file cabinet
+folders.
+When a message is filed, it is linked into the
+destination folder(s) if possible, and is copied otherwise.
+As long
+as the destination folders are all on the same file system, multiple filing
+causes little storage overhead.
+This facility provides a good way to cross-file or multiply-index
+messages.
+For example, if a message is received from Jones about
+the ARPA Map Project, the command
+.nf
+
+ file\0cur\0+jones\0+Map
+
+.fi
+would allow the message to be found in either of the two
+folders `jones' or `Map'.
+.PP
+The option `\-file file' directs \fIfile\fR to use the specified
+file as the source message to be filed, rather than a message from
+a folder.
+.PP
+If a destination folder doesn't exist, \fIfile\fR will ask if you
+want to create one.
+A negative response will abort the file
+operation.
+.PP
+`\-link' preserves the source folder copy of the message
+(i.e., it does a \fIln\fR(1) rather than a \fImv\fR(1)), whereas,
+`\-nolink' deletes the \*(lqfiled\*(rq messages from the source
+folder.
+Normally, when a message is filed, it is assigned the
+next highest number available in each of the destination folders.
+Use of the `\-preserve' switch will override this message
+\*(lqrenaming\*(rq, but name conflicts may occur, so
+use this switch cautiously.
+(See \fIpick\fR for more details on
+message numbering.)
+.PP
+If `\-link' is not specified (or `\-nolink' is specified),
+the filed messages will be removed (
+.IR unlink (2))
+from the source folder.
+.PP
+If `\-src +folder' is given, it will become the
+current folder for future MH commands.
+If neither `\-link' nor
+`all' are specified, the current message in the source
+folder will be set to the last message specified; otherwise, the
+current message won't be changed.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Folder\-Protect: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+Folder\-Protect: To set mode when creating a new folder
+.fi
+.SH DEFAULTS
+.nf
+`\-src +folder' defaults to the current folder
+`msgs' defaults to cur
+`\-nolink'
+`\-nopreserve'
+`\-nofile'
+.fi
+.SH CONTEXT
+If `\-src +folder' is given, it will become the
+current folder for future MH commands.
+If neither `\-link' nor
+`all' are specified, the current message in the source
+folder will be set to the last message specified; otherwise, the
+current message won't be changed.
--- /dev/null
+.TH FOLDER 1 "3 August 1983"
+.UC 4
+.SH NAME
+folder \- set/list current folder/message
+.SH SYNOPSIS
+.B folder
+[ +folder ] [ msg ] [ \-all ] [ \-fast ] [ \-nofast ] [ \-up ] [ \-down ]
+[ \-header ] [ \-noheader ] [ \-total ] [ \-nototal ] [ \-pack ] [ \-nopack ]
+[ \-help ]
+.PP
+folders <equivalent to 'folder \-all'>
+.SH DESCRIPTION
+Since the MH environment is the shell, it is easy to lose
+track of the current folder from day to day.
+\fIFolder\fR will
+list the current folder, the number of messages in it, the
+range of the messages (low-high), and the current message within
+the folder, and will flag a selection list or extra files if they
+exist.
+An example of the output is:
+.nf
+
+ inbox+ has 16 messages ( 3\- 22); cur= 5.
+
+.fi
+If a `+folder' and/or `msg' are specified, they will
+become the current folder and/or message.
+An `\-all' switch
+will produce a line for each folder in the user's MH directory,
+sorted alphabetically.
+These folders are preceded by the read-only
+folders, which occur as \*.mh\(ruprofile \*(lqcur\-\*(rq entries.
+For example,
+.nf
+
+.fc ^ ~
+.ta 1.5i 2.1i 2.7i 3.5i
+^~Folder\ \ ^^~#\ of\ ^^messages~^^(~\ range\~ );\ ^cur msg (other files)
+^~/fsd/rs/m/tacc\ \ ^^has~35\ ^^messages~^^(~1\-\035);\ ^cur=\ 23.
+^~/rnd/phyl/Mail/EP\ \ ^^has~82\ ^^messages~^^(~1\-108);\ ^cur=\ 82.
+^~f\&f\ \ ^^has~4\ ^^messages~^^(~1\-\0\04);\ ^cur=\ \01.
+^~inbox+\ ^^has~16\ ^^messages~^^(~3\-\022);\ ^cur=\ \05.
+^~mh\ \ ^^has~76\ ^^messages~^^(~1\-\076);\ ^cur=\ 70.
+^~notes\ \ ^^has~2\ ^^messages~^^(~1\-\0\02);\ ^cur=\ \01.
+^~ucom\ \ ^^has~124\ ^^messages~^^(~1\-124);\ ^cur=\ \06; (select).
+
+^^^~TOTAL=\0339\ ^messages\0in\0\07\0Folders.
+.re
+.fi
+.PP
+The \*(lq+\*(rq after inbox indicates that it is the current folder.
+The \*(lq(select)\*(rq indicates that the folder ucom has a selection
+list produced by \fIpick\fR.
+If \*(lqothers\*(rq had appeared in parentheses at
+the right of a line, it would indicate that there are files in
+the folder directory that don't belong under the MH file naming
+scheme.
+.PP
+The header is output if either an `\-all' or a `\-header' switch
+is specified; it is suppressed by `\-noheader'.
+Also, if \fIfolder\fR
+is invoked by a name ending with \*(lqs\*(rq (e.g., \fIfolders\fR),
+`\-all' is assumed.
+A `\-total' switch will produce only the
+summary line.
+.PP
+If `\-fast' is given, only the folder name (or names in the
+case of `\-all') will be listed.
+(This is faster because the
+folders need not be read.)
+.PP
+The switches `\-up' and `\-down' change the folder to be the
+one above or below the current folder.
+That is, \*(lqfolder \-down\*(rq
+will set the folder to \*(lq<current\-folder>/select\*(rq, and if the
+current folder is a selection-list folder, \*(lqfolder \-up\*(rq will
+set the current folder to the parent of the selection-list.
+(See \fIpick\fR for details on selection-lists.)
+.PP
+The `\-pack' switch will compress the message names in a folder, removing
+holes in message numbering.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+/bin/ls To fast-list the folders
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to the current folder
+`msg' defaults to none
+`\-nofast'
+`\-noheader'
+`\-nototal'
+`\-nopack'
+.fi
+.SH CONTEXT
+If `+folder' and/or `msg' are given, they will become the
+current folder and/or message.
--- /dev/null
+.TH FORW 1 "3 August 1983"
+.UC 4
+.SH NAME
+forw \- forward messages
+.SH SYNOPSIS
+.B forw
+[ +folder ] [ msgs ] [ \-editor editor ] [ \-form formfile ]
+[ \-annotate ] [ \-noannotate ]
+[ \-inplace ] [ \-noinplace ] [ \-help ]
+.SH DESCRIPTION
+\fIForw\fR may be used to prepare a message containing other
+messages.
+It constructs the new message from the components file
+or `\-form formfile' (see
+.IR comp (1)),
+with a body composed of the message(s) to be forwarded.
+An editor is invoked as in \fIcomp\fR,
+and after editing is complete, the user is prompted before the message
+is sent.
+.PP
+If the `\-annotate' switch is given, each message being
+forwarded will be annotated with the lines
+.nf
+
+ Forwarded: \*(<<date\*(>>
+ Forwarded: To: names
+ Forwarded: cc: names
+
+.fi
+where each \*(lqTo:\*(rq and \*(lqcc:\*(rq list contains as many lines as required.
+This annotation will be done only if the message is sent directly
+from \fIforw\fR.
+If the message is not sent immediately from \fIforw\fR,
+\*(lqcomp \-use\*(rq may be used in a later session to re-edit and send
+the constructed message, but the annotations won't take place.
+The `\-inplace' switch permits annotating a message in place in
+order to preserve its links.
+.PP
+See \fIcomp\fR for a description of the `\-editor' switch.
+.SH FILES
+.nf
+.ta \w'or <mh-dir>/components 'u
+/etc/mh/components The message skeleton
+or <mh-dir>/components Rather than the standard skeleton
+$HOME/\*.mh\(ruprofile The user profile
+<mh-dir>/draft The default message file
+/usr/bin/send To send the composed message
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'<lasteditor>\-next: 'u
+Path: To determine the user's MH directory
+Editor: To override the use of /bin/ned as the default editor
+Current-Folder: To find the default current folder
+<lasteditor>\-next: editor to be used after exit from <lasteditor>
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to the current folder
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.fi
+.SH CONTEXT
+If a +folder is specified, it will become
+the current folder, and the current message will be set to
+the first message being forwarded.
--- /dev/null
+.TH INC 1 "3 August 1983"
+.UC 4
+.SH NAME
+inc \- incorporate new mail
+.SH SYNOPSIS
+.B inc
+[ +folder ] [ \-audit audit-file ] [ \-help ]
+.SH DESCRIPTION
+\fIInc\fR incorporates mail from the user's incoming mail drop
+(\*.mail) into an MH folder.
+If `+folder' isn't specified,
+the folder named \*(lqinbox\*(rq in the user's MH directory will be used.
+The
+new messages being incorporated are assigned numbers starting
+with the next highest number in the folder.
+If the specified (or
+default) folder doesn't exist, the user will be queried prior to
+its creation.
+As the messages are processed, a \fIscan\fR listing
+of the new mail is produced.
+.PP
+If the user's profile contains a \*(lqMsg\-Protect: nnn\*(rq entry, it
+will be used as the protection on the newly created messages,
+otherwise the MH default of 664 will be used.
+During all
+operations on messages, this initially assigned protection will
+be preserved for each message, so \fIchmod\fR(I) may be used to set a
+protection on an individual message, and its protection will be
+preserved thereafter.
+.PP
+If the switch `\-audit audit-file' is specified (usually as a
+default switch in the profile), then \fIinc\fR will append a header
+line and a line per message to the end of the specified
+audit-file with the format:
+.nf
+
+.ti 1i
+\*(<<inc\*(>> date
+.ti 1.5i
+<scan line for first message>
+.ti 1.5i
+<scan line for second message>
+.ti 2.5i
+<etc.>
+
+.fi
+This is useful for keeping track of volume and source of incoming
+mail.
+Eventually, \fIrepl\fR, \fIforw\fR, \fIcomp\fR, and \fIdist\fR may also
+produce audits to this (or another) file, perhaps with
+\*(lqMessage-Id:\*(rq information to keep an exact correspondence history.
+\*(lqAudit-file\*(rq will be in the user's MH directory unless a full
+path is specified.
+.PP
+\fIInc\fR will incorporate even illegally formatted messages into the
+user's MH folder, inserting a blank line prior to the offending
+component and printing a comment identifying the bad message.
+.PP
+In all cases, the \*.mail file will be zeroed.
+.SH FILES
+.nf
+.ta \w'<mh-dir>/audit-file 'u
+$HOME/\*.mh\(ruprofile The user profile
+$HOME/\*.mail The user's mail drop
+<mh-dir>/audit-file Audit trace file (optional)
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Folder\-Protect: 'u
+Path: To determine the user's MH directory
+Folder\-Protect: For protection on new folders
+Msg\-Protect: For protection on new messages
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to \*(lqinbox\*(rq
+.fi
+.SH CONTEXT
+The folder into which the message is
+being incorporated will become the
+current folder, and the first message incorporated will be the
+current message.
+This leaves the context ready for a \fIshow\fR
+of the first new message.
--- /dev/null
+.TH NEXT 1 "3 August 1983"
+.UC 4
+.SH NAME
+next \- show the next message
+.SH SYNOPSIS
+.B next
+[ +folder ] [ \-switches for \fIl\fR ] [ \-help ]
+.SH DESCRIPTION
+\fINext\fR performs a \fIshow\fR on the next message in the
+specified (or current) folder.
+Like \fIshow\fR, it passes any
+switches on to the program \fIl\fR, which is called to list the
+message.
+This command is exactly equivalent to \*(lqshow next\*(rq.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH CONTEXT
+If a folder is specified, it will become the current folder, and the
+message that is shown (i.e., the next message in sequence)
+will become the current message.
--- /dev/null
+.TH PICK 1 "3 August 1983"
+.UC 4
+.SH NAME
+pick \- select messages by content
+.SH SYNOPSIS
+.fc ^ ~
+.ta .4i 1.8i
+.nf
+.in .5i
+^pick~^^\0\-cc~^ \%[\-src\ +folder] \%[msgs] \%[\-help] \%[\-scan] \%[\-noscan]
+^^^\0\-date~^ \%[\-show] \%[\-noshow] \%[\-nofile] \%[\-nokeep]
+^^^\0\-from~^
+^^^\s+2\b'\(lt\(bv\(bv\(lk\(bv\(bv\(lb'\s0 \-search~\s+2\b'\(rt\(bv\(bv\(rk\(bv\(bv\(rb'\s0^ pattern
+^^^\0\-subject~^
+^^^\0\-to~^ \%[\-file \%[\-preserve] \%[\-link] \%+folder\ ... \%[\-nopreserve] \%[\-nolink] ]
+^^^\0\-\-component~^ \%[\-keep \%[\-stay] \%[\-nostay] \%[+folder\ ...]\ ]
+.fi
+.fc
+
+.re
+.ti .5i
+typically:
+.in 1i
+pick\0\-from\0jones\0\-scan
+.br
+pick\0\-to\0holloway
+.br
+pick\0\-subject\0ned\0\-scan\0\-keep
+.SH DESCRIPTION
+\fIPick\fR searches messages within a folder for the specified
+contents, then performs several operations on the selected
+messages.
+.PP
+A modified \fIgrep\fR(I) is used to perform the searching, so the
+full regular expression (see \fIed\fR(I)) facility is available
+within `pattern'.
+With `\-search', pattern is used directly,
+and with the others, the grep pattern constructed is:
+.nf
+
+.ti +.5i
+\*(lq^component:\*.\*(**pattern\*(rq
+
+.fi
+This means that the pattern specified for a `\-search' will be
+found everywhere in the message, including the header and the body,
+while the other search requests are limited to the single
+specified component.
+The expression `\-\-component pattern'
+is a shorthand for
+specifying `\-search \*(lqcomponent:\*.\*(**pattern\*(rq\ '; it is used to pick
+a component not in the set [cc date from subject to].
+An
+example is \*(lqpick \-\-reply\-to pooh \-show\*(rq.
+.PP
+Searching is performed on a per-line basis.
+Within the header of
+the message, each component is treated as one long line, but in
+the body, each line is separate.
+Lower-case letters in the
+search pattern will match either lower or upper case in the
+message, while upper case will match only upper case.
+.PP
+Once the search has been performed, the selected messages
+are scanned (see \fIscan\fR) if the `\-scan' switch is given, and
+then they are shown (see \fIshow\fR) if the `\-show' switch is
+given.
+After these two operations, the file operations (if
+requested) are performed.
+.PP
+The `\-file' switch operates exactly like the \fIfile\fR command, with the
+same meaning for the `\-preserve' and `\-link' switches.
+.PP
+The `\-keep' switch is similar to `\-file', but it produces a folder that
+is a subfolder of the folder being searched and defines it as
+the current folder (unless the `\-stay' flag is used).
+This
+subfolder contains the messages which matched the search
+criteria.
+All of the MH commands may be used with the sub-folder
+as the current folder.
+This gives the user considerable power
+in dealing with subsets of messages in a folder.
+.PP
+The messages in a folder produced by `\-keep' will always have the
+same numbers as they have in the source folder (i.e., the
+`\-preserve' switch is automatic).
+This way, the message
+numbers are consistent with the folder from which the messages
+were selected.
+Messages are not removed from the source folder
+(i.e., the `\-link' switch is assumed).
+If a `+folder' is not
+specified, the standard name \*(lqselect\*(rq will be used.
+(This is the
+meaning of \*(lq(select)\*(rq when it appears in the output of the
+\fIfolder\fR command.) If `+folder' arguments are given to
+`\-keep', they will be used rather than \*(lqselect\*(rq for the names
+of the subfolders.
+This allows for several subfolders to be
+maintained concurrently.
+.PP
+When a `\-keep' is performed, the subfolder becomes the current folder.
+This can be overridden by use
+of the `\-stay' switch.
+.PP
+Here's an example:
+
+.nf
+\01 % folder +inbox
+\02 inbox+ has 16 messages ( 3\- 22); cur= 3.
+\03 % pick \-from dcrocker
+\04 6 hits.
+\05 [+inbox/select now current]
+\06 % folder
+\07 inbox/select+ has \06 messages ( 3\- 16); cur= 3.
+\08 % scan
+.ds p \\h'\\w'+'u'
+\09 \03+ 6/20 Dcrocker Re: ned file update issue...
+10 \06\*p 6/23 Dcrocker removal of files from /tm...
+11 \08\*p 6/27 Dcrocker Problems with the new ned...
+12 13\*p 6/28 d\h'\w'D'u-\w'd'u'crocker newest nned \*(<<I would ap...
+13 15\*p 7/\05 Dcrocker nned \*(<<Last week I asked...
+14 16\*p 7/\05 d\h'\w'D'u-\w'd'u'crocker message id format \*(<<I re...
+15 % show all | print
+16 [produce a full listing of this set of messages on the line printer.]
+17 % folder \-up
+18 inbox+ has 16 messages ( 3\- 22); cur= 3; (select).
+19 % folder \-down
+20 inbox/select+ has 6 messages ( 3\- 16); cur= 3.
+21 % rmf
+22 [+inbox now current]
+23 % folder
+24 inbox+ has 16 messages ( 3\- 22); cur= 3.
+.fi
+
+This is a rather lengthy example, but it shows the power of the
+MH package.
+In item 1, the current folder is set to inbox.
+In 3,
+all of the messages from dcrocker are found in inbox and linked
+into the folder \*(lqinbox/select\*(rq.
+(Since no action switch is
+specified, `\-keep' is assumed.) Items 6 and 7 show that this
+subfolder is now the current folder.
+Items 8 through 14 are a
+\fIscan\fR of the selected messages (note that they are all from dcrocker
+and are all in upper and lower case).
+Item 15 lists all of the messages to
+the high-speed printer.
+Item 17 directs \fIfolder\fR to set the
+current folder to the parent of the selection-list folder, which
+is now current.
+Item 18 shows that this has been done.
+Item 19 resets
+the current folder to the selection list, and 21 removes the
+selection-list folder and resets the current folder to the
+parent folder, as shown in 22 and 23.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Folder\-Protect: For protection on new folders
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`\-src +folder' defaults to current
+`msgs' defaults to all
+`\-keep +select' is the default if no `\-scan', `\-show', or `\-file' is specified
+.fi
+.SH CONTEXT
+If a `\-src +folder' is specified, it will
+become the current folder, unless a `\-keep' with 0 or 1
+folder arguments makes the selection-list subfolder the
+current folder.
+Each selection-list folder will have its
+current message set to the first of the messages linked into
+it unless the selection list already existed, in which case the
+current message won't be changed.
--- /dev/null
+.TH PREV 1 "3 August 1983"
+.UC 4
+.SH NAME
+prev \- show the previous message
+.SH SYNOPSIS
+.B prev
+[ +folder ] [ \-switches for \fIl\fR ] [ \-help ]
+.SH DESCRIPTION
+\fIPrev\fR performs a \fIshow\fR on the previous message in the specified
+(or current) folder.
+Like \fIshow\fR, it passes any switches on to the
+program \fIl\fR, which is called to list the message.
+This command
+is exactly equivalent to \*(lqshow prev\*(rq.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH CONTEXT
+If a folder is specified, it will become current, and the
+message that is shown (i.e., the previous message in sequence)
+will become the current message.
--- /dev/null
+.TH PROMPTER 1 "3 August 1983"
+.UC 4
+.SH NAME
+prompter \- prompting editor front end
+.SH SYNOPSIS
+.B prompter
+[ \-erase chr ] [ \-kill chr ] [ \-help ]
+.SH DESCRIPTION
+This program is not called directly but takes the place
+of an editor and acts as an editor front end.
+\fIPrompter\fR is an editor which allows rapid composition of
+messages.
+It is particularly useful to network and low-speed
+(less than 2400 baud) users of MH.
+It is an MH program in that
+it can have its own profile entry with switches, but it can't
+be invoked directly as all other MH commands can; it is an editor
+in that it is invoked by an \*(lq\-editor prompter\*(rq switch or by the
+profile entry \*(lqEditor: prompter\*(rq, but functionally it is merely
+a text-collector and not a true editor.
+.PP
+\fIPrompter\fR expects to be called from \fIcomp\fR, \fIrepl\fR, \fIdist\fR, or
+\fIforw\fR, with a draft file as an argument.
+For example, \*(lqcomp
+\-editor prompter\*(rq will call \fIprompter\fR with the file \*(lqdraft\*(rq already set
+up with blank components.
+For each blank component it finds in
+the draft, it prompts the user and accepts a response.
+A <RETURN> will cause the whole component to be left out.
+A \*(lq\\\*(rq
+preceding a <RETURN> will continue the response on the next line,
+allowing for multiline components.
+.PP
+Any component that is non-blank will be copied and echoed to the
+terminal.
+.PP
+The start of the message body is prompted by a line of
+dashes.
+If the body is non-blank, the prompt is
+\*(lq--------Enter additional text\*(rq.
+Message-body typing is terminated with
+a <CTRL-D> (or <OPEN>).
+Control is returned to the calling
+program, where the user is asked \*(lqWhat now?\*(rq.
+See \fIcomp\fR for
+the valid options.
+.PP
+The line editing characters for kill and erase may be
+specified by the user via the arguments \*(lq\-kill chr\*(rq and \*(lq\-erase
+chr\*(rq, where chr may be a character; or \*(lq\\nnn\*(rq, where nnn is the
+octal value for the character.
+(Again, these may come from the
+default switches specified in the user's profile.)
+.PP
+A <DEL> during message-body typing is equivalent to
+<CTRL-D> for compatibility with NED.
+A <DEL> during
+component typing will abort the command that invoked
+\fIprompter\fR.
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'prompter-next: 'u
+prompter-next: editor to be used on exit from \fIprompter\fR
+.fi
--- /dev/null
+.TH REPL 1 "3 August 1983"
+.UC 4
+.SH NAME
+repl \- reply to a message
+.SH SYNOPSIS
+.B repl
+[ +folder ] [ msg ] [ \-editor editor ] [ \-inplace ] [ \-annotate ]
+[ \-help ] [ \-noinplace ] [ \-noannotate ]
+.SH DESCRIPTION
+\fIRepl\fR aids a user in producing a reply to an existing
+message.
+In its simplest form (with no arguments), it will set up
+a message-form skeleton in reply to the current message in the
+current folder, invoke the editor, and send the composed
+message if so directed.
+The composed message is constructed as
+follows:
+.nf
+
+.in 1i
+To: <Reply-To> or <From>
+cc: <cc>, <To>
+Subject: Re: <Subject>
+In-reply-to: Your message of <Date>
+.ti +\w'In-reply-to: 'u
+<Message-Id>
+.in .5i
+
+.fi
+where field names enclosed in angle brackets (< >) indicate the
+contents of the named field from the message to which the reply
+is being made.
+Once the skeleton is constructed, an editor is
+invoked (as in \fIcomp\fR, \fIdist\fR, and \fIforw\fR).
+While in the editor,
+the message being replied to is available through a link named
+\*(lq@\*(rq.
+In NED, this means the replied-to message may be \*(lqused\*(rq
+with \*(lquse @\*(rq, or put in a window by \*(lqwindow @\*(rq.
+.PP
+As in \fIcomp\fR, \fIdist\fR, and \fIforw\fR, the user will be queried
+before the message is sent.
+If `\-annotate' is
+specified, the replied-to message will be annotated with the
+single line
+.nf
+
+.ti +.5i
+Replied: \*(<<Date\*(>>.
+
+.fi
+The command
+\*(lqcomp \-use\*(rq may be used to pick up interrupted editing, as in
+\fIdist\fR and \fIforw\fR; the `\-inplace' switch annotates the message in
+place, so that all folders with links to it will see the annotation.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+<mh-dir>/draft The constructed message file
+/usr/bin/send To send the composed message
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Editor: To override the use of /bin/ned as the default editor
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.fi
+.SH CONTEXT
+If a `+folder' is specified, it will become the current
+folder, and the current message will be set to the replied-to
+message.
--- /dev/null
+.TH RMF 1 "3 August 1983"
+.UC 4
+.SH NAME
+rmf \- remove folder
+.SH SYNOPSIS
+.B rmf
+[ +folder ] [ \-help ]
+.SH DESCRIPTION
+\fIRmf\fR removes all of the files (messages) within the specified
+(or default) folder, and then removes the directory (folder).
+If
+there are any files within the folder which are not a part of MH,
+they will \fInot\fR be removed, and an error will be produced.
+If the
+folder is given explicitly or the current folder is a
+subfolder (i.e., a selection list from \fIpick\fR), it will be
+removed without confirmation.
+If no argument is specified and
+the current folder is not a selection-list folder, the
+user will be asked for confirmation.
+.PP
+\fIRmf\fR irreversibly deletes messages that don't have other links,
+so use it with caution.
+.PP
+If the folder being removed is a subfolder, the parent
+folder will become the new current folder, and \fIrmf\fR will
+produce a message telling the user this has happened.
+This
+provides an easy mechanism for selecting a set of messages,
+operating on the list, then removing the list and returning to
+the current folder from which the list was extracted.
+(See the
+example under \fIpick\fR.)
+.PP
+The files that \fIrmf\fR will delete are cur, any file beginning
+with a comma, and files with purely numeric names.
+All others
+will produce error messages.
+.PP
+\fIRmf\fR of a read-only folder will delete the \*(lqcur\-\*(rq entry from the
+profile without affecting the folder itself.
+.SH FILES
+.nf
+.ta \w'or <mh-dir>/components 'u
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to current, usually with confirmation
+.fi
+.SH CONTEXT
+\fIRmf\fR will set the current folder to the parent folder if a
+subfolder is removed; or if the current folder is removed,
+it will make \*(lqinbox\*(rq current.
+Otherwise, it doesn't change the
+current folder or message.
--- /dev/null
+.TH RMM 1 "3 August 1983"
+.UC 4
+.SH NAME
+rmm \- remove messages
+.SH SYNOPSIS
+.B rmm
+[ +folder ] [ msgs ] [ \-help ]
+.SH DESCRIPTION
+\fIRmm\fR removes the specified messages by renaming the message
+files with preceding commas.
+(This is the Rand-UNIX backup file convention.)
+.PP
+The current message is not changed by \fIrmm\fR, so a \fInext\fR will
+advance to the next message in the folder as expected.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to current
+`msgs' defaults to cur
+.fi
+.SH CONTEXT
+If a folder is given, it will become current.
--- /dev/null
+.SC SCAN
+.TH SCAN 1 "3 August 1983"
+.UC 4
+.SH NAME
+scan \- produce a one-line-per-message scan listing
+.SH SYNOPSIS
+.B scan
+[ +folder ] [ msgs ] [ \-ff ] [ \-header ] [ \-help ]
+[ \-noff ] [ \-noheader ]
+.SH DESCRIPTION
+\fIScan\fR produces a one-line-per-message listing of the specified
+messages.
+Each \fIscan\fR line contains the message number (name),
+the date, the \*(lqFrom\*(rq field, the \*(lqSubject\*(rq field, and, if room
+allows, some of the body of the message.
+For example:
+.nf
+
+.ta .5i 1.2i 2.6i
+^ #~^^Date~^^ From~^Subject\ \ \ \ \[\*(<<Body]
+^15+~^^7/\05~^^Dcrocker~^nned \*(<<Last week I asked some of
+^16\ \-~^^7/\05~^^dcrocker~^message id format \*(<<I recommend
+^18~^^7/\06~^^Obrien~^Re: Exit status from mkdir
+^19~^^7/\07~^^Obrien~^"scan" listing format in MH
+.re
+
+.fi
+The `+' on message 15 indicates that it is the current message.
+The `\-' on message 16 indicates that it has been
+replied to, as indicated by a \*(lqReplied:\*(rq component produced by
+an `\-annotate' switch to the \fIrepl\fR command.
+.PP
+If there is sufficient room left on the \fIscan\fR line after the
+subject, the line will be filled with text from the body,
+preceded by \*(<<.
+\fIScan\fR actually reads each of the specified
+messages and parses them to extract the desired fields.
+During parsing, appropriate error messages will be produced if
+there are format errors in any of the messages.
+.PP
+The `\-header' switch produces a header line prior to the \fIscan\fR
+listing, and the `\-f\&f' switch will cause a form feed to be
+output at the end of the \fIscan\fR listing.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+^$HOME/\*.mh\(ruprofile~^The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to current
+`msgs' defaults to all
+`\-nof\&f'
+`\-noheader'
+.fi
+.SH CONTEXT
+If a folder is given, it will become current.
+The current message is unaffected.
--- /dev/null
+.SC SEND
+.TH SEND 1 "3 August 1983"
+.UC 4
+.SH NAME
+send \- send a message
+.SH SYNOPSIS
+.B send
+[ file ] [ \-draft ] [ \-verbose ] [ \-format ] [ \-msgid ]
+[ \-help ] [ \-noverbose ] [ \-noformat ] [ \-nomsgid ]
+.SH DESCRIPTION
+\fISend\fR will cause the specified file (default <mh-dir>/draft) to
+be delivered to each of the addresses in the \*(lqTo:\*(rq, \*(lqcc:\*(rq, and \*(lqBcc:\*(rq
+fields of the message.
+If `\-verbose' is specified, \fIsend;\fR
+will monitor the delivery of local and net mail.
+\fISend\fR with no
+argument will query whether the draft is the intended file, whereas
+`\-draft' will suppress this question.
+Once the message has
+been mailed (or queued) successfully, the file will be renamed
+with a leading comma, which allows it to be retreived until the
+next draft message is sent.
+If there are errors in the
+formatting of the message, \fIsend;\fR will abort with a (hopefully)
+helpful error message.
+.PP
+If a \*(lqBcc:\*(rq field is encountered, its addresses will be used for
+delivery, but the \*(lqBcc:\*(rq field itself will be deleted from all
+copies of the outgoing message.
+.PP
+Prior to sending the message, the fields \*(lqFrom: user\*(rq, and
+\*(lqDate: now\*(rq will be prepended to the message.
+If `\-msgid' is
+specified, then a \*(lqMessage-Id:\*(rq field will also be added to the
+message.
+If the message already contains a \*(lqFrom:\*(rq field, then a
+\*(lqSender: user\*(rq field will be added instead.
+(An already existing
+\*(lqSender:\*(rq field will be deleted from the message.)
+.PP
+If the user doesn't specify `\-noformat', each of the entries in
+the \*(lqTo:\*(rq and \*(lqcc:\*(rq fields will be replaced with \*(lqstandard\*(rq format
+entries.
+This standard format is designed to be usable by all
+of the message handlers on the various systems around the
+ARPANET.
+.PP
+If an \*(lqFcc: folder\*(rq is encountered, the message will be copied
+to the specified folder in the format in which it will appear to any
+receivers of the message.
+That is, it will have the prepended
+fields and field reformatting.
+.PP
+If a \*(lqDistribute-To:\*(rq field is encountered, the message
+is handled as a redistribution message (see \fIdist\fR for
+details), with \*(lqDistribution-Date: now\*(rq and \*(lqDistribution-From: user\*(rq
+added.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Path: 'u
+Path: To determine the user's MH directory
+.fi
+.SH DEFAULTS
+.nf
+`file' defaults to draft
+`\-noverbose'
+`\-format'
+`\-nomsgid'
+.fi
+.SH CONTEXT
+\fISend\fR has no effect on the current message or folder.
--- /dev/null
+.TH SHOW 1 "3 August 1983"
+.UC 4
+.SH NAME
+show \- show (list) messages
+.SH SYNOPSIS
+.B show
+[ +folder ] [ msgs ] [ \-pr ] [ \-nopr ] [ \-draft ] [ \-help ]
+[ \fIl\fR or \fIpr\fR switches ]
+.SH DESCRIPTION
+\fIShow\fR lists each of the specified messages to the standard
+output (typically, the terminal).
+The messages are listed exactly
+as they are, with no reformatting.
+A program called \fIl\fR is
+invoked to do the listing, and any switches not recognized by
+\fIshow\fR are passed along to \fIl\fR.
+.PP
+If no \*(lqmsgs\*(rq are specified, the current message is used.
+If
+more than one message is specified, \fIl\fR will prompt for a
+<return> prior to listing each message.
+.PP
+\fIl\fR will list each message, a page at a time.
+When the end of
+page is reached, \fIl\fR will ring the bell and wait for a <RETURN>
+or <CTRL-D>.
+If a <return> is entered, \fIl\fR will clear the
+screen before listing the next page, whereas <CTRL-D> will not.
+The switches to \fIl\fR are
+`\-p#' to indicate the page length in lines, and `\-w#' to
+indicate the width of the page in characters.
+.PP
+If the standard output is not a terminal, no queries are made,
+and each file is listed with a one-line header and two lines of
+separation.
+.PP
+If `\-pr' is specified, then \fIpr\fR(I) will be invoked rather than
+\fIl\fR, and the switches (other than `\-draft') will be passed
+along.
+\*(lqShow \-draft\*(rq will list the file <mh-dir>/draft if it
+exists.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+/bin/l Screen-at-a-time list program
+/bin/pr \fIpr\fR(1)
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-nopr'
+.fi
+.SH CONTEXT
+If a folder is given, it will become the current message.
+The last message
+listed will become the current message.
--- /dev/null
+/*
+ * This is the program called to deliver mail
+ * on systems where we try to maintain compatibility
+ * with the standard message format.
+ */
+
+char *Mailprog = "/usr/ucb/Mail";
--- /dev/null
+CC = cc -I../cmds
+CFLAGS=-O
+
+strings.a: anoyes.o \
+ components.o \
+ current.o \
+ defalt.o \
+ distcomps.o \
+ draft.o \
+ fileproc.o \
+ foldprot.o \
+ hostname.o \
+ installproc.o \
+ listname.o \
+ lockdir.o \
+ lsproc.o \
+ mailboxes.o \
+ mailproc.o \
+ mh_deliver.o \
+ mh_prof.o \
+ mhnews.o \
+ msgprot.o \
+ pfolder.o \
+ prproc.o \
+ scanproc.o \
+ sendproc.o \
+ showproc.o \
+ stdcomps.o \
+ stddcomps.o \
+ sysed.o \
+ Mailprog.o \
+ unixtomh.o \
+ localname.o
+
+ ar cr strings.a *.o
+
+clean:
+ rm -f *.o strings.a
--- /dev/null
+char *anoyes[] = {
+ "no", 0,
+ "yes", 0,
+ 0,
+};
--- /dev/null
+char *components = "components";
--- /dev/null
+char *current = "cur";
--- /dev/null
+char *defalt = "inbox";
--- /dev/null
+char *distcomps = "distcomps";
--- /dev/null
+char *draft = "draft";
--- /dev/null
+/*
+ * This program is usually called directly by users, but it is
+ * also invoked by the deliver program to process an "fcc".
+ */
+
+char *fileproc = "/usr/new/mh/refile";
--- /dev/null
+/*
+ * Folders (directories) are created with this protection (mode)
+ */
+
+char *foldprot = "0751";
--- /dev/null
+/*
+ * For ARPANET mail, this is the local-site's Host name.
+ * (currently not used.)
+ */
+
+char *hostname = "Berkeley";
--- /dev/null
+/*
+ * When a user runs an MH program for the first time, this program
+ * is called to create his MH profile, and mail directory.
+ */
+
+char *installproc = "/usr/new/lib/mh/install-mh";
--- /dev/null
+char *listname = "select";
--- /dev/null
+/*
+ * Local network host name
+ */
+
+char *localname = "unknown";
--- /dev/null
+/*
+ * This is where the lock files are kept. It MUST be on the same
+ * file system as the "mailboxes" directory. It also must be read/
+ * write by the world. When a mailbox needs locking (while being
+ * read and cleared by inc, or written by deliver), a link to the
+ * mailbox is made in this directory, under the same name (i.e., the
+ * users name). Links are one of the few things even a privileged
+ * process (deliver) cannot over-ride. The deliver process waits
+ * for lockwait seconds for the lock to clear, then it over-rides
+ * the lock. This number should be set around 15-30 seconds in the
+ * case of a VERY loaded system.
+ */
+
+char *lockdir = "/usr/spool/locks/";
+int lockwait = 15; /* Seconds */
--- /dev/null
+/*
+ * This is standard ls, but "folder -all -short" calls it with
+ * a -x switch meaning "list only directories".
+ *
+ * Also, its nice to have columnated output rather than a simple
+ * list... (personal prejudice).
+ */
+
+char *lsproc = "/bin/ls";
--- /dev/null
+/*
+ * This is where the user mailboxes are kept. On our 11/70 they were
+ * kept in each users $HOME directory. This is where the VAX login
+ * program is looking for them, as well as the old BELL mail.
+ */
+
+char *mailboxes = "/usr/spool/mail/";
--- /dev/null
+/*
+ * This is the path for the Bell equivalent mail program... Used
+ * by "news -send" to send news items to the news user.
+ */
+
+char *mailproc = "/bin/mail";
--- /dev/null
+/*
+ * This is the name of the file used to store
+ * the user's MH profile
+ */
+
+char *mh_defs = "/.mh_profile";
--- /dev/null
+/*
+ * This is the delivery program called ONLY through send to
+ * actually deliver mail to users. It is fairly small, and
+ * must run SUID ROOT, to create new mailboxes.
+ */
+
+char *mh_deliver = "/usr/new/lib/mh/deliver";
--- /dev/null
+char *mh_prof = "/.mh_profile";
--- /dev/null
+/*
+ * This program is called to print out MH news IF NEWS is defined
+ * when the MH programs are compiled. This whole mechanism has not
+ * been tested under version 7!
+ */
+
+char *mhnews = "/usr/new/mh/news";
--- /dev/null
+/*
+ * Every NEW message will be created with this protection. When a
+ * message is filed it retains its protection, so this only applies
+ * to messages coming in through inc.
+ */
+
+char *msgprot = "0664";
--- /dev/null
+char *pfolder = "current-folder";
--- /dev/null
+/*
+ * This is the std BELL pr, which is invoked through show with the
+ * -pr switch.
+ */
+
+char *prproc = "/bin/pr";
--- /dev/null
+/*
+ * This program is usually called directly by users, but it is
+ * also invoked by "pick -scan".
+ */
+
+char *scanproc = "/usr/new/mh/scan";
--- /dev/null
+/*
+ * This program is usually called by one of the message composition
+ * programs: comp, repl, dist, and forw, but it may also be called
+ * directly to send a message previously composed.
+ */
+
+char *sendproc = "/usr/new/mh/send";
--- /dev/null
+/*
+ * This program is called to list messages. At Rand, the program
+ * c stops at the end of each page and waits for a <return> or
+ * <open> to continue. Eventually, this path should invoke a
+ * special program which displays messages much more intelligently--
+ * such as layed out nicely on the screen.
+ */
+
+char *showproc = "/usr/ucb/more"; /* 5/6/79 */
--- /dev/null
+/*
+ * This is the standard skeleton for message composition with both
+ * comp and forw.
+ */
+
+char *stdcomps = "/usr/new/lib/mh/components";
--- /dev/null
+/*
+ * This is the standard skeleton for message composition with dist.
+ */
+
+char *stddcomps = "/usr/new/lib/mh/distcomps";
--- /dev/null
+/*
+ * This file gives extern declarations to all the strings
+ * that we might ever reference.
+ *
+ * I don't know if this what strings.h is supposed to be,
+ * but this is as good a first guess as I can handle.
+ */
+
+extern char *anoyes[];
+extern char *components;
+extern char *current;
+extern char *defalt;
+extern char *distcomps;
+extern char *draft;
+extern char *fileproc;
+extern char *foldprot;
+extern char *hostname;
+extern char *installproc;
+extern char *listname;
+extern char *lockdir;
+extern int lockwait;
+extern char *lsproc;
+extern char *mailboxes;
+extern char *mailproc;
+extern char *mh_deliver;
+extern char *mh_prof;
+extern char *mhnews;
+extern char *msgprot;
+extern char *pfolder;
+extern char *prproc;
+extern char *scanproc;
+extern char *sendproc;
+extern char *showproc;
+extern char *stdcomps;
+extern char *stddcomps;
+extern char *sysed;
--- /dev/null
+/*
+ * This is the editor invoked by the various message composition
+ * programs. It SHOULD be a 2-D scope editor, such as Rand's Ned
+ * or Berkeley's ex, but any editor will work. If you don't have
+ * a scope editor, you might want to default to prompter, but it
+ * works very marginally with forw and dist.
+ */
+
+char *sysed = "/bin/ex";
--- /dev/null
+/*
+ * This program is called to convert UNIX style
+ * mailboxes to MH style mail boxes, if we are trying
+ * to stay UNIX mailbox compatible.
+ */
+
+char *unixtomh = "/usr/new/lib/mh/unixtomh";
--- /dev/null
+_add add.o
+_ambigsw ambigsw.o
+_atooi atooi.o
+_brkany brkstring.o
+_brkstri brkstring.o
+_cdate cdate.o
+_cndfree cndfree.o
+_concat concat.o
+_copy copy.o
+_copyip copyip.o
+_cputc cputc.o
+_done done.o
+_fdcompa fdcompare.o
+_gans gans.o
+_g_sig getans.o
+_getans getans.o
+_getcpy getcpy.o
+_help help.o
+_invo_na invo_name.o
+_locv locv.o
+_m_conv m_convert.o
+_m_conve m_convert.o
+_m_delet m_delete.o
+_m_edit m_edit.o
+_m_find m_find.o
+_m_getde m_getdefs.o
+_procs m_getdefs.o
+_m_getfl m_getfld.o
+_m_getfo m_getfolder.o
+_m_gmpro m_gmprot.o
+_m_gmsg m_gmsg.o
+_mu_atoi m_gmsg.o
+_m_maild m_maildir.o
+_m_name m_name.o
+_m_repla m_replace.o
+_m_send m_send.o
+_m_setcu m_setcur.o
+_m_updat m_update.o
+_makedir makedir.o
+_makenam makename.o
+_peekc peekc.o
+_pr_arra pr_array.o
+_printsw printsw.o
+_putdate putdate.o
+_r1binde r1bindex.o
+_showfil showfile.o
+_smatch smatch.o
+_ssequal ssequal.o
+_trimcpy trimcpy.o
+_type type.o
+_uleq uleq.o
--- /dev/null
+_cndfree add.o
+_malloc add.o
+_sprintf add.o
+_strlen add.o
+cret add.o
+csv add.o
+__iob ambigsw.o
+_fprintf ambigsw.o
+_invo_na ambigsw.o
+_printsw ambigsw.o
+cret ambigsw.o
+csv ambigsw.o
+cret atooi.o
+csv atooi.o
+cret brkstring.o
+csv brkstring.o
+_ctime cdate.o
+cret cdate.o
+csv cdate.o
+_end cndfree.o
+_free cndfree.o
+cret cndfree.o
+csv cndfree.o
+_compone concat.o
+_copy concat.o
+_current concat.o
+_def_fla concat.o
+_defalt concat.o
+_distcom concat.o
+_draft concat.o
+_filepro concat.o
+_foldpro concat.o
+_hostnam concat.o
+_install concat.o
+_listnam concat.o
+_lockdir concat.o
+_lsproc concat.o
+_m_defs concat.o
+_mailbox concat.o
+_malloc concat.o
+_mh_deli concat.o
+_mh_prof concat.o
+_mhnews concat.o
+_msgprot concat.o
+_mypath concat.o
+_pfolder concat.o
+_prproc concat.o
+_scanpro concat.o
+_sendpro concat.o
+_showpro concat.o
+_stdcomp concat.o
+_stddcom concat.o
+_strlen concat.o
+_sysed concat.o
+cret concat.o
+csv concat.o
+cret copy.o
+csv copy.o
+cret copyip.o
+csv copyip.o
+__flsbuf cputc.o
+_done cputc.o
+_perror cputc.o
+cret cputc.o
+csv cputc.o
+_exit done.o
+cret done.o
+csv done.o
+_lseek fdcompare.o
+_read fdcompare.o
+cret fdcompare.o
+csv fdcompare.o
+__filbuf gans.o
+__iob gans.o
+_compone gans.o
+_current gans.o
+_def_fla gans.o
+_defalt gans.o
+_distcom gans.o
+_draft gans.o
+_fflush gans.o
+_filepro gans.o
+_foldpro gans.o
+_hostnam gans.o
+_install gans.o
+_listnam gans.o
+_lockdir gans.o
+_lsproc gans.o
+_m_defs gans.o
+_mailbox gans.o
+_mh_deli gans.o
+_mh_prof gans.o
+_mhnews gans.o
+_msgprot gans.o
+_mypath gans.o
+_pfolder gans.o
+_printf gans.o
+_prproc gans.o
+_scanpro gans.o
+_sendpro gans.o
+_showpro gans.o
+_smatch gans.o
+_stdcomp gans.o
+_stddcom gans.o
+_sysed gans.o
+cret gans.o
+csv gans.o
+__filbuf getans.o
+__iob getans.o
+_ambigsw getans.o
+_brkstri getans.o
+_compone getans.o
+_current getans.o
+_def_fla getans.o
+_defalt getans.o
+_distcom getans.o
+_draft getans.o
+_fflush getans.o
+_filepro getans.o
+_foldpro getans.o
+_g_sigin getans.o
+_hostnam getans.o
+_install getans.o
+_listnam getans.o
+_lockdir getans.o
+_lsproc getans.o
+_m_defs getans.o
+_mailbox getans.o
+_mh_deli getans.o
+_mh_prof getans.o
+_mhnews getans.o
+_msgprot getans.o
+_mypath getans.o
+_pfolder getans.o
+_printf getans.o
+_printsw getans.o
+_prproc getans.o
+_scanpro getans.o
+_sendpro getans.o
+_showpro getans.o
+_signal getans.o
+_smatch getans.o
+_stdcomp getans.o
+_stddcom getans.o
+_sysed getans.o
+cret getans.o
+csv getans.o
+_malloc getcpy.o
+_strcpy getcpy.o
+_strlen getcpy.o
+cret getcpy.o
+csv getcpy.o
+_compone help.o
+_current help.o
+_def_fla help.o
+_defalt help.o
+_distcom help.o
+_draft help.o
+_filepro help.o
+_foldpro help.o
+_hostnam help.o
+_install help.o
+_listnam help.o
+_lockdir help.o
+_lsproc help.o
+_m_defs help.o
+_mailbox help.o
+_mh_deli help.o
+_mh_prof help.o
+_mhnews help.o
+_msgprot help.o
+_mypath help.o
+_pfolder help.o
+_printf help.o
+_printsw help.o
+_prproc help.o
+_scanpro help.o
+_sendpro help.o
+_showpro help.o
+_stdcomp help.o
+_stddcom help.o
+_sysed help.o
+cret help.o
+csv help.o
+cret invo_name.o
+csv invo_name.o
+_sprintf locv.o
+cret locv.o
+csv locv.o
+__iob m_convert.o
+_atoi m_convert.o
+_compone m_convert.o
+_convdir m_convert.o
+_current m_convert.o
+_def_fla m_convert.o
+_defalt m_convert.o
+_delimp m_convert.o
+_distcom m_convert.o
+_draft m_convert.o
+_filepro m_convert.o
+_foldpro m_convert.o
+_fprintf m_convert.o
+_hostnam m_convert.o
+_install m_convert.o
+_listnam m_convert.o
+_lockdir m_convert.o
+_lsproc m_convert.o
+_m_defs m_convert.o
+_mailbox m_convert.o
+_mh_deli m_convert.o
+_mh_prof m_convert.o
+_mhnews m_convert.o
+_mp m_convert.o
+_msgprot m_convert.o
+_mypath m_convert.o
+_pfolder m_convert.o
+_prproc m_convert.o
+_scanpro m_convert.o
+_sendpro m_convert.o
+_showpro m_convert.o
+_stdcomp m_convert.o
+_stddcom m_convert.o
+_strcmp m_convert.o
+_sysed m_convert.o
+cret m_convert.o
+csv m_convert.o
+_cndfree m_delete.o
+_compone m_delete.o
+_current m_delete.o
+_def_fla m_delete.o
+_defalt m_delete.o
+_distcom m_delete.o
+_draft m_delete.o
+_filepro m_delete.o
+_foldpro m_delete.o
+_free m_delete.o
+_hostnam m_delete.o
+_install m_delete.o
+_listnam m_delete.o
+_lockdir m_delete.o
+_lsproc m_delete.o
+_m_defs m_delete.o
+_m_getde m_delete.o
+_mailbox m_delete.o
+_mh_deli m_delete.o
+_mh_prof m_delete.o
+_mhnews m_delete.o
+_msgprot m_delete.o
+_mypath m_delete.o
+_pfolder m_delete.o
+_prproc m_delete.o
+_scanpro m_delete.o
+_sendpro m_delete.o
+_showpro m_delete.o
+_stdcomp m_delete.o
+_stddcom m_delete.o
+_sysed m_delete.o
+_uleq m_delete.o
+cret m_delete.o
+csv m_delete.o
+__iob m_edit.o
+_compone m_edit.o
+_concat m_edit.o
+_current m_edit.o
+_def_fla m_edit.o
+_defalt m_edit.o
+_distcom m_edit.o
+_done m_edit.o
+_draft m_edit.o
+_execlp m_edit.o
+_fflush m_edit.o
+_filepro m_edit.o
+_foldpro m_edit.o
+_fork m_edit.o
+_fprintf m_edit.o
+_getcpy m_edit.o
+_hostnam m_edit.o
+_install m_edit.o
+_invo_na m_edit.o
+_link m_edit.o
+_listnam m_edit.o
+_lockdir m_edit.o
+_lsproc m_edit.o
+_m_defs m_edit.o
+_m_find m_edit.o
+_m_updat m_edit.o
+_mailbox m_edit.o
+_mh_deli m_edit.o
+_mh_prof m_edit.o
+_mhnews m_edit.o
+_mp m_edit.o
+_msgprot m_edit.o
+_mypath m_edit.o
+_perror m_edit.o
+_pfolder m_edit.o
+_prproc m_edit.o
+_rindex m_edit.o
+_scanpro m_edit.o
+_sendpro m_edit.o
+_showpro m_edit.o
+_signal m_edit.o
+_stat m_edit.o
+_stdcomp m_edit.o
+_stddcom m_edit.o
+_sysed m_edit.o
+_unlink m_edit.o
+_wait m_edit.o
+cret m_edit.o
+csv m_edit.o
+_compone m_find.o
+_current m_find.o
+_def_fla m_find.o
+_defalt m_find.o
+_distcom m_find.o
+_draft m_find.o
+_filepro m_find.o
+_foldpro m_find.o
+_hostnam m_find.o
+_install m_find.o
+_listnam m_find.o
+_lockdir m_find.o
+_lsproc m_find.o
+_m_defs m_find.o
+_m_getde m_find.o
+_mailbox m_find.o
+_mh_deli m_find.o
+_mh_prof m_find.o
+_mhnews m_find.o
+_msgprot m_find.o
+_mypath m_find.o
+_pfolder m_find.o
+_prproc m_find.o
+_scanpro m_find.o
+_sendpro m_find.o
+_showpro m_find.o
+_stdcomp m_find.o
+_stddcom m_find.o
+_sysed m_find.o
+_uleq m_find.o
+cret m_find.o
+csv m_find.o
+__iob m_getdefs.o
+_compone m_getdefs.o
+_current m_getdefs.o
+_def_fla m_getdefs.o
+_defalt m_getdefs.o
+_defpath m_getdefs.o
+_distcom m_getdefs.o
+_done m_getdefs.o
+_draft m_getdefs.o
+_execl m_getdefs.o
+_fclose m_getdefs.o
+_filepro m_getdefs.o
+_foldpro m_getdefs.o
+_fopen m_getdefs.o
+_fork m_getdefs.o
+_fprintf m_getdefs.o
+_getcpy m_getdefs.o
+_getenv m_getdefs.o
+_hostnam m_getdefs.o
+_install m_getdefs.o
+_listnam m_getdefs.o
+_lockdir m_getdefs.o
+_lsproc m_getdefs.o
+_m_defs m_getdefs.o
+_m_getfl m_getdefs.o
+_mailbox m_getdefs.o
+_malloc m_getdefs.o
+_mh_deli m_getdefs.o
+_mh_prof m_getdefs.o
+_mhnews m_getdefs.o
+_msgprot m_getdefs.o
+_mypath m_getdefs.o
+_perror m_getdefs.o
+_pfolder m_getdefs.o
+_prproc m_getdefs.o
+_scanpro m_getdefs.o
+_sendpro m_getdefs.o
+_showpro m_getdefs.o
+_sprintf m_getdefs.o
+_stdcomp m_getdefs.o
+_stddcom m_getdefs.o
+_strcmp m_getdefs.o
+_sysed m_getdefs.o
+_trimcpy m_getdefs.o
+_wait m_getdefs.o
+cret m_getdefs.o
+csv m_getdefs.o
+__filbuf m_getfld.o
+__iob m_getfld.o
+_compone m_getfld.o
+_current m_getfld.o
+_def_fla m_getfld.o
+_defalt m_getfld.o
+_distcom m_getfld.o
+_draft m_getfld.o
+_filepro m_getfld.o
+_foldpro m_getfld.o
+_fprintf m_getfld.o
+_hostnam m_getfld.o
+_install m_getfld.o
+_listnam m_getfld.o
+_lockdir m_getfld.o
+_lsproc m_getfld.o
+_m_defs m_getfld.o
+_m_fldsz m_getfld.o
+_mailbox m_getfld.o
+_mh_deli m_getfld.o
+_mh_prof m_getfld.o
+_mhnews m_getfld.o
+_msgprot m_getfld.o
+_mypath m_getfld.o
+_peekc m_getfld.o
+_pfolder m_getfld.o
+_prproc m_getfld.o
+_scanpro m_getfld.o
+_sendpro m_getfld.o
+_showpro m_getfld.o
+_stdcomp m_getfld.o
+_stddcom m_getfld.o
+_sysed m_getfld.o
+cret m_getfld.o
+csv m_getfld.o
+_compone m_getfolder.o
+_current m_getfolder.o
+_def_fla m_getfolder.o
+_defalt m_getfolder.o
+_distcom m_getfolder.o
+_draft m_getfolder.o
+_filepro m_getfolder.o
+_foldpro m_getfolder.o
+_hostnam m_getfolder.o
+_install m_getfolder.o
+_listnam m_getfolder.o
+_lockdir m_getfolder.o
+_lsproc m_getfolder.o
+_m_defs m_getfolder.o
+_m_find m_getfolder.o
+_m_getde m_getfolder.o
+_mailbox m_getfolder.o
+_mh_deli m_getfolder.o
+_mh_prof m_getfolder.o
+_mhnews m_getfolder.o
+_msgprot m_getfolder.o
+_mypath m_getfolder.o
+_pfolder m_getfolder.o
+_prproc m_getfolder.o
+_scanpro m_getfolder.o
+_sendpro m_getfolder.o
+_showpro m_getfolder.o
+_stdcomp m_getfolder.o
+_stddcom m_getfolder.o
+_sysed m_getfolder.o
+cret m_getfolder.o
+csv m_getfolder.o
+_atooi m_gmprot.o
+_compone m_gmprot.o
+_current m_gmprot.o
+_def_fla m_gmprot.o
+_defalt m_gmprot.o
+_distcom m_gmprot.o
+_draft m_gmprot.o
+_filepro m_gmprot.o
+_foldpro m_gmprot.o
+_hostnam m_gmprot.o
+_install m_gmprot.o
+_listnam m_gmprot.o
+_lockdir m_gmprot.o
+_lsproc m_gmprot.o
+_m_defs m_gmprot.o
+_m_find m_gmprot.o
+_mailbox m_gmprot.o
+_mh_deli m_gmprot.o
+_mh_prof m_gmprot.o
+_mhnews m_gmprot.o
+_msgprot m_gmprot.o
+_mypath m_gmprot.o
+_pfolder m_gmprot.o
+_prproc m_gmprot.o
+_scanpro m_gmprot.o
+_sendpro m_gmprot.o
+_showpro m_gmprot.o
+_stdcomp m_gmprot.o
+_stddcom m_gmprot.o
+_sysed m_gmprot.o
+cret m_gmprot.o
+csv m_gmprot.o
+_access m_gmsg.o
+_close m_gmsg.o
+_closedi m_gmsg.o
+_compone m_gmsg.o
+_current m_gmsg.o
+_def_fla m_gmsg.o
+_defalt m_gmsg.o
+_distcom m_gmsg.o
+_draft m_gmsg.o
+_filepro m_gmsg.o
+_foldpro m_gmsg.o
+_hostnam m_gmsg.o
+_install m_gmsg.o
+_listnam m_gmsg.o
+_lockdir m_gmsg.o
+_lsproc m_gmsg.o
+_m_defs m_gmsg.o
+_m_find m_gmsg.o
+_mailbox m_gmsg.o
+_malloc m_gmsg.o
+_mh_deli m_gmsg.o
+_mh_prof m_gmsg.o
+_mhnews m_gmsg.o
+_mp m_gmsg.o
+_msgprot m_gmsg.o
+_mypath m_gmsg.o
+_open m_gmsg.o
+_opendir m_gmsg.o
+_pfolder m_gmsg.o
+_prproc m_gmsg.o
+_read m_gmsg.o
+_readdir m_gmsg.o
+_scanpro m_gmsg.o
+_sendpro m_gmsg.o
+_showpro m_gmsg.o
+_sprintf m_gmsg.o
+_stat m_gmsg.o
+_stdcomp m_gmsg.o
+_stddcom m_gmsg.o
+_strcmp m_gmsg.o
+_sysed m_gmsg.o
+cret m_gmsg.o
+csv m_gmsg.o
+_compone m_maildir.o
+_copy m_maildir.o
+_current m_maildir.o
+_def_fla m_maildir.o
+_defalt m_maildir.o
+_distcom m_maildir.o
+_draft m_maildir.o
+_filepro m_maildir.o
+_foldpro m_maildir.o
+_hostnam m_maildir.o
+_install m_maildir.o
+_listnam m_maildir.o
+_lockdir m_maildir.o
+_lsproc m_maildir.o
+_m_defs m_maildir.o
+_m_find m_maildir.o
+_m_getde m_maildir.o
+_m_getfo m_maildir.o
+_mailbox m_maildir.o
+_mh_deli m_maildir.o
+_mh_prof m_maildir.o
+_mhnews m_maildir.o
+_msgprot m_maildir.o
+_mypath m_maildir.o
+_pfolder m_maildir.o
+_prproc m_maildir.o
+_scanpro m_maildir.o
+_sendpro m_maildir.o
+_showpro m_maildir.o
+_sprintf m_maildir.o
+_stdcomp m_maildir.o
+_stddcom m_maildir.o
+_strcpy m_maildir.o
+_strlen m_maildir.o
+_sysed m_maildir.o
+cret m_maildir.o
+csv m_maildir.o
+cret m_name.o
+csv m_name.o
+_cndfree m_replace.o
+_compone m_replace.o
+_current m_replace.o
+_def_fla m_replace.o
+_defalt m_replace.o
+_distcom m_replace.o
+_draft m_replace.o
+_filepro m_replace.o
+_foldpro m_replace.o
+_getcpy m_replace.o
+_hostnam m_replace.o
+_install m_replace.o
+_listnam m_replace.o
+_lockdir m_replace.o
+_lsproc m_replace.o
+_m_defs m_replace.o
+_m_getde m_replace.o
+_mailbox m_replace.o
+_malloc m_replace.o
+_mh_deli m_replace.o
+_mh_prof m_replace.o
+_mhnews m_replace.o
+_msgprot m_replace.o
+_mypath m_replace.o
+_pfolder m_replace.o
+_prproc m_replace.o
+_scanpro m_replace.o
+_sendpro m_replace.o
+_showpro m_replace.o
+_stdcomp m_replace.o
+_stddcom m_replace.o
+_strcmp m_replace.o
+_sysed m_replace.o
+_uleq m_replace.o
+cret m_replace.o
+csv m_replace.o
+__iob m_send.o
+_compone m_send.o
+_current m_send.o
+_def_fla m_send.o
+_defalt m_send.o
+_distcom m_send.o
+_draft m_send.o
+_execv m_send.o
+_fflush m_send.o
+_filepro m_send.o
+_foldpro m_send.o
+_fprintf m_send.o
+_hostnam m_send.o
+_install m_send.o
+_listnam m_send.o
+_lockdir m_send.o
+_lsproc m_send.o
+_m_defs m_send.o
+_m_updat m_send.o
+_mailbox m_send.o
+_mh_deli m_send.o
+_mh_prof m_send.o
+_mhnews m_send.o
+_msgprot m_send.o
+_mypath m_send.o
+_pfolder m_send.o
+_prproc m_send.o
+_scanpro m_send.o
+_sendpro m_send.o
+_showpro m_send.o
+_stdcomp m_send.o
+_stddcom m_send.o
+_sysed m_send.o
+cret m_send.o
+csv m_send.o
+__iob m_setcur.o
+_close m_setcur.o
+_compone m_setcur.o
+_concat m_setcur.o
+_creat m_setcur.o
+_current m_setcur.o
+_def_fla m_setcur.o
+_defalt m_setcur.o
+_distcom m_setcur.o
+_draft m_setcur.o
+_exit m_setcur.o
+_filepro m_setcur.o
+_foldpro m_setcur.o
+_fprintf m_setcur.o
+_free m_setcur.o
+_hostnam m_setcur.o
+_install m_setcur.o
+_listnam m_setcur.o
+_lockdir m_setcur.o
+_lsproc m_setcur.o
+_m_defs m_setcur.o
+_m_name m_setcur.o
+_m_repla m_setcur.o
+_mailbox m_setcur.o
+_mh_deli m_setcur.o
+_mh_prof m_setcur.o
+_mhnews m_setcur.o
+_mp m_setcur.o
+_msgprot m_setcur.o
+_mypath m_setcur.o
+_pfolder m_setcur.o
+_prproc m_setcur.o
+_scanpro m_setcur.o
+_sendpro m_setcur.o
+_showpro m_setcur.o
+_stdcomp m_setcur.o
+_stddcom m_setcur.o
+_strcmp m_setcur.o
+_strcpy m_setcur.o
+_strlen m_setcur.o
+_sysed m_setcur.o
+_write m_setcur.o
+cret m_setcur.o
+csv m_setcur.o
+__iob m_update.o
+_compone m_update.o
+_current m_update.o
+_def_fla m_update.o
+_defalt m_update.o
+_defpath m_update.o
+_distcom m_update.o
+_done m_update.o
+_draft m_update.o
+_fclose m_update.o
+_filepro m_update.o
+_foldpro m_update.o
+_fopen m_update.o
+_fprintf m_update.o
+_hostnam m_update.o
+_install m_update.o
+_listnam m_update.o
+_lockdir m_update.o
+_lsproc m_update.o
+_m_defs m_update.o
+_mailbox m_update.o
+_mh_deli m_update.o
+_mh_prof m_update.o
+_mhnews m_update.o
+_msgprot m_update.o
+_mypath m_update.o
+_pfolder m_update.o
+_prproc m_update.o
+_scanpro m_update.o
+_sendpro m_update.o
+_showpro m_update.o
+_signal m_update.o
+_stdcomp m_update.o
+_stddcom m_update.o
+_sysed m_update.o
+cret m_update.o
+csv m_update.o
+__iob makedir.o
+_atooi makedir.o
+_chmod makedir.o
+_compone makedir.o
+_current makedir.o
+_def_fla makedir.o
+_defalt makedir.o
+_distcom makedir.o
+_draft makedir.o
+_execl makedir.o
+_filepro makedir.o
+_foldpro makedir.o
+_fork makedir.o
+_fprintf makedir.o
+_hostnam makedir.o
+_install makedir.o
+_listnam makedir.o
+_lockdir makedir.o
+_lsproc makedir.o
+_m_defs makedir.o
+_m_find makedir.o
+_mailbox makedir.o
+_mh_deli makedir.o
+_mh_prof makedir.o
+_mhnews makedir.o
+_msgprot makedir.o
+_mypath makedir.o
+_pfolder makedir.o
+_prproc makedir.o
+_scanpro makedir.o
+_sendpro makedir.o
+_showpro makedir.o
+_stdcomp makedir.o
+_stddcom makedir.o
+_sysed makedir.o
+_wait makedir.o
+cret makedir.o
+csv makedir.o
+__iob makename.o
+_compone makename.o
+_current makename.o
+_def_fla makename.o
+_defalt makename.o
+_distcom makename.o
+_draft makename.o
+_exit makename.o
+_filepro makename.o
+_foldpro makename.o
+_fprintf makename.o
+_getpid makename.o
+_hostnam makename.o
+_install makename.o
+_listnam makename.o
+_lockdir makename.o
+_lsproc makename.o
+_m_defs makename.o
+_mailbox makename.o
+_mh_deli makename.o
+_mh_prof makename.o
+_mhnews makename.o
+_msgprot makename.o
+_mypath makename.o
+_pfolder makename.o
+_prproc makename.o
+_scanpro makename.o
+_sendpro makename.o
+_showpro makename.o
+_stdcomp makename.o
+_stddcom makename.o
+_sysed makename.o
+cret makename.o
+csv makename.o
+__filbuf peekc.o
+_ungetc peekc.o
+cret peekc.o
+csv peekc.o
+_printf pr_array.o
+cret pr_array.o
+csv pr_array.o
+_compone printsw.o
+_current printsw.o
+_def_fla printsw.o
+_defalt printsw.o
+_distcom printsw.o
+_draft printsw.o
+_filepro printsw.o
+_foldpro printsw.o
+_hostnam printsw.o
+_install printsw.o
+_listnam printsw.o
+_lockdir printsw.o
+_lsproc printsw.o
+_m_defs printsw.o
+_mailbox printsw.o
+_mh_deli printsw.o
+_mh_prof printsw.o
+_mhnews printsw.o
+_msgprot printsw.o
+_mypath printsw.o
+_pfolder printsw.o
+_printf printsw.o
+_prproc printsw.o
+_scanpro printsw.o
+_sendpro printsw.o
+_showpro printsw.o
+_ssequal printsw.o
+_stdcomp printsw.o
+_stddcom printsw.o
+_strlen printsw.o
+_sysed printsw.o
+cret printsw.o
+csv printsw.o
+_asctime putdate.o
+_fprintf putdate.o
+_ftime putdate.o
+_localti putdate.o
+_strncmp putdate.o
+_time putdate.o
+_timezon putdate.o
+cret putdate.o
+csv putdate.o
+cret r1bindex.o
+csv r1bindex.o
+__iob showfile.o
+_compone showfile.o
+_current showfile.o
+_def_fla showfile.o
+_defalt showfile.o
+_distcom showfile.o
+_draft showfile.o
+_execv showfile.o
+_fflush showfile.o
+_filepro showfile.o
+_foldpro showfile.o
+_fork showfile.o
+_fprintf showfile.o
+_hostnam showfile.o
+_install showfile.o
+_listnam showfile.o
+_lockdir showfile.o
+_lsproc showfile.o
+_m_defs showfile.o
+_m_updat showfile.o
+_mailbox showfile.o
+_mh_deli showfile.o
+_mh_prof showfile.o
+_mhnews showfile.o
+_msgprot showfile.o
+_mypath showfile.o
+_perror showfile.o
+_pfolder showfile.o
+_prproc showfile.o
+_scanpro showfile.o
+_sendpro showfile.o
+_showpro showfile.o
+_signal showfile.o
+_stdcomp showfile.o
+_stddcom showfile.o
+_sysed showfile.o
+_wait showfile.o
+cret showfile.o
+csv showfile.o
+_compone smatch.o
+_current smatch.o
+_def_fla smatch.o
+_defalt smatch.o
+_distcom smatch.o
+_draft smatch.o
+_filepro smatch.o
+_foldpro smatch.o
+_hostnam smatch.o
+_install smatch.o
+_listnam smatch.o
+_lockdir smatch.o
+_lsproc smatch.o
+_m_defs smatch.o
+_mailbox smatch.o
+_mh_deli smatch.o
+_mh_prof smatch.o
+_mhnews smatch.o
+_msgprot smatch.o
+_mypath smatch.o
+_pfolder smatch.o
+_prproc smatch.o
+_scanpro smatch.o
+_sendpro smatch.o
+_showpro smatch.o
+_stdcomp smatch.o
+_stddcom smatch.o
+_strlen smatch.o
+_sysed smatch.o
+cret smatch.o
+csv smatch.o
+cret ssequal.o
+csv ssequal.o
+_malloc trimcpy.o
+_strcpy trimcpy.o
+cret trimcpy.o
+csv trimcpy.o
+_write type.o
+cret type.o
+csv type.o
+cret uleq.o
+csv uleq.o
--- /dev/null
+subs.a: add.o \
+ ambigsw.o \
+ atooi.o \
+ brkstring.o \
+ cdate.o \
+ cndfree.o \
+ concat.o \
+ copy.o \
+ copyip.o \
+ cputc.o \
+ done.o \
+ fdcompare.o \
+ gans.o \
+ getans.o \
+ getcpy.o \
+ help.o \
+ invo_name.o \
+ locv.o \
+ m_convert.o \
+ m_delete.o \
+ m_edit.o \
+ m_find.o \
+ m_getdefs.o \
+ m_getfld.o \
+ m_getfolder.o \
+ m_gmprot.o \
+ m_gmsg.o \
+ m_maildir.o \
+ m_name.o \
+ m_replace.o \
+ m_send.o \
+ m_setcur.o \
+ m_update.o \
+ makedir.o \
+ makename.o \
+ peekc.o \
+ pr_array.o \
+ printsw.o \
+ putdate.o \
+ r1bindex.o \
+ showfile.o \
+ smatch.o \
+ ssequal.o \
+ trimcpy.o \
+ type.o \
+ uleq.o
+
+ ar cr subs.a `lorder *.o | tsort`
+
+.c.o:
+ cc -I../cmds -I/usr/src/ucb/libndir -c -O $*.c
+ -@ld -x -r $@
+ @mv a.out $@
+
+clean:
+ rm -f *.o subs.a
--- /dev/null
+char *add(this, that)
+register char *this, *that;
+{
+ register char *r;
+
+ if(!this)
+ this = "";
+ if(!that)
+ that = "";
+ r = (char *) malloc(strlen(this)+strlen(that)+1);
+ sprintf(r, "%s%s", that, this);
+ if(*that)
+ cndfree(that);
+ return(r);
+}
--- /dev/null
+#include <stdio.h>
+
+ambigsw(arg, swp)
+char *arg;
+{
+ fprintf(stderr, "%s: ", invo_name());
+ fprintf(stderr, "-%s ambiguous. It matches \n", arg);
+ printsw(arg, swp, "-");
+}
+
--- /dev/null
+atooi(cp)
+register char *cp;
+{
+ register int i, base;
+
+/* base = 10; */
+ i = 0;
+/* if(*cp == '0') */
+ base = 8;
+ while(*cp >= '0' && *cp <= '9') {
+ i *= base;
+ i += *cp++ - '0';
+ }
+ return(i);
+}
--- /dev/null
+#define NSTR 25
+char **brkstring(strg,brksep,brkterm) /* returns pointer to static table of substring ptrs */
+char *strg;
+char *brksep, *brkterm;
+{
+
+ register char c, *bp, *sp;
+ static char *broken[NSTR+1]; /* static array of substring start addresses */
+ int bi;
+
+ sp = strg; /* scan string, replacing separators with zeroes */
+
+ for (bi=0; bi<NSTR; bi++) { /* and entering start addrs in "broken" */
+ while (brkany(c = *sp, brksep)) *sp++ = 0;
+ if (!c || brkany(c, brkterm)) {
+ *sp=0;
+ broken[bi] = 0;
+ return(broken); /* terminator found, finish up */
+ }
+
+ broken[bi] = sp; /* set next start addr */
+
+ while ((c = *++sp) && !brkany(c,brksep) && !brkany(c,brkterm));
+
+ }
+ broken[NSTR] = 0; /* reached limit of NSTR substrings */
+ return (broken);
+}
+
+brkany (chr,strg) /* returns 1 if chr in strg, 0 otherwise */
+char chr,*strg;
+{
+ register char *sp;
+
+ for (sp=strg; *sp; sp++)
+ if (chr == *sp) return (1);
+ return (0);
+}
--- /dev/null
+/* returns date in format dd-mon-yy@hh:mm:ss\0 */
+char *cdate(dataddr)
+long *dataddr;
+{
+ register char *cp;
+ char *ctime();
+
+ cp = ctime(dataddr);
+ cp[1] = cp[8];
+ cp[2] = cp[9];
+ cp[3] = '-';
+ cp[7] = '-';
+ cp[8] = cp[22];
+ cp[9] = cp[23];
+ cp[10] = '@';
+ cp[19] = 0;
+ return(cp+1);
+}
--- /dev/null
+/* Conditional free -- perform a free call if the address passed
+ * is in free storage; else NOP
+ */
+
+
+cndfree(addr)
+char *addr;
+{
+ extern char end;
+
+ if(addr >= &end) free(addr);
+}
--- /dev/null
+#include "mh.h"
+
+char *concat(args)
+char *args;
+{
+ register char **a;
+ register char *cp;
+ register int len;
+ register char *ret;
+
+ len = 1;
+ for(a = &args; *a; )
+ len += strlen(*a++);
+ ret = cp = (char *) malloc(len);
+ for(a = &args; *a; )
+ cp = copy(*a++, cp);
+ return(ret);
+}
--- /dev/null
+char *copy(from,to)
+register char *from, *to;
+{
+ while(*to++ = *from++);
+ return to-1;
+};
--- /dev/null
+int *copyip(ipf, ipt)
+register int *ipf, *ipt;
+{
+ while((*ipt = *ipf) && *ipf++ != -1)
+ ipt++;
+ *ipt = 0;
+ return(ipt);
+}
+
--- /dev/null
+#include <stdio.h>
+
+cputc(chr, ip)
+register FILE *ip;
+{
+ if(ip != NULL) {
+ putc(chr, ip);
+ if(ferror(ip)) {
+ perror("Write error");
+ done(-1);
+ }
+ }
+}
--- /dev/null
+#define NSTR 25
+
+/*
+ * Parse the given string into a number of sub strings separated
+ * by characters in brksep. Terminate on brkterm or 0.
+ */
+
+char **
+brkstring(strg, brksep, brkterm)
+ char *strg;
+ char *brksep, *brkterm;
+{
+ register int c;
+ register char *cp, **ap;
+ static char *broken[NSTR+1];
+
+ cp = strg;
+ ap = broken;
+ for (;;) {
+ if (ap-broken > NSTR) {
+ broken[NSTR] = 0;
+ return(broken);
+ }
+ while (brkany(*cp, brksep))
+ cp++;
+ if (*cp == 0 || *cp == brkterm) {
+done:
+ *ap = 0;
+ return(broken);
+ }
+ *ap++ = cp;
+ while (!brkany(*cp, brksep) && *cp && *cp != brkterm)
+ cp++;
+ if (*cp == 0 || *cp == brkterm) {
+ *cp = 0;
+ goto done;
+ }
+ *cp++ = 0;
+ }
+}
+
+brkany (chr,strg) /* returns 1 if chr in strg, 0 otherwise */
+char chr,*strg;
+{
+ register char *sp;
+
+ for (sp=strg; *sp; sp++)
+ if (chr == *sp) return (1);
+ return (0);
+}
--- /dev/null
+/* This routine is replaced by some modules if they need to do
+ * cleanup. All exits in the code call done rather than exit.
+ */
+
+done(status)
+{
+ exit(status);
+}
--- /dev/null
+fdcompare(fd1, fd2)
+{
+ int n1, n2, resp;
+ register int i;
+ register char *c1, *c2;
+ char b1[512], b2[512];
+
+ resp = 1;
+ while((n1 = read(fd1, b1, 512)) >= 0 &&
+ (n2 = read(fd2, b2, 512)) >= 0 &&
+ n1 == n2) {
+
+ c1 = b1; c2 = b2;
+ for(i = n1 < 512? n1 : 512; i--; )
+ if(*c1++ != *c2++) {
+ resp = 0;
+ goto leave;
+ }
+ if(n1 < 512)
+ goto leave;
+ }
+ resp = 0;
+leave:
+ lseek(fd1, 0l, 0);
+ lseek(fd2, 0l, 0);
+ return(resp);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+gans(prompt, ansp)
+struct swit *ansp;
+{
+ char ansbuf[32];
+ register char *cp;
+ register int i;
+ struct swit *ap;
+
+ for(;;) {
+ printf("%s", prompt);
+ fflush(stdout);
+ cp = ansbuf;
+ while((i = getchar()) != '\n') {
+ if(i == EOF)
+ return(0);
+ if(cp < &ansbuf[31]) {
+ if(i >= 'A' && i <= 'Z')
+ i += 'a'-'A';
+ *cp++ = i;
+ }
+ }
+ *cp = 0;
+ if(ansbuf[0] == '?' || cp == ansbuf) {
+ printf("Options are:\n");
+ for(ap = ansp; ap->sw; ap++)
+ printf(" %s\n", ap->sw);
+ continue;
+ }
+ if((i = smatch(ansbuf, ansp)) < 0) {
+ printf("%s: %s.\n", ansbuf, i == -1? "unknown":"ambiguous");
+ continue;
+ }
+ return(i);
+ }
+}
--- /dev/null
+#include "mh.h"
+#include <signal.h>
+#include <stdio.h>
+
+int g_sigint; /* sensed an interrupt */
+int g_sig();
+
+char **getans(prompt, ansp)
+struct swit *ansp;
+{
+ static char ansbuf[128];
+ register char *cp, **cpp;
+ register int i;
+ struct swit *ap;
+
+ signal(SIGINT, g_sig);
+ for(;;) {
+ printf("%s", prompt);
+ fflush(stdout);
+ cp = ansbuf;
+ while((i = getchar()) != '\n') {
+ if(i == EOF || g_sigint) {
+ g_sigint = 0;
+ return(0);
+ }
+ if(cp < &ansbuf[127])
+ *cp++ = i;
+ }
+ *cp = 0;
+ if(ansbuf[0] == '?' || cp == ansbuf) {
+ printf("Options are:\n");
+ printsw(ALL, ansp, "");
+ continue;
+ }
+ cpp = brkstring(ansbuf, " ", 0);
+ switch(smatch(*cpp, ansp)) {
+ case -2:ambigsw(*cpp, ansp); /* ambiguous */
+ continue;
+ case -1: /* unknown */
+ printf(" -%s unknown. Hit <CR> for help.\n", *cpp);
+ continue;
+ default:
+ return(cpp); /* list, edit, quit, send */
+ }
+ }
+}
+
+
+g_sig()
+{
+ signal(SIGINT, g_sig);
+ g_sigint = 1;
+ return;
+}
--- /dev/null
+char *getcpy(str)
+{
+ register char *cp;
+
+ cp = (char *) malloc(strlen(str) + 1);
+ strcpy(cp, str);
+ return(cp);
+}
--- /dev/null
+#include "mh.h"
+
+help(str, swp)
+char *str;
+{
+ printf("syntax: %s\n", str);
+ printf(" switches are:\n");
+ printsw(ALL, swp, "-");
+}
--- /dev/null
+/*
+ * This routine returns the address on the stack of the text of the
+ * first argument to the process. It only works on the VAX, and only
+ * if the process was not called with 4 empty args in a row.
+ */
+
+char *invo_name()
+{
+ register int *ip;
+
+ ip = (int *) 0x7ffffff8; /* Highest stack address -4 */
+
+ while(*--ip != 0) /* Look backwards for bumber */
+ ;
+ return (char *) &ip[1]; /* Next string is it. */
+}
--- /dev/null
+char *locv(longint)
+long longint;
+{
+ static char locvbuf[12];
+
+ sprintf(locvbuf, "%ld", longint);
+ return locvbuf;
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+int convdir;
+struct msgs *mp;
+char *delimp;
+
+m_convert(name)
+char *name;
+{
+ register char *cp;
+ register int first, last;
+ int found, group, range, err;
+ char *bp;
+
+ found = group = 0;
+ if(strcmp((cp = name), "all") == 0)
+ cp = "first-last";
+ if((err = first = m_conv(cp)) <= 0)
+ goto badbad;
+ if(*(cp = delimp) && *cp != '-' && *cp != ':') {
+ baddel: fprintf(stderr, "Illegal argument delimiter: \"%c\"\n", *delimp);
+ return(0);
+ }
+ if(*cp == '-') {
+ group++; cp++;
+ if((err = last = m_conv(cp)) <= 0) {
+ badbad: if(err == -1)
+ fprintf(stderr, "No %s message\n", cp);
+ else
+ badlist: fprintf(stderr, "Bad message list \"%s\".\n", name);
+ return(0);
+ }
+ if(last < first) goto badlist;
+ if(*delimp) goto baddel;
+ if(first > mp->hghmsg || last < mp->lowmsg) {
+ rangerr: fprintf(stderr, "No messages in range \"%s\".\n", name);
+ return(0);
+ }
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ } else if(*cp == ':') {
+ cp++;
+ if(*cp == '-') {
+ convdir = -1;
+ cp++;
+ } else if(*cp == '+') {
+ convdir = 1;
+ cp++;
+ }
+ if((range = atoi(bp = cp)) == 0)
+ goto badlist;
+ while(*bp >= '0' && *bp <= '9') bp++;
+ if(*bp)
+ goto baddel;
+ if((convdir > 0 && first > mp->hghmsg) ||
+ (convdir < 0 && first < mp->lowmsg))
+ goto rangerr;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ if(first > mp->hghmsg)
+ first = mp->hghmsg;
+ for(last = first; last >= mp->lowmsg && last <= mp->hghmsg;
+ last += convdir)
+ if(mp->msgstats[last]&EXISTS)
+ if(--range <= 0)
+ break;
+ if(last < mp->lowmsg)
+ last = mp->lowmsg;
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(last < first) {
+ range = last; last = first; first = range;
+ }
+ } else {
+ if(first > mp->hghmsg || first < mp->lowmsg ||
+ !(mp->msgstats[first]&EXISTS)) {
+ fprintf(stderr, "Message %d doesn't exist.\n", first);
+ return(0);
+ }
+ last = first;
+ }
+ while(first <= last) {
+ if(mp->msgstats[first]&EXISTS) {
+ if(!(mp->msgstats[first]&SELECTED)) {
+ mp->numsel++;
+ mp->msgstats[first] |= SELECTED;
+ if(first < mp->lowsel)
+ mp->lowsel = first;
+ if(first > mp->hghsel)
+ mp->hghsel = first;
+ }
+ found++;
+ }
+ first++;
+ }
+ if(!found)
+ goto rangerr;
+ return(1);
+}
+
+m_conv(str)
+char *str;
+{
+ register char *cp, *bp;
+ register int i;
+ char buf[16];
+
+ convdir = 1;
+ cp = bp = str;
+ if(*cp >= '0' && *cp <= '9') {
+ while(*bp >= '0' && *bp <= '9') bp++;
+ delimp = bp;
+ return(atoi(cp));
+ }
+ bp = buf;
+ while((*cp >= 'a' && *cp <= 'z') || *cp == '.')
+ *bp++ = *cp++;
+ *bp++ = 0;
+ delimp = cp;
+ if(strcmp(buf, "first") == 0)
+ return(mp->lowmsg);
+ else if(strcmp(buf, "last") == 0) {
+ convdir = -1;
+ return(mp->hghmsg);
+ } else if(strcmp(buf, "cur") == 0 || strcmp(buf, ".") == 0)
+ return(mp->curmsg > 0 ? mp->curmsg : -1);
+ else if(strcmp(buf, "prev") == 0) {
+ convdir = -1;
+ for(i = (mp->curmsg<=mp->hghmsg)? mp->curmsg-1: mp->hghmsg;
+ i >= mp->lowmsg; i--) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1); /* non-existent message */
+ } else if(strcmp(buf, "next") == 0) {
+ for(i = (mp->curmsg>=mp->lowmsg)? mp->curmsg+1: mp->lowmsg;
+ i <= mp->hghmsg; i++) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1);
+ } else
+ return(0); /* bad message list */
+}
--- /dev/null
+#include "mh.h"
+
+m_delete(key)
+char *key;
+{
+ register struct node *np, *npprev;
+
+ m_getdefs();
+ for(np = (struct node *) &m_defs; npprev = np; ) {
+ if((np = np->n_next) == 0)
+ break;
+ if(uleq(np->n_name, key)) {
+ npprev->n_next = np->n_next;
+ cndfree(np->n_name);
+ cndfree(np->n_field);
+ free(np);
+ def_flags |= DEFMOD;
+ return(0);
+ }
+ }
+ return(1);
+}
--- /dev/null
+#include "mh.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <stdio.h>
+#include "strings.h"
+
+struct msgs *mp;
+
+char *rindex();
+
+m_edit(ed, file, use, altmsg)
+char **ed, *file, *altmsg;
+int use;
+{
+ /* Exec editor. Normal exit returns 0.
+ * To abort, returns -1. To try again, returns -2
+ */
+
+ static char *edsave;
+ static int reedit;
+ struct stat stbuf;
+ int retstat;
+ register char *cp;
+ int pid, wpid;
+ int intr;
+ union { int statint;
+ struct {char lobyte, hibyte;} statby;
+ } status;
+
+ if(!reedit) { /* set initial editor */
+ if(!*ed && (*ed = m_find("editor")) == NULL)
+ *ed = sysed;
+ } else
+ if(!*ed) { /* no explicit editor */
+ *ed = edsave;
+ cp = rindex(*ed, '/');
+ if(cp == 0)
+ cp = *ed;
+ cp = concat(cp, "-next", 0);
+ if((cp = m_find(cp)) != NULL)
+ *ed = cp;
+ }
+ intr = (int) signal(SIGINT, SIG_IGN);
+ if((pid = fork()) == 0) {
+ if(altmsg) {
+ unlink("@");
+ link(altmsg, "@"); /* An easy handle on cur msg */
+ }
+ m_update();
+ fflush(stdout);
+ signal(SIGINT, (int (*)()) intr);
+ execlp(*ed, *ed, file, 0);
+ fprintf(stderr, "Can't exec the editor: ");
+ perror(*ed); done(-1);
+ } else if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ retstat = -1;
+ goto leave;
+ } else
+ while((wpid = wait(&status)) != -1 && wpid != pid) ;
+ signal(SIGINT, (int (*)()) intr);
+ if(status.statint) {
+ if((status.statby.hibyte == -1) || /* Can't exec editor */
+ (reedit && !status.statby.lobyte)) { /*2nd edit.Aborted by user*/
+ retstat = -2;
+ goto leave;
+ }
+ fprintf(stderr, "[%s aborted--%s ", invo_name(), file);
+ if(!use && status.statby.hibyte) { /* edit aborted by user */
+ unlink(file);
+ fprintf(stderr, "deleted]\n");
+ } else /* 'use' or system abort */
+ fprintf(stderr, "preserved]\n");
+ retstat = -2;
+ goto leave;
+ }
+ reedit++;
+ retstat = 0;
+ if(altmsg && !mp->msgflags&READONLY) {
+ stat("@", &stbuf);
+ if(stbuf.st_nlink == 1) /*@'s been edited by Ned*/
+ if(unlink(altmsg) == -1 || link("@", altmsg) == -1){
+ fprintf(stderr, "Can't update %s from @ file!\n",altmsg);
+ retstat = 0;
+ goto leave;
+ }
+ }
+ leave:
+ edsave = getcpy(*ed);
+ *ed = 0;
+ unlink("@"); /* Remove this extra link */
+ return(retstat);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+char *m_find(str)
+{
+ register struct node *n;
+
+ m_getdefs();
+ for(n = m_defs; n; n = n->n_next)
+ if(uleq(n->n_name, str))
+ return(n->n_field);
+ return(NULL);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+char defpath[128];
+
+struct procs {
+ char *procname;
+ char **procnaddr;
+} procs [] = {
+ { "lsproc", &lsproc },
+ { "mh_deliver", &mh_deliver },
+ { "prproc", &prproc },
+ { "scanproc", &scanproc },
+ { "showproc", &showproc },
+ { "sendproc", &sendproc },
+ { "fileproc", &fileproc },
+ { 0, 0 },
+};
+
+m_getdefs()
+{
+ register struct node *np;
+ register int state, wpid, pid;
+ register struct procs *ps;
+ int status;
+ FILE *ib;
+ char name[NAMESZ], field[128];
+
+ if(defpath[0])
+ return; /* We've already been called! */
+ if(!mypath)
+ if((mypath = getenv("HOME")) == NULL) {
+ fprintf(stderr, "HOME environment variable not set!\n");
+ done(1);
+ }
+ sprintf(defpath, "%s%s", mypath, mh_prof);
+/*** copy(mh_prof, copy(mypath, defpath)); ***/
+
+ if((ib = fopen(defpath, "r")) == NULL) {
+ if((pid = fork()) == 0) {
+ execl(installproc, "install-mh", "-auto", 0);
+ fprintf(stderr, "Can't exec ");perror(installproc);
+ done(1);
+ } else if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ done(1);
+ } else
+ while((wpid = wait(&status)) != -1 && wpid != pid)
+ ;
+ if(status || (ib = fopen(defpath, "r")) == NULL) {
+ fprintf(stderr, "[install-mh aborted]\n");
+ done(1);
+ }
+ }
+
+#ifdef NEWS /* NOT CONVERTED TO V7!!! */
+ fstat(fildes(ib), field);
+ deftime = (&field)->i_atime;
+#endif
+
+ np = (struct node *) &m_defs;
+ state = FLD;
+ for(;;)
+ switch(state = m_getfld(state,name,field,sizeof field,ib)) {
+ case FLD:
+ case FLDEOF:
+ np->n_next = (struct node *) malloc(sizeof *np);
+ np = np->n_next;
+ np->n_name = getcpy(name);
+ np->n_field = trimcpy(field);
+ np->n_next = 0;
+ for(ps = procs; ps->procname; ps++)
+ if(strcmp(np->n_name, ps->procname) == 0) {
+ *ps->procnaddr = np->n_field;
+ break;
+ }
+ if(state == FLDEOF) {
+ fclose(ib);
+ return(0);
+ }
+ continue;
+ case BODY:
+ case BODYEOF:
+ fprintf(stderr, ".mh_profile must not contain a body--it can't \
+end with a blank line!\n");
+ default:
+ fprintf(stderr, "Bad format: .mh_profile!\n");
+ done(1);
+ }
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+int m_fldsz;
+
+m_getfld(state, name, buf, bufsz, iob)
+int state, bufsz;
+char *name, *buf;
+FILE *iob;
+{
+ register char *cp;
+ register c;
+
+ top: while((c = getc(iob)) == '\001' && peekc(iob) == '\001')
+ while(getc(iob) != '\n');
+
+ if(c < 0)
+ return(FILEEOF);
+ m_fldsz = 0;
+
+ switch(state) {
+
+ case FLDEOF:
+ case BODYEOF:
+ case FLD:
+ if(c == '\n' || c == '-')
+ goto body;
+ cp = name;
+ for(;;) {
+ if(cp >= name+NAMESZ-1) {
+ *cp = 0;
+fprintf(stderr, "??Component Name Exceeds %d Chars:\n \"%s\"\n", NAMESZ-1, name);
+ return(LENERR);
+ }
+ if(c == ':')
+ break;
+ if(c == '\n' || c < 0) {
+ *cp = 0;
+fprintf(stderr, "??%s Encountered While Scanning for a colon:\n \"%s\"\n",
+ (c < 0)? "<eof>":"<end of line>", name);
+ return(FMTERR);
+ }
+ *cp++ = c;
+ *cp = 0;
+ c = getc(iob);
+ }
+
+ case FLDPLUS:
+ cp = buf;
+ for(;;) {
+ if((c = getc(iob)) < 0)
+ return(FLDEOF);
+ *cp++ = c;
+ *cp = 0;
+ m_fldsz++;
+ if(c == '\n')
+ if((c = peekc(iob)) != ' ' && c != '\t')
+ if(c == '\001' || c < 0)
+ return(FLDEOF);
+ else
+ return(FLD);
+ if(cp >= buf+bufsz-1)
+ return(peekc(iob) < 0? FLDEOF:FLDPLUS);
+ }
+
+ body: if(c == '-')
+ while(getc(iob) != '\n') ;
+ buf[0] = 0;
+ if((c = getc(iob)) == '\001' && peekc(iob) == '\001')
+ return(BODYEOF);
+
+ case BODY:
+ cp = buf; *cp = 0;
+ for(;;) {
+ if(c < 0 || (c == '\001' && peekc(iob) == '\001'))
+ return(BODYEOF);
+ *cp++ = c;
+ *cp = 0;
+ m_fldsz++;
+ if(cp >= buf+bufsz-1)
+ return(((c=peekc(iob))<0||c=='\001')?
+ BODYEOF: BODY);
+ c = getc(iob);
+ }
+
+ }
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+char *m_getfolder()
+{
+ register char *folder;
+
+ m_getdefs();
+ if((folder = m_find(pfolder)) == NULL || *folder == 0)
+ folder = defalt;
+ return(folder);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+m_gmprot()
+{
+ register char *cp;
+ register int prot;
+
+ if((cp = m_find("msg-protect")) != NULL)
+ prot = atooi(cp);
+ else
+ prot = atooi(msgprot);
+ return(prot);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <dir.h>
+
+struct msgs *mp;
+
+struct msgs *m_gmsg(name)
+char *name;
+{
+ register int i, j;
+ register char *cp;
+ register struct msgs *msgp;
+ register struct direct *dir;
+ DIR *dirp;
+ int curfil;
+ struct stat statb;
+ char buf[132];
+
+ struct {
+ int xhghmsg,
+ xnummsg,
+ xlowmsg,
+ xcurmsg;
+ char xselist,
+ xflags,
+ xfiller,
+ xothers;
+ char xmsgs[1000];
+ } msgbuf;
+
+ if ((dirp = opendir(".")) == 0)
+ return (0);
+ for(j = 0; j < 1000; j++)
+ msgbuf.xmsgs[j] = 0;
+ msgbuf.xcurmsg = 0;
+ msgbuf.xnummsg = 0;
+ msgbuf.xselist = 0;
+ msgbuf.xothers = 0;
+ msgbuf.xlowmsg = 5000;
+ msgbuf.xhghmsg = 0;
+ msgbuf.xflags = (access(".",2) == -1)? READONLY:0;
+
+ /*
+ * The following hack is that if the directory is writable
+ * and the cur file is not, we consider it to be read only
+ * folder.
+ */
+
+ if (stat("cur", &statb) >= 0 && access("cur", 2) < 0)
+ msgbuf.xflags |= READONLY;
+ curfil = 0;
+ while (dir = readdir(dirp)) {
+ cp = dir->d_name;
+ if (j = mu_atoi(cp)) {
+ if (j > msgbuf.xhghmsg)
+ msgbuf.xhghmsg = j;
+ msgbuf.xnummsg++;
+ if (j < msgbuf.xlowmsg)
+ msgbuf.xlowmsg = j;
+ msgbuf.xmsgs[j] = EXISTS;
+ } else if (*cp != ',' && *cp != '.' && *cp != '#')
+ if (strcmp(cp, current) == 0)
+ curfil++;
+ else if (strcmp(cp, listname) == 0)
+ msgbuf.xselist++;
+ else
+ msgbuf.xothers++;
+ }
+ if(!msgbuf.xhghmsg)
+ msgbuf.xlowmsg = 0;
+ closedir(dirp);
+ if(msgbuf.xflags&READONLY) {
+ sprintf(buf, "cur-%s", name);
+/*** copy(name, copy("cur-", buf)); ***/
+ if((cp = m_find(buf)) != NULL)
+ if(j = mu_atoi(cp))
+ msgbuf.xcurmsg = j;
+ } else if(curfil && (i = open(current, 0)) >= 0) {
+ if((j = read(i, buf, sizeof (buf))) >= 2) {
+ buf[j-1] = '\0'; /* Zap <lf> */
+ if (j = mu_atoi(buf))
+ msgbuf.xcurmsg = j;
+ }
+ close(i);
+ }
+ if( (int) (msgp = (struct msgs *) malloc(sizeof *mp + msgbuf.xhghmsg + 2)) == -1)
+ return(0);
+ msgp->hghmsg = msgbuf.xhghmsg;
+ msgp->nummsg = msgbuf.xnummsg;
+ msgp->lowmsg = msgbuf.xlowmsg;
+ msgp->curmsg = msgbuf.xcurmsg;
+ msgp->selist = msgbuf.xselist;
+ msgp->msgflags = msgbuf.xflags;
+ msgp->others = msgbuf.xothers;
+ msgp->foldpath = name;
+ msgp->lowsel = 5000;
+ msgp->hghsel = 0;
+ msgp->numsel = 0;
+ for(j = 0; j <= msgbuf.xhghmsg; j++)
+ msgp->msgstats[j] = msgbuf.xmsgs[j];
+ return(msgp);
+}
+
+
+mu_atoi(str)
+char *str;
+{
+ register char *cp;
+ register int i;
+
+ i = 0;
+ cp = str;
+ while(*cp) {
+ if(*cp < '0' || *cp > '9' || i > 99)
+ return(0);
+ i *= 10;
+ i += *cp++ - '0';
+ }
+ return(i);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+char *mypath;
+
+char *m_maildir(folder)
+char *folder;
+{
+ register char *fold, *path, *cp;
+ static char mailfold[128];
+
+ m_getdefs();
+ if(!(fold = folder))
+ fold = m_getfolder();
+ if(*fold == '/' || *fold == '.')
+ return(fold);
+ cp = mailfold;
+ if((path = m_find("path")) != NULL && *path) {
+ if(*path != '/') {
+ sprintf(cp, "%s/", mypath);
+ cp += strlen(cp);
+ }
+ cp = copy(path, cp);
+ if(cp[-1] != '/')
+ *cp++ = '/';
+ }
+ strcpy(cp, fold);
+ return(mailfold);
+}
--- /dev/null
+char *m_name(num)
+{
+ static char name[4];
+ register char *cp;
+ register int i;
+
+ name[0] = 0;
+ name[1] = 0;
+ name[2] = 0;
+ name[3] = 0;
+ i = num;
+ cp = &name[3];
+ if(i > 0 && i < 1000)
+ do {
+ *--cp = (i % 10) + '0';
+ i /= 10;
+ } while(i);
+ else
+ *--cp = '?';
+ return(cp);
+}
--- /dev/null
+#include "mh.h"
+
+
+m_replace(key,value)
+char *key, *value;
+
+{
+ register struct node *np;
+
+ m_getdefs();
+ for(np = m_defs; ; np = np->n_next) {
+ if(uleq(np->n_name, key)) {
+ if(strcmp(value, np->n_field) != 0) {
+ cndfree(np->n_field);
+ np->n_field = value;
+ def_flags |= DEFMOD;
+ }
+ return;
+ }
+ if(!np->n_next)
+ break;
+ }
+ np->n_next = (struct node *) malloc(sizeof *np);
+ np = np->n_next;
+ np->n_name = getcpy(key);
+ np->n_next = 0;
+ np->n_field = value;
+ def_flags |= DEFMOD;
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+m_send(arg, file)
+char *arg, *file;
+{
+ char *vec[10];
+ int ivec;
+
+ ivec = 0;
+ vec[ivec++] = "send";
+ vec[ivec++] = file;
+ if(*arg == 'v')
+ vec[ivec++] = "-verbose";
+ vec[ivec++] = 0;
+ m_update();
+ fflush(stdout);
+ execv(sendproc, vec);
+ fprintf(stderr, "Can't exec %s.\n", sendproc);
+ return(0);
+
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+struct msgs *mp;
+
+m_setcur(num)
+{
+ char buf[6];
+ register int i;
+ register char *cp1;
+
+ if(mp->msgflags&READONLY) {
+ m_replace(cp1 = concat("cur-",mp->foldpath,0), m_name(num));
+ free(cp1);
+ } else {
+ strcpy(buf, m_name(num));
+ cp1 = buf + strlen(buf);
+ *cp1++ = '\n';
+ if(strcmp(current, "cur"))
+ error("\"current\" got Clobbered!! Tell B. Borden");
+ if((i = creat(current, 0660)) >= 0) {
+ write(i, buf, cp1-buf);
+ close(i);
+ }
+ }
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <signal.h>
+
+char defpath[];
+
+m_update()
+{
+ FILE *out;
+ register struct node *np;
+ int save;
+
+ if(def_flags & DEFMOD) {
+ save = (int) signal(SIGINT, SIG_IGN);
+ if((out = fopen(defpath, "w")) == NULL) {
+ fprintf(stderr, "Can't create %s!!\n", defpath);
+ done(1);
+ }
+ for(np = m_defs; np; np = np->n_next)
+ fprintf(out, "%s: %s\n", np->n_name, np->n_field);
+ fclose(out);
+ signal(SIGINT, (int (*)()) save);
+ def_flags &= ~DEFMOD;
+ }
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+makedir(dir)
+{
+ register int i, pid, wpid;
+ register char *c;
+ int status;
+
+ if((pid = fork()) == 0) {
+ execl("/bin/mkdir", "mkdir", dir, 0);
+ execl("/usr/bin/mkdir", "mkdir", dir, 0);
+ fprintf(stderr, "Can't exec mkdir!!?\n");
+ return(0);
+ }
+ if(pid == -1) {
+ fprintf(stderr, "Can't fork\n");
+ return(0);
+ }
+ while((wpid = wait(&status)) != pid && wpid != -1) ;
+ if(status) {
+ fprintf(stderr, "Bad exit status (%o) from mkdir.\n", status);
+ return(0);
+ }
+ chmod(dir, ((c = m_find("folder-protect")) != NULL)?
+ atooi(c) : atooi(foldprot));
+ return(1);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+char *makename(prefix,suffix)
+char *prefix, *suffix;
+{
+ static char tmpname[15];
+ register char *cp1, *cp2;
+ register int pid;
+
+ pid = getpid();
+ cp1 = tmpname;
+ for (cp2 = prefix; *cp1++ = *cp2++; );
+ cp1--;
+ do *cp1++ = pid%10 + '0'; while (pid /= 10);
+ for (cp2 = suffix; *cp1++ = *cp2++; );
+ if (cp1 >= &tmpname[15]) error("strs too long to makename");
+ return (tmpname);
+}
--- /dev/null
+#include <stdio.h>
+
+peekc(ib)
+FILE *ib;
+{
+ register c;
+
+ c = getc(ib);
+ ungetc(c,ib);
+ return(c);
+}
--- /dev/null
+pr_array(cp,ap)
+char *cp, **ap;
+{
+ register int i;
+
+ for(i=0; *ap; ap++,i++)
+ printf("%s[%d]=> %s\n", cp,i,*ap);
+}
+
--- /dev/null
+#include "mh.h"
+
+printsw(substr, swp, prefix)
+char *substr, *prefix;
+struct swit *swp;
+{
+ char buf[128];
+ register char *cp, *cp1;
+ register int i;
+ int len;
+
+ len = strlen(substr);
+ for(; swp->sw; swp++)
+ if(!*substr || /* null matches all strings */
+ (ssequal(substr, swp->sw) && len >= swp->minchars))
+ if(swp->minchars > 0) {
+ cp = buf;
+ *cp++ = '(';
+ for(cp1 = swp->sw, i = 0; i < swp->minchars; i++)
+ *cp++ = *cp1++;
+ *cp++ = ')';
+ while(*cp++ = *cp1++);
+ printf(" %s%s\n", prefix, buf);
+ } else if(swp->minchars == 0)
+ printf(" %s%s\n", prefix, swp->sw);
+}
--- /dev/null
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <sys/time.h>
+
+/*
+ * Output the date in right format gotten from
+ * the passed ctime(3) format date.
+ * If the passed date is NULL, output the current
+ * date and time.
+ */
+
+putdate(timestr, out)
+ char *timestr;
+ register FILE *out;
+{
+ register char *t, *p, *cp;
+ char *timezone();
+ struct tm *tmp;
+ struct tm *localtime();
+ struct timeb tb;
+ long now;
+ int isdst;
+ char *asctime();
+ static char *str = "SunMonTueWedThuFriSat";
+ static char *daytag[] = {
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday"
+ };
+
+ now = time((long *) 0);
+ tmp = localtime(&now);
+ isdst = tmp->tm_isdst;
+ if (timestr == 0)
+ timestr = asctime(tmp);
+ cp = str;
+ t = timestr;
+ while (*cp) {
+ if (strncmp(cp, t, 3) == 0)
+ break;
+ cp += 3;
+ }
+ if (*cp)
+ cp = daytag[(cp - str) / 3];
+ else
+ cp = 0;
+ ftime(&tb);
+ /*
+ * This call to timezone() may be wrong:
+ * really need the tm_isdst whoever generated timestr.
+ */
+ p = timezone(tb.timezone, isdst);
+
+ if (cp == 0)
+ fprintf(out, "Date: %.2s %.3s %.4s %.2s%.2s-%.3s\n",
+ t+8, t+4, t+20, t+11, t+14, p);
+ else
+ fprintf(out, "Date: %.2s %.3s %.4s %.2s%.2s-%.3s (%s)\n",
+ t+8, t+4, t+20, t+11, t+14, p, cp);
+}
--- /dev/null
+/*
+ * r1bindex(str, chr) stands for Right plus 1 or Beginning index of
+ * chr in str. I.e. return ptr 1 past LAST occurance of chr in
+ * str, OR beginning of the string if str doesn't contain chr.
+ */
+
+char *
+r1bindex(str, chr)
+register char *str;
+register int chr;
+{
+ register char *cp;
+
+ for(cp = str; *cp; cp++) ;
+ --cp;
+ while(cp >= str && *cp != chr)
+ --cp;
+ return ++cp;
+}
--- /dev/null
+#include "mh.h"
+#include <signal.h>
+#include <stdio.h>
+
+showfile(file)
+char *file;
+{
+ int pid, wpid, intr, status;
+ char *vec[4];
+
+ intr = (int) signal(SIGINT, SIG_IGN);
+ m_update();
+ fflush(stdout);
+ if((pid = fork()) == 0) {
+ vec[0] = "mh-type";
+ vec[1] = file;
+ vec[2] = 0;
+ signal(SIGINT, (int (*)()) intr);
+ execv(showproc, vec);
+ perror("Can't exec showproc");
+ goto badleave;
+ } else if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ goto badleave;
+ } else
+ while((wpid = wait(&status)) != -1 && wpid != pid) ;
+ signal(SIGINT, (int (*)()) intr);
+ if(status & 0377)
+ goto badleave;
+ return(0);
+
+ badleave:
+ fflush(stdout);
+ return(1);
+
+}
+
--- /dev/null
+#include "mh.h"
+
+/* switch match, or any unambiguous abbreviation */
+/* exact match always wins, even if shares same root */
+/* returns subscript in zero-terminated tbl[] of strings */
+/* returns -1 if no match, -2 if ambiguous */
+
+#define abs(i) (i < 0 ? -i : i)
+
+smatch(string, swp)
+char *string;
+struct swit *swp;
+{
+ register char *sp, *tcp;
+ struct swit *tp;
+ int firstone, stringlen;
+
+ firstone = -1;
+
+ for (stringlen = strlen(string), tp = swp; tcp = tp->sw; tp++) {
+ if(stringlen < abs(tp->minchars)) continue; /* no match */
+ for (sp = string; *sp == *tcp++; ) {
+ if (*sp++ == 0) return(tp-swp); /* exact match */
+ }
+ if (*sp != 0) {
+ if (*sp != ' ') continue; /* no match */
+ if (*--tcp == 0) return(tp-swp); /* exact match */
+ }
+ if (firstone == -1) firstone = tp-swp; /* possible match */
+ else firstone = -2; /* ambiguous */
+ }
+
+ return (firstone);
+}
--- /dev/null
+ssequal(substr, str)
+char *substr, *str;
+{
+ while(*substr)
+ if(*substr++ != *str++)
+ return(0);
+ return(1);
+}
--- /dev/null
+char *trimcpy(cp)
+register char *cp;
+{
+ register char *sp;
+
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+ sp = cp;
+ while(*sp)
+ if(*sp++ == '\n')
+ break;
+ *--sp = 0;
+ sp = (char *) malloc(sp - cp + 1);
+ strcpy(sp, cp);
+ return(sp);
+}
--- /dev/null
+type(ch, s)
+char *s;
+{
+ register char *p;
+
+ for (p = s; *p++; );
+ --p;
+ write(ch, s, p-s);
+ return(p-s);
+}
--- /dev/null
+uleq(c1, c2)
+register char *c1, *c2;
+{
+ register int c;
+
+ while(c = *c1++)
+ if((c|040) != (*c2|040))
+ return(0);
+ else
+ c2++;
+ return(*c2 == 0);
+}
--- /dev/null
+To:
+Cc:
+Subject:
+-------
--- /dev/null
+Distribution-to:
+Distribution-cc:
--- /dev/null
+/* Rewrite for VAX: BSB 9/9/79 */
+/* Compiled with V7 cc: BSB 6/2/79 */
+
+#include <stdio.h>
+#include <sgtty.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/types.h>
+#include <stat.h>
+
+#define CLEARPAGE write(2,"\014\000",2);
+#define PAUSE 0
+#define NOTIFY 1
+#define CLEAR 2
+#define NOTICLEAR 3
+
+int spage = 37;
+int page;
+short int width = 79;
+short int noclr = 0;
+short int first = 0;
+short int numop = 0;
+short int flagctl = 1;
+short int ontty = 1; /* assume we're outputting to a tty */
+short int delflg; /* a <DEL> was typed. */
+
+FILE *fin;
+jmp_buf envir;
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ register int i,k,n;
+ register char *c1, *c2;
+ int j, clrflag;
+ int int2(), getout();
+ struct sgttyb sg;
+ struct stat st;
+ extern char _sibuf[], _sobuf[];
+
+ if(gtty(1, &sg) == -1) {
+ ontty = 0;
+ flagctl = 0;
+ }
+ c1 = c2 = argv[0];
+ do
+ if(*c1++ == '/')
+ c2 = c1;
+ while(*c1);
+ if(*c2 == 'c')
+ noclr++;
+ k=0;
+ for( i=1; i<argc; i++ ) {/* look for - args */
+ if(argv[i][0] == '-' ) {
+ switch( argv[i][1] ) {
+ case 'c': noclr++; break;
+ case 'f': first=num(&argv[i][2]); /* set first line */
+ break;
+ case 'n': numop=1; /* set number option */
+ break;
+ case 'l':
+ case 'p': spage =num(&argv[i][2]); /* set page size */
+ break;
+ case 'w': width =num(&argv[i][2]);
+ break;
+ case 'x': flagctl = flagctl? 0 : 1;
+ break;
+ default: printf("Unknown switch: %s\n", argv[i]);
+ return;
+ }
+ } else
+ argv[k++] = argv[i];
+ }
+
+ if (spage<=0)
+ spage = 0x07fffffff; /* largest positive number! */
+ setbuf(stdout, _sobuf);
+ if(ontty)
+ signal(SIGINT,int2);
+ signal(SIGQUIT,getout);
+ page = spage;
+ if(k == 0) { /* filter */
+ if(!setjmp(envir)) {
+ fin = stdin;
+ setbuf(fin, _sibuf);
+ pfile(0);
+ }
+ getout();
+ }
+ j = 0;
+ setjmp(envir);
+ while((i=j++) < k) {
+ page = spage;
+ clrflag = 0;
+ if(fin != NULL) { fclose(fin); fin = NULL; }
+ if(stat(argv[i], &st) == 0 && (st.st_mode&S_IFMT) == S_IFDIR){
+ printf("%s: Is a directory!\n", argv[i]);
+ continue;
+ }
+ if((fin = fopen(argv[i],"r")) == NULL) {
+ printf("Cannot open \"%s\" for reading!\n", argv[i]);
+ continue;
+ }
+ if(st.st_size == 0) {
+ printf("File \"%s\" is empty.\n", argv[i]);
+ continue;
+ }
+ if(k>1) {
+ if(i && delflg <= 0)
+ printf("\n\n");
+ delflg = 0;
+ if(ontty) {
+ printf("Press <RETURN> to list \"%s\"\n", argv[i]);
+ clrflag = 1;
+ } else
+ printf(">>>>> File \"%s\"\n", argv[i]);
+ }
+
+ pfile(clrflag);
+ }
+ getout();
+}
+
+int linpos, line, ct;
+
+pfile(flg)
+{
+ register int c;
+
+ if(flg) nextpage(NOTICLEAR);
+ else if(!noclr && ontty)
+ CLEARPAGE;
+ delflg = -1;
+ line = 1;
+ ct = page;
+ while (line < first) /* Dcrocker: skip to first line */
+ if((c = getch()) == EOF)
+ return;
+ else if(c == '\n')
+ line++;
+ linpos = 0;
+
+ while ((c = getch()) != EOF)
+ putch(c);
+
+ fflush(stdout);
+}
+
+num(s) /* computes the internal form of a number */
+register char *s; /* bad chars are ignored */
+{
+ register int c, i, sign;
+
+ sign=1; i=0;
+ while(c = *s++) {
+ if(c=='-' && sign==1) sign = -1;
+ c -= '0';
+ if(c>=0 && c<=9) i=i*10+c;
+ }
+ return(i*sign);
+}
+
+nextpage (clearpage)
+{ char c;
+
+ if(!ontty)
+ return;
+ if (clearpage & NOTIFY)
+ putchar('\007');
+ fflush(stdout);
+ c = 0;
+ while(read(2, &c, 1) && c != '\n') ;
+ if (clearpage & CLEAR && c) {
+ CLEARPAGE;
+ page = spage;
+ } else {
+ page = (spage>>1) + (spage>>3);
+/*** page = spage * .6; ***/
+ }
+ return;
+}
+
+int2()
+{
+ signal(SIGINT,int2);
+ stdout->_cnt = BUFSIZ;
+ stdout->_ptr = stdout->_base;
+ if(delflg)
+ putchar('\n');
+ delflg++;
+ longjmp(envir, 1);
+}
+
+int peekc = -2;
+
+peekch()
+{
+ return(peekc = getch());
+}
+
+getch()
+{
+ register int c;
+ static word;
+
+ if(peekc != -2) {
+ c = peekc;
+ peekc = -2;
+ return(c);
+ };
+ c = getc(fin);
+ if(c != EOF)
+ c &= 0177;
+ return(c);
+}
+
+putch(c)
+register int c;
+{
+ if(linpos == 0 && numop) {
+ printf("%-5d | ");
+ linpos += 8;
+ }
+ if(c < 040 || c == 0177) switch(c) {
+ case '\n': line++;
+ linpos = -1;
+ break;
+ case 014: goto npage;
+ case 011: linpos += 8;
+ linpos &= ~07;
+ linpos--;
+ break;
+ default: if(flagctl) {
+ if(c == '\7')
+ putchar(c);
+ putch('^');
+ if(c != 0177)
+ c += '@';
+ else
+ c = 'd';
+ }
+ }
+ putchar(c);
+ linpos++;
+ if(width && linpos >= width && peekch() != '\n') {
+ putchar('\n'); linpos = 0;
+ }
+ if(linpos == 0 && --ct <= 0) {
+ npage: nextpage(NOTICLEAR);
+ ct = page;
+ }
+}
+
+
+getout()
+{
+ exit(0);
+}
--- /dev/null
+
\ No newline at end of file
--- /dev/null
+F=`grep '[Tt][Oo]:' $1 | sed 's/[Tt][Oo]:.*news\.//p'`
+if [ -d /usr/mhnews/$F ] ; then
+ cat /usr/mhnews/.1char >> /usr/mhnews/.$F
+ /usr/new/mh/file -link -file $1 +$F
+else
+ echo Unknown News Category: $F
+ exit 1
+fi
+This directory
+--------------
The most recent versions of the documents in this directory were
downloaded from ftp://ftp.vim.org/pub/mail/mh/doc/
designOfMH.pdf was downloaded from
http://www.dtic.mil/cgi-bin/GetTRDoc?AD=ADA257836
-mh-6.8.5/ contains the entire MH 6.8.5, include source code and
-RCS files, and was downloaded from
+
+Subdirectories
+--------------
+SRI-NOSC/ was downloaded from from Warren Toomey's minnie.tuhs.org using:
+ rsync -avz minnie.tuhs.org::UA_Distributions/Early_Networking/NOSC/ NOSC
+ tar xzBpf NOSC/nosc.tar.gz ./mh
+ cp -p NOSC/nosc.txt mh
+ chmod -R go+r mh
+ chmod go+x mh mh/subs.dir
+ find mh -name '*.[ao]' -execdir /bin/rm {} \;
+
+2.9BSD/ was downloaded from from Warren Toomey's minnie.tuhs.org using:
+ rsync -avz minnie.tuhs.org::UA_Distributions/UCB/2.9BSD/ 2.9BSD
+ tar xzBpf usr.tar.gz ./contrib/mh
+ chmod g-w contrib/mh/Makefile
+
+mh-jun-1982/ was downloaded from
+http://bitsavers.trailing-edge.com/bits/Rand/Rand_Software_Distribution_1.7_May82.zip
+
+mh-nov-1983/ was downloaded from
+http://www.tuhs.org/Archive/Distributions/UCB/4.2BSD/new.tar.gz
+
+Other versions of MH are, as of May 2019, available at these locations:
+mh-6.4 http://www.tuhs.org/Archive/Distributions/UCB/4.3BSD/new.tar.gz
+mh-6.5-4.3BSD-Tahoe http://www.tuhs.org/Archive/Distributions/UCB/4.3BSD-Tahoe/new.tar.gz
+mh-6.5-4.3BSD-Reno http://www.tuhs.org/Archive/Distributions/UCB/4.3BSD-Reno/contrib.tar.gz
+mh-6.8 https://stuff.mit.edu/afs/athena/astaff/source/src-7.7/third/supported/mh.6.8/
+
+mh-6.8.5/ contains the entire MH 6.8.5 sources and RCS files, and was
+downloaded from
http://iweb.dl.sourceforge.net/project/rand-mh/MH/6.8.5/mh-6.8.5.tgz
-Some obviously unnecessary files were removed. mh.rf and mh.me
-were renamed to mh-intro.rf and mh-intro.me, respectively, to avoid
-name clashes with other files on case-insensitive file systems.
+Some obviously unnecessary files were removed. mh.rf and mh.me were
+renamed to mh-intro.rf and mh-intro.me, respectively, to avoid name
+clashes with other files on case-insensitive file systems.
-MH source code, versions 6.3 through 6.8.5, is archived under
+
+Other repositories
+------------------
+MH source code, versions 5 through 6.8.5, is archived under
http://sourceforge.net/projects/rand-mh/files/
+That repository contains other useful MH artifacts including
+the Jerry Peek's MH Book and mailing list archives.
+
+-------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
The README below is retained in its original form for posterity. All
of the txt (.doc and .tty) files have been renamed to .txt. All of
D. Levine 28 Feb 2012
-------------------------------------------------------------------------
-------------------------------------------------------------------------
+-------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
mh/doc/README
changes.ps - Changes from MH 6.6 to MH 6.8
mh-gen.ps - The "READ-ME" file - how to generate MH (aka mh-gen(8))
-------------------------------------------------------------------------
+-------------------------------------------------------------------------------
These are postscript conversions of the MH papers which were written
using the TeX typesetting language:
copies of these papers which will print (identically to the originals or
otherwise) on a Laserwriter, please contact "Bug-MH@ICS.UCI.EDU".
-------------------------------------------------------------------------
+-------------------------------------------------------------------------------
These files are tty-readable conversions of the MH papers which were
written using the TeX typesetting language:
--- /dev/null
+#include "mh.h"
+#include "stat.h"
+
+/* annotate file component data
+ *
+ * prepends Component: data
+ * date stamp
+ */
+
+/*extern int inplace;*/ /* preserve links in anno */
+int inplace 1; /* preserve links in anno */
+
+annotate(file, comp, text)
+char *file, *comp, *text;
+{
+ register int src, tmp;
+ register char *cp;
+ int cnt;
+ char buf[512], *sp, tmpfil[128];
+ long now;
+ struct inode stbuf;
+
+ if((src = open((cp = file), 2)) == -1) { /* this should be an X-open*/
+ printf("Can't open "); flush();
+ perror(cp);
+ return(1);
+ }
+ copy(cp, buf);
+ sp = cp = buf;
+ while(*cp) if(*cp++ == '/') sp = cp;
+ if(sp != buf) {
+ *sp = 0;
+ cp = copy(buf, tmpfil);
+ } else
+ cp = tmpfil;
+ copy(makename("annot",".tmp"), cp);
+ fstat(src, &stbuf);
+ if((tmp = creat(tmpfil, stbuf.i_mode&0777)) == -1) {
+ printf("Can't create "); flush();
+ perror(tmpfil);
+ return(1);
+ }
+ cp = comp;
+ if(*cp >= 'a' && *cp <= 'z') *cp =- 040;
+ type(tmp, cp);
+ type(tmp, ": ");
+ time(&now);
+ cp = cdate(&now);
+ cp[9] = ' '; cp[15] = 0;
+ if(*cp == ' ') cp++;
+ type(tmp, "<<");
+ type(tmp, cp);
+ type(tmp, ">>\n");
+ cp = text;
+ do {
+ if(*cp == ' ' || *cp == '\t') cp++;
+ sp = cp;
+ while(*cp && *cp++ != '\n') ;
+ if(cp - sp) {
+ type(tmp, comp);
+ type(tmp, ": ");
+ write(tmp, sp, cp-sp);
+ }
+ } while(*cp);
+ if(cp[-1] != '\n' && cp != text) type(tmp, "\n");
+ do
+ if((cnt = read(src, buf, sizeof buf)) > 0)
+ write(tmp, buf, cnt);
+ while(cnt == sizeof buf);
+ if(inplace) {
+ close(tmp);
+ tmp = open(tmpfil, 0); /* reopen for reading */
+ seek(src, 0, 0);
+ do
+ if((cnt = read(tmp, buf, sizeof buf)) > 0)
+ write(src, buf, cnt);
+ while(cnt == sizeof buf);
+ } else {
+ /* cp = copy(file, buf); */
+ /* *--cp =| 0200; */
+ /* copy(".bak", copy(file, buf)); */
+ cp = copy(file, buf);
+ cp[1] = 0;
+ do
+ *cp = cp[-1];
+ while(--cp >= buf && *cp != '/');
+ *++cp = ','; /* New backup convention */
+ unlink(buf);
+ if(link(file, buf) == -1) {
+ printf("Can't rename %s to bak file.\n", file);
+ return(1);
+ }
+ if(unlink(file) == -1) {
+ printf("Can't unlink %s\n", file);
+ return(1);
+ }
+ if(link(tmpfil, file) == -1) {
+ printf("Can't lnk temp file \"%s\" to %s\n",
+ tmpfil, file);
+ return(1);
+ }
+ }
+ close(src);
+ close(tmp);
+ unlink(tmpfil);
+ return(0);
+}
--- /dev/null
+/* formerly rmm */
+#include "mh.h"
+
+int vecp, *vec[MAXARGS], fout;
+struct msgs *mp;
+struct swit switches[] {
+ "all", -3, /* 0 */
+ "help", 4, /* 1 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *nfolder, *maildir, *msgs[100], buf[32];
+ register int msgnum;
+ register char *cp, *sp;
+ int msgp;
+ char *ap, *inp;
+ char *arguments[50], **argp;
+
+ fout = dup(1);
+#ifdef NEWS
+ m_news();
+#endif
+ folder = msgp = 0;
+ vecp = 1;
+ inp = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ inp = cp;
+ ap = inp;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("-%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: printf("\"-all\" changed to \"all\"\n");
+ goto leave;
+ /* -help */
+ case 1: help(concat( inp, " [+folder] [msgs] [switches]", 0),
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ printf("Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ printf("Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ printf("No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum], UNDELETED, UNDELETED))
+ goto leave;
+ if(mp->numsel == 0) {
+ goto leave;
+ }
+ m_replace("folder", folder);
+ if((cp = m_find("delete-prog")) == -1) {
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum] & SELECTED) {
+ sp = getcpy(m_name(msgnum));
+ cp = copy(sp, buf);
+ cp[1] = 0;
+ do
+ *cp = cp[-1];
+ while(--cp >= buf && *cp != '/');
+ *++cp = ','; /* backup convention */
+ unlink(buf);
+ if(link(sp, buf) == -1 || unlink(sp) == -1)
+ printf("Can't rename %s to %s.\n", sp, buf);
+ }
+ } else {
+ if(mp->numsel > MAXARGS-2) {
+ printf("More than %d messages for deletion-prog\n",MAXARGS-2);
+ goto leave;
+ }
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ vec[vecp++] = getcpy(m_name(msgnum));
+ vec[vecp] = 0;
+ vec[0] = cp;
+ m_update();
+ flush();
+ execvsrh(vec);
+ printf("Can't exec deletion prog--"); flush();
+ perror(cp);
+ }
+leave:
+ m_update();
+ flush();
+}
--- /dev/null
+if -r delete rm delete
+load -n delete subs.a strings.a wait -O libg.a libh.a libg.a
+if -r a.out mv a.out delete
+: fini
+
--- /dev/null
+cc -n send.o subs.a strings-ec.a libg.a libh.a mailib.a mailib.a
--- /dev/null
+#
+/* u_error codes */
+#define EFAULT 106
+#define EPERM 1
+#define ENOENT 2
+#define ESRCH 3
+#define EINTR 4
+#define EIO 5
+#define ENXIO 6
+#define E2BIG 7
+#define ENOEXEC 8
+#define EBADF 9
+#define ECHILD 10
+#define EAGAIN 11
+#define ENOMEM 12
+#define EACCES 13
+#define ENOTBLK 15
+#define EBUSY 16
+#define EEXIST 17
+#define EXDEV 18
+#define ENODEV 19
+#define ENOTDIR 20
+#define EISDIR 21
+#define EINVAL 22
+#define ENFILE 23
+#define EMFILE 24
+#define ENOTTY 25
+#define ETXTBSY 26
+#define EFBIG 27
+#define ENOSPC 28
+#define ESPIPE 29
+#define EROFS 30
+#define EMLINK 31
+#define EPIPE 32
+
+/* Harvard error codes */
+
+#define EPLIM 99 /* process limit reached */
+#define EPROTO 98 /* Protocol error */
+
+int errno; /* where c saves the error code */
--- /dev/null
+#include "mh.h"
+#include "stat.h"
+#include "errors.h"
+#define NFOLD 20 /* Allow 20 folder specs */
+
+/* file [-src folder] [msgs] +folder [+folder ...]
+ *
+ * moves messages from src folder (or current) to other one(s).
+ *
+ * all = first-last for a message sequence
+ * -preserve says preserve msg numbers
+ * -link says don't delete old msg
+ */
+
+char *anoyes[]; /* Std no/yes gans array */
+
+int fout, vecp, foldp, prsrvf;
+char *vec[MAXARGS], maildir[128], *folder;
+struct msgs *mp;
+
+struct st_fold {
+ char *f_name;
+ struct msgs *f_mp;
+} folders[NFOLD];
+
+struct swit switches[] {
+ "all", -3, /* 0 */
+ "link", 0, /* 1 */
+ "nolink", 0, /* 2 */
+ "preserve", 0, /* 3 */
+ "nopreserve", 0, /* 4 */
+ "src +folder", 0, /* 5 */
+ "help", 4, /* 6 */
+ 0, 0
+};
+main(argc, argv)
+char *argv[];
+{
+ register int i, msgnum;
+ register char *cp;
+ char *msgs[128];
+ int msgp, linkf;
+ char *ap;
+ char *arguments[50], **argp;
+
+ fout = dup(1);
+ if(argc < 2) {
+ badarg: printf("Usage: file [-src folder] [msg ...] +folder [+folder]\n");
+ goto leave;
+ }
+#ifdef NEWS
+ m_news();
+#endif
+ folder = msgp = linkf = 0;
+ vecp = 1;
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("file: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: printf("\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: linkf = 1; continue; /* -link */
+ case 2: linkf = 0; continue; /* -nolink */
+ case 3: prsrvf = 1; continue; /* -preserve */
+ case 4: prsrvf = 0; continue; /* -nopreserve */
+ case 5: if(folder) { /* -src */
+ printf("Only one src folder.\n");
+ goto leave;
+ }
+ if(!(folder = *argp++) || *folder == '-') {
+ printf("file: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ if(*folder == '+')
+ folder++;
+ continue;
+ /* -help */
+ case 6: help("file [msgs] [switches] +folder ...",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(foldp < NFOLD)
+ folders[foldp++].f_name = cp + 1;
+ else {
+ printf("Only %d folders allowed.\n", NFOLD);
+ goto leave;
+ }
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!foldp) {
+ printf("No folder specified.\n");
+ goto badarg;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ copy(m_maildir(folder), maildir);
+ if(chdir(maildir) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ printf("Can't read folder %s!?\n",folder);
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ printf("No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert((cp = msgs[msgnum]), UNDELETED, UNDELETED))
+ goto leave;
+ if(mp->numsel == 0) {
+ printf("No undeleted messages specified\n");
+ goto leave;
+ }
+ m_replace("folder", folder);
+ if(mp->hghsel != mp->curmsg && ((mp->numsel != mp->nummsg) || linkf))
+ m_setcur(mp->hghsel);
+ if(opnfolds())
+ goto leave;
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum] & SELECTED)
+ if(process(getcpy(m_name(msgnum))))
+ goto leave;
+ if(!linkf) {
+ if((cp = m_find("delete-prog")) != -1) {
+ if(mp->numsel > MAXARGS-2) {
+ printf("file: more than %d messages for deletion-prog\n",MAXARGS-2);
+ printf("[messages not unlinked]\n");
+ goto leave;
+ }
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ vec[vecp++] = getcpy(m_name(msgnum));
+ vec[vecp] = 0;
+ m_update();
+ flush();
+ vec[0] = cp;
+ execvsrh(vec);
+ printf("Can't exec deletion-prog--"); flush();
+ perror(cp);
+ } else {
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum] & SELECTED)
+ if(unlink(cp = getcpy(m_name(msgnum)))== -1) {
+ printf("Can't unlink %s:",folder);
+ flush(); perror(cp);
+ }
+ }
+ }
+leave:
+ m_update();
+ flush();
+}
+
+
+opnfolds()
+{
+ register int i;
+ register char *cp;
+ char nmaildir[128];
+ struct inode stbuf;
+
+ for(i = 0; i < foldp; i++) {
+ copy(m_maildir(folders[i].f_name), nmaildir);
+ if(stat(nmaildir, &stbuf) < 0) {
+ cp = concat("Create folder \"", nmaildir, "\"? ", 0);
+ if(!gans(cp, anoyes))
+ goto bad;
+ free(cp);
+ if(!makedir(nmaildir)) {
+ printf("Can't create folder.\n");
+ goto bad;
+ }
+ }
+ if(chdir(nmaildir) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(nmaildir);
+ goto bad;
+ }
+ if(!(folders[i].f_mp = m_gmsg())) {
+ printf("Can't read folder %s\n", folders[i].f_name);
+ goto bad;
+ }
+ }
+ chdir(maildir); /* return to src folder */
+ return(0);
+bad:
+ return(1);
+}
+
+
+process(msg)
+{
+ char newmsg[256], buf[512];
+ register int i;
+ register char *nmsg;
+ register struct st_fold *fp;
+ struct inode stbuf, stbf1;
+ int n, o;
+
+ for(fp = folders; fp < &folders[foldp]; fp++) {
+ if(prsrvf)
+ nmsg = msg;
+ else
+ nmsg = m_name(fp->f_mp->hghmsg++ + 1);
+ copy(nmsg, copy("/", copy(m_maildir(fp->f_name), newmsg)));
+ if(link(msg, newmsg) < 0) {
+ if(errno == EEXIST ||
+ (errno == EXDEV && stat(newmsg, &stbuf) != -1)) {
+ if(errno != EEXIST || stat(msg, &stbf1) < 0 ||
+ stat(newmsg, &stbuf) < 0 ||
+ stbf1.i_number != stbuf.i_number) {
+ printf("Message %s:%s already exists.\n",
+ fp->f_name, msg);
+ return(1);
+ }
+ continue;
+ }
+ if(errno == EXDEV) {
+ if((o = open(msg, 0)) == -1) {
+ printf("Can't open %s:%s.\n",
+ folder, msg);
+ return(1);
+ }
+ fstat(o, &stbuf);
+ if((n = creat(newmsg, stbuf.i_mode&0777)) == -1) {
+ printf("Can't create %s:%s.\n",
+ fp->f_name, nmsg);
+ close(o);
+ return(1);
+ }
+ do
+ if((i=read(o, buf, sizeof buf)) < 0 ||
+ write(n, buf, i) == -1) {
+ printf("Copy error on %s:%s to %s:%s!\n",
+ folder, msg, fp->f_name, nmsg);
+ close(o); close(n);
+ return(1);
+ }
+ while(i == sizeof buf);
+ close(n); close(o);
+ } else {
+ printf("Error on link %s:%s to %s:",
+ folder, msg, fp->f_name);
+ flush();
+ perror(nmsg);
+ return(1);
+ }
+ }
+cont: ;
+ }
+ return(0);
+}
--- /dev/null
+if -r file rm file
+load -n file subs.a strings.a wait -O libg.a libh.a
+if -r a.out mv a.out file
--- /dev/null
+/* formerly forw */
+#include "mh.h"
+#include "iobuf.h"
+#include "signals.h"
+
+/*#define TEST 1*/
+
+char draft[],
+ components[],
+ stdcomps[],
+ sysed[],
+#ifdef PROMPT
+ prmtproc[],
+#endif
+ sndproc[];
+
+int *vec[MAXARGS], fout;
+struct msgs *mp;
+char drft[128];
+
+char *anysh[] {
+ "no", 0,
+ "yes", 0,
+ "show", 0,
+ 0,
+};
+
+char *anyv[] {
+ "no", 0,
+ "yes", 0,
+ "verbose", 0,
+ 0,
+};
+struct swit switches[] {
+ "all", -3, /* 0 */
+ "annotate", 0, /* 1 */
+ "noannotate", 0, /* 2 */
+ "editor editor", 0, /* 3 */
+ "form formfile", 0, /* 4 */
+ "help", 4, /* 5 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100], *ed, *form;
+ register int msgnum;
+ register char *cp, *ap;
+ char *inp;
+ int msgp, status, anot;
+ int in, out, intr;
+ char *arguments[50], **argp;
+
+ fout = dup(1);
+#ifdef NEWS
+ m_news();
+#endif
+ form = anot = folder = msgp = ed = 0;
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ inp = ap;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("-%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: printf("\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: anot = 1; continue; /* -annotate */
+ case 2: anot = 0; continue; /* -noannotate */
+ case 3: if(!(ed = *argp++)) { /* -editor */
+ missing: printf("Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 4: if(!(form = *argp++)) /* -form */
+ goto missing;
+ continue;
+ /* -help */
+ case 5: help(concat( inp, " [+folder] [msgs] [switches]", 0),
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ printf("Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ printf("Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ printf("No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum], UNDELETED, UNDELETED))
+ goto leave;
+ if(mp->numsel == 0) {
+ printf("No undeleted messages specified\n");
+ goto leave;
+ }
+ if(form) {
+ if((in = open(m_maildir(form), 0)) < 0) {
+ printf("Can't open form file: %s\n", form);
+ goto leave;
+ }
+ } else if((in = open(m_maildir(components), 0)) < 0 &&
+ (in = open(stdcomps, 0)) < 0) {
+ printf("Can't open default components file!!\n");
+ goto leave;
+ }
+ copy(m_maildir(draft), drft);
+ if((out = open(drft, 0)) >= 0) {
+/*
+ if(!fdcompare(in, out)) {
+ cp = concat("\"", drft, "\" exists; Delete? ", 0);
+ while((msgnum = gans(cp, anysh)) == 2)
+ showfile(drft);
+ if(!msgnum)
+ return;
+ }
+*/
+ close(out);
+ }
+ if((out = creat(drft, m_gmprot())) < 0) {
+ printf("Can't create \"%s\"\n", drft);
+ goto leave;
+ }
+ cpydata(in, out);
+ close(in);
+ printf("Forwarding message%s ", mp->numsel > 1 ? "s" : "");
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED) {
+ if((in = open(cp = m_name(msgnum), 0)) < 0) {
+ printf("Can't open message \"%s\"\n", cp);
+ unlink(drft);
+ goto leave;
+ }
+ printf("%d ", msgnum);
+ type(out, "-------");
+ if(msgnum == mp->lowsel) {
+ type(out, " Forwarded Message");
+ if(mp->numsel > 1)
+ type(out, "s");
+ }
+ type(out, "\n");
+ cpydata(in, out);
+ close(in);
+ }
+ type(out, "------- End of Forwarded Message");
+ if(mp->numsel > 1)
+ type(out, "s");
+ type(out, "\n");
+ close(out);
+ printf("\n");
+ flush();
+ m_replace("folder", folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ if(!ed && (ed = m_find("editor")) == -1)
+#ifdef PROMPT
+ ed = prmtproc;
+#else
+ ed = sysed;
+#endif
+ intr = signal(SIGINT, 1);
+ if((in = fork()) == 0) {
+ m_update();
+ flush();
+ execlsrh(ed, drft, 0);
+ printf("Can't exec the editor!!\n");
+ flush(); exit(1);
+ } else if(in == -1) {
+ printf("No forks!\n");
+ goto leave;
+ } else
+ while((out = waita(&status)) != -1 && out != in) ;
+ signal(SIGINT, intr);
+ if(status) {
+ if(status > 0377)
+ unlink(drft);
+ printf("[command aborted--%s %s]\n", drft,
+ status > 0377? "deleted" : "preserved");
+ goto leave;
+ }
+#ifdef TEST
+ printf("!! Test Version of SEND Being Run !!\n");
+ printf(" Send verbose !\n\n");
+#endif
+/* cp = concat("Send \"", draft, "\"? ", 0); */
+ cp = "Send? ";
+ if((out = gans(cp, anyv)) > 0) {
+ if(anot) {
+ while((in = fork()) == -1) sleep(5);
+ if(in) {
+ while(msgnum = wait() != -1 && msgnum != in);
+ doano();
+ goto leave;
+ }
+ }
+ in = 0;
+ vec[in++] = "mh-sndproc";
+ vec[in++] = drft;
+ if(out == 2)
+ vec[in++] = "-verbose";
+ vec[in++] = 0;
+ m_update();
+ flush();
+ execv(sndproc, vec);
+ printf("Can't exec send process.\n");
+ flush(); exit(1);
+ }
+
+ leave:
+ m_update();
+ flush();
+}
+
+
+cpydata(in, out)
+{
+ char buf[512];
+ register int i;
+
+ do
+ if((i = read(in, buf, sizeof buf)) > 0)
+ write(out, buf, i);
+ while(i == sizeof buf);
+}
+
+
+doano()
+{
+ struct iobuf in;
+ char name[NAMESZ], field[256];
+ register int ind, state;
+ register char *text;
+
+ if(stat(drft, field) != -1) {
+ printf("%s not sent-- no annotations made.\n", drft);
+ return;
+ }
+ text = copy(drft, field);
+ text[1] = 0;
+ do
+ *text = text[-1];
+ while(--text >= field && *text != '/');
+ *++text = ','; /* New backup convention */
+ if(fopen(field, &in) < 0) {
+ printf("Can't open %s\n", field);
+ return;
+ }
+ state = FLD;
+ text = 0;
+ for(;;) switch(state = m_getfld(state, name, field, sizeof field, &in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(uleq(name, "to") || equal(name, "cc")) {
+ if(state == FLD) {
+ text = add(name, text);
+ text = add(":", text);
+ }
+ text = add(field, text);
+ }
+ if(state == FLDEOF)
+ goto out;
+ continue;
+ case BODY:
+ case BODYEOF:
+ goto out;
+ default:
+ printf("Getfld returned %d\n", state);
+ return;
+ }
+
+out:
+ close(in.b_fildes);
+
+ for(ind = mp->lowsel; ind <= mp->hghsel; ind++)
+ if(mp->msgstats[ind] & SELECTED)
+ annotate(m_name(ind), "Forwarded", text);
+}
--- /dev/null
+if -r forward rm forward
+load -n forward annotate subs.a strings.a wait \
+ -O libg.a libh.a libg.a
+if -r a.out mv a.out forward
+: fini
+
--- /dev/null
+#define TRUE 1
+#include "mh.h"
+#include "stat.h"
+
+char *anoyes[], /* Std no/yes gans array */
+ mh_defs[],
+ defalt[];
+
+int fout;
+char *mypath, defpath[128];
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp, *path;
+ register struct node *np;
+ int autof, detached, exitstat;
+ struct inode stbuf;
+
+ fout = dup(1);
+ autof = (argc == 2 && equal(argv[1], "-auto"));
+ detached = (argc == 2 && equal(argv[1], "-detached"));
+ exitstat = 1; /* Assume errors will occur */
+ mypath = getpath(getruid()); /* to prevent recursion via m_getdefs */
+ copy(mh_defs, copy(mypath, defpath));
+ if(stat(defpath, &stbuf) != -1) {
+ if(autof)
+ printf("Install-defs invocation error!\n");
+ else if (!detached)
+ printf("You already have an MH profile... use an editor \
+to modify it.\n");
+ goto leave;
+
+ }
+ if(!detached && (autof || gans("Do you want help? ", anoyes))) {
+printf("\nPrior to using MH, it is necessary to have a file in your login\n");
+printf("directory (%s) named .mh_defs which contains information\n",mypath);
+printf("to direct certain MH operations. The only item which is required\n");
+printf("is the path to use for all MH folder operations. The suggested MH\n");
+printf("path for you is %s/mail...\n\n", mypath);
+ }
+ cp = concat(mypath, "/", "mail", 0);
+ if(stat(cp, &stbuf) != -1) {
+ if((stbuf.i_mode&IFMT) == IFDIR) {
+ cp = concat("You already have the standard MH directory \"",
+ cp, "\".\nDo you want to use it for MH? ", 0);
+ if( detached ? TRUE : gans(cp, anoyes))
+ path = "mail";
+ else
+ goto xyz;
+ }
+ } else {
+ cp = concat("Do you want the standard MH path \"", mypath,
+ "/", "mail\"? ", 0);
+ if( detached ? TRUE : gans(cp, anoyes))
+ path = "mail";
+ else {
+ xyz: if(gans("Do you want a path below your login directory? ",
+ anoyes)) {
+ printf("What is the path ?? %s/", mypath);
+ path = getans();
+ } else {
+ printf("What is the whole path?? /");
+ path = concat("/", getans(), 0);
+ }
+ }
+ }
+ chdir(mypath);
+ if(chdir(path) == -1) {
+ cp = concat("\"", path, "\" doesn't exist; Create it? ", 0);
+ if( detached ? TRUE : gans(cp, anoyes))
+ if(makedir(path) == 0) {
+ if (!detached) printf("Can't create it!\n");
+ goto leave;
+ }
+ } else
+ if (!detached) printf("[Using existing directory]\n");
+
+ np = m_defs = alloc(sizeof *np);
+ np->n_name = "Path";
+ np->n_field = path;
+ np->n_next = 0;
+ m_replace("folder", defalt);
+ exitstat = 0;
+
+leave:
+ m_update();
+ flush();
+ exit(exitstat);
+}
+
+
+getans()
+{
+ static char line[128];
+ register char *cp;
+ register int c;
+
+ flush();
+ cp = line;
+ while(c = getchar()) {
+ if(c == '\n') {
+ *cp = 0;
+ return(line);
+ }
+ if(cp < (&line) + 1)
+ *cp++ = c;
+ }
+ exit(1);
+}
--- /dev/null
+if -r install-defs rm install-defs
+load install-defs subs.a strings.a wait -O /m/mh/libg.a /m/mh/libh.a
+if -r a.out mv a.out install-defs
+: fini
+
--- /dev/null
+/* file used for getc/putc */
+struct iobuf {
+ int b_fildes;
+ int b_nleft;
+ char *b_nextp;
+ char b_buff[512];
+};
--- /dev/null
+#define TRUE 1
+#define FALSE 0
+
+#define ALL ""
+
+#define MAXARGS 152 /* Max messages to exec */
+
+#define EXISTS 01 /* existing msg msgstat bit - may be del or undel */
+#define DELETED 02 /* msg has been deleted */
+#define UNDELETED 04 /* msg is not deleted */
+#define SELECTED 010 /* Message selected by an arg */
+
+#define READONLY 01 /* No write access to folder */
+#define DEFMOD 01 /* In-core profile has been modified */
+
+/*#define NEWS 1 /* Define for news inclusion */
+#define PROMPT 1 /* Use prompter in compose, etc */
+
+struct swit {
+ char *sw;
+ int minchars;
+};
+
+/*
+ * m_gmsg() returns this structure. It contains the per folder
+ * information which is obtained from reading the folder directory.
+ */
+
+struct msgs {
+ int hghmsg; /* Highest msg in directory */
+ int nummsg; /* Actual Number of msgs */
+ int lowmsg; /* Lowest msg number */
+ int curmsg; /* Number of current msg if any */
+ int lowsel; /* Lowest selected msg number */
+ int hghsel; /* Highest selected msg number */
+ int numsel; /* Number of msgs selected */
+ char *foldpath; /* Pathname of folder */
+ char selist, /* Folder has a "select" file */
+ msgflags, /* Folder status bits */
+ filler,
+ others; /* Folder has other file(s) */
+ char msgstats[]; /* Stat bytes for each msg */
+};
+
+ /* m_getfld definitions and return values */
+
+#define NAMESZ 64 /* Limit on component name size */
+#define LENERR -2 /* Name too long error from getfld */
+#define FMTERR -3 /* Message Format error */
+
+ /* m_getfld return codes */
+#define FLD 0 /* Field returned */
+#define FLDPLUS 1 /* Field " with more to come */
+#define FLDEOF 2 /* Field " ending at eom */
+#define BODY 3 /* Body " with more to come */
+#define BODYEOF 4 /* Body " ending at eom */
+#define FILEEOF 5 /* Reached end of input file */
+
+#ifdef COMMENT /* Commented out to reduce space */
+/*
+ * These standard strings are defined in strings.c. They are the
+ * only system-dependent parameters in MH, and thus by redefining
+ * their values in strings.c and reloading the various modules, MH
+ * will run on any system.
+ */
+
+char mailbox[], /* Std incoming mail file (.mail) */
+ draft[], /* Name of the normal draft file */
+ defalt[], /* Name of the std folder (inbox) */
+ components[], /* Name of user's component file (in mh dir) */
+ stdcomps[], /* Std comp file if missing user's own */
+ sndproc[], /* Path of the send message program */
+ showproc[], /* Path of the type (l) program */
+ scanproc[], /* Path of the scan program */
+ prproc[], /* Path of the pr program */
+ lsproc[], /* Path of the Harvard ls program */
+ sbmitloc[], /* Path of the submit program */
+ sbmitnam[], /* Name of submit program */
+ mypath[], /* User's log-on path */
+ sysed[], /* Path of the std (ned) editor */
+ msgprot[], /* Default message protection (s.a. 0664) */
+ foldprot[], /* Default folder protection " */
+ listname[], /* Default selection list folder name */
+ mhnews[]; /* Name of MH news file */
+#endif
+
+/*
+ * node structure used to hold a linked list of the users profile
+ * information taken from logpath/.mh_defs.
+ */
+
+struct node {
+ struct node *n_next;
+ char *n_name,
+ *n_field;
+} *m_defs;
+
+char def_flags;
+
+
+/*
+ * The first char in the mhnews file indicates whether the program
+ * calling m_news() should continue running or halt.
+ */
+
+#define NEWSHALT '!' /* Halt after showing the news */
+#define NEWSCONT ' ' /* Continue (ditto) */
+#define NEWSPAUSE '\001' /* Pause during news output... */
--- /dev/null
+University of Illinois 'Network Unix'
+(from Noel Chiappa)
+
+ The first networked Unix system was one produced at the University of
+ Illinois in 1974-75 for use on the <a href="http://en.wikipedia.org/wiki/ARPANET">ARPANET</a>;
+ it used the <a href="http://en.wikipedia.org/wiki/Network_Control_Program">NCP</a> protocol.
+
+ The code is divided into three main groups: code for the kernel (further divided into
+ device drivers, and code common to all methods of interfacing to the ARPANET); a daemon
+ which ran as a process, which handled a lot of the protocol overhead (e.g. opening and
+ closing connections); and programs (also run as processes) to implement applications
+ such as FTP and TELNET.
+
+ The code was originally written mostly by Gary R. Grossman and Steve
+ F. Holmgren; many others later contributed fixes and improvements. The code
+ rapidly spread among computer science centers which were connected to the
+ ARPANET; this copy of the code came via NOSC (Naval Ocean Systems Center)
+ and SRI.
+
+ Also included are two important major application packages produced
+ elsewhere: the MH mail reader, done by Bruce S. Borden at RAND based on
+ suggestions by R. Stockton Gaines; and the MMDF mail agent, written by David
+ Crocker at the University of Delaware.
+
+ For more information about this system, see:
+ - Steve Holmgren; "The Network UNIX System"; Center for Advanced
+ Computation, University of Illinois at Urbana-Champaign; Urbana, Illinois;
+ 1975
+ - Karl C Kelley, Richard Balocca, Jody Kravitz; "A Network Unix System for
+ the ARPANET: Volume 1 - The Network Control Program"; Center for Advanced
+ Computation and Computing Services Office, University of Illinois at
+ Urbana-Champaign; Urbana, Illinois; 1978
+
--- /dev/null
+main(argc,argv) char *argv[];
+{ int i;printf("NULL PROCESS\n");
+ for (i=0; i<argc; i++)printf("%s\n",argv[i]); return; }
--- /dev/null
+/* formerly folder */
+#include "mh.h"
+#include "stat.h"
+#define NFOLDERS 100
+
+char lsproc[],
+ listname[];
+
+int fout, all, hdrflag, foldp;
+struct msgs *mp;
+char folder[128], *folds[NFOLDERS];
+int msgtot, foldtot, totonly, shrt;
+struct swit switches[] {
+ "all", 0, /* 0 */
+ "down", 0, /* 1 */
+ "fast", 0, /* 2 */
+ "nofast", 0, /* 3 */
+ "header", 0, /* 4 */
+ "noheader", 0, /* 5 */
+ "short", 0, /* 6 */
+ "total", 0, /* 7 */
+ "nototal", 0, /* 8 */
+ "up", 0, /* 9 */
+ "help", 4, /*10 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp, *curm;
+ register int i;
+ char *argfolder;
+ int up, down, j, def_short;
+ char *ap, *inp;
+ char *arguments[50], **argp;
+ struct inode stbf, *np;
+ struct { int inum;
+ char name[14];
+ int pad;
+ } ent;
+
+ fout = dup(1);
+#ifdef NEWS
+ m_news();
+#endif
+ up = down = argfolder = 0;
+ curm = 0;
+ if(argv[0][length(argv[0])-1] == 's') /* Plural name?? */
+ all++;
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ inp = ap;
+ if(!uleq("folder", ap) && (cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("-%s unknown\n", cp);
+ goto leave;
+ case 0: all++; continue; /* -all */
+ case 1: down++; continue; /* -down */
+ case 2: /* -fast */
+ case 6: shrt = 1; continue; /* -short */
+ case 3: shrt = 0; continue; /* -nofast */
+ case 4: hdrflag = -1; continue; /* -header */
+ case 5: hdrflag = 0; continue; /* -noheader */
+ case 7: all++; totonly = 1; /* -total */
+ continue;
+ case 8: if(totonly) all--; /* -nototal */
+ totonly =0; continue;
+ case 9: up++; continue; /* -up */
+ /* -help */
+ case 10:help(concat( inp, " [+folder] [msg] [switches]",0),
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(argfolder) {
+ printf("Only one folder at a time.\n");
+ goto leave;
+ } else
+ argfolder = cp + 1;
+ } else if(curm) {
+ printf("Only one current may be given.\n");
+ goto leave;
+ } else
+ curm = cp;
+ }
+ if(all) {
+ hdrflag = 0;
+ cp = m_maildir("");
+ m_getdefs();
+ for(np = m_defs; np; np = np->n_next) {
+ if(!ssequal("cur-", np->n_name))
+ continue;
+ if(shrt) {
+ def_short++;
+ printf("%s\n", np->n_name+4);
+ } else
+ addfold(np->n_name+4);
+ }
+ if(def_short)
+ putchar('\n');
+ if(shrt) {
+ m_update();
+ flush();
+ execl(lsproc, "mh-ls", "-x", cp, 0);
+ printf("Can't exec: "); flush();
+ perror(lsproc);
+ goto leave;
+ }
+ if(chdir(cp) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(cp);
+ goto leave;
+ }
+ if((cp = m_find("folder")) == -1)
+ *folder = 0;
+ else
+ copy(cp, folder);
+ i = open(".", 0);
+ ent.pad = 0;
+ while(read(i, &ent.inum, sizeof ent.name + sizeof ent.inum))
+ if(ent.inum && ent.name[0] != '.' &&
+ stat(ent.name, &stbf) >= 0 &&
+ (stbf.i_mode&IFMT) == IFDIR)
+ addfold(ent.name);
+ close(i);
+ for(i = 0; i < foldp; i++) {
+ pfold(folds[i], 0); flush();
+ }
+ if(!totonly)
+ printf("\n\t\t ");
+ printf("TOTAL= %3d message%c in %d Folder%s.\n",
+ msgtot, msgtot!=1? 's':' ',
+ foldtot, foldtot!=1? "s":"");
+ } else {
+ hdrflag++;
+ if(argfolder)
+ cp = copy(argfolder, folder);
+ else
+ cp = copy(m_getfolder(), folder);
+ if(up) {
+ while(cp > folder && *cp != '/') --cp;
+ if(cp > folder)
+ *cp = 0;
+ argfolder = folder;
+ } else if(down) {
+ copy(listname, copy("/", cp));
+ argfolder = folder;
+ }
+ if(pfold(folder, curm) && argfolder)
+ m_replace("folder",argfolder);
+ }
+
+ leave:
+ m_update();
+ flush();
+}
+
+
+addfold(fold)
+char *fold;
+{
+ register int i,j;
+ register char *cp;
+
+ if(foldp >= NFOLDERS) {
+ printf("More than %d folders!!\n", NFOLDERS);
+ return(1);
+ }
+ cp = getcpy(fold);
+ for(i = 0; i < foldp; i++)
+ if(compare(cp, folds[i]) < 0) {
+ for(j = foldp - 1; j >= i; j--)
+ folds[j+1] = folds[j];
+ foldp++;
+ folds[i] = cp;
+ return(0);
+ }
+ folds[foldp++] = cp;
+ return(0);
+}
+
+
+pfold(fold, curm)
+char *fold;
+{
+ register char *mailfile;
+
+ mailfile = m_maildir(fold);
+ if(chdir(mailfile) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(mailfile);
+ return(0);
+ }
+ if(shrt) {
+ printf("%s\n", fold);
+ return(0);
+ }
+ mp = m_gmsg(fold);
+ foldtot++;
+ msgtot =+ mp->nummsg;
+ if(totonly)
+ goto out;
+ if(curm) {
+ if(!m_convert(curm))
+ return(0);
+ if(mp->numsel > 1) {
+ printf("Can't set current msg to %s\n", curm);
+ return(0);
+ }
+ m_setcur(mp->curmsg = mp->hghsel);
+ }
+ if(!hdrflag++)
+ printf("\t\tFolder # of messages ( range ); cur msg (other files)\n");
+ printf("%22s", fold);
+ if(equal(folder, fold))
+ printf("+ ");
+ else
+ printf(" ");
+ if(mp->hghmsg == 0)
+ printf("has no messages");
+ else {
+ printf("has %3d message%s (%3d-%3d)",
+ mp->nummsg, (mp->nummsg==1)?" ":"s",
+ mp->lowmsg, mp->hghmsg);
+ if(mp->curmsg >= mp->lowmsg && mp->curmsg <= mp->hghmsg)
+ printf("; cur=%3s", m_name(mp->curmsg));
+ }
+ if(mp->selist || mp->others) {
+ printf("; (");
+ if(mp->selist) {
+ printf("%s", listname);
+ if(mp->others)
+ printf(", ");
+ }
+ if(mp->others)
+ printf("others");
+ putchar(')');
+ }
+ putchar('.');
+ putchar('\n');
+out:
+ free(mp);
+ mp = 0;
+ return(1);
+}
+
+
+compare(s1, s2)
+char *s1, *s2;
+{
+ register char *c1, *c2;
+ register int i;
+
+ c1 = s1; c2 = s2;
+ while(*c1 || *c2)
+ if(i = *c1++ - *c2++)
+ return(i);
+ return(0);
+}
--- /dev/null
+if -r open rm open
+load -n open subs.a strings.a wait -O libg.a libh.a
+if -r a.out mv a.out open
+: fini
+
--- /dev/null
+#include "mh.h"
+#include "iobuf.h"
+#include "stat.h"
+#include "errors.h"
+
+char *anoyes[], /* Std no/yes gans array */
+ *mypath,
+ mailbox[],
+ defalt[];
+
+char scanl[];
+struct msgs *mp;
+struct iobuf in, fout, *aud;
+struct inode stbuf;
+
+struct swit switches[] {
+ "audit audit-file", 0, /* 0 */
+ "ms ms-folder", 0, /* 1 */
+ "help", 4, /* 2 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+
+ char newmail[128], maildir[128], *folder, *from, *audfile;
+ register char *cp;
+ register int i, msgnum;
+ long now;
+ char *ap, *inp;
+ char *arguments[50], **argp;
+
+ fout.b_fildes = dup(1);
+#ifdef NEWS
+ m_news();
+#endif
+ from = folder = audfile = 0;
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ inp = ap;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("-%s unknown\n", cp);
+ goto leave;
+ case 0: if(!(audfile = *argp++)) { /* -audit */
+ missing: printf("Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 1: if(!(from = *argp++)) /* -ms */
+ goto missing;
+ continue;
+ case 2: /* -help */
+ help(concat( inp, " [+folder] [switches]", 0), switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ printf("Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else {
+ printf("Bad arg: %s\n", argp[-1]);
+ printf(concat("Usage: ", inp, " [+folder] [-ms ms-folder] [-audit audit-file]\n", 0));
+ goto leave;
+ }
+ }
+ if(from)
+ copy(from, newmail);
+ else {
+ mypath = getpath(getruid());
+ copy(mailbox, copy(mypath, newmail));
+ if(stat(newmail, &stbuf) < 0 ||
+ !(stbuf.i_size0 | stbuf.i_size1)) {
+ printf("No new mail.\n");
+ goto leave;
+ }
+ }
+ if(fopen(newmail, &in) < 0) {
+ printf("Can't read \"%s\"??\n", newmail);
+ goto leave;
+ }
+ if(!folder) {
+ folder = defalt;
+ if(from && !equal(from, "inbox")) {
+ cp = concat("Do you really want to convert from ",
+ from, " into ", folder, "?? ", 0);
+ if(!gans(cp, anoyes))
+ goto leave;
+ }
+ }
+ copy(m_maildir(folder), maildir);
+ if(stat(maildir, &stbuf) < 0) {
+ if(errno != ENOENT) {
+ printf("Error on folder "); flush();
+ perror(maildir);
+ goto leave;
+ }
+/* cp = concat("Create folder \"", maildir, "\"? ", 0);
+ if(!gans(cp, anoyes))
+ goto leave; */
+ if(!makedir(maildir)) {
+ printf("Can't create folder \"%s\"\n", maildir);
+ goto leave;
+ }
+ }
+ if(chdir(maildir) < 0) {
+ printf("Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ printf("Can't read folder!?\n");
+ goto leave;
+ }
+ if(audfile) {
+ aud = alloc(sizeof *aud);
+ cp = m_maildir(audfile);
+ if(fopen2(cp, aud) == -1) {
+ printf("Creating Receive-Audit: %s\n", cp);
+ if(fcreat(cp, aud) == -1) {
+ printf("Can't create "); flush();
+ perror(cp);
+ goto leave;
+ }
+ chmod(cp, 0600);
+ putchar('\n');
+ } else
+ seek(aud->b_fildes, 0, 2);
+ time(&now);
+ puts("<<inc>> ", aud);
+ cp = cdate(&now);
+ cp[9] = ' ';
+ puts(cp, aud);
+ if(from) {
+ puts(" -ms ", aud);
+ puts(from, aud);
+ }
+ putc('\n', aud);
+ }
+ printf("Incorporating new mail into %s...\n\n", folder);
+ flush();
+ msgnum = mp->hghmsg;
+
+ while((i = scan(&in, msgnum+1, msgnum+1, msgnum == mp->hghmsg))) {
+ if(i == -1) {
+ printf("command aborted!\n");
+ if(aud)
+ puts("inc aborted!\n", aud);
+ goto leave;
+ }
+ if(aud)
+ puts(scanl, aud);
+ flush();
+ msgnum++;
+ }
+
+ close(in.b_fildes);
+ if(aud)
+ fflush(aud);
+
+ if(!from) {
+ if((i = creat(newmail, 0600)) >= 0) /* Zap .mail file */
+ close(i);
+ else
+ printf("Error zeroing %s\n", newmail);
+ } else
+ printf("%s not zero'd\n", newmail);
+
+ i = msgnum - mp->hghmsg;
+ /* printf("%d new message%s\n", i, i==1? "":"s"); */
+ if(!i)
+ printf("[No messages incorporated.]\n");
+ else {
+ if(!equal(m_getfolder(), folder))
+ m_replace("folder", folder);
+ m_setcur(mp->hghmsg + 1);
+ }
+leave:
+ m_update();
+ flush();
+}
+
+
+
+
--- /dev/null
+if -r pickup rm pickup
+load -n pickup scansub subs.a strings.a putc wait -O libg.a libh.a
+if -r a.out mv a.out pickup
+: fini
+
--- /dev/null
+#
+/*
+ * print file with headings
+ * precl[2]+head+2+page[56]+endl[5]
+ */
+
+/*
+ * NOTE: Defaults are set in the routine dflts()
+ * and not in these declares.
+ */
+
+int errno;
+char *sys_errlst[];
+
+int ncol 1; /* number of columns */
+char *header; /* header text */
+int col;
+int icol;
+int file;
+char *bufp;
+#define BUFS 5120
+char buffer[BUFS];
+#define FF 014
+int line; /* current line on page */
+int linum; /* current text line */
+int ftext; /* first text line on page */
+char *colp[72];
+int nofile; /* number of current file */
+char isclosed[10];
+int peekc;
+int swval; /* value for next switch */
+int fpage; /* first page to print */
+int page; /* current page number */
+int oheadr; /* use old header format */
+int colw; /* column width */
+int nspace;
+int width 65; /* line width */
+int pwidth 65; /* width of physical line */
+int length 66; /* length of physical page */
+int plength 61; /* last print line */
+int margin 10;
+int prone 1; /* print header on page one */
+int ntflg; /* no header or trailer */
+int nuflg; /* not header line */
+int mflg;
+int tabc; /* print this as column separator */
+char *tty;
+int mode;
+int precl 2; /* # blank lines preceding hdr */
+int endl 5; /* min # blank lines end of page */
+int indent; /* spaces preceding each line */
+int ff; /* use ff, not blank lines */
+int wasff; /* page break caused by ff */
+int blankl; /* # blank lines between lines */
+int count; /* whether to count linums */
+int tab2sp; /* change tabs => spaces */
+int queeze; /* squeeze blank lines from top */
+ /* of each page */
+int jnamflg; /* print just file and not path */
+int rapflg; /* wrap-around line overflow */
+int spaftfil 0; /* space between files */
+
+
+struct inode
+{
+ int dev;
+ int inum;
+ int flags;
+ char nlink;
+ char uid;
+ char gid;
+ char siz0;
+ int size;
+ int ptr[8];
+ int atime[2];
+ int mtime[2];
+};
+
+main (argc, argv)
+char **argv;
+{
+ int nfdone;
+ int onintr ();
+ extern fout;
+
+ tty = "/dev/ttyx";
+ fout = dup (1);
+ close (1);
+ if ((signal (2, 1) & 01) == 0)
+ signal (2, onintr);
+ fixtty ();
+ dflts (0);
+ for (nfdone = 0; argc > 1; argc--)
+ {
+ argv++;
+ if (**argv == '-')
+ {
+ swval = 1; /* default to on */
+ setsw:
+ switch (*++*argv)
+ {
+ case 'b':
+ blankl = getn (++*argv);
+ continue;
+
+ case 'c':
+ count = swval;
+ continue;
+
+ case 'd':
+ dflts (*++*argv);
+ continue;
+
+ case 'e':
+ endl = getn (++*argv);
+ continue;
+
+ case 'f':
+ ff = swval;
+ continue;
+
+ case 'h':
+ if (argc >= 2)
+ {
+ header = *++argv;
+ argc--;
+ }
+ continue;
+
+ case 'i':
+ indent = getn (++*argv);
+ continue;
+
+ case 'j':
+ jnamflg = swval;
+ continue;
+
+ case 'l':
+ length = getn (++*argv);
+ continue;
+
+ case 'm':
+ mflg = swval;
+ continue;
+
+ case 'n':
+ prone = (swval ^ 1);
+ /* Yes => no */
+ continue;
+
+ case 'o':
+ oheadr = swval;
+ continue;
+
+ case 'p':
+ precl = getn (++*argv);
+ continue;
+
+ case 'q':
+ queeze = swval;
+ continue;
+
+ case 'r':
+ rapflg = swval;
+ continue;
+
+ case 's':
+ spaftfil = getn( ++*argv);
+ continue;
+
+ case 't':
+ ntflg = swval;
+ continue;
+
+ case 'u':
+ nuflg = swval;
+ continue;
+
+ case 'w':
+ width = getn (++*argv);
+ continue;
+
+ case 'x':
+ tab2sp = swval;
+ continue;
+
+ case '-':
+ swval = 0;
+ goto setsw;
+
+ default:
+ ncol = getn (*argv);
+ continue;
+ }
+ }
+ else
+ if (**argv == '+')
+ {
+ fpage = getn (++*argv);
+ }
+ else
+ {
+ col = 0;
+ icol = 0;
+ line = 0;
+ nspace = 0;
+ print (*argv, argv);
+ nfdone++;
+ if (mflg)
+ break;
+ }
+ }
+ if (nfdone == 0)
+ print (0);
+ flush ();
+ onintr ();
+}
+
+onintr ()
+{
+
+ chmod (tty, mode);
+ exit (0);
+}
+
+fixtty ()
+{
+ struct inode sbuf;
+ extern fout;
+
+ tty[8] = ttyn (fout);
+ fstat (fout, &sbuf);
+ mode = sbuf.flags & 0777;
+ chmod (tty, 0600);
+}
+
+dflts (dfltpkg)
+{
+ switch (dfltpkg)
+ {
+ case 'd':
+ ncol = 1; /* number of columns */
+ width = 65; /* line width */
+ length = 60; /* length of physical page */
+ plength = 61; /* last print line */
+ margin = 10;
+ precl = 1; /* # blank lines preceding hdr */
+ endl = 5; /* min # blank lines end of page */
+ indent = 5; /* spaces preceding each line */
+ ff = 1; /* use ff, not blank lines */
+ blankl = 0; /* # blank lines between lines */
+ count = 0; /* whether to count linums */
+ prone = 0; /* print header on page one */
+ tab2sp = 0; /* change tabs into spaces */
+ queeze = 1; /* squeeze beginning of pages */
+ jnamflg = 0; /* print full pathname */
+ rapflg = 1; /* wrap around long lines */
+ oheadr = 0; /* nothin' but the best... */
+ break;
+
+ case 'l':
+ ncol = 1; /* number of columns */
+ width = 77; /* line width */
+ length = 60; /* length of physical page */
+ plength = 61; /* last print line */
+ margin = 10;
+ precl = 2; /* # blank lines preceding hdr */
+ endl = 5; /* min # blank lines end of page */
+ indent = 5; /* spaces preceding each line */
+ ff = 1; /* use ff, not blank lines */
+ blankl = 0; /* # blank lines between lines */
+ count = 0; /* whether to count linums */
+ prone = 1; /* print header on page one */
+ tab2sp = 0; /* change tabs into spaces */
+ queeze = 0; /* preserve start of each page */
+ jnamflg = 0; /* print full pathname */
+ rapflg = 1; /* wrap around long lines */
+ oheadr = 0; /* nothin' but the best... */
+ break;
+
+ case 'n':
+ ncol = 1; /* number of columns */
+ width = 80; /* line width */
+ length = 60; /* length of physical page */
+ plength = 61; /* last print line */
+ margin = 10;
+ precl = 2; /* # blank lines preceding hdr */
+ endl = 5; /* min # blank lines end of page */
+ indent = 5; /* spaces preceding each line */
+ ff = 1; /* use ff, not blank lines */
+ blankl = 0; /* # blank lines between lines */
+ count = 1; /* whether to count linums */
+ prone = 1; /* print header on page one */
+ tab2sp = 0; /* don't change tabs into spaces */
+ queeze = 0; /* preserve start of each page */
+ jnamflg = 0; /* print full pathname */
+ rapflg = 1; /* wrap around long lines */
+ oheadr = 0; /* nothin' but the best... */
+ break;
+
+ case 0:
+ default:
+ ncol = 0; /* number of columns */
+ width = 72; /* line width */
+ length = 66; /* length of physical page */
+ plength = 61; /* last print line */
+ margin = 10;
+ precl = 2; /* # blank lines preceding hdr */
+ endl = 5; /* min # blank lines end of page */
+ indent = 0; /* spaces preceding each line */
+ ff = 0; /* use ff, not blank lines */
+ blankl = 0; /* # blank lines between lines */
+ count = 0; /* whether to count linums */
+ prone = 1; /* print header on page one */
+ tab2sp = 0; /* don't change tabs into spaces */
+ queeze = 0; /* preserve start of each page */
+ jnamflg = 1; /* don't print full pathname */
+ rapflg = 0; /* don't wrap around long lines */
+ oheadr = 1; /* nothin' but the worst... */
+ break;
+ }
+}
+
+
+print (fp, argp)
+char *fp;
+char **argp;
+{
+ struct inode sbuf;
+ int tmp1;
+ register int sncol,
+ sheader;
+ register char *cbuf;
+ extern fout;
+
+ linum = 1;
+ if (ntflg)
+ margin = 0;
+ else
+ margin = precl + endl + (nuflg ? 0 : 3);
+ if (length <= margin)
+ length = 66;
+ if (width <= 0)
+ width = 65;
+ if (ncol > 72 || ncol > width)
+ {
+ write (2, "Very funny.\n", 12);
+ exit ();
+ }
+ if (mflg)
+ {
+ mopen (argp);
+ ncol = nofile;
+ }
+ if (ncol > 1)
+ rapflg = 0;
+ colw = width / ncol;
+ sncol = ncol;
+ sheader = header;
+ plength = length - endl;
+ pwidth = width + indent;
+ if (ntflg)
+ plength = length;
+ if (--ncol < 0)
+ ncol = 0;
+ if (mflg)
+ fp = 0;
+ if (fp)
+ {
+ file = open (fp, 0);
+ if (file < 0)
+ {
+ errrpt (fp, sys_errlst[errno]);
+ return;
+ }
+ fstat (file, &sbuf);
+ }
+ else
+ {
+ file = 0;
+ time (sbuf.mtime);
+ }
+ if ((header == 0) && (file != 0))
+ header = jnamflg ? fp
+ : getpath (fp);
+ cbuf = ctime (sbuf.mtime);
+ cbuf[16] = '\0';
+ cbuf[24] = '\0';
+ page = 1;
+ icol = 0;
+ colp[ncol] = bufp = buffer;
+ if (mflg == 0)
+ nexbuf ();
+ while (mflg && nofile || (!mflg) && tpgetc (ncol) > 0)
+ {
+ if (mflg == 0)
+ {
+ colp[ncol]--;
+ if (colp[ncol] < buffer)
+ colp[ncol] = &buffer[BUFS];
+ }
+ line = 0;
+ if (ntflg == 0)
+ {
+ for (tmp1 = precl; tmp1--;)
+ put ('\n');
+ if ((nuflg == 0) &&
+ (prone || (page > 1)))
+ {
+ for (tmp1 = indent; tmp1--;)
+ put (' ');
+ if (!oheadr && header)
+ {
+ puts (header);
+ puts (" ");
+ }
+ puts (cbuf + 4);
+ put (' ');
+ puts (cbuf + 20);
+ if (oheadr)
+ {
+ puts (" ");
+ if (header)
+ {
+ puts (header);
+ put (' ');
+ }
+ }
+ else
+ do
+ put (' ');
+ while (col < (pwidth - 9));
+ puts ("Page ");
+ if (oheadr)
+ putd (page);
+ else
+ putrd (page);
+ puts ("\n\n\n");
+ }
+ }
+ ftext = line; /* # of first text line */
+ putpage ();
+
+ if (ff)
+ put ('\014');
+ else
+ if (ntflg == 0)
+ while (line < length)
+ put ('\n');
+ page++;
+ }
+ if ( (ntflg != 0) && (spaftfil > 0))
+ for (tmp1 = spaftfil; tmp1--;)
+ put('\n');
+ if (file)
+ close (file);
+ ncol = sncol;
+ header = sheader;
+}
+
+mopen (ap)
+char **ap;
+{
+ register char **p,
+ *p1;
+
+ p = ap;
+ while ((p1 = *p++) && p1 != -1)
+ {
+ isclosed[nofile] = fopen (p1, &buffer[2 * 259 * nofile]);
+ if (++nofile >= 10)
+ {
+ write (2, "Too many args.\n", 15);
+ exit ();
+ }
+ }
+}
+
+putpage ()
+{
+ register int lastcol,
+ i,
+ c;
+ int j;
+
+ if (ncol == 0)
+ {
+ i = 1; /* always starting on new line */
+ while (c = pgetc (0))
+ {
+ if (i) /* new line */
+ {
+ if ((queeze) &&
+ (c == '\n') &&
+ (line == ftext) &&
+ (!wasff) &&
+ (page > 1)
+ )
+ {
+ linum++;
+ continue;
+ }
+
+ for (i = indent; i--;)
+ put (' ');
+ if (count)
+ {
+ putrd (linum);
+ puts (" ");
+ };
+ i = 0;
+ };
+ switch (c)
+ {
+ case FF:
+ wasff = 1;
+ return;
+ case '\n':
+ linum++;
+ for ((i = (blankl + 1)); i--;)
+ {
+ put ('\n');
+ if (line >= plength)
+ {
+ wasff = 0;
+ return;
+ }
+ }
+ i = 1; /* signal new line */
+ break;
+ default:
+ put (c);
+ }
+
+ }
+ return;
+ }
+ colp[0] = colp[ncol];
+ if (mflg == 0)
+ for (i = 1; i <= ncol; i++)
+ {
+ colp[i] = colp[i - 1];
+ for (j = margin; j < length; j++)
+ while ((c = tpgetc (i)) != '\n')
+ if (c == 0)
+ break;
+ }
+ while (line < plength)
+ {
+ for (i = indent; i--;)
+ put (' ');
+ lastcol = colw + indent;
+ for (i = 0; i < ncol; i++)
+ {
+ while ((c = pgetc (i)) && c != '\n')
+ if (col < lastcol || tabc != 0)
+ put (c);
+ if (c == 0 && ntflg)
+ return;
+ if (tabc)
+ put (tabc);
+ else
+ while (col < lastcol)
+ put (' ');
+ lastcol =+ colw;
+ }
+ while ((c = pgetc (ncol)) && c != '\n')
+ put (c);
+ put ('\n');
+ }
+}
+
+nexbuf ()
+{
+ register int n;
+ register char *rbufp;
+
+ rbufp = bufp;
+ n = &buffer[BUFS] - rbufp;
+ if (n > 512)
+ n = 512;
+ if ((n = read (file, rbufp, n)) <= 0)
+ *rbufp = 0376;
+ else
+ {
+ rbufp =+ n;
+ if (rbufp >= &buffer[BUFS])
+ rbufp = buffer;
+ *rbufp = 0375;
+ }
+ bufp = rbufp;
+}
+
+tpgetc (ai)
+{
+ register char **p;
+ register int c,
+ i;
+
+ i = ai;
+ if (mflg)
+ {
+ if ((c = getc (&buffer[2 * 259 * i])) < 0)
+ {
+ if (isclosed[i] == 0)
+ {
+ isclosed[i] = 1;
+ if (--nofile <= 0)
+ return (0);
+ }
+ return ('\n');
+ }
+ if (c == FF && ncol > 0)
+ c = '\n';
+ return (c);
+ }
+loop:
+ c = **(p = &colp[i]) & 0377;
+ if (c == 0375)
+ {
+ nexbuf ();
+ c = **p & 0377;
+ }
+ if (c == 0376)
+ return (0);
+ (*p)++;
+ if (*p >= &buffer[BUFS])
+ *p = buffer;
+ if (c == 0)
+ goto loop;
+ return (c);
+}
+
+pgetc (i)
+{
+ register int c;
+
+ if (peekc)
+ {
+ c = peekc;
+ peekc = 0;
+ }
+ else
+ c = tpgetc (i);
+ if (tabc)
+ return (c);
+ switch (c)
+ {
+
+ case '\t':
+ icol++;
+ if ((icol & 07) != 0)
+ peekc = '\t';
+ return (' ');
+
+ case '\n':
+ icol = 0;
+ break;
+ }
+ if (c >= ' ')
+ icol++;
+ return (c);
+}
+
+puts (as)
+char *as;
+{
+ register int c;
+ register char *s;
+
+ if ((s = as) == 0)
+ return;
+ while (c = *s++)
+ put (c);
+}
+
+putrd (an)
+{
+ register int mag;
+
+ for (mag = 1000; ((mag > 1) && (mag > an)); mag =/ 10)
+ put (' ');
+ putd (an);
+}
+
+
+putd (an)
+{
+ register int a,
+ n;
+
+ n = an;
+ if (a = n / 10)
+ putd (a);
+ put (n % 10 + '0');
+}
+
+put (ac)
+{
+ register c;
+ int tspace;
+
+ c = ac;
+ if (tabc)
+ {
+ putcp (c);
+ if (c == '\n')
+ line++;
+ return;
+ }
+ switch (c)
+ {
+
+ case ' ':
+ nspace++;
+ col++;
+ return;
+
+ /* case '\t': */
+ /* c = '~';
+ */
+ /* break;
+ */
+ /* nspace =& 0177770;
+ */
+ /* nspace =+ 010;
+ */
+ /* col =& 0177770;
+ */
+ /* col =+ 010;
+ */
+ /* return;
+ */
+
+ case '\n':
+ nspace = 0;
+ line++;
+ col = 0;
+ break;
+
+ case 010:
+ case 033:
+ if (--col < 0)
+ col = 0;
+ if (--nspace < 0)
+ nspace = 0;
+
+ }
+
+ if (rapflg && (col >= 84)) /* overflow */
+ {
+ putcp ('\n');
+ line++;
+ tspace = col - 84;
+ col = nspace = 62; /* 84 - 22 */
+ sppr ();
+ putcp ('*');
+ putcp ('*');
+ col =+ (2 + (nspace = tspace));
+ };
+
+ sppr ();
+
+ if (c >= ' ')
+ col++;
+ putcp (c);
+}
+
+sppr ()
+{
+ register int c,
+ ns;
+
+ if ((c != '\n') && (c != FF))
+ while (nspace)
+ {
+ if (
+ (!tab2sp) &&
+ (nspace > 2) &&
+ (col > (ns = ((col - nspace) | 07)))
+ )
+ {
+ nspace = col - ns - 1;
+ putcp ('\t');
+ }
+ else
+ {
+ nspace--;
+ putcp (' ');
+ }
+ }
+}
+
+getn (ap)
+char *ap;
+{
+ register int n,
+ c;
+ register char *p;
+
+ p = ap;
+ n = 0;
+ if ((*p < '0') || (*p > '9'))
+ errrpt (p, "in parameter is supposed to be a number");
+
+ while ((c = *p++) >= '0' && c <= '9')
+ n = n * 10 + c - '0';
+ return (n);
+}
+
+putcp (c)
+{
+ if (page >= fpage)
+ putchar (c);
+}
+
+int fout;
+
+errrpt (str1, str2)
+char *str1,
+ *str2;
+{
+ int ofout;
+
+ flush ();
+ ofout = fout;
+ fout = 2;
+
+ printf ("pr: \"%s\" %s.\n", str1, str2);
+
+ flush ();
+ fout = ofout;
+};
+
+
+#define DOT "."
+#define DOTDOT ".."
+#define ROOT "/"
+#define DEBUG
+
+getpath (filestr)
+char *filestr;
+{
+ int n;
+ int gpfile;
+ char *fulpath;
+ struct statb
+ {
+ int devn,
+ inum,
+ i[18];
+ } x;
+ struct entry
+ {
+ int jnum;
+ char name[16];
+ } y;
+
+
+
+ if (*filestr == '/')
+ {
+ fulpath = filestr; /* already a full name */
+ return (fulpath);
+ }
+
+ fulpath = alloc (1); /* got to start somewhere */
+ *fulpath = 0;
+ setexit ();
+
+ if (*fulpath) /* been here before ? */
+ {
+ chdir (fulpath); /* get back to original dir */
+ rplstr (&fulpath,
+ dircat ("", fulpath));
+ rplstr (&fulpath,
+ dircat (fulpath, filestr));
+ return (fulpath);
+ }
+
+ while (1)
+ {
+ stat (DOT, &x);
+ if ((gpfile = open (DOTDOT, 0)) < 0)
+ reset ();
+ do
+ {
+ if ((n = read (gpfile, &y, 16)) < 16)
+ reset ();
+ /* printf("y.name = %s\n",y.name); */
+ }
+ while (y.jnum != x.inum);
+ close (gpfile);
+ /* printf("y.jnum = %d\n",y.jnum); */
+ if (y.jnum == 1)
+ ckroot (y.name, &fulpath);
+
+ rplstr (&fulpath,
+ dircat (y.name, fulpath));
+ /* printf("fulpath = %s\n",fulpath); */
+ chdir (DOTDOT);
+ }
+}
+
+ckroot (name, fulpath)
+char *name,
+ **fulpath;
+{
+ int i,
+ n;
+ int gpfile;
+ struct statb
+ {
+ int devn,
+ inum,
+ i[18];
+ } x;
+ struct entry
+ {
+ int jnum;
+ char name[16];
+ } y;
+
+
+ if ((n = stat (name, &x)) < 0)
+ reset ();
+ i = x.devn;
+
+ if (((n = chdir (ROOT)) < 0) ||
+ ((gpfile = open (ROOT, 0)) < 0))
+ reset ();
+
+ /* printf("fulpath = %s\n",*fulpath); */
+ while (1)
+ {
+ if ((n = read (gpfile, &y, 16)) < 16)
+ reset ();
+ if (y.jnum == 0)
+ continue;
+ if ((n = stat (y.name, &x)) < 0)
+ reset ();
+ if (x.devn != i)
+ continue;
+ x.i[0] =& 060000;
+ if (x.i[0] != 040000)
+ continue;
+ if ((strequ (y.name, ".")) ||
+ (strequ (y.name, "..")))
+ break;
+ /* printf("y.name = %s\n",y.name); */
+ rplstr (fulpath,
+ dircat (y.name, *fulpath));
+ /* printf("fulpath = %s\n",*fulpath); */
+ }
+ reset ();
+}
+
+
+/* */
+/* Return the length of the given string. This length */
+/* does not include the terminating null character. */
+
+pstrlen (string)
+char *string;
+{
+ register char *rstring;
+ register int rlength; /* length of string */
+
+ rstring = string;
+
+ for (rlength = 0; *rstring++ != 0; ++rlength);
+ return (rlength);
+}
+
+
+/* */
+/* Copy the given string to the given location. */
+/* */
+
+strcpy (from, to)
+char *from,
+ *to;
+{
+ register char *rfrom,
+ *rto;
+
+ rfrom = from;
+ rto = to;
+
+ while (*rto++ = *rfrom++);
+}
+
+/* */
+/* Concatenate the first given string the the second */
+/* given string. */
+
+dircat (prefix, suffix)
+char *prefix,
+ *suffix;
+{
+ register char *rprefix,
+ *rsuffix,
+ *ptr;
+ char *newstr;
+
+ if ((ptr = newstr =
+ alloc (pstrlen (rprefix = prefix) +
+ pstrlen (rsuffix = suffix) + 2))
+ == -1)
+ {
+ write (1, "No more string storage!\n", 24);
+ exit ();
+ }
+ while (*ptr++ = *rprefix++);
+ ptr--;
+ if (ptr[-1] != '/')
+ *ptr++ = '/';
+ while (*ptr++ = *rsuffix++);
+ return (newstr);
+}
+
+/* */
+/* Determine if the two given strings are equivalent. */
+/* */
+
+strequ (str1, str2)
+char *str1,
+ *str2;
+{
+ register char *rstr1,
+ *rstr2;
+
+ rstr1 = str1;
+ rstr2 = str2;
+
+ while (*rstr1 == *rstr2++)
+ if (*rstr1++ == 0)
+ return (1);
+ return (0);
+}
+
+rplstr (oldstr, newstr)
+char **oldstr,
+ *newstr;
+{
+ /* printf("oldstr = %s\nnewstr =
+ %s\n",*oldstr,newstr); */
+ free (*oldstr);
+ *oldstr = newstr;
+}
--- /dev/null
+cc -n pr.c
+if -r a.out mv a.out pr
--- /dev/null
+#include "mh.h"
+#include "iobuf.h"
+#include "errors.h"
+#include "sgtty.h"
+#include "signals.h"
+
+/*#define CEDIT 01 */ /* use following editing chars */
+#define CKILL 006 /* @ => <CLOSE> */
+#define CERASE 001 /* # => <CTRL A> */
+
+/*define EDIT 001*/ /* edit after filling in fields */
+char sysed[];
+
+int fout;
+struct iobuf in, out;
+struct sgtty sg;
+struct swit switches[] {
+ "editor editor", 0, /* 0 */
+ "erase chr", 2, /* 1 */
+ "kill chr", 0, /* 2 */
+ "help", 4, /* 3 */
+ 0, 0
+};
+
+
+main(argc, argv)
+char *argv[];
+{
+ char tmpfil[32], *drft, name[NAMESZ], field[512], *ed;
+ int exitstat;
+ char skill, serase;
+ char *killp, *erasep;
+ register int i, state;
+ register char *cp;
+ char *ap;
+ char *arguments[50], **argp;
+ int sig();
+ int status, pid, wpid, intr;
+
+ fout = dup(1);
+ skill = exitstat = 0;
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", '\n');
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++)
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto badleave;
+ /* unknown */
+ case -1:printf("prompter: -%s unknown\n", cp);
+ goto badleave;
+ case 0: if(!(ed = *argp++)) { /* -editor */
+ missing: printf("prompter: Missing argument for %s switch\n", argp[-2]);
+ goto badleave;
+ }
+ continue;
+ case 1: if(!(erasep = *argp++)) /* -erase */
+ goto missing;
+ continue;
+ case 2: if(!(killp= *argp++)) /* -kill */
+ goto missing;
+ continue;
+ case 3: help("prompter [file] [switches]",
+ switches);
+ goto badleave;
+ }
+ else
+ drft = cp;
+ if(!drft) {
+ printf("prompter: missing skeleton\n");
+ goto badleave;
+ }
+ if(fopen(drft, &in) == -1) {
+ printf("Can't open %s\n", drft);
+ goto badleave;
+ }
+ copy(makename("prmt", ".tmp"), copy("/tmp/", tmpfil));
+ if(fcreat(tmpfil, &out) == -1) {
+ printf("Can't create %s\n", tmpfil);
+ goto badleave;
+ }
+ chmod(tmpfil, 0700);
+ signal(SIGINT, &sig);
+ gtty(0, &sg);
+ skill = sg.sg_kill;
+ serase = sg.sg_erase;
+#ifdef CEDIT
+ sg.sg_kill = killp ? chrcnv(killp) : CKILL;
+ sg.sg_erase = erasep ? chrcnv(erasep) : CERASE;
+#else
+ sg.sg_kill = killp ? chrcnv(killp) : skill;
+ sg.sg_erase = erasep ? chrcnv(erasep) : serase;
+#endif
+ stty(0, &sg);
+ if ( skill != sg.sg_kill || serase != sg.sg_erase ) {
+ printf("Erase Char="); chrdisp(sg.sg_erase);
+ printf("; Kill Line="); chrdisp(sg.sg_kill);
+ printf(".\n"); flush();
+ }
+
+ state = FLD;
+ for(;;) switch(state = m_getfld(state,name,field,sizeof field,&in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(field[0] != '\n' || field[1] != 0) {
+ printf("%s:%s", name, field);
+ puts(name, &out);
+ putc(':', &out);
+ puts(field, &out);
+ while(state == FLDPLUS) {
+ state=m_getfld(state,name,field,sizeof field,&in);
+ printf("%s", field);
+ puts(field, &out);
+ }
+ } else {
+ printf("%s: ", name);
+ flush();
+ i = getln(&field);
+ if(i == -1)
+ goto badleave;
+ if(i == 0 && (field[0] == '\n' || !field[0]))
+ continue;
+ puts(name, &out); putc(':', &out);
+ do {
+ if(field[0] != ' ' && field[0] != '\t')
+ putc(' ', &out);
+ puts(field, &out);
+ } while(i == 1 && (i = getln(&field)) >= 0);
+ if(i == -1)
+ goto badleave;
+ }
+ field[0] = 0;
+ if(state == FLDEOF)
+ goto body;
+ continue;
+
+ case BODY:
+ case BODYEOF:
+ case FILEEOF:
+ body: puts("--------\n", &out);
+ printf("--------\n");
+ if(field[0]) {
+ do {
+ puts(field, &out);
+ /*printf("%s", field);*/
+ } while(state == BODY &&
+ (state=m_getfld(state,name,field,sizeof field,&in)));
+ }
+ flush();
+ for(;;) {
+ i = getln(&field);
+ if (i == -1) goto badleave; /**/
+ if(field[0] == 0)
+ break;
+ puts(field, &out);
+ }
+ goto done;
+
+ default:
+ printf("Bad format file!\n");
+ goto badleave;
+ }
+
+
+done:
+ printf("--------\n"); flush();
+ fflush(&out);
+ close(out.b_fildes);
+ fopen(tmpfil, &out);
+ close(in.b_fildes);
+ fcreat(drft, &in); /* Truncate prior to copy back */
+ do
+ if((i = read(out.b_fildes, field, sizeof field)) > 0)
+ write(in.b_fildes, field, i);
+ while(i == sizeof field);
+ close(in.b_fildes);
+ close(out.b_fildes);
+ unlink(tmpfil);
+again:
+ if(skill) {
+ sg.sg_kill = skill;
+ sg.sg_erase = serase;
+ stty(0, &sg);
+ skill = 0;
+ }
+
+#ifdef EDIT
+ printf("Edit? ");
+ flush();
+ getln(&field);
+ if(field[0] == 0)
+ goto badleave;
+ field[length(field) - 1] = 0; /* zap <lf> */
+ if(field[0] == 0) {
+ printf("Options are:\n no\n yes\n show\n <any editor>\n");
+ goto again;
+ }
+ if(ssequal(field, "no"))
+ goto leave;
+ if(ssequal(field, "show")) {
+ if(showfile(drft))
+ goto badleave;
+ goto again;
+ }
+ if(ssequal(field, "yes")) {
+ if(!ed &&
+ ((ed = m_find("editor")) == -1 || equal(invo_name(), ed)))
+ ed = sysed;
+ } else
+ ed = field;
+ intr = signal(SIGINT, 1);
+ if((pid = fork()) == 0) {
+ /* m_update(); */
+ flush();
+ execlsrh(ed, drft, 0);
+ exit(-1); /* can't exec editor */
+ } else if(pid == -1) {
+ printf("prompter: no forks!\n");
+ goto leave;
+ } else
+ while((wpid = waita(&status)) != -1 && wpid != pid) ;
+ if((status & 0177400) == 0177400) goto again; /* -1 */
+ signal(SIGINT, intr);
+#endif
+ goto leave;
+
+badleave:
+ exitstat = 1;
+leave:
+ m_update();
+ flush();
+ if(skill) {
+ sg.sg_kill = skill;
+ sg.sg_erase = serase;
+ stty(0, &sg);
+ }
+ exit(exitstat);
+}
+
+
+
+
+getln(buf)
+char *buf;
+{
+ register char *cp;
+ register int c;
+
+ cp = buf;
+ *cp = 0;
+ for(;;) {
+ c = getchar();
+ if(c == 0)
+ if(errno == EINTR)
+ return(-1);
+ else
+ return(0);
+ if(c == '\n') {
+ if ( cp != buf ) /* if not first char in line */
+ if(cp[-1] == '\\') {
+ cp[-1] = c;
+ return(1);
+ }
+ if((buf==&(cp[-1]))&&(cp[-1] == '.')) {
+ buf[0] = 0;
+ return(0);
+ }
+ *cp++ = c;
+ *cp = 0;
+ return(0);
+ }
+ if(cp < buf + 500)
+ *cp++ = c;
+ *cp = 0;
+ }
+}
+
+
+sig()
+{
+ signal(SIGINT, &sig);
+ return;
+}
+
+
+chrcnv(str)
+{
+ register char *cp;
+ register int c;
+
+ cp = str;
+ if((c = *cp++) != '\\')
+ return(c);
+ c = 0;
+ while(*cp && *cp != '\n') {
+ c =* 8;
+ c =+ *cp++ - '0';
+ }
+ return c;
+}
+
+
+chrdisp(chr)
+{
+ register int c;
+
+ c = chr;
+ if(c < ' ')
+ printf("<CTRL-%c>", c + '@');
+ else
+ printf("%c", c);
+}
--- /dev/null
+if -r prompter rm prompter
+load -n prompter subs.a strings.a wait.o -O libg.a libh.a libg.a
+if -r a.out mv a.out prompter
+: fini
+
--- /dev/null
+#include "mh.h"
+#include "stat.h"
+
+char *anoyes[]; /* Std no/yes gans array */
+char defalt[];
+
+int fout;
+
+struct msgs *mp;
+struct dirent {
+ int inum;
+ char name[14];
+ int pad;
+};
+struct swit switches[] {
+ "help", 4, /* 0 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp, *ap;
+ char *folder, *inp, buf[128];
+ int i, def_fold;
+ struct inode stbf;
+ struct dirent ent;
+ char *arguments[50], **argp;
+
+ fout = dup(1);
+#ifdef NEWS
+ m_news();
+#endif
+ folder = 0;
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ inp = ap;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("-%s unknown\n", cp);
+ goto leave;
+ /* -help */
+ case 0: help(concat( inp, " [+folder] [switches]", 0), switches);
+ goto leave;
+ }
+ if(*cp == '+')
+ if(folder) {
+ printf("Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ else {
+ printf(concat("Usage: ", inp, " [+folder]\n",0));
+ goto leave;
+ }
+ }
+ if(!folder) {
+ folder = m_getfolder();
+ def_fold++;
+ }
+ expfold(folder);
+ leave:
+ m_update();
+ flush();
+}
+
+
+expfold(fold)
+char *fold;
+{
+ char *maildir;
+ int i, expcount, nxtmsg, compactok;
+ register int msgnum;
+ register char *cp, *sp;
+ char nambuf[10];
+ struct inode stbf;
+
+ expcount = 0;
+ maildir = m_maildir(fold);
+ if(chdir(maildir) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(maildir);
+ return(1);
+ }
+ if(access(".", 2) == -1) {
+ printf("You cannot manipulate %s\n", fold);
+ return(1);
+ }
+ if(!(mp = m_gmsg(fold))) {
+ printf("Can't read folder!\n");
+ return(1);
+ }
+ if(mp->hghmsg == 0) {
+ printf("No messages in \"%s\".\n", fold);
+ return(1);
+ }
+ nxtmsg = 0;
+ compactok = TRUE;
+ for(msgnum = 1; msgnum<=mp->hghmsg; msgnum++)
+ if(mp->msgstats[msgnum]&EXISTS) {
+ cp = getcpy(m_name(msgnum));
+ if (mp->msgstats[msgnum]&DELETED)
+ if(unlink(cp) == -1)
+ printf("Can't unlink %s: %s\n", fold,cp);
+ else {
+ mp->msgstats[msgnum] =& ~EXISTS & ~DELETED;
+ if(msgnum==mp->curmsg)
+ m_setcur(0);
+ expcount++;
+ if (nxtmsg == 0) nxtmsg = msgnum;
+ }
+ else if ((nxtmsg > 0) && compactok) {
+ if(link(cp,sp=m_name(nxtmsg)) == -1) {
+ compactok = FALSE;
+ printf("Can't rename %s to %s.\n", cp, sp);
+ }
+ else if(unlink(cp) == -1) {
+ compactok = FALSE;
+ printf("Can't rename %s to %s.\n", cp, sp);
+ }
+ else {
+ if(msgnum==mp->curmsg)
+ m_setcur(nxtmsg);
+ nxtmsg++;
+ }
+ }
+ }
+ else if(nxtmsg==0) nxtmsg = msgnum;
+ printf("%d message%s gone\n", expcount, expcount==1 ? "":"s");
+ return(0);
+}
--- /dev/null
+if -r purge rm purge
+load -n purge subs.a strings.a wait -O libg.a libh.a
+if -r a.out mv a.out purge
+: fini
+
--- /dev/null
+/ putw/putc -- write words/characters on output file
+
+ .globl _putc, _putw, _fflush, _fcreat
+ .globl cerror
+ .comm _errno,2
+
+_fcreat:
+ mov r5,-(sp)
+ mov sp,r5
+ mov 4(r5),0f
+ mov 6(r5),r1
+ mov pc,(r1) / a putatively illegal file desc.
+ sys 0; 9f
+.data
+9: sys creat; 0:..; 666
+.text
+ bes badret
+ mov r0,(r1)+
+ clr (r1)+
+ clr (r1)+
+ br goodret
+
+_putw:
+ mov r5,-(sp)
+ mov sp,r5
+ mov 6(r5),r1
+ dec 2(r1)
+ bge 1f
+ jsr pc,fl
+ bes badret
+ dec 2(r1)
+1:
+ movb 4(r5),*4(r1)
+ inc 4(r1)
+ dec 2(r1)
+ bge 1f
+ jsr pc,fl
+ bes badret
+ dec 2(r1)
+1:
+ movb 5(r5),*4(r1)
+ inc 4(r1)
+ mov 4(r5),r0
+ br goodret
+
+_putc:
+ mov r5,-(sp)
+ mov sp,r5
+ mov 6(r5),r1
+ dec 2(r1)
+ bge 1f
+ jsr pc,fl
+ bes badret
+ dec 2(r1)
+1:
+ mov 4(r5),r0
+ movb r0,*4(r1)
+ inc 4(r1)
+ br goodret
+
+_fflush:
+ mov r5,-(sp)
+ mov sp,r5
+ mov 4(r5),r1
+ jsr pc,fl
+ bes badret
+ br goodret
+
+fl:
+ mov r1,r0
+ add $6,r0
+ mov r0,-(sp)
+ mov r0,0f
+ mov 4(r1),0f+2
+ beq 1f
+ sub r0,0f+2
+ mov (r1),r0
+ sys 0; 9f
+.data
+9: sys write; 0:..; ..
+.text
+1:
+ mov (sp)+,4(r1)
+ mov $512.,2(r1)
+ rts pc
+
+badret:
+ jmp cerror
+
+goodret:
+ clr _errno
+ mov (sp)+,r5
+ rts pc
--- /dev/null
+#include "mh.h"
+#include "iobuf.h"
+#include "stat.h"
+#include "signals.h"
+
+/*#define TEST 1*/
+
+char draft[],
+ sysed[],
+#ifdef PROMPT
+ prmtproc[],
+#endif
+ sndproc[];
+
+char *anysh[] {
+ "no", 0,
+ "yes", 0,
+ "show", 0,
+ 0
+};
+char *anyv[] {
+ "no", 0,
+ "yes", 0,
+ "verbose", 0,
+ 0
+};
+
+int *vec[MAXARGS], fout, anot;
+int ccme 1;
+struct msgs *mp;
+char *ed;
+
+struct swit switches[] {
+ "annotate", 0, /* 0 */
+ "noannotate", 0, /* 1 */
+ "ccme", 0, /* 2 */
+ "noccme", 0, /* 3 */
+ "editor editor", 0, /* 4 */
+ "help", 4, /* 5 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *inp, *folder, *nfolder, *msg, *maildir;
+ register char *cp, *ap;
+ register int cur;
+ char *arguments[50], **argp;
+
+ fout = dup(1);
+#ifdef NEWS
+ m_news();
+#endif
+ msg = anot = folder = 0;
+
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ inp = ap;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("-%s unknown\n", cp);
+ goto leave;
+ case 0: anot = 1; continue; /* -annotate */
+ case 1: anot = 0; continue; /* -noannotate */
+ case 2: ccme = 1; continue; /* -ccme */
+ case 3: ccme = 0; continue; /* -noccme */
+ case 4: if(!(ed = *argp++)) { /* -editor */
+ printf("Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ /* -help */
+ case 5: help(concat( inp, " [+folder] [msg] [switches]", 0),
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ printf("Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else if(msg) {
+ printf("Only one message at a time.\n");
+ goto leave;
+ } else
+ msg = cp;
+ }
+ if(!msg)
+ msg = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ printf("Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ printf("No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!m_convert(msg, UNDELETED, UNDELETED))
+ goto leave;
+ if(mp->numsel == 0) {
+ printf("No undeleted message specified\n");
+ goto leave;
+ }
+ if(mp->numsel > 1) {
+ printf("Only one message at a time.\n");
+ goto leave;
+ }
+ m_replace("folder", folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ repl(getcpy(m_name(mp->lowsel)));
+ leave:
+ m_update();
+ flush();
+}
+
+
+repl(msg)
+{
+ register char *cp;
+ register int i,j;
+ struct iobuf in;
+ char name[NAMESZ], field[512], *from, *cc, *sub, *date, *to;
+ char *drft, *msgid;
+ int state, out, status, intr;
+ struct inode stbuf;
+
+ if(fopen(msg, &in) < 0) {
+ printf("Can't open \"%s\"\n", msg);
+ return;
+ }
+ drft = m_maildir(draft);
+ if((out = open(drft, 0)) >= 0) {
+/*
+ cp = concat("\"", drft, "\" exists; delete? ", 0);
+ while((i = gans(cp, anysh)) == 2)
+ showfile(drft);
+ if(!i)
+ return;
+ free(cp);
+*/
+ close(out);
+ }
+ if((out = creat(drft, m_gmprot())) < 0) {
+ printf("Can't create \"%s\".\n", drft);
+ return;
+ }
+
+ state = FLD;
+ msgid = to = from = cc = sub = date = 0;
+
+ for(;;) {
+
+ switch(state = m_getfld(state, name, field, sizeof field, &in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(uleq(name, "from"))
+ from = add(field, from);
+ if(uleq(name, "cc"))
+ cc = add(field, cc);
+ if(uleq(name, "subject"))
+ sub = add(field, sub);
+ if(uleq(name, "date"))
+ date = add(field, date);
+ if(uleq(name, "to"))
+ to = add(field, to);
+ if(uleq(name, "message-id"))
+ msgid = add(field, msgid);
+ if(state == FLDEOF)
+ goto done;
+ break;
+
+ case BODY:
+ case BODYEOF:
+ case FILEEOF:
+ goto done;
+
+ default:
+ printf("getfld returned %d\n", state);
+ return;
+ }
+
+ }
+
+done: if(!from) {
+ printf("No one to reply to!!!\n");
+ return;
+ }
+ close(in.b_fildes);
+ type(out, "To: ");
+ if(*from == ' ') from++;
+ type(out, from);
+ if(cc) {
+ while(*cc == ' ') cc++;
+ if(*cc == '\n' && cc[1] == 0) cc = 0;
+ }
+ if(to) {
+ while(*to == ' ') to++;
+ if(*to == 0) to = 0;
+ }
+ if(!ccme)
+ to = 0;
+ if(cc || to)
+ type(out, "cc: ");
+ if(cc) {
+ if(to) {
+ cp = cc+length(cc)-1;
+ if(*cp == '\n') *cp = 0;
+ while(*--cp == ' ') ;
+ *++cp = 0;
+ }
+ type(out, cc);
+ }
+ if(to) {
+ if(cc)
+ type(out, ",\n ");
+ type(out, to);
+ }
+ if(sub) {
+ type(out, "Subject: ");
+ if(*sub == ' ') sub++;
+ if((sub[0] != 'R' && sub[0] != 'r') ||
+ (sub[1] != 'E' && sub[1] != 'e') ||
+ sub[2] != ':')
+ type(out, "Re: ");
+ type(out, sub);
+ }
+ if(date) {
+ type(out, "In-reply-to: Your message of ");
+ date[length(date)-1] = '.';
+ if(*date == ' ') date++;
+ type(out, date);
+ type(out, "\n");
+ if(msgid) {
+ type(out, " ");
+ if(*msgid == ' ') msgid++;
+ type(out, msgid);
+ }
+ }
+ type(out, "----------\n");
+ close(out);
+ if(!ed && (ed = m_find("editor")) == -1)
+#ifdef PROMPT
+ ed = prmtproc;
+#else
+ ed = sysed;
+#endif
+ intr = signal(SIGINT, 1);
+ if((out = fork()) == 0) {
+ unlink("@"); link(msg, "@"); /* An easy handle on cur msg */
+ m_update();
+ flush();
+ /*** printf("execlsh(%s, %s, 0)\n", ed, drft); flush(); ***/
+ execlsrh(ed, drft, 0);
+ printf("Can't exec the editor: ");
+ flush(); perror(ed); exit(1);
+ } else if(out == -1) {
+ printf("No Forks\n");
+ return;
+ } else {
+ while((state = waita(&status)) != -1 && state != out) ;
+ signal(SIGINT, intr);
+ if(status) {
+ if(status > 0377)
+ unlink(drft);
+ printf("[command aborted--%s %s]\n", drft,
+ status > 0377? "deleted" : "preserved");
+ unlink("@");
+ return;
+ }
+ }
+#ifdef TEST
+ printf("!! Test Version of SEND Being Run !!\n");
+ printf(" Send verbose !\n\n");
+#endif
+/* cp = concat("Send \"", draft, "\"? ", 0); */
+ cp = "Send? ";
+ if((j = gans(cp, anyv)) > 0) {
+ stat("@", &stbuf);
+ if(stbuf.i_nlink == 1)
+ if(unlink(msg) == -1 || link("@", msg) == -1) {
+ printf("Can't update %s from @ file!\n",msg);
+ return(0);
+ }
+ unlink("@"); /* Remove this extra link */
+ if(anot > 0 || (!anot && m_find("reply-annotate") != -1)) {
+ while((state = fork()) == -1) sleep(5);
+ if(state) {
+ while(out=wait()!= -1 && out != state);
+ if(stat(drft, field) == -1)
+ annotate(msg, "Replied", "");
+ return;
+ }
+ }
+ i = 0;
+ vec[i++] = "mh-sndproc";
+ vec[i++] = drft;
+ if(j == 2)
+ vec[i++] = "-verbose";
+ vec[i++] = 0;
+ m_update();
+ flush();
+ execv(sndproc, vec);
+ printf("Can't exec send!!\n");
+ } else
+ unlink("@"); /* Remove this extra link */
+}
+
--- /dev/null
+if -r reply rm reply
+load -n reply annotate subs.a strings.a wait -O libg.a libh.a libg.a
+if -r a.out mv a.out reply
+: fini
+
--- /dev/null
+#include "mh.h"
+#include "stat.h"
+
+char *anoyes[]; /* Std no/yes gans array */
+char defalt[];
+
+int fout;
+int subf;
+
+struct msgs *mp;
+struct dirent {
+ int inum;
+ char name[14];
+ int pad;
+};
+struct swit switches[] {
+ "help", 4, /* 0 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp, *ap;
+ char *folder, buf[128];
+ int i, def_fold;
+ struct inode stbf;
+ struct dirent ent;
+ char *arguments[50], **argp;
+
+ fout = dup(1);
+#ifdef NEWS
+ m_news();
+#endif
+ folder = 0;
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("rmf: -%s unknown\n", cp);
+ goto leave;
+ /* -help */
+ case 0: help("rmf [+folder] [switches]", switches);
+ goto leave;
+ }
+ if(*cp == '+')
+ if(folder) {
+ printf("Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ else {
+ printf("Usage: rmf [+folder]\n");
+ goto leave;
+ }
+ }
+ if(!folder) {
+ folder = m_getfolder();
+ def_fold++;
+ }
+ subf = !((!any('/', folder)) | (*folder == '/') | (*folder == '.'));
+ if(def_fold && !subf) {
+ cp = concat("Remove folder \"", folder, "\" ?? ", 0);
+ if(!gans(cp, anoyes))
+ goto leave;
+ free(cp);
+ }
+ if(rmfold(folder))
+ goto leave;
+ if(subf) {
+ cp = copy(folder, buf);
+ while(cp > buf && *cp != '/') --cp;
+ if(cp > buf) {
+ *cp = 0;
+ printf("[+%s now current]\n", buf);
+ m_replace("folder", buf);
+ }
+ }
+ leave:
+ m_update();
+ flush();
+}
+
+struct dirent ent;
+
+rmfold(fold)
+char *fold;
+{
+ register char *maildir;
+ int i, leftover;
+ register char *cp, *sp;
+ char nambuf[10];
+ struct inode stbf;
+
+ leftover = 0;
+ if(!subf && equal(m_find("folder"), fold)) { /* don't re-do */
+ printf("[+%s now current]\n", defalt);
+ flush(); /*??*/
+ m_replace("folder", defalt);
+ }
+ maildir = m_maildir(fold);
+ if(chdir(maildir) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(maildir);
+ return(1);
+ }
+ if(access(".", 2) == -1) {
+ if(!m_delete(concat("cur-", fold, 0)))
+ printf("[Folder %s de-referenced]\n", fold);
+ else
+ printf("You have no profile entry for the read-only folder %s\n", fold);
+ return(1);
+ }
+ i = open(".", 0);
+ ent.pad = 0;
+ while(read(i, &ent.inum, sizeof ent.name + sizeof ent.inum))
+ if(ent.inum)
+ if((ent.name[0] >= '0' && ent.name[0] <= '9') ||
+ ent.name[0] == ',' ||
+ equal(ent.name, "cur") ||
+ equal(ent.name, "@")) {
+ if(unlink(ent.name) == -1) {
+ printf("Can't unlink %s:%s\n", fold,ent.name);
+ leftover++;
+ }
+ } else if(!equal(ent.name,".")&& !equal(ent.name,"..")) {
+ printf("File \"%s/%s\" not deleted!\n",
+ fold, ent.name);
+ leftover++;
+ }
+ close(i);
+ if(!leftover && removedir(maildir))
+ return(0);
+ else
+ printf("Folder %s not removed!\n", fold);
+ return(1);
+}
+
+
+removedir(dir)
+{
+ register int i, j;
+ int status;
+
+ if((i = fork()) == 0) {
+ m_update();
+ flush();
+ execl("/bin/rmdir", "rmdir", dir, 0);
+ printf("Can't exec rmdir!!?\n");
+ flush();
+ return(0);
+ }
+ if(i == -1) {
+ printf("Can't fork\n");
+ flush();
+ return(0);
+ }
+ while((j = waita(&status)) != i && j != -1) ;
+ if(status) {
+ printf("Bad exit status (%o) from rmdir.\n", status);
+ flush();
+ /* return(0); */
+ }
+ return(1);
+}
--- /dev/null
+if -r rmf rm rmf
+load rmf subs.a strings.a wait -O libg.a libh.a
+if -r a.out mv a.out rmf
+: fini
+
--- /dev/null
+#include "mh.h"
+#include "iobuf.h"
+
+int hdrflag 1;
+struct msgs *mp;
+struct iobuf fout;
+struct swit switches[] {
+ "all", -3, /* 0 */
+ "ff", 0, /* 1 */
+ "noff", 0, /* 2 */
+ "header", 0, /* 3 */
+ "noheader", 0, /* 4 */
+ "help", 4, /* 5 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *inp, *folder, *maildir, *msgs[100];
+ register int msgnum;
+ register char *cp, *ap;
+ int msgp, ff;
+ struct iobuf in;
+ long now;
+ char *arguments[50], **argp;
+
+ fout.b_fildes = dup(1);
+#ifdef NEWS
+ m_news();
+#endif
+ ff = msgp = folder = 0;
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ inp = ap;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ /* printf("1:\n"); flush(); ##*/
+ /* pr_array("arguments", arguments); flush(); ##*/
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ /* printf("2:\n"); flush(); ##*/
+ /* pr_array("arguments", arguments); flush(); ##*/
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("-%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: printf("\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: ff = 1; continue; /* -ff */
+ case 2: ff = 0; continue; /* -noff */
+ case 3: hdrflag = 0; continue; /* -header */
+ case 4: hdrflag = 1; continue; /* -noheader */
+ case 5: help(concat( inp, " [+folder] [msgs] [switches]", 0),
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ printf("Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ printf("Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ printf("No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!msgp)
+ msgs[msgp++] = "first-last";
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum], EXISTS, EXISTS))
+ goto leave;
+ m_replace("folder",folder);
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
+ if(mp->msgstats[msgnum]&SELECTED) {
+ if(fopen(cp = m_name(msgnum), &in) < 0)
+ printf("--Can't open %s\n", cp);
+ else {
+ if(!hdrflag++) {
+ time(&now);
+ cp = cdate(&now);
+ cp[9] = ' '; cp[15] = 0;
+printf("\
+ Folder %-32s%s\n\n\
+ # Date From Subject [<<Body]\n\n", folder, cp);
+ }
+ scan(&in, msgnum, 0, msgnum == mp->curmsg);
+ close(in.b_fildes);
+ if(fout.b_nextp + 80 >= (&fout) + 1)
+ /* if(msgnum & 1) */
+ flush();
+ }
+ }
+ }
+ if(ff)
+ putchar('\014');
+leave:
+ m_update();
+ flush();
+}
+
--- /dev/null
+if -r scan rm scan
+load -n scan scansub subs.a strings.a wait -O libg.a libh.a
+if -r a.out mv a.out scan
+: fini
+
--- /dev/null
+#include "mh.h"
+#include "iobuf.h"
+
+#define FROM 13 /* Start of From field */
+#define SFROM 16 /* Length of " " */
+#define DATE 5 /* Start of Date field */
+#define SDATE 7 /* Length */
+#define SUBJ 31 /* Start of Subject field */
+#define SSUBJ (79-SUBJ) /* Size of Subject field */
+#define BSUBJ 20 /* Room needed in Sub field to */
+ /* add stuff from the body */
+#define MSGN 0 /* Start of msg name field */
+#define SMSGN 3 /* Length */
+#define FLGS 3 /* Start of flags field */
+#define SFLGS 2 /* Width of flag field */
+
+struct iobuf scnout, fout;
+int errno;
+char scanl[82];
+
+scan(inb, innum, outnum, curflg)
+struct iobuf *inb;
+int outnum;
+{
+
+ char buf[512], name[NAMESZ], tobuf[32], frombuf[32];
+ register char *cp;
+ int state, subsz, first, compnum;
+ static char *myname;
+
+ if(!myname)
+ myname = getlogn(getruid());
+ tobuf[0] = frombuf[0] = 0;
+ errno = first = 0;
+ state = FLD;
+ compnum = 1;
+
+ for(;;) {
+
+ state = m_getfld(state, name, buf, sizeof buf, inb);
+ if(!first++ && state >= FLD && state != FILEEOF) {
+ if(outnum) {
+ if(fcreat((cp = m_name(outnum)),&scnout)<0) {
+ printf("Error creating msg "); flush();
+ perror(cp); exit(-1);
+ }
+ chmod(cp, m_gmprot());
+ }
+ sfill(scanl, sizeof scanl);
+ scanl[sizeof scanl - 1] = 0;
+ subsz = 0;
+ tobuf[0] = 0;
+ }
+
+ switch(state) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ compnum++;
+ if(uleq(name, "from"))
+ frombuf[cpyfrm(buf, frombuf, sizeof frombuf)]=0;
+ else if(uleq(name, "date"))
+ cpydat(buf, scanl+DATE, SDATE);
+ else if(uleq(name, "subject") && scanl[SUBJ] == ' ')
+ subsz = cpy(buf, scanl+SUBJ, SSUBJ);
+ else if(uleq(name, "to") && !tobuf[0])
+ tobuf[cpyfrm(buf, tobuf, sizeof tobuf-1)] = 0;
+ else if(uleq(name, "replied"))
+ cpy("-", scanl+FLGS+1, 1);
+ put(name, buf, &scnout);
+ while(state == FLDPLUS) {
+ state=m_getfld(state,name,buf,sizeof buf,inb);
+ puts(buf, &scnout);
+ }
+ if(state == FLDEOF)
+ goto putscan;
+ continue;
+
+ case BODY:
+ case BODYEOF:
+ compnum = -1;
+ if(buf[0] && subsz < SSUBJ - BSUBJ) {
+ scanl[SUBJ+subsz+1] = '<';
+ scanl[SUBJ+subsz+2] = '<';
+ cpy(buf, scanl+SUBJ+subsz+3, SSUBJ-subsz-3);
+ subsz = SSUBJ;
+ }
+ if(buf[0] && scnout.b_fildes) {
+ putc('\n', &scnout);
+ if(errno) {
+ perror("Write error:");exit(-1);
+ }
+ }
+ puts(buf, &scnout);
+ while(state == BODY) {
+ state=m_getfld(state,name,buf,sizeof buf,inb);
+ puts(buf, &scnout);
+ }
+ if(state == BODYEOF) {
+ putscan: cpymsgn(m_name(innum), scanl+MSGN, SMSGN);
+ if(!frombuf[0] || uleq(frombuf, myname)) {
+ cpy("To:", scanl+FROM, 3);
+ cpy(tobuf, scanl+FROM+3, SFROM-3);
+ } else
+ cpy(frombuf, scanl+FROM, SFROM);
+ if(curflg)
+ cpy("+", scanl+FLGS, SFLGS);
+ trim(scanl);
+ puts(scanl, &fout);
+
+ if(scnout.b_fildes) {
+ fflush(&scnout);
+ if(errno) {
+ perror("Write error");
+ exit(-1);
+ }
+ close(scnout.b_fildes);
+ scnout.b_fildes = 0;
+ }
+ return(1);
+ }
+ break;
+
+ case LENERR:
+ case FMTERR:
+ printf("??Message Format Error ");
+ if(outnum) printf("(Message %d) ", outnum);
+ if(compnum < 0) printf("in the Body.\n");
+ else printf("in Component #%d.\n", compnum);
+ goto badret;
+ default:
+ printf("Getfld returned %d\n", state);
+ badret: if(scnout.b_fildes)
+ fflush(&scnout);
+ return(-1);
+ case FILEEOF:
+ return(0);
+
+ }
+
+ }
+}
+
+
+trim(str)
+{
+ register char *cp;
+
+ cp = str;
+ while(*cp) cp++;
+ while(*--cp == ' ') ;
+ cp++;
+ *cp++ = '\n';
+ *cp++ = 0;
+}
+
+sfill(str, cnt)
+{
+ register char *cp;
+ register int i;
+
+ cp = str; i = cnt;
+ do
+ *cp++ = ' ';
+ while(--i);
+}
+
+
+put(name, buf, iob)
+{
+ register struct iobuf *ip;
+
+ ip = iob;
+ if(ip->b_fildes) {
+ puts(name, iob);
+ putc(':', iob);
+ if(errno) { perror("Write error");exit(-1);}
+ puts(buf, iob);
+ }
+}
+
+
+cpy(sfrom, sto, cnt)
+{
+ register char *from, *to;
+ register int c;
+ int i;
+
+ from = sfrom; to = sto;
+ i = cnt;
+ while(*from == ' ' || *from == '\t' || *from == '\n')
+ from++;
+ while(i--)
+ if(c = *from) {
+ if(c == '\t' || c == ' ' || c == '\n') {
+ *to++ = ' ';
+ do
+ from++;
+ while((c= *from)==' '||c=='\t'||c=='\n');
+ continue;
+ } else
+ *to++ = c;
+ from++;
+ } else
+ break;
+ return(from - sfrom - 1);
+}
+
+
+cpydat(sfrom, sto, cnt)
+{
+ register char *from, *cp;
+ register int c;
+ static int *locvec;
+ long now;
+ char *to;
+
+ if(!locvec) {
+ time(&now);
+ locvec = localtime(&now);
+ }
+ to = sto;
+ for(from = sfrom; (c = *from) < '0' || c > '9'; from++)
+ if(!c)
+ return;
+ c = cnt;
+ for(cp = from; (*cp >= '0' && *cp <= '9') || *cp == ' '; cp++);
+ if(cp = findmonth(cp)) {
+ if(!cp[1]) {
+ *to++ = ' ';
+ c--;
+ }
+ while(*cp && c--)
+ *to++ = *cp++;
+ c--; *to++ = '/';
+ if(from[1] == ' ') {
+ *to++ = ' ';
+ c--;
+ }
+ while(*from >= '0' && *from <= '9' && c--)
+ *to++ = *from++;
+ if(c >= 2) {
+ while(*from < '0' || *from > '9') from++;
+ if((c = atoi(from)) > 1970 && c-1900 < locvec[5]) {
+ *to++ = '/';
+ *to++ = c - 1970 + '0';
+ }
+ }
+ return;
+ }
+ if(from[1] == ' ') {
+ *to++ = ' ';
+ c--;
+ }
+ while(*from && c--)
+ *to++ = *from++;
+}
+
+
+char *fromp, fromdlm, pfromdlm;
+
+cpyfrm(sfrom, sto, cnt)
+{
+ register char *to, *cp;
+ register int c;
+
+ fromdlm = ' ';
+ fromp = sfrom; to = sto;
+ cp = frmtok();
+ do
+ if(c = *cp++)
+ *to++ = c;
+ else
+ break;
+ while(--cnt);
+ for(;;) {
+ if(cnt < 3) break;
+ if(*(cp = frmtok()) == 0) break;
+ if(*cp == '@' || uleq(cp, "at")) {
+ cp = frmtok();
+ if(!uleq(cp, "rand-unix")) {
+ *to++ = '@';
+ cnt--;
+ do
+ if(c = *cp++)
+ *to++ = c;
+ else
+ break;
+ while(--cnt);
+ }
+ } else if(cnt > 4) {
+ cnt--; *to++ = pfromdlm;
+ do
+ if(c = *cp++)
+ *to++ = c;
+ else
+ break;
+ while(--cnt);
+ }
+ }
+ return(to - sto);
+}
+
+
+frmtok()
+{
+ static tokbuf[64];
+ register char *cp;
+ register int c;
+
+ pfromdlm = fromdlm;
+ cp = tokbuf; *cp = 0;
+ while(c = *fromp++) {
+ if(c == '\t')
+ c = ' ';
+ if(c == ' ' && cp == tokbuf)
+ continue;
+ if(c == ' ' || c == '\n' || c == ',')
+ break;
+ *cp++ = c;
+ *cp = 0;
+ if(c == '@' || *fromp == '@' || cp == &tokbuf[63])
+ break;
+ }
+ fromdlm = c;
+ return(tokbuf);
+}
+
+
+/* num specific! */
+
+cpymsgn(msgnam, addr, len)
+char *msgnam, *addr;
+{
+ register char *cp, *sp;
+
+ sp = msgnam;
+ cp = addr + (len - length(sp));
+ while(*sp)
+ *cp++ = *sp++;
+}
+
+char *monthtab[] {
+ "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec",
+};
+
+findmonth(str)
+{
+ register char *cp, *sp;
+ register int i;
+ char buf[4];
+
+ for(cp=str, sp=buf; (*sp++ = *cp++) && sp < &buf[3] && *cp != ' '; );
+ *sp = 0;
+ for(i = 0; i < 12; i++)
+ if(uleq(buf, monthtab[i]))
+ return(locv(0, i+1));
+ return(0);
+}
--- /dev/null
+if -r send-ec rm send-ec
+load -n send subs.a strings-ec.a \
+ libg.a libh.a \
+ mailib.a \
+ mailib.a \
+ | tee errlst
+if -r a.out mv a.out send-ec
--- /dev/null
+#include "mh.h";
+#include "iobuf.h"
+#include "stat.h"
+
+#define DEBUG 1 /* Comment out normally */
+#define TIMJUL 1
+#define TIMSECS 2
+#define TIMREG 3
+
+/* Include a -msgid switch to .mh_defs to cause a
+ * Message-Id component to be added to outgoing mail.
+ */
+
+char *anoyes[], /* Std no/yes gans array */
+ draft[],
+ locname[], /* local host name */
+ sbmitloc[], /* location (pathname) of submit process */
+ sbmitnam[]; /* name of submit process */
+struct swit switches[]
+{
+ "debug", -1, /* 0 */
+ "draft", 0, /* 1 */
+ "format", 0, /* 2 */
+ "noformat", 0, /* 3 */
+ "msgid", 0, /* 4 */
+ "nomsgid", 0, /* 5 */
+ "verbose", 1, /* 6 *//* DBG dhc */
+ "noverbose", 0, /* 7 */
+ "help", 4, /* 8 */
+ 0, 0
+};
+struct iobuf in,
+ pin,
+ pout,
+ fout,
+ fccout;
+int errno;
+int format 0; /* re-formatting is the default */
+int sbmitfd[2];
+int sbchild;
+
+char *logn,
+ *parptr,
+ *nmsg,
+ fccfile[256],
+ sberrline[256];
+
+main (argc, argv)
+char *argv[];
+{
+ int debug;
+ register char *cp;
+ register int state;
+ char *to,
+ *cc,
+ *bcc,
+ *dist_to,
+ *dist_cc,
+ *dist_bcc;
+ char *tolist,
+ *cclist,
+ *adrlist,
+ *sender,
+ *fieldptr,
+ *fcc,
+ *dist_fcc;
+ char msg[128];
+ char name[NAMESZ],
+ field[512];
+ int specfld,
+ dist,
+ fcconly;
+ int from,
+ loc,
+ net,
+ verbose,
+ msgid;
+ char *ap,
+ inp;
+ char *arguments[50],
+ **argp;
+
+ fout.b_fildes = dup (1);
+ msgid = from = loc = net = to = cc = bcc = dist = fcc = dist_fcc =
+ dist_to = dist_cc = dist_bcc = fcconly = debug = 0;
+
+ loc = net = 1; /* DBG during testing of new submit */
+
+ state = FLD;
+ msg[0] = 0;
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ inp = ap;
+ copyip (argv + 1, arguments);
+ argp = arguments;
+ while (cp = *argp++)
+ {
+ if (*cp == '-')
+ switch (smatch (++cp, switches))
+ {
+ case -2:
+ ambigsw (cp, switches);
+ /* ambiguous */
+ leave ("Illegal switch setting: \"%s\"", --cp);
+ /* unknown */
+ case -1:
+ leave ("-%s unknown", cp);
+ case 0:
+ verbose++;
+ debug++;
+ continue; /* -debug */
+ case 1:
+ copy (m_maildir (draft), msg);
+ continue; /* -draft */
+ case 2:
+/* disabled for now format = 1; */
+ continue; /* -format */
+ case 3:
+ format = 0;
+ continue; /* -noformat */
+ case 4:
+ msgid = 1;
+ continue; /* -msgid */
+ case 5:
+ msgid = 0;
+ continue; /* -nomsgid */
+ case 6:
+ loc = 1;
+ net = 1;
+ continue; /* -verbose */
+ case 7:
+ loc = 0;
+ net = 0;
+ continue; /* -noverbose */
+ case 8:
+ help (concat( inp, " [file] [switches]", 0),
+ switches);
+ leave (0);
+ }
+ if (msg[0])
+ leave ("Only one message at a time!");
+ else
+ copy (cp, msg);
+ }
+ if (msg[0] == 0)
+ {
+ copy (m_maildir (draft), msg);
+ if (stat (msg, &field) == -1)
+ {
+ printf ("Draft file: %s doesn't exist.\n", msg);
+ flush ();
+ exit (1);
+ }
+ /* cp = concat ("Use \"", msg, "\"? ", 0);
+ if (!gans (cp, anoyes))
+ exit (0); */
+ }
+ if (fopen (msg, &in) < 0)
+ leave ("Can't open \"%s\" for reading.", msg);
+
+ state = FLD;
+
+ if (!loc && !net)
+ printf ("Message being processed...\n");
+ flush ();
+ for (;;)
+ switch (state = m_getfld (state, name, field, sizeof field, &in))
+ {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if (!dist && field[0] != 'n' && uleq (name, "to"))
+ to = adrlist = add (field, adrlist);
+ else
+ if (!dist && field[0] != 'n' && uleq (name, "cc"))
+ cc = adrlist = add (field, adrlist);
+ else
+ if (!dist && uleq (name, "bcc"))
+ adrlist = add (field, adrlist);
+ else
+ if (!dist && uleq (name, "fcc"))
+ fcc = add (field, fcc);
+ else
+ if (field[0] != 'n' && uleq (name, "distribute-to"))
+ {
+ dist++;
+ /* use presence of field as flag */
+ to = adrlist = add (field, adrlist);
+ }
+ else
+ if (field[0] != 'n' && uleq (name, "distribute-cc"))
+ cc = adrlist = add (field, adrlist);
+ else
+ if (field[0] != 'n' && uleq (name, "distribute-bcc"))
+ adrlist = add (field, adrlist);
+ else
+ if (uleq (name, "distribute-fcc"))
+ dist_fcc = add (field, dist_fcc);
+ else
+ if (uleq (name, "from"))
+ from++;
+
+ if (state != FLDEOF)
+ continue;
+ case BODY:
+ case BODYEOF:
+ goto done;
+
+ default:
+ leave ("getfld returned %d", state);
+ }
+done:
+ if (dist)
+ {
+/* to = dist_to; */
+/* cc = dist_cc; */
+/* bcc = dist_bcc; */
+ fcc = dist_fcc;
+ }
+ if (!(to || cc))
+ if (!fcc)
+ leave ("Message %s has no addresses!!", msg);
+ else
+ fcconly++;
+ /****/ pin.b_fildes = dup (2);
+/**** pout.b_fildes = 3;*/
+
+/* if ((to && parse (to, 'c')) || */
+/* (cc && parse (cc, 'c')) || */
+/* (bcc && parse (bcc, 'c')) */
+/* leavit (); */
+
+/* parptr = adrlist; */
+/* compress (); */
+/* adrlist = parptr; */
+ parptr = 0;
+ if (verbose)
+ {
+ printf ("Address List:\n%s", adrlist);
+ flush ();
+ }
+
+/* if (to && parse (to, 'r', dist ? "Distribute-To: " : "To: ")) */
+/* leave (0); */
+/* tolist = parptr; */
+/* parptr = 0; */
+/* if (cc && parse (cc, 'r', dist ? "Distribute-cc: " : "cc: ")) */
+/* leave (0); */
+/* cclist = parptr; */
+/* parptr = 0; */
+/* */
+/* if (verbose) */
+/* { */
+/* if (tolist) */
+/* printf (tolist); */
+/* if (cclist) */
+/* printf (cclist); */
+/* flush (); */
+/* } */
+ if (fcc)
+ {
+ if (*fcc == ' ')
+ fcc++;
+ for (cp = fcc; *cp && *cp != '\n'; cp++);
+ *cp = 0;
+ if (debug)
+ printf ("fcc: \"%s\"\n", fcc);
+ flush ();
+ if ((fccout.b_fildes = filemsg (fcc)) == -1)
+ leave ("Problem beginning fcc message transfer");
+ }
+
+/* if (parse (field, 'r', dist ? "Distributed-By: " */
+/* : (from ? "Sender: " : "From: "))) */
+/* leave (0); */
+
+ sender = add ((dist) ? "Distributed-By: "
+ : (from) ? "Sender: "
+ : "From: ", sender);
+fieldptr = copy ((logn = getlogn (getruid ())), field);
+fieldptr = copy (" at ", fieldptr);
+fieldptr = copy ( locname, fieldptr);
+copy ( "\n", fieldptr);
+ sender = add (field, sender);
+/* parptr = 0; */
+ seek (in.b_fildes, 0, 0);
+/* *** INVOKE SUBMIT, AT LAST *** */
+ ap = arguments;
+ *ap++ = '-'; /* indicate a switch sequence
+ */
+ /* *ap++ = 'd'; /*DBG have submit output messages */
+ *ap++ = 'm'; /* mail, not screen-notice, yet
+ */
+/* cputc ('s', &pout); */
+/* ******* During initial testing, mail always sent immediately, ****** */
+/* so that users can verify delivery... */
+/* Can't trust new software these days... ****** */
+
+/* if (loc) */
+ *ap++ = 'l'; /* send local mail now */
+ if (net)
+ *ap++ = 'n'; /* send net mail now */
+ if (net || loc)
+ *ap++ = 'w'; /* user will watch deliveries */
+
+/* ******* * * * * * * * * * * * * * * * * * * * * * * * * * * ****** */
+
+ *ap++ = 'r'; /* return messages go to sender
+ */
+ *ap = '\0';
+
+ if (debug)
+ pout.b_fildes = 1; /* Send msg to std output for debugging */
+ else
+ if (fcconly)
+ pout.b_fildes = 0; /* Flush send output if only an fcc */
+ else
+ {
+ if ((sbchild = sbmitinit (arguments, sbmitfd)) == -1)
+ leave ("Unable to invoke submit");
+ pout.b_fildes = sbmitfd[1];
+ }
+
+ puts (adrlist, &pout);
+ puts ("!\n", &pout); /* end the address list */
+ puts2 (sender, &pout);
+ puts2 (dist ? "Distribution-Date: " : "Date: ", &pout);
+ puts2 (cnvtdate (TIMREG), &pout);
+ puts2 ("\n", &pout);
+ if (msgid)
+ {
+ puts2 (dist ? "Distribution-ID: " : "Message-ID: ", &pout);
+ puts2 ("<", &pout);
+ puts2 (cnvtdate (TIMJUL), &pout);
+ puts2 (".", &pout);
+ puts2 (locv (0, getpid ()), &pout);
+ puts2 (" at ", &pout);
+ puts2 (locname, &pout);
+ puts2 ("\n", &pout);
+ }
+ seek (in.b_fildes, 0, 0);
+ in.b_nleft = in.b_nextp = 0;
+ state = FLD;
+ for (;;)
+ switch (state = m_getfld (state, name, field, sizeof field, &in))
+ {
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ specfld = 0;
+ if (format && uleq (name, dist ? "distribute-to" : "to"))
+ {
+ specfld++;
+ if (tolist)
+ puts2 (tolist, &pout);
+ }
+ else
+ if (format && uleq (name, dist ? "distribute-cc" : "cc"))
+ {
+ specfld++;
+ if (cclist)
+ puts2 (cclist, &pout);
+ }
+ else
+ if (uleq (name, dist ? "distribute-bcc" : "bcc") ||
+ uleq (name, dist ? "distributed-by" : "sender") ||
+ uleq (name, dist ? "distribution-date" : "date") ||
+ uleq (name, dist ? "distribution-id" : "message-id") ||
+ uleq (name, dist ? "distribution-fcc" : "fcc"))
+ specfld++;
+ /* Ignore these if present */
+ else
+ {
+ puts2 (name, &pout);
+ puts2 (":", &pout);
+ puts2 (field, &pout);
+ }
+ while (state == FLDPLUS)
+ { /* read rest of field */
+ state = m_getfld (state, name, field, sizeof field, &in);
+ if (specfld)
+ continue;
+/* puts2(name, &pout); puts2(":", &pout); */
+ puts2 (field, &pout);
+ }
+ if (state == FLDEOF)
+ goto endit;
+ continue;
+ case BODY:
+ case BODYEOF:
+ if (field[0])
+ {
+ puts2 ("\n", &pout);
+ puts2 (field, &pout);
+ }
+
+ while (state == BODY)
+ {
+ state = m_getfld (state, name, field, sizeof field, &in);
+ puts2 (field, &pout);
+ }
+ if (state == BODYEOF)
+ goto endit;
+ default:
+ leave ("Error from getfld=%d", state);
+ }
+
+endit:
+ errno = 0;
+ if (pout.b_fildes)
+ if (fflush (&pout) < 0 || errno != 0)
+ leave ("Problem writing data to Submit.");
+ if (fccout.b_fildes)
+ {
+ fflush (&fccout);
+ close (fccout.b_fildes);
+ }
+ if (!debug && !fcconly)
+ {
+/* if ((state = read (2, &field, sizeof field)) != 1 || field[0]) */
+ if (loc || net)
+ {
+ printf ("Delivery being attempted...\n");
+ flush ();
+ }
+ if (sbresp (&sbmitfd) != 0)
+ leave ("Mail submission program ended abnormally");
+ }
+ if (fccout.b_fildes)
+ printf ("Filed: %s:%s\n", fcc, nmsg);
+ if (!debug)
+ {
+ if (!fcconly)
+ {
+ printf ("Message processed.\n");
+/* printf ("Message %s processed.\n", msg);*/
+ flush ();
+ }
+ cp = copy (msg, field);
+ /* for(cp = field; *cp++; ) ; */
+ cp[1] = 0;
+ do
+ *cp = cp[-1];
+ while (--cp >= field && *cp != '/');
+ *++cp = ','; /* New backup convention */
+ unlink (field);
+ if (link (msg, field) == -1 || unlink (msg) == -1)
+ printf ("Can't rename %s to %s\n", msg, field);
+ }
+ m_update ();
+/* childend (); */
+ flush ();
+ exit (0);
+}
+
+leave (form, a1, a2, a3)
+char *form,
+ *a1,
+ *a2,
+ *a3;
+{
+ if (form != 0)
+ {
+ printf (form, a1, a2, a3);
+ putchar ('\n');
+ }
+if (sbchild != 0)
+ kill (sbchild, 9);
+ printf ("[ Message NOT Delivered! ]\n");
+ if (fccout.b_fildes)
+ unlink (fccfile);
+ m_update ();
+ flush ();
+ exit (1);
+}
+
+parse (ptr, type, fldname)
+char *fldname;
+{
+ register int i;
+ register int l;
+ char line[128];
+
+ errno = 0;
+ putc (type, &pout);
+ puts ("\n", &pout);
+ puts (ptr, &pout);
+ if (fflush (&pout) < 0 || errno != 0)
+ leave ("Problem sending data to Submit.");
+ write (pout.b_fildes, "", 1);
+ l = 0;
+
+ while ((i = getl (&pin, line, (sizeof line) - 1)) > 0)
+ {
+ line[i] = 0;
+ if (line[0] == 0)
+ {
+ if (type == 'r')
+ {
+ if (l > 0)
+ parptr = add ("\n", parptr);
+ }
+ return (0);
+ }
+ else
+ if (line[0] == '?')
+ {
+ printf ("Submit returned: %s", line);
+ return (1);
+ }
+ if (type == 'r')
+ {
+ line[--i] = 0;
+ if (l + i > 70)
+ {
+ parptr = add ("\n", parptr);
+ l = 0;
+ }
+ if (l == 0)
+ {
+ parptr = add (fldname, parptr);
+ l =+ length (fldname);
+ }
+ else
+ {
+ parptr = add (", ", parptr);
+ l =+ 2;
+ }
+ parptr = add (line + 1, parptr);
+ l =+ i;
+ }
+ else
+ parptr = add (line, parptr);
+ }
+ printf ("Error from Submit.\n");
+ return (1);
+}
+
+cnvtdate (flag)
+int flag; /* date format option value */
+{
+ static char datbuf[128];
+ extern int daylight;
+ int tvec[2];
+ long int seconds;
+ register int
+ *i;
+ register char
+ *p,
+ *t;
+
+ time (tvec);
+ i = localtime (tvec);
+ t = ctime (tvec);
+ p = datbuf;
+
+ switch (flag)
+ {
+ case TIMJUL: /* Julian-oriented for msg-ids */
+ for (itoa (i[5], p); *p; p++);
+ *p++ = '.';
+ for (itoa (i[7], p); *p; p++);
+ *p++ = '.';
+ seconds = i[2];
+ seconds = i[0] + (i[1] * 60) + (seconds * 3600);
+ litoa (seconds, p); /* seconds since midnight */
+ break;
+ case TIMREG: /* RFC 733 standard time string */
+ default: /* "Sat, 21 Jan 76 14:30-PDT" */
+ *p++ = t[0];
+ *p++ = t[1];
+ *p++ = t[2];
+ *p++ = ',';
+ *p++ = ' ';
+ *p++ = t[8]; /* day of month */
+ *p++ = t[9];
+ *p++ = ' ';
+ *p++ = t[4]; /* month abbreviation eg: "JAN" */
+ *p++ = t[5];
+ *p++ = t[6];
+ *p++ = ' ';
+ *p++ = t[22]; /* year eg: "76" */
+ *p++ = t[23];
+ *p++ = ' ';
+ *p++ = t[11]; /* hours & minutes eg: "14:30" */
+ *p++ = t[12];
+ *p++ = ':';
+ *p++ = t[14];
+ *p++ = t[15];
+ *p++ = '-';
+ *p++ = 'P'; /* time zone eg: "PDT" */
+ *p++ = (i[8]) ? 'D' : 'S';
+ *p++ = 'T';
+ *p++ = '\000';
+ }
+ free (i);
+ free (t);
+ return (datbuf);
+}
+
+getl (iob, buf, size)
+{
+ register char *cp;
+ register int cnt,
+ c;
+
+ for (cp = buf, cnt = size; (c = getc (iob)) >= 0;)
+ {
+ *cp++ = c;
+ --cnt;
+ switch (c)
+ {
+ case '\0':
+ case '\n':
+ break;
+ default:
+ continue;
+ }
+ break;
+ }
+ return (size - cnt);
+}
+
+compress ()
+{
+ register char *f1,
+ *f2,
+ *f3;
+
+#ifdef DEBUG
+ printf ("compress:\n%s-----\n", parptr);
+#endif
+ for (f1 = parptr; *f1;)
+ {
+ for (f2 = f1; *f2++ != '\n';);
+ while (*f2)
+ {
+ if (eqqq (f1, f2))
+ {
+ for (f3 = f2; *f3++ != '\n';);
+ copy (f3, f2);
+ }
+ else
+ while (*f2++ != '\n');
+ }
+ while (*f1++ != '\n');
+ }
+}
+
+eqqq (s1, s2)
+{
+ register char *c1,
+ *c2;
+
+ c1 = s1;
+ c2 = s2;
+ while (*c1 != '\n' && *c2 != '\n')
+ if (*c1++ != *c2++)
+ return (0);
+ return (*c1 == *c2);
+}
+filemsg (folder)
+char *folder;
+{
+ register int i;
+ register char *fp;
+ struct inode stbuf;
+ struct msgs *mp;
+
+ fp = m_maildir (folder);
+ if (stat (fp, &stbuf) < 0)
+ {
+/* nmsg = concat ("Create folder \"",
+ fp, "\"? ", 0);
+ if (!gans (nmsg, anoyes))
+ return (-1); */
+ if (!makedir (fp))
+ {
+ printf ("Can't create folder.\n");
+ return (-1);
+ }
+ }
+ if (chdir (fp) < 0)
+ {
+ perror (concat ("Can't chdir to ", fp, 0));
+ return (-1);
+ }
+ if (!(mp = m_gmsg ()))
+ {
+ printf ("Can't read folder %s\n", folder);
+ return (-1);
+ }
+ nmsg = m_name (mp -> hghmsg + 1);
+ copy (nmsg, copy ("/", copy (m_maildir (fp), fccfile)));
+ if ((i = creat (fccfile, m_gmprot ())) == -1)
+ printf ("Can't create %s\n", fccfile);
+ return (i);
+}
+
+puts2 (str, iob)
+{
+ puts (str, &fccout);
+ errno = 0;
+ puts (str, iob);
+ if (fflush (iob) < 0 || errno != 0)
+ leave ("Problem writing out data");
+}
+/* subroutines to interface to submit */
+
+#define CLOSEFD -1 /* if equals fdarray[i], close (i); */
+#define PUREXEC 0 /* simply exec over current process */
+#define FRKEXEC 1 /* run it in lower process */
+#define SPNEXEC 2 /* separate new process from old */
+#define FRKWAIT 1 /* wait for FRKEXEC to complete */
+#define FRKPIGO 2 /* Parent's signals off during FRKWAIT */
+#define FRKCIGO 4 /* Childs signals off before execl */
+/*#define EXECR 8 ** Use execr, instead of execv */
+#define HIGHFD 16
+#define NUMTRY 30
+
+struct pstruct
+{
+ int prd;
+ int pwrt;
+};
+int highfd
+{
+ HIGHFD
+};
+int regfdary[]
+{
+ 0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+sbmitinit (args, ioary)
+char *args;
+int *ioary;
+{
+
+ struct pstruct sbpout;
+ int sbmitid;
+ char linebuf[256];
+ char *p;
+
+ if (pipe (&sbpout) == -1)
+ return (-1);
+ regfdary[0] = sbpout.prd;
+ regfdary[1] = fout.b_fildes;
+
+ if ((sbmitid = newpgml (FRKEXEC, 0, regfdary,
+ sbmitloc, sbmitnam, args, 0)) == -1)
+ {
+flush ();
+ close (sbpout.prd);
+ close (sbpout.pwrt);
+ return (-1);
+ }
+
+dbglog ("Ready to close");
+ close (sbpout.prd);
+ ioary[1] = sbpout.pwrt;
+ return (sbmitid);
+}
+
+#ifdef COMMNET
+sbmitadr (name, ioary)
+char *name;
+int *ioary;
+{
+ int tmp;
+ char linebuf[256];
+ char *from,
+ *to;
+
+ for (from = name, to = linebuf; *to = *from++; to++);
+ for (from = "\n"; *to++ = *from++;);
+ tmp = to - &linebuf;
+
+ if (write (ioary[1], linebuf, tmp) == -1)
+ return (-1);
+
+ return (sbresp (ioary));
+}
+#endif
+
+sbresp (ioary)
+int *ioary;
+{
+ return (childend ());
+}
+
+newpgml (proctyp, pgmflags, fdarray, pgm, pgmparm)
+int proctyp,
+ pgmflags,
+ fdarray[];
+char *pgm,
+ *pgmparm;
+{
+ int retval;
+ char *parmptr;
+ /* printf ("newpgml: calling newpgmv\n"); */
+ parmptr = &pgmparm;
+ retval = newpgmv (proctyp, pgmflags, fdarray, pgm, parmptr);
+ return (retval);
+}
+
+newpgmv (proctyp, pgmflags, fdarray, pgm, pgmparm)
+int proctyp,
+ pgmflags,
+ fdarray[];
+char *pgm,
+ *pgmparm[];
+{
+ register int tmp;
+ int tmp2;
+ int childid;
+ int tried;
+ int osig[3];
+
+ if (proctyp != PUREXEC)
+ {
+ /* printf ("This is a forking call.\n"); */
+ for (tried = NUMTRY; (childid = fork ()) == -1 && tried--; sleep (1));
+ if (childid == -1)
+ return (-1);
+ /* printf ("Successful fork\n"); */
+ if (childid != 0)
+ { /* parent process */
+ if (pgmflags & FRKPIGO)
+ { /* disable parent signals */
+ /* printf ("Parent to be
+ non-interruptible\n"); */
+ osig[0] = signal (1, 1);
+ osig[1] = signal (2, 1);
+ osig[2] = signal (3, 1);
+ }
+ if ((proctyp == FRKEXEC) && (pgmflags & FRKWAIT))
+ {
+ /* printf ("Parent is to wait\n"); */
+ while ((tmp = wait (&tmp2)) != childid && tmp != -1);
+ /* printf ("Parent done waiting\n"); */
+ if (pgmflags & FRKPIGO)
+ {
+ signal (1, osig[0]);
+ signal (2, osig[1]);
+ signal (3, osig[2]);
+ }
+ return (tmp2);
+ }
+ return (childid);
+ }
+ if (proctyp == SPNEXEC)
+ { /* want it to be a spawn */
+ /* printf ("This is a spawn\n"); */
+ for (tried = NUMTRY; (tmp = fork ()) < 0 && tried--;
+ sleep (1));
+ if (tmp != 0) /* split the grandparent from the */
+ exit (tmp < 0 ? -2 : 0);
+ /* grandchild: kill middle proc */
+ }
+ }
+ if (fdarray)
+ { /* re-align fd array list */
+ fout.b_fildes = fdarray[1];
+ for (tmp = 0; tmp < highfd; tmp++)
+ { /* first do the re-positions */
+ if (fdarray[tmp] != CLOSEFD && fdarray[tmp] != tmp)
+ {
+ dbglog ("Closing %2d\n", tmp);
+flush ();
+ close (tmp);
+ while ((tmp2 = dup (fdarray[tmp])) < tmp && tmp2 != -1);
+ dbglog ("Last dup'd %d into %d\n", fdarray[tmp], tmp2);
+flush ();
+ /* did we get right fd? */
+ }
+ }
+ for (tmp = 0; tmp < highfd; tmp++)
+ if (fdarray[tmp] == CLOSEFD)
+ {
+ dbglog ("Closing %2d\n", tmp);
+flush ();
+ close (tmp); /* get rid of unwanted ones */
+ }
+ }
+fout.b_fildes = 1;
+
+ if (pgmflags & FRKCIGO)
+ {
+ /* printf ("Child's interrupts to be
+ disabled\n"); */
+ signal (1, 1);
+ signal (2, 1);
+ signal (3, 1);
+ }
+
+ /* printf ("Execing %s\n", pgm); */
+/* if (pgmflags & EXECR) */
+/* execr (pgm, pgmparm); */
+/* else */
+ execv (pgm, pgmparm);
+ /* printf ("Exec not successful\n"); */
+ if (proctyp == PUREXEC)
+ return (-1);
+ fout.b_fildes = 1;
+ printf ("Unable to exec \"%s\"\n", pgm);
+ flush ();
+ for (tmp = 0; tmp < 20 && pgmparm[tmp][0] != 0 ; tmp++)
+ {
+ printf ("Parm %d = \"%s\"\n", tmp, pgmparm[tmp]); flush ();
+ }
+ exit (-3);
+}
+
+childend ()
+{
+ int tmp,
+ tmp2;
+
+ /* close (sbmitfd[0]); */
+ close (sbmitfd[1]);
+ while ((tmp = wait (&tmp2)) != sbchild && tmp != -1);
+ return (tmp2 >> 8);
+}
+dbglog (str)
+{
+return;
+printf(str);
+}
--- /dev/null
+if -r send rm send
+load -n send subs.a strings.a \
+ libg.a libh.a \
+ mailib.a \
+ mailib.a \
+ | tee errlst
+if -r a.out mv a.out send
--- /dev/null
+/*
+ * struct for stty/gtty system call
+ *
+ *
+ * sg_ispd = input speed
+ * sg_ospd = output speed
+ *
+ * sg_erase = character erase
+ * sg_kill = line kill
+ *
+.* sg_flag = flags
+ */
+
+struct sgtty {
+ char sg_ispd, sg_ospd;
+ char sg_erase, sg_kill;
+ int sg_flag;
+};
+
+#define NODELAY 01
+#define XTABS 02
+#define LCASE 04
+#define ECHO 010
+#define CRMOD 020
+#define RAW 040
+#define ALTESC 0400
+#define NTDELAY 010000
+#define PPL 020000
+#define TECO 040000
+#define NOSLASH 0100000
+
+#define CQUIT 002 /* control - b */
+#define CINTR 003 /* control - c */
+#define CEOT 004 /* control - d */
+#define CKILL 025 /* control - u */
+#define CERASE 0177 /* rubout */
+#define CRETYPE 022 /* control - r */
+#define CALTNEW 033 /* new style alt mode */
--- /dev/null
+#include "mh.h"
+#include "signals.h"
+
+char draft[], /* Std strings */
+ showproc[],
+ prproc[];
+
+int vecp, *vec[MAXARGS], fout;
+struct msgs *mp;
+struct swit switches[] {
+ "all", -3, /* 0 */
+ "draft", 2, /* 1 */
+ "pr", 2, /* 2 */
+ "nopr", 2, /* 3 */
+ "help", 4, /* 4 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *inp, *folder, *maildir, *msgs[100], *proc;
+ register int msgnum;
+ register char *cp, *ap;
+ int msgp, all, drft, pr, infrk, status, frk;
+ char *arguments[50], **argp;
+
+ fout = dup(1);
+#ifdef NEWS
+ m_news();
+#endif
+ pr = all = msgp = folder = 0;
+ vecp = 1;
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ inp = ap;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:vec[vecp++] = --cp; continue;
+ /* -all */
+ case 0: printf("\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: drft = 1; continue; /* -draft */
+ case 2: pr = 1; continue; /* -pr */
+ case 3: pr = 0; vecp = 1; continue;/* -nopr */
+ case 4: /* -help */
+ help(concat( inp, " [+folder] [msgs] [switches] [switches for l or pr (see /doc) ]", 0),
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ printf("Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if (!pr) {
+ vec[vecp++] = "-t"; /* no header */
+ }
+ if(drft)
+ maildir = m_maildir("");
+ else {
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ }
+ if(chdir(maildir) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(maildir);
+ goto leave;
+ }
+ if(!pr) {
+ vec[0] = "mh-type";
+ proc = showproc;
+ } else {
+ vec[0] = "mh-pr";
+ proc = prproc;
+ }
+ if(drft) {
+ vec[vecp++] = draft;
+ vec[vecp] = 0;
+ m_update();
+ flush();
+ execv( proc, vec);
+ perror("Can't exec type");
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ printf("Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ printf("No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(msgp)
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum], UNDELETED, UNDELETED))
+ goto leave;
+ if(mp->numsel == 0) {
+ printf("No undeleted messages specified.\n");
+ goto leave;
+ }
+ vec[vecp+1]=0;
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED) {
+ vec[vecp] = getcpy(m_name(msgnum));
+ printf("\nMessage %s\n", m_name(msgnum));
+ flush();
+ if((infrk = fork())==0) { /* inferior */
+ execv( proc, vec);
+ exit(1); /* execute didnt work */
+ } else if(infrk== -1) {
+ printf("No forks\n");
+ break;
+ } else
+ while((frk=waita(&status)) != -1 && frk != infrk);
+ if(status) {
+ printf("[command aborted]\n");
+ break;
+ }
+ }
+ m_replace("folder", folder);
+ if(mp->hghsel != mp->curmsg)
+ m_setcur(mp->hghsel);
+ leave:
+ m_update();
+ flush();
+}
--- /dev/null
+if -r show rm show
+load -n show subs.a strings.a wait -O libg.a libh.a
+if -r a.out mv a.out show
+: fini
+
--- /dev/null
+#define NSIG 20 /* # of Bell signals */
+#define NHSIG 1 /* # of Harvard signals */
+#define SIGHUP 1 /* hangup */
+#define SIGINT 2 /* interrupt (^C) */
+#define SIGQIT 3 /* quit (^B) */
+#define SIGINS 4 /* illegal instruction */
+#define SIGTRC 5 /* trace or breakpoint */
+#define SIGIOT 6 /* iot */
+#define SIGEMT 7 /* emt */
+#define SIGFPT 8 /* floating exception */
+#define SIGKIL 9 /* kill */
+#define SIGBUS 10 /* bus error */
+#define SIGSEG 11 /* segmentation violation */
+#define SIGSYS 12 /* sys */
+#define SIGPIPE 13 /* end of pipe */
+#define SIGALA 14 /* alarm clock */
+
+/* harvard signals */
+
+#define SIGBRK (-1) /* break (break) */
--- /dev/null
+#
+/*
+ * Inode structure as returned by
+ * system call stat.
+ */
+struct inode
+{
+ int i_dev;
+ int i_number;
+ int i_mode;
+ char i_nlink;
+ char i_uid;
+ char i_gid;
+ char i_size0;
+ char *i_size1;
+ int i_addr[8];
+ long i_atime;
+ long i_mtime;
+};
+/* advisable to use this define to generate owner as 16-bit num */
+#define IOWNER(i_n_buf) (((i_n_buf).i_uid<<8)|(i_n_buf).i_gid&0377)
+/* modes */
+#define IALLOC 0100000
+#define IFMT 060000
+#define IFDIR 040000
+#define IFCHR 020000
+#define IFBLK 060000
+#define ILARG 010000
+#define ISUID 04000
+#define ISGID 02000
+#define ISVTX 01000
+#define IREAD 0400
+#define IWRITE 0200
+#define IEXEC 0100
+
+struct { char d_minor, d_major; };
--- /dev/null
+char *anoyes[] {
+ "no", 0,
+ "yes", 0,
+ 0,
+};
+char components[] "components";
+char current[] "cur";
+char defalt[] "inbox";
+char distcomps[] "distcomps";
+char draft[] "draft";
+char foldprot[] "0751";
+/*char installproc[] "/rnd/borden/bin/install-defs";*/
+/*char installproc[] "/rnd/phyl/bin/install-defs";*/
+char installproc[] "/m/mh/install-defs";
+char listname[] "select";
+/*char lsproc[] "/bin/nls";*/
+char lsproc[] "bin/ls";
+char mailbox[] "/.mail";
+char mh_defs[] "/.mh_defs";
+char mhnews[] "/m/mh/news";
+char msgprot[] "0664";
+/*char prproc[] "/rnd/borden/bin/ppr";*/
+char prproc[] "/bin/pr";
+/* char scanproc[] "/rnd/borden/bin/mh.2/scan"; */
+/* char scanproc[] "/fsd/phyl/mh/scan"; */
+/*char scanproc[] "/rnd/phyl/bin/mh/scan";*/
+char scanproc[] "/m/mh/nullproc";
+/*char showproc[] "/rnd/borden/bin/type";*/
+char showproc[] "/m/mh/pr";
+char prmtproc[] "/m/mh/prompter";
+/* char sndproc[] "/rnd/borden/bin/mh.2/send"; */
+/* char sndproc[] "/fsd/phyl/mh/send"; */
+/*char sndproc[] "/rnd/phyl/bin/mh/send";*/
+char sndproc[] "/m/mh/send";
+char sbmitloc[] "/m/mmdf/submit-ec";
+char sbmitnam[] "submit";
+/*char stdcomps[] "/rnd/borden/etc/components";*/
+char stdcomps[] "/m/mh/components";
+/*char stddcomps[] "/rnd/borden/etc/distcomps";*/
+char stddcomps[] "/m/mh/distcomps";
+char sysed[] "/bin/ed";
+char locname[] "GC"; /* local host name */
--- /dev/null
+char *anoyes[] {
+ "no", 0,
+ "yes", 0,
+ 0,
+};
+char components[] "components";
+char current[] "cur";
+char defalt[] "inbox";
+char distcomps[] "distcomps";
+char draft[] "draft";
+char foldprot[] "0751";
+/*char installproc[] "/rnd/borden/bin/install-defs";*/
+/*char installproc[] "/rnd/phyl/bin/install-defs";*/
+char installproc[] "/m/mh/install-defs";
+char listname[] "select";
+/*char lsproc[] "/bin/nls";*/
+char lsproc[] "bin/ls";
+char mailbox[] "/.mail";
+char mh_defs[] "/.mh_defs";
+char mhnews[] "/m/mh/news";
+char msgprot[] "0664";
+/*char prproc[] "/rnd/borden/bin/ppr";*/
+char prproc[] "/bin/pr";
+/* char scanproc[] "/rnd/borden/bin/mh.2/scan"; */
+/* char scanproc[] "/fsd/phyl/mh/scan"; */
+/*char scanproc[] "/rnd/phyl/bin/mh/scan";*/
+char scanproc[] "/m/mh/nullproc";
+/*char showproc[] "/rnd/borden/bin/type";*/
+char showproc[] "/m/mh/pr";
+char prmtproc[] "/m/mh/prompter";
+/* char sndproc[] "/rnd/borden/bin/mh.2/send"; */
+/* char sndproc[] "/fsd/phyl/mh/send"; */
+/*char sndproc[] "/rnd/phyl/bin/mh/send";*/
+char sndproc[] "/m/mh/send";
+char sbmitloc[] "/m/mmdf/submit";
+char sbmitnam[] "submit";
+/*char stdcomps[] "/rnd/borden/etc/components";*/
+char stdcomps[] "/m/mh/components";
+/*char stddcomps[] "/rnd/borden/etc/distcomps";*/
+char stddcomps[] "/m/mh/distcomps";
+char sysed[] "/bin/ed";
+char locname[] "SRI-TSC"; /* local host name */
--- /dev/null
+cc -c strings.c
+if -r strings.o mv strings.o strings.a
--- /dev/null
+ambigsw(arg, swp)
+char *arg;
+{
+ printf("%s: ", invo_name());
+ printf("-%s ambiguous. It matches \n", arg);
+ printsw(arg, swp);
+}
+
--- /dev/null
+atoi(str)
+{
+ register char *cp;
+ register int i;
+
+ i = 0;
+ cp = str;
+ while(*cp >= '0' && *cp <= '9') {
+ i =* 10;
+ i =+ *cp++ - '0';
+ }
+ return(i);
+}
--- /dev/null
+atooi(str)
+{
+ register char *cp;
+ register int i, base;
+
+ base = 10;
+ i = 0;
+ cp = str;
+ if(*cp == '0')
+ base = 8;
+ while(*cp >= '0' && *cp <= '9') {
+ i =* base;
+ i =+ *cp++ - '0';
+ }
+ return(i);
+}
--- /dev/null
+/* Conditional free -- perform a free call if the address passed
+ * is in free storage; else NOP
+ */
+
+
+cfree(addr)
+char *addr;
+{
+ extern end;
+
+ if(addr >= &end) free(addr);
+}
--- /dev/null
+concat(args)
+int args[];
+{
+ register char **a;
+ register char *cp;
+ register int len;
+
+ len = 1;
+ for(a = &args; *a; )
+ len =+ length(*a++);
+ len = cp = alloc(len);
+ for(a = &args; *a; )
+ cp = copy(*a++, cp);
+ return(len);
+}
--- /dev/null
+copyip(ipfrom, ipto)
+int *ipfrom, *ipto;
+{
+ register int *ipf, *ipt;
+
+ ipf=ipfrom; ipt=ipto;
+ while((*ipt = *ipf) && *ipf++ != -1)
+ ipt++;
+ *ipt = 0;
+ return(ipt);
+}
+
--- /dev/null
+#include "/rnd/borden/h/iobuf.h"
+
+cputc(chr, iob)
+{
+ register struct iobuf *ip;
+ extern int errno;
+
+ ip = iob;
+
+ errno = 0;
+ if(ip->b_fildes) {
+ putc(chr, ip);
+ if(errno) { perror("Write error"); exit(-1); }
+ }
+}
--- /dev/null
+#include "mh.h"
+
+gans(prompt, ansp)
+struct swit *ansp;
+{
+ char ansbuf[32];
+ register char *cp;
+ register int i;
+ struct swit *ap;
+
+ for(;;) {
+ printf("%s", prompt);
+ flush();
+ cp = ansbuf;
+ while((i = getchar()) != '\n') {
+ if(i == 0)
+ return(0);
+ if(cp < &ansbuf[31]) {
+ if(i >= 'A' && i <= 'Z')
+ i =+ 'a'-'A';
+ *cp++ = i;
+ }
+ }
+ *cp = 0;
+ if(ansbuf[0] == '?' || cp == ansbuf) {
+ printf("Options are:\n");
+ for(ap = ansp; ap->sw; ap++)
+ printf(" %s\n", ap->sw);
+ continue;
+ }
+ if((i = smatch(ansbuf, ansp)) < 0) {
+ printf("%s: %s.\n", ansbuf, i == -1? "unknown":"ambiguous");
+ continue;
+ }
+ return(i);
+ }
+}
--- /dev/null
+getchar()
+{
+ int c;
+
+ c = 0;
+ if(read(0, &c, 1) != 1)
+ return(0);
+ return(c);
+}
--- /dev/null
+getcpy(str)
+{
+ register char *cp;
+
+ cp = alloc(length(str) + 1);
+ copy(str, cp);
+ return(cp);
+}
--- /dev/null
+#include "mh.h"
+
+help(str, swp)
+char *str;
+{
+ printf("syntax: %s\n", str);
+ printf(" switches are:\n");
+ printsw(ALL, swp);
+}
--- /dev/null
+invo_name()
+{
+ register int *ip;
+
+ ip = 0;
+
+ while(*--ip != -1)
+ ;
+ while(*--ip < 0)
+ ;
+ return(ip[2]);
+}
--- /dev/null
+#include "/m/mh/mh.h"
+int convdir;
+struct msgs *mp;
+char *delimp;
+
+m_convert(name, mask, match)
+{
+ register char *cp;
+ register int first, last;
+ int found, group, range, err;
+ char *bp;
+
+ found = group = 0;
+ mask =| EXISTS; /* dont fool with nonexistent msgs */
+ match =| EXISTS; /* ditto */
+ cp = name;
+ if(equal(cp, "all"))
+ cp = "first-last";
+ if(equal(cp, "del")) {
+ cp = "first-last";
+ mask =| DELETED;
+ match =| DELETED;
+ }
+ if(equal(cp, "undel")) {
+ cp = "first-last";
+ mask =| UNDELETED;
+ match =| UNDELETED;
+ }
+ if((err = first = m_conv(cp)) <= 0)
+ goto badbad;
+ if(*(cp = delimp) && *cp != '-' && *cp != ':') {
+ baddel: printf("Illegal argument delimiter: \"%c\"\n", *delimp);
+ return(0);
+ }
+ if(*cp == '-') {
+ group++; cp++;
+ if((err = last = m_conv(cp)) <= 0) {
+ badbad: if(err == -1)
+ printf("No %s message\n", cp);
+ else
+ badlist: printf("Bad message list \"%s\".\n", name);
+ return(0);
+ }
+ if(last < first) goto badlist;
+ if(*delimp) goto baddel;
+ if(first > mp->hghmsg || last < mp->lowmsg) {
+ rangerr: printf("No messages in range \"%s\".\n", name);
+ return(0);
+ }
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ } else if(*cp == ':') {
+ cp++;
+ if(*cp == '-') {
+ convdir = -1;
+ cp++;
+ } else if(*cp == '+') {
+ convdir = 1;
+ cp++;
+ }
+ if((range = atoi(bp = cp)) == 0)
+ goto badlist;
+ while(*bp >= '0' && *bp <= '9') bp++;
+ if(*bp)
+ goto baddel;
+ if((convdir > 0 && first > mp->hghmsg) ||
+ (convdir < 0 && first < mp->lowmsg))
+ goto rangerr;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ if(first > mp->hghmsg)
+ first = mp->hghmsg;
+ for(last = first; last >= mp->lowmsg && last <= mp->hghmsg;
+ last =+ convdir)
+ if((mp->msgstats[last]&mask)==match)
+ if(--range <= 0)
+ break;
+ if(last < mp->lowmsg)
+ last = mp->lowmsg;
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(last < first) {
+ range = last; last = first; first = range;
+ }
+ } else {
+ if(first > mp->hghmsg || first < mp->lowmsg ||
+ !(mp->msgstats[first]&EXISTS)) {
+ printf("Message %d doesn't exist.\n", first);
+ return(0);
+ }
+ last = first;
+ }
+ while(first <= last) {
+ if((mp->msgstats[first]&mask)==match) {
+ if(!(mp->msgstats[first]&SELECTED)) {
+ mp->numsel++;
+ mp->msgstats[first] =| SELECTED;
+ if(first < mp->lowsel)
+ mp->lowsel = first;
+ if(first > mp->hghsel)
+ mp->hghsel = first;
+ }
+ found++;
+ }
+ first++;
+ }
+ /* if(!found)
+ goto rangerr; */
+ return(1);
+}
+
+m_conv(str)
+{
+ register char *cp, *bp;
+ register int i;
+ char buf[16];
+
+ convdir = 1;
+ cp = bp = str;
+ if(*cp >= '0' && *cp <= '9') {
+ while(*bp >= '0' && *bp <= '9') bp++;
+ delimp = bp;
+ return(atoi(cp));
+ }
+ bp = buf;
+ while((*cp >= 'a' && *cp <= 'z') || *cp == '.')
+ *bp++ = *cp++;
+ *bp++ = 0;
+ delimp = cp;
+ if(equal(buf, "first"))
+ return(mp->lowmsg);
+ else if(equal(buf, "last")) {
+ convdir = -1;
+ return(mp->hghmsg);
+ } else if(equal(buf, "cur") || equal(buf, "."))
+ return(mp->curmsg);
+ else if(equal(buf, "prev")) {
+ convdir = -1;
+ for(i = (mp->curmsg<=mp->hghmsg)? mp->curmsg-1: mp->hghmsg;
+ i >= mp->lowmsg; i--) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1); /* non-existent message */
+ } else if(equal(buf, "next")) {
+ for(i = (mp->curmsg>=mp->lowmsg)? mp->curmsg+1: mp->lowmsg;
+ i <= mp->hghmsg; i++) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1);
+ } else
+ return(0); /* bad message list */
+}
--- /dev/null
+#include "mh.h"
+
+int convdir;
+struct msgs *mp;
+char *delimp;
+
+m_convert(name)
+{
+ register char *cp;
+ register int first, last;
+ int found, group, range;
+ char *bp;
+
+ found = group = 0;
+ if(equal((cp = name), "all"))
+ cp = "first-last";
+ if((first = m_conv(cp)) == -1)
+ goto badbad;
+ printf("first=%s\n",first); flush(); /*##*/
+ if(*(cp = delimp) && *cp != '-' && *cp != ':') {
+ baddel: printf("Illegal argument delimiter: \"%c\"\n", *delimp);
+ return(0);
+ }
+ if(*cp == '-') {
+ group++; cp++;
+ if((last = m_conv(cp)) == -1) {
+ badbad: if(*cp > '9')
+ printf("No %s message\n", cp);
+ else
+ badlist: printf("Bad message list \"%s\".\n", name);
+ return(0);
+ }
+ if(last < first) goto badlist;
+ if(*delimp) goto baddel;
+ if(first > mp->hghmsg || last < mp->lowmsg) {
+ rangerr: printf("No messages in range \"%s\".\n", name);
+ return(0);
+ }
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ } else if(*cp == ':') {
+ cp++;
+ if(*cp == '-') {
+ convdir = -1;
+ cp++;
+ } else if(*cp == '+') {
+ convdir = 1;
+ cp++;
+ }
+ if((range = atoi(bp = cp)) == 0)
+ goto badlist;
+ while(*bp >= '0' && *bp <= '9') bp++;
+ if(*bp)
+ goto baddel;
+ if((convdir > 0 && first > mp->hghmsg) ||
+ (convdir < 0 && first < mp->lowmsg))
+ goto rangerr;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ if(first > mp->hghmsg)
+ first = mp->hghmsg;
+ for(last = first; last >= mp->lowmsg && last <= mp->hghmsg;
+ last =+ convdir)
+ if(mp->msgstats[last]&EXISTS)
+ if(--range <= 0)
+ break;
+ if(last < mp->lowmsg)
+ last = mp->lowmsg;
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(last < first) {
+ range = last; last = first; first = range;
+ }
+ } else {
+ if(first > mp->hghmsg || first < mp->lowmsg ||
+ !(mp->msgstats[first]&EXISTS)) {
+ printf("Message %d doesn't exist.\n", first);
+ return(0);
+ }
+ last = first;
+ }
+ while(first <= last) {
+ if(mp->msgstats[first]&EXISTS) {
+ if(!(mp->msgstats[first]&SELECTED)) {
+ mp->numsel++;
+ mp->msgstats[first] =| SELECTED;
+ if(first < mp->lowsel)
+ mp->lowsel = first;
+ if(first > mp->hghsel)
+ mp->hghsel = first;
+ }
+ found++;
+ }
+ first++;
+ }
+ if(!found)
+ goto rangerr;
+ return(1);
+}
+
+m_conv(str)
+{
+ register char *cp, *bp;
+ register int i;
+ char buf[16];
+
+ convdir = 1;
+ cp = bp = str;
+ if(*cp >= '0' && *cp <= '9') {
+ while(*bp >= '0' && *bp <= '9') bp++;
+ delimp = bp;
+ return(atoi(cp));
+ }
+ bp = buf;
+ while((*cp >= 'a' && *cp <= 'z') || *cp == '.')
+ *bp++ = *cp++;
+ *bp++ = 0;
+ delimp = cp;
+ if(equal(buf, "first"))
+ return(mp->lowmsg);
+ else if(equal(buf, "last")) {
+ convdir = -1;
+ return(mp->hghmsg);
+ } else if(equal(buf, "cur") || equal(buf, "."))
+ return(mp->curmsg);
+ else if(equal(buf, "prev")) {
+ convdir = -1;
+ for(i = (mp->curmsg<=mp->hghmsg)? mp->curmsg-1: mp->hghmsg;
+ i >= mp->lowmsg; i--) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ } else if(equal(buf, "next"))
+ for(i = (mp->curmsg>=mp->lowmsg)? mp->curmsg+1: mp->lowmsg;
+ i <= mp->hghmsg; i++) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1);
+}
--- /dev/null
+#include "mh.h"
+
+int convdir;
+struct msgs *mp;
+char *delimp;
+
+m_convert(name)
+{
+ register char *cp;
+ register int first, last;
+ int found, group, range;
+ char *bp;
+
+ found = group = 0;
+ if(equal((cp = name), "all"))
+ cp = "first-last";
+ if((first = m_conv(cp)) == -1)
+ goto badbad;
+ if(*(cp = delimp) && *cp != '-' && *cp != ':') {
+ baddel: printf("Illegal argument delimiter: \"%c\"\n", *delimp);
+ return(0);
+ }
+ if(*cp == '-') {
+ group++; cp++;
+ if((last = m_conv(cp)) == -1 || last < first ) {
+ badbad: if(
+
+ printf("Bad message list \"%s\".\n", name);
+ return(0);
+ }
+ if(*delimp) goto baddel;
+ if(first > mp->hghmsg || last < mp->lowmsg) {
+ rangerr: printf("No messages in range \"%s\".\n", name);
+ return(0);
+ }
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ } else if(*cp == ':') {
+ cp++;
+ if(*cp == '-') {
+ convdir = -1;
+ cp++;
+ } else if(*cp == '+') {
+ convdir = 1;
+ cp++;
+ }
+ if((range = atoi(bp = cp)) == 0)
+ goto badbad;
+ while(*bp >= '0' && *bp <= '9') bp++;
+ if(*bp)
+ goto baddel;
+ if((convdir > 0 && first > mp->hghmsg) ||
+ (convdir < 0 && first < mp->lowmsg))
+ goto rangerr;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ if(first > mp->hghmsg)
+ first = mp->hghmsg;
+ for(last = first; last >= mp->lowmsg && last <= mp->hghmsg;
+ last =+ convdir)
+ if(mp->msgstats[last]&EXISTS)
+ if(--range <= 0)
+ break;
+ if(last < mp->lowmsg)
+ last = mp->lowmsg;
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(last < first) {
+ range = last; last = first; first = range;
+ }
+ } else {
+ if(first > mp->hghmsg || first < mp->lowmsg ||
+ !(mp->msgstats[first]&EXISTS)) {
+ printf("Message %d doesn't exist.\n", first);
+ return(0);
+ }
+ last = first;
+ }
+ while(first <= last) {
+ if(mp->msgstats[first]&EXISTS) {
+ if(!(mp->msgstats[first]&SELECTED)) {
+ mp->numsel++;
+ mp->msgstats[first] =| SELECTED;
+ if(first < mp->lowsel)
+ mp->lowsel = first;
+ if(first > mp->hghsel)
+ mp->hghsel = first;
+ }
+ found++;
+ }
+ first++;
+ }
+ if(!found)
+ goto rangerr;
+ return(1);
+}
+
+m_conv(str)
+{
+ register char *cp, *bp;
+ register int i;
+ char buf[16];
+
+ convdir = 1;
+ cp = bp = str;
+ if(*cp >= '0' && *cp <= '9') {
+ while(*bp >= '0' && *bp <= '9') bp++;
+ delimp = bp;
+ return(atoi(cp));
+ }
+ bp = buf;
+ while((*cp >= 'a' && *cp <= 'z') || *cp == '.')
+ *bp++ = *cp++;
+ *bp++ = 0;
+ delimp = cp;
+ if(equal(buf, "first"))
+ return(mp->lowmsg);
+ else if(equal(buf, "last")) {
+ convdir = -1;
+ return(mp->hghmsg);
+ } else if(equal(buf, "cur") || equal(buf, "."))
+ return(mp->curmsg);
+ else if(equal(buf, "prev")) {
+ convdir = -1;
+ for(i = (mp->curmsg<=mp->hghmsg)? mp->curmsg-1: mp->hghmsg;
+ i >= mp->lowmsg; i--) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ } else if(equal(buf, "next"))
+ for(i = (mp->curmsg>=mp->lowmsg)? mp->curmsg+1: mp->lowmsg;
+ i <= mp->hghmsg; i++) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1);
+}
--- /dev/null
+#include "/m/mh/mh.h"
+
+#define ONLYDEL 1 /* use only deleted msgs */
+#define ONLYUNDEL 2 /* use only undelted msgs */
+#define DELORUNDEL 3 /* use either deleted msg or undeleted */
+int convdir;
+struct msgs *mp;
+char *delimp;
+
+m_convert(name)
+{
+ register char *cp;
+ register int first, last;
+ int found, group, range, err, seltype, selected;
+ char *bp;
+
+ found = group = 0;
+ cp = name;
+ seltype = DELORUNDEL;
+ if(equal(cp, "all")) {
+ cp = "first-last";
+ }
+ else if(equal(cp, "undel")) {
+ cp = "first-last";
+ seltype = ONLYUNDEL;
+ }
+ else if(equal(cp, "del")) {
+ cp = "first-last";
+ seltype = ONLYDEL;
+ }
+ if((err = first = m_conv(cp)) <= 0)
+ goto badbad;
+ if(*(cp = delimp) && *cp != '-' && *cp != ':') {
+ baddel: printf("Illegal argument delimiter: \"%c\"\n", *delimp);
+ return(0);
+ }
+ if(*cp == '-') {
+ group++; cp++;
+ if((err = last = m_conv(cp)) <= 0) {
+ badbad: if(err == -1)
+ printf("No %s message\n", cp);
+ else
+ badlist: printf("Bad message list \"%s\".\n", name);
+ return(0);
+ }
+ if(last < first) goto badlist;
+ if(*delimp) goto baddel;
+ if(first > mp->hghmsg || last < mp->lowmsg) {
+ rangerr: printf("No messages in range \"%s\".\n", name);
+ return(0);
+ }
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ } else if(*cp == ':') {
+ cp++;
+ if(*cp == '-') {
+ convdir = -1;
+ cp++;
+ } else if(*cp == '+') {
+ convdir = 1;
+ cp++;
+ }
+ if((range = atoi(bp = cp)) == 0)
+ goto badlist;
+ while(*bp >= '0' && *bp <= '9') bp++;
+ if(*bp)
+ goto baddel;
+ if((convdir > 0 && first > mp->hghmsg) ||
+ (convdir < 0 && first < mp->lowmsg))
+ goto rangerr;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ if(first > mp->hghmsg)
+ first = mp->hghmsg;
+ for(last = first; last >= mp->lowmsg && last <= mp->hghmsg;
+ last =+ convdir)
+ if(mp->msgstats[last]&EXISTS)
+ if(--range <= 0)
+ break;
+ if(last < mp->lowmsg)
+ last = mp->lowmsg;
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(last < first) {
+ range = last; last = first; first = range;
+ }
+ } else {
+ if(first > mp->hghmsg || first < mp->lowmsg ||
+ !(mp->msgstats[first]&EXISTS)) {
+ printf("Message %d doesn't exist.\n", first);
+ return(0);
+ }
+ last = first;
+ }
+ while(first <= last) {
+ if(mp->msgstats[first]&EXISTS) {
+ if(!(mp->msgstats[first]&SELECTED)) {
+ if (seltype == ONLYDEL)
+ selected = mp->msgstats[first]&DELETED;
+ else if (seltype == ONLYUNDEL)
+ selected = !(mp->msgstats[first]&DELETED);
+ else selected = TRUE;
+ if (selected) {
+ mp->numsel++;
+ mp->msgstats[first] =| SELECTED;
+ if(first < mp->lowsel)
+ mp->lowsel = first;
+ if(first > mp->hghsel)
+ mp->hghsel = first;
+ }
+ }
+ found++;
+ }
+ first++;
+ }
+ if(!found)
+ goto rangerr;
+ return(1);
+}
+
+m_conv(str)
+{
+ register char *cp, *bp;
+ register int i;
+ char buf[16];
+
+ convdir = 1;
+ cp = bp = str;
+ if(*cp >= '0' && *cp <= '9') {
+ while(*bp >= '0' && *bp <= '9') bp++;
+ delimp = bp;
+ return(atoi(cp));
+ }
+ bp = buf;
+ while((*cp >= 'a' && *cp <= 'z') || *cp == '.')
+ *bp++ = *cp++;
+ *bp++ = 0;
+ delimp = cp;
+ if(equal(buf, "first"))
+ return(mp->lowmsg);
+ else if(equal(buf, "last")) {
+ convdir = -1;
+ return(mp->hghmsg);
+ } else if(equal(buf, "cur") || equal(buf, "."))
+ return(mp->curmsg);
+ else if(equal(buf, "prev")) {
+ convdir = -1;
+ for(i = (mp->curmsg<=mp->hghmsg)? mp->curmsg-1: mp->hghmsg;
+ i >= mp->lowmsg; i--) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1); /* non-existent message */
+ } else if(equal(buf, "next")) {
+ for(i = (mp->curmsg>=mp->lowmsg)? mp->curmsg+1: mp->lowmsg;
+ i <= mp->hghmsg; i++) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1);
+ } else
+ return(0); /* bad message list */
+}
--- /dev/null
+#include "mh.h"
+
+m_delete(key)
+char *key;
+{
+ register struct node *np, *npprev;
+
+ m_getdefs();
+ for(np = &m_defs; npprev = np; ) {
+ np = np->n_next;
+ if(uleq(np->n_name, key)) {
+ npprev->n_next = np->n_next;
+ cfree(np->n_name);
+ cfree(np->n_field);
+ free(np);
+ def_flags =| DEFMOD;
+ return(0);
+ }
+ }
+ return(1);
+}
--- /dev/null
+#include "mh.h"
+
+m_find(str)
+{
+ register struct node *n;
+
+ m_getdefs();
+ for(n = m_defs; n; n = n->n_next)
+ if(uleq(n->n_name, str))
+ return(n->n_field);
+ return(-1);
+}
--- /dev/null
+#include "/m/mh/mh.h"
+#include "/m/mh/iobuf.h"
+
+char *mypath, defpath[128];
+char mh_defs[];
+char installproc[];
+
+m_getdefs()
+{
+ register struct node *np;
+ register int state, pid;
+ int status;
+ struct iobuf ib;
+ char name[NAMESZ], field[128];
+
+ if(defpath[0])
+ return; /* We've already been called! */
+ if(!mypath)
+ mypath = getpath(getruid());
+ copy(mh_defs, copy(mypath, defpath));
+
+ if(fopen(defpath, &ib) < 0) {
+ if((pid = fork()) == 0) {
+ execl(installproc, "install-defs", "-detached", 0);
+ printf("Can't install .mh_defs!!\n");
+ flush(); exit(1);
+ } else if(pid == -1) {
+ printf("No forks!\n");
+ flush(); exit(1);
+ } else
+ while((state = waita(&status)) != -1 && state != pid)
+ ;
+ if(status || fopen(defpath, &ib) < 0) {
+ printf("[install-defs aborted]\n");
+ flush(); exit(1);
+ }
+ }
+
+#ifdef NEWS
+ fstat(ib.b_fildes, field);
+ deftime = (&field)->i_atime;
+#endif
+
+ np = &m_defs;
+ state = FLD;
+ for(;;)
+ switch(state = m_getfld(state,name,field,sizeof field,&ib)) {
+ case FLD:
+ case FLDEOF:
+ np->n_next = alloc(sizeof *np);
+ np = np->n_next;
+ np->n_name = getcpy(name);
+ np->n_field = trimcpy(field);
+ np->n_next = 0;
+ if(state == FLDEOF) {
+ close(ib.b_fildes);
+ return(0);
+ }
+ continue;
+ case BODY:
+ case BODYEOF:
+ printf(".mh_defs must not contain a body--it can't \
+end with a blank line!\n");
+ default:
+ printf("Bad format: .mh_defs!\n");
+ flush();
+ exit(1);
+ }
+}
--- /dev/null
+#include "mh.h"
+
+int m_fldsz;
+
+m_getfld(state, name, buf, bufsz, iob)
+int state, bufsz;
+char *name, *buf;
+struct iobuf *iob;
+{
+ register char *cp;
+ register c;
+
+ top: while((c = getc(iob)) == '\001' && peekc(iob) == '\001')
+ while(getc(iob) != '\n');
+
+ if(c < 0)
+ return(FILEEOF);
+ m_fldsz = 0;
+
+ switch(state) {
+
+ case FLDEOF:
+ case BODYEOF:
+ case FLD:
+ if(c == '\n' || c == '-')
+ goto body;
+ cp = name;
+ for(;;) {
+ if(cp >= name+NAMESZ-1) {
+ *cp = 0;
+printf("??Component Name Exceeds %d Chars:\n \"%s\"\n", NAMESZ-1, name);
+ return(LENERR);
+ }
+ if(c == ':')
+ break;
+ if(c == '\n' || c < 0) {
+ *cp = 0;
+printf("??%s Encountered While Scanning for a colon:\n \"%s\"\n",
+ (c < 0)? "<eof>":"<end of line>", name);
+ return(FMTERR);
+ }
+ *cp++ = c;
+ *cp = 0;
+ c = getc(iob);
+ }
+
+ case FLDPLUS:
+ cp = buf;
+ for(;;) {
+ if((c = getc(iob)) < 0)
+ return(FLDEOF);
+ *cp++ = c;
+ *cp = 0;
+ m_fldsz++;
+ if(c == '\n')
+ if((c = peekc(iob)) != ' ' && c != '\t')
+ if(c == '\001' || c < 0)
+ return(FLDEOF);
+ else
+ return(FLD);
+ if(cp >= buf+bufsz-1)
+ return(peekc(iob) < 0? FLDEOF:FLDPLUS);
+ }
+
+ body: if(c == '-')
+ while(getc(iob) != '\n') ;
+ buf[0] = 0;
+ if((c = getc(iob)) == '\001' && peekc(iob) == '\001')
+ return(BODYEOF);
+
+ case BODY:
+ cp = buf; *cp = 0;
+ for(;;) {
+ if(c < 0 || (c == '\001' && peekc(iob) == '\001'))
+ return(BODYEOF);
+ *cp++ = c;
+ *cp = 0;
+ m_fldsz++;
+ if(cp >= buf+bufsz-1)
+ return(((c=peekc(iob))<0||c=='\001')?
+ BODYEOF: BODY);
+ c = getc(iob);
+ }
+
+ }
+}
--- /dev/null
+char defalt[];
+
+m_getfolder()
+{
+ register char *folder;
+
+ m_getdefs();
+ if((folder = m_find("folder")) == -1 || *folder == 0)
+ folder = defalt;
+ return(folder);
+}
--- /dev/null
+char msgprot[];
+
+m_gmprot()
+{
+ register int prot;
+
+ if((prot = m_find("msg-protect")) != -1)
+ prot = atooi(prot);
+ else
+ prot = atooi(msgprot);
+ return(prot);
+}
--- /dev/null
+#include "/m/mh/mh.h"
+
+char current[];
+char listname[];
+struct msgs *mp;
+
+m_gmsg(name)
+char *name;
+
+{
+ register int i, j;
+ register char *cp;
+ int curfil;
+ char buf[132];
+
+ struct {
+ struct {
+ int d_inum;
+ char d_name[14];
+ } ent;
+ int terminator;
+ } dir;
+
+ struct {
+ int xhghmsg,
+ xnummsg,
+ xlowmsg,
+ xcurmsg;
+ char xselist,
+ xflags,
+ xfiller,
+ xothers;
+ char xmsgs[1000];
+ } msgbuf;
+
+ if((i = open(".", 0)) < 0)
+ return(0);
+ for(j = 0; j < 1000; j++)
+ msgbuf.xmsgs[j] = 0;
+ msgbuf.xcurmsg = 0;
+ msgbuf.xnummsg = 0;
+ msgbuf.xselist = 0;
+ msgbuf.xothers = 0;
+ msgbuf.xlowmsg = 5000;
+ msgbuf.xhghmsg = 0;
+ msgbuf.xflags = (access(".",2) == -1)? READONLY:0; /*RAND sys call*/
+ curfil = 0;
+ dir.terminator = 0;
+ cp = dir.ent.d_name;
+ for(;;) {
+ if(read(i, &dir, sizeof dir.ent) != sizeof dir.ent)
+ break;
+ if(dir.ent.d_inum) {
+ if(j = mu_atoi(cp)) {
+ if(j > msgbuf.xhghmsg)
+ msgbuf.xhghmsg = j;
+ msgbuf.xnummsg++;
+ if(j < msgbuf.xlowmsg)
+ msgbuf.xlowmsg = j;
+ msgbuf.xmsgs[j] = EXISTS;
+ if(*cp == ',') msgbuf.xmsgs[j] =| DELETED;
+ else msgbuf.xmsgs[j] =| UNDELETED;
+ } else if(!equal(cp, ".") &&
+ !equal(cp, "..") &&
+ *cp != ',')
+ if(equal(cp, current))
+ curfil++;
+ else if(equal(cp, listname))
+ msgbuf.xselist++;
+ else
+ msgbuf.xothers++;
+ }
+ }
+ if(!msgbuf.xhghmsg)
+ msgbuf.xlowmsg = 0;
+ close(i);
+ if(msgbuf.xflags&READONLY) {
+ copy(name, copy("cur-", buf));
+ if((cp = m_find(buf)) != -1)
+ if(j = mu_atoi(cp))
+ msgbuf.xcurmsg = j;
+ } else if(curfil && (i = open(current, 0)) >= 0) {
+ if((j = read(i, dir.ent.d_name, sizeof dir.ent.d_name)) >= 2){
+ dir.ent.d_name[j-1] = 0; /* Zap <lf> */
+ if(j = mu_atoi(dir.ent.d_name))
+ msgbuf.xcurmsg = j;
+ }
+ close(i);
+ }
+ if((i = alloc(sizeof *mp + msgbuf.xhghmsg + 2)) == -1)
+ return(0);
+ i->hghmsg = msgbuf.xhghmsg;
+ i->nummsg = msgbuf.xnummsg;
+ i->lowmsg = msgbuf.xlowmsg;
+ i->curmsg = msgbuf.xcurmsg;
+ i->selist = msgbuf.xselist;
+ i->msgflags = msgbuf.xflags;
+ i->others = msgbuf.xothers;
+ i->foldpath = name;
+ i->lowsel = 5000;
+ i->hghsel = 0;
+ i->numsel = 0;
+ for(j = 0; j <= msgbuf.xhghmsg; j++)
+ i->msgstats[j] = msgbuf.xmsgs[j];
+ return(i);
+}
+
+
+mu_atoi(str)
+char *str;
+{
+ register char *cp;
+ register int i;
+
+ i = 0;
+ cp = str;
+ if(*cp==',') cp++;
+ while(*cp) {
+ if(*cp < '0' || *cp > '9' || i > 99)
+ return(0);
+ i =* 10;
+ i =+ *cp++ - '0';
+ }
+ return(i);
+}
--- /dev/null
+char *mypath;
+
+m_maildir(folder)
+{
+ register char *fold, *path, *cp;
+ static char mailfold[128];
+
+ m_getdefs();
+ if(!(fold = folder))
+ fold = m_getfolder();
+ if(*fold == '/' || *fold == '.')
+ return(fold);
+ cp = mailfold;
+ if((path = m_find("path")) != -1 && *path) {
+ if(*path != '/')
+ cp = copy("/", copy(mypath, cp));
+ cp = copy(path, cp);
+ if(cp[-1] != '/')
+ *cp++ = '/';
+ }
+ copy(fold, cp);
+ return(mailfold);
+}
--- /dev/null
+#include "/m/mh/mh.h"
+struct msgs *mp;
+m_name(num)
+{
+ static char name[4];
+ register char *cp;
+ register int i;
+
+ name[0] = 0;
+ name[1] = 0;
+ name[2] = 0;
+ name[3] = 0;
+ i = num;
+ cp = &name[3];
+ if(i > 0 && i < 1000) {
+ do {
+ *--cp = (i % 10) + '0';
+ i =/ 10;
+ } while(i);
+ if(( mp->msgstats[num]&EXISTS) && ( mp->msgstats[num]&DELETED))
+ *--cp = ',';
+ } else
+ *--cp = '?';
+ return(cp);
+}
--- /dev/null
+#include "mh.h"
+
+m_news()
+{
+ struct inode stbf;
+ struct iobuf in;
+ register flag, c;
+
+ m_getdefs();
+ if(stat(mhnews, &stbf) != -1 &&
+ stbf.i_mtime > deftime) {
+ fopen(mhnews, &in);
+ flag = getc(&in);
+ while((c = getc(&in)) != -1)
+ if(c == NEWSPAUSE) {
+ if(!gans("More? ", anoyes))
+ break;
+ } else
+ putchar(c);
+ flush();
+ if(flag == NEWSHALT)
+ exit(0);
+ close(in.b_fildes);
+ }
+}
--- /dev/null
+#include "mh.h"
+
+
+m_replace(key,value)
+char *key, *value;
+
+{
+ register struct node *np;
+
+ m_getdefs();
+ for(np = m_defs; ; np = np->n_next) {
+ if(uleq(np->n_name, key)) {
+ if(!equal(value, np->n_field)) {
+ cfree(np->n_field);
+ np->n_field = value;
+ def_flags =| DEFMOD;
+ }
+ return;
+ }
+ if(!np->n_next)
+ break;
+ }
+ np->n_next = alloc(sizeof *np);
+ np = np->n_next;
+ np->n_name = key;
+ np->n_next = 0;
+ np->n_field = value;
+ def_flags =| DEFMOD;
+}
--- /dev/null
+#include "mh.h"
+
+char current[];
+struct msgs *mp;
+
+m_setcur(num)
+
+{
+ char buf[6];
+ register int i;
+ register char *cp1;
+
+ if(mp->msgflags&READONLY) {
+ m_replace(cp1 = concat("cur-",mp->foldpath,0), m_name(num));
+ free(cp1);
+ }
+ else {
+ cp1 = copy(m_name(num), buf);
+ *cp1++ = '\n';
+ if(!equal(current, "cur"))
+ error("\"current\" got Clobbered!! Tell B. Borden");
+ if((i = creat(current, 0660)) >= 0) {
+ write(i, buf, cp1-buf);
+ close(i);
+ }
+ }
+}
--- /dev/null
+#include "mh.h"
+#include "/rnd/borden/h/iobuf.h"
+#include "/rnd/borden/h/signals.h"
+
+char defpath[];
+
+m_update()
+{
+ struct iobuf out;
+ register struct node *np;
+ int save;
+
+ if(def_flags & DEFMOD) {
+ save = signal(SIGINT, 1);
+ if(fcreat(defpath, &out) < 0) {
+ printf("Can't create %s!!\n", defpath);
+ flush(); exit(1);
+ }
+ for(np = m_defs; np; np = np->n_next) {
+ puts(np->n_name, &out);
+ puts(": ", &out);
+ puts(np->n_field, &out);
+ putc('\n', &out);
+ }
+ fflush(&out);
+ signal(SIGINT, save);
+ close(out.b_fildes);
+ def_flags =& ~DEFMOD;
+ }
+}
--- /dev/null
+char foldprot[];
+
+makedir(dir)
+{
+ register int i, j;
+ int status;
+
+ if((i = fork()) == 0) {
+ execl("/bin/mkdir", "mkdir", dir, 0);
+ printf("Can't exec mkdir!!?\n");
+ flush();
+ return(0);
+ }
+ if(i == -1) {
+ printf("Can't fork\n");
+ flush();
+ return(0);
+ }
+ while((j = waita(&status)) != i && j != -1) ;
+ if(status) {
+ printf("Bad exit status (%o) from mkdir.\n", status);
+ flush();
+ return(0);
+ }
+ chmod(dir, ((i = m_find("folder-protect")) != -1)?
+ atooi(i) : atooi(foldprot));
+ return(1);
+}
--- /dev/null
+#include "/rnd/borden/h/iobuf.h"
+
+peekc(iob)
+struct iobuf *iob;
+{
+ register c;
+ register struct iobuf *p;
+
+ p = iob;
+ if((c = getc(p)) >= 0) {
+ p->b_nleft++;
+ p->b_nextp--;
+ }
+ return(c);
+}
--- /dev/null
+pr_array(cp,ap)
+char *cp, **ap;
+{
+ register int i;
+
+ for(i=0; *ap; ap++,i++)
+ printf("%s[%d]=> %s\n", cp,i,*ap);
+}
+
--- /dev/null
+#include "mh.h"
+
+printsw(substr, swp)
+char *substr;
+struct swit *swp;
+{
+ char buf[128];
+ register char *cp, *cp1;
+ register int i;
+ int len;
+
+ len = length(substr);
+ for(; swp->sw; swp++)
+ if(!*substr || /* null matches all strings */
+ (ssequal(substr, swp->sw) && len >= swp->minchars))
+ if(swp->minchars > 0) {
+ cp = buf;
+ *cp++ = '(';
+ for(cp1 = swp->sw, i = 0; i < swp->minchars; i++)
+ *cp++ = *cp1++;
+ *cp++ = ')';
+ while(*cp++ = *cp1++);
+ printf(" -%s\n", buf);
+ } else if(swp->minchars == 0)
+ printf(" -%s\n", swp->sw);
+}
--- /dev/null
+#include "/rnd/borden/h/iobuf.h"
+
+puts(buf, iob)
+{
+ register char *cp;
+ register struct iobuf *ip;
+ extern int errno;
+
+ cp = buf;
+ ip = iob;
+
+ errno = 0;
+ if(ip->b_fildes)
+ while(*cp) {
+ putc(*cp++, ip);
+ if(errno) { perror("Write error"); exit(-1); }
+ }
+}
--- /dev/null
+showfile(file)
+{
+ register int i, cnt;
+ char buf[512];
+
+ type(1, "\n");
+ if((i = open(file, 0)) == -1) {
+ printf("Can't open %s\n", file);
+ return 1;
+ }
+ do
+ if((cnt = read(i, buf, sizeof buf)) > 0)
+ write(1, buf, cnt);
+ while(cnt == sizeof buf);
+ close(i);
+ type(1, "\n");
+ return 0;
+}
--- /dev/null
+#include "mh.h"
+
+/* switch match, or any unambiguous abbreviation */
+/* exact match always wins, even if shares same root */
+/* returns subscript in zero-terminated tbl[] of strings */
+/* returns -1 if no match, -2 if ambiguous */
+
+smatch(string, swp)
+char *string;
+struct swit *swp;
+{
+ register char *sp, *tcp;
+ struct swit *tp;
+ int firstone, strlen;
+
+ firstone = -1;
+
+ for (strlen = length(string), tp = swp; tcp = tp->sw; tp++) {
+ if(strlen < abs(tp->minchars)) continue; /* no match */
+ for (sp = string; *sp == *tcp++; ) {
+ if (*sp++ == 0) return(tp-swp); /* exact match */
+ }
+ if (*sp != 0) {
+ if (*sp != ' ') continue; /* no match */
+ if (*--tcp == 0) return(tp-swp); /* exact match */
+ }
+ if (firstone == -1) firstone = tp-swp; /* possible match */
+ else firstone = -2; /* ambiguous */
+ }
+
+ return (firstone);
+}
+
+abs(i)
+{
+ return(i < 0 ? -i : i);
+}
--- /dev/null
+ssequal(substr, str)
+char *substr, *str;
+{
+ while(*substr)
+ if(*substr++ != *str++)
+ return(0);
+ return(1);
+}
--- /dev/null
+ar rv /m/mh/subs.a m_maildir.o \
+ m_setcur.o \
+ makedir.o \
+ m_gmprot.o \
+ m_getfolder.o \
+ m_convert.o \
+ m_find.o \
+ m_replace.o \
+ m_update.o \
+ m_getdefs.o \
+ m_getfld.o \
+ m_gmsg.o \
+ m_name.o \
+ add.o atoi.o atooi.o concat.o \
+ gans.o getchar.o \
+ getcpy.o peekc.o puts.o cputc.o trimcpy.o uleq.o \
+ showfile.o \
+ fdcompare.o cfree.o copyip.o \
+ locv.o m_delete.o ambigsw.o help.o \
+ invo_name.o printsw.o ssequal.o smatch.o pr_array.o
--- /dev/null
+trimcpy(str)
+{
+ register char *cp, *sp;
+
+ cp = str;
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+ sp = cp;
+ while(*sp)
+ if(*sp++ == '\n')
+ break;
+ *--sp = 0;
+ sp = alloc(sp - cp + 1);
+ copy(cp, sp);
+ return(sp);
+}
--- /dev/null
+uleq(s1, s2)
+{
+ register char *c1, *c2;
+ register int c;
+
+ c1 = s1; c2 = s2;
+ while(c = *c1++)
+ if(c != *c2 && (c =| 040) != *c2)
+ return(0);
+ else
+ c2++;
+ return(*c2 == 0);
+}
--- /dev/null
+#include "mh.h"
+
+int vecp, *vec[MAXARGS], fout;
+struct msgs *mp;
+struct swit switches[] {
+ "all", -3, /* 0 */
+ "help", 4, /* 1 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *nfolder, *maildir, *msgs[100], buf[32];
+ register int msgnum;
+ register char *cp, *sp;
+ int msgp;
+ char *ap, *inp;
+ char *arguments[50], **argp;
+
+ fout = dup(1);
+#ifdef NEWS
+ m_news();
+#endif
+ folder = msgp = 0;
+ vecp = 1;
+ inp = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ inp = cp;
+ ap = inp;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("-%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: printf("\"-all\" changed to \"all\"\n");
+ goto leave;
+ /* -help */
+ case 1: help(concat( inp, " [+folder] [msgs] [switches]", 0),
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ printf("Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ printf("Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ printf("No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum], DELETED, DELETED))
+ goto leave;
+ if(mp->numsel == 0) {
+ goto leave;
+ }
+ m_replace("folder", folder);
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum] & SELECTED) {
+ sp = getcpy(m_name(msgnum));
+ cp = copy(sp, buf);
+ while(--cp >= buf && *cp != '/');
+ do *++cp = cp[1];
+ while(*cp);
+ unlink(buf);
+ if(link(sp, buf) == -1 || unlink(sp) == -1)
+ printf("Can't rename %s to %s.\n", sp, buf);
+ }
+leave:
+ m_update();
+ flush();
+}
--- /dev/null
+if -r undelete rm undelete
+load -n undelete subs.a strings.a wait -O libg.a libh.a libg.a
+if -r a.out mv a.out undelete
+: fini
+
--- /dev/null
+/ C library -- wait /* modified - does not call nargs */
+
+/ pid = wait(&status);
+/
+/ pid == -1 if error
+/ status indicates fate of process, if given
+
+.globl _wait, _waita, cerror
+
+_waita:
+_wait:
+ mov r5,-(sp)
+ mov sp,r5
+ sys wait
+ bec 1f
+ tst (sp)+
+ jmp cerror
+1:
+ mov r1,*4(r5) / status return
+ mov (sp)+,r5
+ rts pc
--- /dev/null
+#include "mh.h"
+#include "signals.h"
+
+
+char draft[],
+ components[],
+ stdcomps[],
+ sysed[],
+#ifdef PROMPT
+ prmtproc[],
+#endif
+ sndproc[];
+
+int fout;
+
+char *anyus[] {
+ "no", 0,
+ "yes", 0,
+ "use", 0,
+ "show", 0,
+ 0,
+};
+
+char *anyv[] {
+ "no", 0,
+ "yes", 0,
+ "verbose", 0,
+ 0,
+};
+
+struct swit switches[] {
+ "editor editor", 0, /* 0 */
+ "form formfile", 0, /* 1 */
+ "use", 0, /* 2 */
+ "nouse", 0, /* 3 */
+ "help", 4, /* 4 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp;
+ register int in, out;
+ int use, cnt, status, intr;
+ char buf[512], path[128], *ed, *file, *vec[10], *form;
+ char *inp, *ap;
+ char *arguments[50], **argp;
+
+ fout = dup(1);
+#ifdef NEWS
+ m_news();
+#endif
+ form = use = file = ed = 0;
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ inp = ap;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", '\n');
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-') {
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("-%s unknown\n", cp);
+ goto leave;
+ case 0: if(!(ed = *argp++)) { /* -editor */
+ missing: printf("Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 1: if(!(form = *argp++)) /* -form */
+ goto missing;
+ continue;
+ case 2: use = 1; continue; /* -use */
+ case 3: use = 0; continue; /* -nouse */
+ case 4: help(concat( inp, " [file] [switches]", 0),
+ switches);
+ goto leave;
+ }
+ }
+ file = cp;
+ }
+ if(form) {
+ if((in = open(m_maildir(form), 0)) < 0) {
+ printf("Can't open form file: %s\n", form);
+ goto leave;
+ }
+ } else if((in = open(m_maildir(components), 0)) < 0 &&
+ (in = open(stdcomps, 0)) < 0) {
+ printf("Can't open default components file!!\n");
+ goto leave;
+ }
+ if(!file)
+ file = draft;
+ copy(m_maildir(file), path);
+ if((out = open(path, 0)) >= 0) {
+ if(use || fdcompare(in, out))
+ goto editit;
+/*
+ cp = concat("\"", path, "\" exists; delete? ", 0);
+ while((status = gans(cp, anyus)) == 3)
+ showfile(path);
+ if(status == 2) {
+ use++;
+ goto editit;
+ }
+ if(status == 0)
+ goto leave;
+*/
+ close(out);
+ } else if(use) {
+ printf("\"%s\" doesn't exist!\n", path);
+ goto leave;
+ }
+ if((out = creat(path, m_gmprot())) < 0) {
+ printf("Can't create \"%s\"\n", path);
+ goto leave;
+ }
+ do
+ if(cnt = read(in, buf, sizeof buf))
+ write(out, buf, cnt);
+ while(cnt == sizeof buf);
+ close(in);
+editit:
+ close(out);
+ if(!ed && (ed = m_find("editor")) == -1)
+#ifdef PROMPT
+ ed = prmtproc;
+#else
+ ed = sysed;
+#endif
+ intr = signal(SIGINT, 1);
+ if((in = fork()) == 0) {
+ m_update();
+ flush();
+ execlsrh(ed, path, 0);
+ printf("Can't exec editor!!\n");
+ flush(); exit(1);
+ } else if(in == -1) {
+ printf("No forks!\n");
+ goto leave;
+ } else
+ while((out = waita(&status)) != -1 && out != in) ;
+ if(status) {
+ printf("[command aborted--%s ", file);
+ if(!use && status > 0377) {
+ unlink(path);
+ printf("deleted]\n");
+ } else
+ printf("preserved]\n");
+ goto leave;
+ }
+ signal(SIGINT, intr);
+#ifdef TEST
+ printf("!! Test Version of SEND Being Run !!\n");
+ printf(" Send verbose !\n\n");
+#endif
+/* in = concat("Send \"", file, "\"? ", 0); */
+ in = "Send? ";
+/*** printf("Send \"%s\"? ", file); ***/
+ if((out = gans(in, anyv)) > 0) {
+ in = 0;
+ vec[in++] = "mh-sndproc";
+ vec[in++] = path;
+ if(out == 2)
+ vec[in++] = "-verbose";
+ vec[in++] = 0;
+ m_update();
+ flush();
+ execv(sndproc, vec);
+ printf("Can't exec send process.\n");
+ }
+leave:
+ m_update();
+ flush();
+}
+
+
+
+
+
--- /dev/null
+if -r write rm write
+load -n write subs.a strings.a wait.o -O libg.a libh.a libg.a
+if -r a.out mv a.out write
+: fini
+
--- /dev/null
+
+
+11/15/80
+
+ _sobuf is defined. Previously it was in stdio.h
+
+ errno is defined. Previously it was in errno.h
--- /dev/null
+"Extras" contains several weird C sources. They should be checked.
+Still gotta fix Mail
+Gotta make sure the Make onceonly installs /etc/MailAliases and /usr/spool/locks
+Should make a whole subsection for installing the News stuff. It should
+all be in a subdirectory with its own makefile, in fact, since it basically
+is an entirely separate module from the other stuff.
+
+Berkeley seems to have their own program called "l" in /usr/ucb.
+
+Some systems purge /usr/tmp in their /etc/rc file, thus destroying the
+/usr/tmp/mh directory. MH programs which need that directory should attempt
+to make it if it is not there.
--- /dev/null
+The Alias file for mail delivery is the file
+
+ /etc/MailAliases
+
+Each line of the alias file has the format:
+
+match : alias
+
+Where:
+
+ alias := simple-list
+ | "<" alias-file
+ | "=" UNIX-group
+ | "*"
+
+ simple-list := simple-name
+ | simple-list, simple-name
+
+Alias-file is a fully qualified UNIX file name. UNIX-group is a
+group name from /etc/group. A simple-name is a local user login
+name, including only alphanumerics, `.' and `-'. Throughout this
+file case is ignored, except for alias-file.
+
+In match, a trailing * on a name will match anything. (See example
+below.)
+
+The procedure for mail aliasing is:
+
+1) Build a list of all addresses from the message to be
+ delivered, eliminating duplicates.
+
+2) For each line in the alias file, compare "match" against all
+ of the existing addresses. If a match, remove the matched
+ name from the address list, and add each new alias name to the
+ address list if it is not already on the list.
+
+Since the alias file is read line by line, forward references
+work, but backward references are not recognized, thus, there is
+no recursion.
+
+E.g.:
+
+Borden: bruce
+Bruce: bsb
+Wharman: mike
+ASRL: bsb, mike, obrien, giarla
+UNIX-committee: < /usr/people/unix-committee
+System: = sys
+Everyone: *
+news.*: news
+ ...
+
+In the "unix-committee" example, the file "/usr/people/unix-
+committee" contains one simple-name, or a list of comma separated
+simple-names. A new-line will be treated as a blank in this
+file, s.a.
+
+ foo, fie,
+ fum, fiddle
+
+In the "system" case, the names from the group "sys" will be used
+as the expanded name list.
+
+In the "news.*" case, all names of the form "news.<anything>" will
+be mapped to "news". This is used for the MH news facility.
+
+Bruce Borden October 1979
--- /dev/null
+11/14/79
+ If .mh_profile contains an entry like "show: -pr -a -b -c" and you
+ call "show" with the explicit switch -nopr, then you have those
+ dangling -a -b -c switches that were intended for pr.
+ (Bound the switch list for pr, etc., with a semi-colon?)
+
+2/1/80
+ "file +junk" makes junk a folder, while "file +.junk" makes ".junk"
+ a subfolder. "file" should test for pathname beginning with "./"
+ instead of just '.'
+
+9/15/80
+ When repl gets an adrparse error, it should return to
+ "What now?" instead of aborting. (But see objections in
+ /r/phyl/Mail/MH/16)
+
+ The same goes for comp, dist, forw
+
+9/29/80
+ When send is invoked with no args, and the draft already
+ exists, options to "use draft?" should include "list" along with
+ yes/no
+
+10/21/80
+ Tabs in address lists aren't recognized.
+
+12/23/80
+ Fix and install "dist"
+
+1/14/81
+ inc -nochangecur displays that the first-inc'ed message is the current
+ message, and it's not. It should also do a scan from cur, I think.
+ (I fixed the 1st bug, but not the scan from cur. /phyl 7/9/81)
+
+5/28/81
+ 'news' will break when there are multiple news folders in the 'To:'
+ field(s)!
+
+
+7/7/81 phyl
+ Re:Log:"3/23/81 jdg/day: changed deliver.c to check for effective
+ uid and gid while it is preventing forgery of mail. Needed for
+ uucp, when uucico is invoked by a real person instead of uucp
+ itself."
+
+ The real fix should be to check for real uid==0 (srvrftp) or real
+ gid==daemon (any uu program) or effective gid==daemon (human
+ running uucico, and uucico should be SGID daemon).
+
+2/16/81
+ /usr/tmp/mh files are readable by the world.
+ So are /usr/spool/uucp files.
+
+2/21/81
+ A message should not have to exist for you to be able to use
+ its number in a range, as in 'scan cur-last' when cur does
+ not exist.
+
+2/28/81
+ "This RAND-UNIX stuff (adding and removing them from message
+ headers on the vax) is a crock. Reply strips 'RAND-UNIX' off of
+ addresses, but not 'rand-unix'. If I type it up myself, deliver
+ rejects either of them." --guyton
+
+
+4/4/81
+ "The delivery program should not leave headers that the mailer doesn't
+ understand. Replying to the following header was painful: " --jim
+
+ (Message inbox:1)
+ From: graphics!root
+ Date: 4 Apr 1981 at 2138-PST
+ To: Vax!mh-discussion at RAND-UNIX
+ Cc: greep at SU-ISL
+ Subject: Mail to terminals
+ From: greep at SU-ISL
+
+
+ ...AND LOTS OF OTHER MESSAGE HEADER OBJECTIONS
+
+4/7/81
+ scan and inc should check ALIASES and recognize UUCP localhost!me
+ when deciding whether or not the message is from me.
+
+4/16/81
+ Deliver should run one uux per site instead of one per addressee.
+
+6/2/81
+ "rmf" should automatically remove .e* files from the named folder.
+
+7/81
+ deliver fails to recognize "at" when it is preceded by
+ more than one blank.
+
+ repl tries to parse a Sender [or From] field, and a To
+ field, without first testing for their existence.
+
+ file protections on rmail/uucico are inconsistent with
+ deliver's internal user/group tests.
+
+ deliver fails to recognize that localhost!user is indeed user.
+ (Should it?)
+
+ temporary mail files stay around when the "no such local user"
+ error occurs--because of a spurious flag test.
+
+ deliver should parenthesize (user at host) as well as (host!user)
+ when constructing the uux command.
+
+ rmail should direct stderr to a file before invoking deliver.
+
+ rmail should check for unknown local user and send return mail to the
+ originator. (Can't fix unless no intervening Arpanet addresses.)
+
+ rmail should add a Date: component if there is none.
+
+ mail headers should be reordered.
+
+7/23/81
+ "mail" should be in /bin, not in /usr/randbin. (?)
+
+8/17/81
+ "rmf" should verify that the requested folder is not the current
+ directory.
+
+8/20/81
+ /usr/tmp/mh and /usr/MailAliases should be defined in strings.a
+
+9/1/81
+ repl should remove leading blanks from date and subject fields
+ before putting them in the new in-reply-to and subject fields.
+ (Greep)
+
+9/9/81
+ Adrparse should recognize the full RFC733 syntax; viz, colon
+ as part of the address list.
+
+10/2/81
+ Subject: news bug
+ From: phyl at RAND-UNIX
+
+ The table of news topics overflowed.
+
+ news.c counts all non-dot files in the directory /usr/news to
+ determine the number of news topics. But mail sent to an UNKNOWN
+ news topic remains in the top level news directory, erroneously
+ getting counted into the total. Either .mh-receive should stow
+ undeliverable news into another directory, or news.c should count
+ only directory entries.
+
+10/6/81
+ mhl should know about termcap
+
+10/14/81
+ Subject: Mail to "everyone"
+ From: obrien at RAND-UNIX
+
+ An insoluble problem: sending mail to "everyone" (a risky
+ business at best) generates mail to every line in /etc/passwd,
+ including those like "uucp", "unix32v", and such which aren't real
+ people. An exception list is no help because it gets out of date.
+ Only cure I know of is to go through /usr/spool/mail every now and
+ again and get rid of phony files.
+
+11/10/81
+ Subject: HOSTNUM not necessary
+ From: greep at SU-DSN
+
+ Mh deliver should really not need HOSTNUM (this is in
+ /usr/include/whoami.h) - it can get the number by searching for
+ HOSTNAME in the host table.
+
+11/18/81
+ SUBJECT: folder with a -fast flag doesn't change current folder
+ From: norm at RAND-UNIX
+
+11/81
+ Message lists should not be reordered. (Norm, Phyl)
+
+12/17/81
+ The alias function doesn't work when a single message contains
+ multiple instances of the address form "foo.*"--ergo, a message
+ cannot be sent to more than one news group.
+
+ Note that /usr/news/.mh_receive won't recognize multiple news
+ groups in a single message either!
+
+12/19/81
+ If a message is addressed to more than one local alias-group,
+ people who are in more than one of the groups receive multiple
+ copies of the message. (I think! --phyl--)
+
+1/5/82
+ If you send a message to a bad uucp host name, it a) gives you
+ an error message, b) queues the mail anyway, and c) deletes the
+ draft because the mail was "correctly sent". Ha!
+ It should a) give you an error message and b) punt.
+ --Michael W.--
+
+1/19/82
+
+ MH argument parsing should be upgraded to allow
+ folder arguments to have a space between the +
+ and the folder name so you can use shell matching
+ syntax. Example:
+
+ % folder + /usr/news/net-g*
+ % cd !$
+
+ --dave
+
+3/11/82
+ deliver should clean up before exiting.
\ No newline at end of file
--- /dev/null
+More recent information is to be found in the man pages in ../man
--- /dev/null
+
+
+
+
+ R-2367-AF, The MH Message Handling System: Users Manual,
+ B. S. Borden, R. S. Gaines, N. Z. Shapiro, November 1979.
+
+
+
+PURPOSE: To describe an electronic message handling system. The report
+outlines the implementation and provides complete user level documentation
+for efficient utilization of a new computer utility.
+
+RELATED TO: Project AIR FORCE work on command and control, ...
+
+
+DISCUSSION: The MH message handling system was designed and implemented
+to provide comprehensive electronic message facilities. It implements
+no new facilities which are not available in other message systems, but
+its close integration with the system's command interpreter lends it
+more power and flexibility than is otherwise available. Rather than a
+standard implementation in which all of the functions of message
+handling are implemented in one monolithic program, MH is a collection
+of loosly coupled programs, each of which implement one particular
+aspect of message handling.
+ This implementation strategy has been found to be very flexible and
+easy to use. Rather than having to learn a new set of commands and
+conventions for interacting with the message system, users use the
+standard system command facility which they are already familiar with.
+Also, each module is relatively small, easy to debug and modify, and new
+modules are easy to add in a completely transparent manner. Another
+important design feature of MH is its use of the operating system file
+facilities directly. That is, there are no monolithic message data
+bases, rather messages are stored as individual files within
+directories, which act as message folders. Thus, all standard utilities
+are available on the messages without having to code them into the
+message system itself.
+ Finally, each user of MH has a personal profile which allows for
+tailoring of each command. With these facilities, users are able to
+start using the package immediately, and to enhance their interface as
+they gain knowledge of their own usage patterns.
--- /dev/null
+.de $c \" Major Heading printer
+.ce
+.b "\\s12\\n+(ch.\\ \\$1\\s0" \" 12 Point Bold Header
+.(x
+
+\ \ \ \\n(ch.\\ \\ \\$1
+.)x
+.sp 45p \" 45 point space or about 1/2 inch
+..
+\".nr xs .15v \" Put index entries closer together
+.(x
+
+Section
+.)x _
+.de $0 \" Sub-Heading macro called AFTER printing the heading
+.(x
+.sp .3v
+.ti .5i
+\\$1
+.)x
+..
+.de $s \" Macro to print footnote separator
+\"\l'2i' \" No line drawn
+.if n \
+. sp 1.3 \" But extra space to make up for it.
+..
+.fc ^ ~ \" The characters ^ and ~ CANNOT BE USED
+\" throughout this document except as field
+\" delimiter & pad indicator!
+.he ''-%-''
+.ll 32P \" 32 Picas or about 5+1/3 inch Line Length
+.if n .ll 72m \" Use 72 ems for nroff
+.nr ss 30p \" 30 point space before section titles
+.nr fm 5v \" Rand likes bigger than normal [3v] bottom margins
+.nr bm 7v \" ditto
+.ds . \\fB.\\fP\\h'-(1m/3)' \" Bold period to stand out.
+.ds << <\\h!-(\\w'<'/2)!<
+.ds >> >\\h!-(\\w'>'/2)!>
+.ds ** \v'-3p'\s+1*\s0\v'+3p'
+.++ C
+.+c INTRODUCTION
+.pp
+Although people can travel cross-country in hours and can
+reach others by telephone in seconds, communications still depend
+heavily upon paper, most of which is distributed through the mails.
+.pp
+There are several major reasons for this continued dependence on
+written documents.
+First, a written document may be proofread
+and corrected prior to its distribution, giving the author
+complete control over his words.
+Thus, a written document is
+better than a telephone conversation in this respect.
+Second,
+a carefully written document is far less likely to be
+misinterpreted or poorly translated than a phone conversation.
+Third, a signature offers reasonable verification of authorship,
+which cannot be provided with media such as telegrams.
+.pp
+However, the need for
+.u fast ,
+accurate, and reproducible document distribution is
+obvious.
+One solution in widespread use is the telefax.
+Another
+that is rapidly gaining popularity is electronic mail.
+Electronic mail is similar to telefax in that the data to be sent
+are digitized, transmitted via phone lines, and
+turned back into a document at the receiver.
+The advantage of
+electronic mail is in its compression factor.
+Whereas a telefax
+must scan a page in very fine lines and send all of the black and
+white information, electronic mail assigns characters fixed
+codes which can be transmitted as a few bits of information.
+Telefax presently has the advantage of being able to transmit an
+arbitrary page, including pictures, but electronic mail is
+beginning to deal with this problem.
+Electronic mail also integrates well
+with current directions in office automation, allowing documents
+prepared with sophisticated equipment at one site to be quickly
+transferred and printed at another site.
+.pp
+Currently, most electronic mail is intraorganizational,
+with mail transfer remaining within one computer.
+As computer
+networking becomes more common, however, it is becoming more feasible to
+communicate with anyone whose computer can be linked to your
+own via a network.
+.pp
+The pioneering efforts on general-purpose electronic mail
+were by organizations using the Defense Department's ARPANET.[1]
+The capability to send messages between computers existed before
+the ARPANET was developed, but it was used only in limited ways.
+With the advent of the
+ARPANET, tools began to be developed which made it convenient for
+individuals or organizations to distribute messages
+over broad geographic areas, using
+diverse computer facilities.
+The interest and activity in
+message systems has now reached such proportions that steps
+have been taken within the DoD to coordinate and
+unify the development of military message systems.
+The use of electronic mail is expected to increase
+dramatically in the next few years.
+The utility of such systems
+in the command and control and intelligence environments is
+clear, and applications in these areas will probably lead the
+way.
+As the costs for sending and handling electronic messags
+continue their rapid decrease, such uses can be
+expected to spread rapidly into other areas and, of course, will
+not be limited to the DoD.
+.pp
+A message system provides tools that help users (individuals
+or organizations) deal with messages in various ways.
+Messages
+must be composed, sent, received, stored, retrieved,
+forwarded, and replied to.
+Today's best interactive computer
+systems provide a variety of word-processing and information
+handling capabilities.
+The message handling facilities should be
+well integrated with the rest of the system, so as to be a
+graceful extension of overall system capability.
+.pp
+The message system described in this report, MH, provides most of the
+features that can be found in other message systems and also
+incorporates some new ones.
+It has been built on the UNIX time-sharing
+system,[2] a popular operating system for the DEC PDP-11
+and VAX classes of computers.
+A \*(lqsecure\*(rq operating
+system similar to UNIX is currently being developed,[3]
+and that system will also run MH.
+.pp
+This report provides a complete description of MH and
+thus may serve as a user's manual, although parts of the report
+will be of interest to non-users as well.
+Sections 2 and 3, the
+Overview and Tutorial, present the key
+ideas of MH and will give those not familiar with message systems
+an idea of what such systems are like.
+.pp
+MH consists of a set of commands which use some special
+files and conventions.
+Section 4 covers the information
+a user needs to know in addition to the
+commands.
+The final section, Sec. 5, describes each of
+the MH commands in detail.
+A summary of the commands is given in
+Appendix A, and Appendixes B and C describe the ARPANET
+conventions for messages (we expect that many users of MH
+will be using the ARPANET) and the formal syntax of such
+messages, respectively.
+Finally, Appendix D provides
+an illustration of how MH commands may be used in
+conjunction with other UNIX facilities.
+.pp
+A novel approach has been taken in the design of MH.
+The
+design concept will be reported in detail in a forthcoming Rand
+report, but it can be described briefly as follows.
+Instead of creating a large subsystem that appears as a single
+command to the user, (such as MS[4])
+MH is a collection of separate commands
+which are run as separate programs.
+The file and directory
+system of UNIX are used directly.
+Messages are stored as
+individual files (datasets), and collections of them are grouped
+into directories.
+In contrast, most other message systems store
+messages in a complicated data structure within a monolithic
+file.
+With the MH approach, UNIX commands can be
+interleaved with commands invoking the functions of the message
+handler.
+Conversely, existing UNIX commands
+can be used in connection with messages.
+For
+example, all the usual UNIX editing, text-formatting, and printing
+facilities can be applied directly to individual messages.
+MH,
+therefore, consists of a relatively small amount of new code; it
+makes extensive use of other UNIX software to provide the
+capabilities found in other message systems.
+.+c OVERVIEW
+.pp
+There are three main aspects of MH: the way messages are
+stored (the message database), the user's profile (which directs
+how certain actions of the message handler take place), and the
+commands for dealing with messages.
+.pp
+Under MH, each message is stored as a separate file.
+A user
+can take any action with a message that he could with an ordinary
+file in UNIX.
+A UNIX directory in which messages are stored is
+called a folder.
+Each folder contains some standard entries to support
+the message-handling functions.
+The messages in a folder have numerical
+names.
+These folders (directories)
+are entries in a particular directory path, described in
+the user profile, through which MH can find message folders.
+Using the UNIX \*(lqlink\*(rq facility, it is possible for one copy of a
+message to be \*(lqfiled\*(rq in more than one folder, providing a
+message index facility.
+Also, using the UNIX tree-structured
+file system, it is possible to have a folder within a folder.
+This two-level organization provides a \*(lqselection-list\*(rq
+facility, with the full power of the MH commands available on
+selected sublists of messages.
+.pp
+Each user of MH has a user profile, a file in his $HOME (initial
+login)
+directory called \*(lq\*.mh\(ruprofile\*(rq.
+This profile contains several
+pieces of information used by the MH commands: a
+path name to the directory that contains the message folders,
+information concerning which folder the user last referenced (the
+\*(lqcurrent\*(rq folder), and parameters that tailor MH commands
+to the individual user's requirements.
+It also contains
+most of the necessary state information concerning how
+the user is dealing with his messages, enabling MH to be
+implemented as a set of individual UNIX commands, in contrast to the
+usual approach of a monolithic subsystem.
+.pp
+In MH, incoming mail is appended
+to the end of a file called \*.mail in a user's $HOME
+directory.
+The user adds the new messages to his collection of MH messages
+by invoking the command
+.i inc .
+.i Inc
+(incorporate) adds the new
+messages to a folder called \*(lqinbox\*(rq, assigning them names which
+are consecutive integers starting with the next highest integer
+available in inbox.
+.i Inc
+also produces a
+.i scan
+summary of
+the messages thus incorporated.
+.pp
+There are four commands for examining the messages in a
+folder:
+.i show ,
+.i prev ,
+.i next ,
+and
+.i scan .
+.i Show
+displays a
+message in a folder,
+.i prev
+displays the message preceding the
+current message, and
+.i next
+displays the message following the
+current message.
+.i Scan
+summarizes the messages in a folder,
+producing one line per message, showing who the message is from,
+the date, the subject, etc.
+.pp
+The user may move a message from one folder to another with
+the command
+.i file .
+Messages may be removed from a folder
+by means of the command
+.i rmm .
+In addition, a user may query
+what the current folder is and may specify that a new folder
+become the current folder, through the command
+.i folder .
+.pp
+A set of messages based on content may be selected by
+use of the command
+.i pick .
+This command searches through
+messages in a folder and selects those that match a given
+criterion.
+A subfolder is created within the original folder,
+containing links to all the messages that satisfy the selection
+criteria.
+.pp
+A message folder (or subfolder) may be removed by means of
+the command
+.i rmf .
+.pp
+There are five commands enabling the user to create new
+messages and send them:
+.i comp ,
+.i dist ,
+.i forw ,
+.i repl ,
+and
+.i send .
+.i Comp
+provides the facility for the user to compose a
+new message;
+.i dist
+redistributes mail to additional addressees;
+.i forw
+enables the user to forward messages; and
+.i repl
+facilitates the generation of a reply to an incoming message.
+If
+a message is not sent directly by one of these commands, it may
+be sent at a later time using the command
+.i send .
+.pp
+All of the elements summarized above
+are described in more detail in the following sections.
+Many of the
+normal facilities of UNIX provide additional capabilities for
+dealing with messages in various ways.
+For example, it is
+possible to print messages
+on the line-printer without requiring any additional code within
+MH.
+Using standard UNIX facilities, any terminal output can be
+redirected to a file for repeated or future viewing.
+In general,
+the flexibility and capabilities of the UNIX interface with the
+user are preserved as a result of the integration of MH into the UNIX
+structure.
+.+c TUTORIAL
+.pp
+This tutorial provides a brief introduction to the MH commands.
+It should be sufficient
+to allow the user to read his mail, do some simple manipulations of
+it, and create and send messages.
+.pp
+A message has two major pieces: the
+header and the body.
+The body consists of the text of the message
+(whatever you care to type in).
+It follows the header and is separated from
+it by an empty line.
+(When you compose a message, the form that appears
+on your terminal shows a line of dashes after the header.
+This is for
+convenience and is replaced by an empty line when the message is
+sent.) The header is composed of several components, including the
+subject of the message and the person to whom it is addressed.
+Each component starts with a name
+and a colon; components must not start with a blank.
+The text of the
+component may take more than one line, but each continuation line must
+start with a blank.
+Messages typically have \*(lqto:\*(rq, \*(lqcc:\*(rq, and
+\*(lqsubject:\*(rq components.
+When composing a message, you should include
+the \*(lqto:\*(rq and \*(lqsubject:\*(rq components; the \*(lqcc:\*(rq (for people
+you want to send copies to) is not necessary.
+.pp
+The basic MH commands are
+.i inc ,
+.i scan ,
+.i show ,
+.i next ,
+.i prev ,
+.i rmm ,
+.i comp ,
+and
+.i repl .
+These are described below.
+
+.i inc
+.pp
+When you get the message \*(lqYou have mail\*(rq, type the command
+.i inc .
+You will get a \*(lqscan listing\*(rq such as:
+
+.nf
+.if t .ta .4i 1.0i 2i
+.if n .ta .4i 1.2i 3i
+^7+~^^\07/13~^^Cas~^revival of measurement work
+^8~^^10/\09~^^Norm~^NBS people and publications
+^9~^^11/26~^^To:norm~^question \*(<<Are there any functions
+.re
+.fi
+.pp
+This shows the messages you received since the last time you
+executed this command (
+.i inc
+adds these new messages to
+your inbox folder).
+You can see this list again, plus a list of any
+other messages you have, by using the
+.i scan
+command.
+
+.i scan
+.pp
+The scan listing shows the message number, followed by the
+date and the sender.
+(If you are the sender, the addressee in the \*(lqto:\*(rq
+component is displayed.
+You may send yourself a message by including
+your name among the \*(lqto:\*(rq or \*(lqcc:\*(rq addressees.)
+It also shows the message's subject; if
+the subject is short, the first part of the body of the message is
+included after the characters \*(<<.
+
+.ne 5
+.i show
+.pp
+This command shows the current message, that is,
+the first one of the new messages after an
+.i inc .
+If the message is not
+specified by name (number), it is
+generally the last message referred to by an MH command.
+For example,
+
+.ta 1i
+.ti .5i
+^\fIshow\fP\05~^will show message 5.
+.pp
+You can use the show command to copy a message or print a
+message.
+
+.(b L
+.in .5i
+.if t .ta 1i
+.if n .ta 1.5i
+^\fIshow\fR\0>\0\fIx\fR~^will copy the message to file x.
+.br
+^\fIshow\fR\0|\0\fIprint\fR~^will print the message, using the \fIprint\fR command.
+.br
+^\fInext\fR~^will show the message that follows the current message.
+.br
+^\fIprev\fR~^will show the message previous to the current message.
+.br
+^\fIrmm\fR~^will remove the current message.
+.br
+^\fIrmm\03\fR~^will remove message 3.
+.)b
+
+.ne 5
+.i comp
+.pp
+The
+.i comp
+command puts you in the editor to write or edit a message.
+Fill in or
+delete the \*(lqto:\*(rq, \*(lqcc:\*(rq, and \*(lqsubject:\*(rq fields, as appropriate, and
+type the body of the message.
+Then
+exit normally from the editor.
+You will be asked
+\*(lqWhat now?\*(rq.
+Type a carriage return to see the options.
+Typing \fBsend\fR
+will cause the message to be sent; typing \fBquit\fR will cause an exit
+from
+.i comp ,
+with the message draft saved.
+.pp
+If you quit without sending the message, it will be saved in a file
+called /usr/<name>/Mail/draft (where /usr/<name> is your $HOME directory).
+You can edit this file and send the message later, using the
+.i send
+command.
+
+.ne 4
+.i "comp\0\-editor\0prompter"
+.pp
+This command uses a different editor and is useful for preparing
+\*(lqquick and dirty\*(rq messages.
+It prompts you for each component of the
+header.
+Type the information for that component, or type a carriage
+return to omit the component.
+After that, type the body of the
+message.
+Backspacing is the only form of editing allowed with this editor.
+When the body is complete, type a carriage return followed by <CTRL-D>
+(<OPEN> on Ann Arbor terminals).
+This completes the initial preparation of the message; from then on, use
+the same procedures as with
+.i comp
+(above).
+
+.ne 5
+.i repl
+.br
+.i "repl\0n"
+.pp
+This command makes up an initial message form with a header
+that is appropriate for
+replying to an existing message.
+The message being answered is the
+current message if no message number is mentioned, or n if a number
+is specified.
+After the header is completed, you can finish the message as in
+.i comp
+(above).
+.pp
+This is enough information to get you going using MH.
+There are more commands,
+and the commands described here have more features.
+Subsequent sections
+explain MH in complete detail.
+The system is quite powerful if you
+want to use its sophisticated features, but the foregoing commands
+suffice for sending and receiving messages.
+.pp
+There are numerous additional capabilities you may wish to explore.
+For example, the
+.i pick
+command will select a subset of messages
+based on specified criteria such as sender or subject.
+Groups of
+messages may be designated, as described in Sec. V, under \*(lqMessage
+Naming\*(rq.
+The file \*(lq\*.mh\(ruprofile\*(rq can be used to tailor your use of
+the message system to your needs and preferences, as described in Sec. V,
+under \*(lqThe User Profile\*(rq.
+In general, you may
+learn additional features of the system selectively, according to your
+requirements,
+by studying the relevant sections of this manual.
+There is no need to
+learn all the details of the system at once.
+.+c "DETAILED DESCRIPTION"
+.pp
+This section describes the MH system in detail, including the components
+of the user profile, the conventions for message naming, and some of
+the other MH conventions.
+Readers who are
+generally familiar with computer systems will be able to follow
+the principal ideas, although some details may be meaningful only to
+those familiar with UNIX.
+.uh "THE USER PROFILE"
+.pp
+The first time an MH command is issued by a new user, the system
+prompts for a \*(lqpath\*(rq and creates an MH \*(lqprofile\*(rq.
+.pp
+Each MH user has a profile which contains current
+state information for the MH package and, optionally, tailoring
+information for each individual program.
+When a folder becomes
+the current folder, it is recorded in the user's profile.
+Other profile entries control the MH path (where folders and
+special files are kept), folder and message protections, editor
+selection, and default arguments for each MH program.
+.pp
+The MH profile is stored in the file \*(lq\*.mh\(ruprofile\*(rq in the
+user's $HOME directory.
+It has the format of a message without
+any body.
+That is, each profile entry is on one line, with a
+keyword followed by a colon (:) followed by text particular to
+the keyword.
+.br
+\(rh\ \ \&
+.i "This file must not have blank lines."
+.br
+The keywords
+may have any combination of upper and lower case.
+(See Appendix
+B for a description of message formats.)
+.pp
+For the average MH user, the only profile entry of
+importance is \*(lqPath\*(rq.
+Path specifies a directory in which MH
+folders and certain files such as \*(lqdraft\*(rq are found.
+The
+argument to this keyword must be a legal UNIX path that names an
+existing directory.
+If this path is unrooted (i.e., does not
+begin with a \fB/\fR), it will be presumed to start from the
+user's $HOME directory.
+All folder and message references within
+MH will relate to this path unless full path names are used.
+.pp
+Message protection defaults to 664, and folder protection to
+751.
+These may be changed by profile entries \*(lqMsg-Protect\*(rq
+and \*(lqFolder-Protect\*(rq, respectively.
+The argument to these
+keywords is an octal number which is used as the UNIX file mode.\**
+.(f
+\**See
+.i chmod (I)
+in the
+.i "UNIX Programmer's Manual" .[5]
+.)f
+.pp
+When an MH program starts running, it looks through the
+user's profile for an entry with a keyword matching the program's
+name.
+For example, when
+.i comp
+is run, it looks for a \*(lqcomp\*(rq
+profile entry.
+If one is found, the text of the profile entry is
+used as the default switch setting until all defaults are overridden
+by explicit switches passed to the program as arguments.
+Thus the profile
+entry \*(lqcomp:\0\-form\0standard.list\*(rq would direct
+.i comp
+to use the
+file \*(lqstandard.list\*(rq as the message skeleton.
+If an explicit
+form switch is given to the
+.i comp
+command, it will override the
+switch obtained from the profile.
+.pp
+In UNIX, a program may exist under several names, either by
+linking or aliasing.
+The actual invocation name is used by an MH
+program when scanning for its profile defaults.
+Thus, each MH program
+may have several names by which it can be invoked, and each name
+may have a different set of default switches.
+For example, if
+.i comp
+is invoked by the name
+.i icomp ,
+the profile entry
+\*(lqicomp\*(rq will control the default switches for this invocation of
+the
+.i comp
+program.
+This provides a powerful
+definitional facility for commonly used switch settings.
+.pp
+The default editor
+for editing within
+.i comp ,
+.i repl ,
+.i forw ,
+and
+.i dist ,
+is \*(lq/bin/ned\*(rq.\**
+.(f
+\**See Ref. 6 for a description of
+the NED text editor.
+.)f
+A different editor may be used by specifying
+the profile entry
+\*(lqEditor: \*(rq.
+The argument to \*(lqEditor\*(rq is the name of an
+executable program or shell command file which can be found via
+the user's $PATH defined search path, excluding the current
+directory.
+The \*(lqEditor:\*(rq profile specification
+may in turn be overridden by a \*(lq\-editor\0<editor>\*(rq
+profile switch associated with
+.i comp ,
+.i repl ,
+.i forw ,
+or
+.i dist .
+Finally, an explicit editor switch specified with any
+of these four commands will have ultimate precedence.
+.pp
+During message composition, more than one editor may be
+used.
+For example, one editor (such as
+.i prompter )
+may be used
+initially, and a second editor may be invoked later to revise
+the message being composed
+(see the discussion of
+.i comp
+in Section 5 for details).
+A profile entry \*(lq<lasteditor>\-next:\0<editor>\*(rq specifies the name of
+the editor to be used after a particular editor.
+Thus \*(lqcomp:\0\-e\0prompter\*(rq
+causes the initial text to be collected by
+.i prompter ,
+and the profile entry \*(lqprompter\-next:\0ed\*(rq names ed as the
+editor to be invoked for the next round of editing.
+.pp
+Some of the MH commands, such as
+.i show ,
+can be used on
+message folders owned by others, if those folders are readable.
+However,
+you cannot write in someone else's folder.
+All the MH command
+actions not requiring write permission may be used with
+a \*(lqread-only\*(rq folder.
+In a writable folder, a file named
+\*(lqcur\*(rq is used to contain its current message name.
+For read-only folders, the current message name is
+stored in the user's profile.
+.pp
+Table 1 lists examples of the currently defined profile
+entries, typical arguments, and the programs that reference the
+entries.
+.in .9i
+.ll -.9i
+.ta 2.3i
+.sp 30p
+.ce
+Table 1
+.sp 8p
+.ce
+P\s-2ROFILE\s0 C\s-2OMPONENTS\s0
+.hl \" ~12p preceding + 1v (12p) after
+.nf
+^^MH Programs that
+^Keyword and Argument~^\ Use Component\h'|\n(.lu-.9i'\v'4p'\l'|0'\v'-4p' \" \l'..' does underlining
+.sp
+^Path:\0Mail~^All
+^Current-Folder:\0inbox~^Most
+^Editor:\0/bin/ed~^\fIcomp, dist, forw, repl\fR
+^Msg\-Protect:\0644~^\fIinc\fR
+^Folder\-Protect:\0711~^\fIfile, inc, pick\fR
+^<program>:\0default switches~^All
+^cur\-<read-onlyfolder>:\0172~^Most
+^prompter\-next:\0ed~^\fIcomp, dist, forw, repl\fR
+.hl
+.ll +.9i
+.in 0
+.fi
+.pp
+Path
+.u should
+be present.
+Folder is maintained
+automatically by many MH commands (see the \*(lqContext\*(rq sections of
+the individual commands in Sec. V).
+All other entries are optional,
+defaulting to the values described above.
+.uh "MESSAGE NAMING"
+.pp
+Messages may be referred to explicitly or implicitly when
+using MH commands.
+A formal syntax of message names is given in Appendix C, but the
+following description should be sufficient for most MH users.
+Some details of message naming that apply only to certain
+commands are included in the description of those
+commands.
+.pp
+Most of the MH commands accept arguments specifying one or
+more folders, and one or more messages to operate on.
+The use of
+the word \*(lqmsg\*(rq as an argument to a command means that exactly one
+message name may be specified.
+A message name may be a number,
+such as 1, 33, or 234, or it may be
+one of the \*(lqreserved\*(rq message names:
+first, last, prev, next, and cur.
+(As a shorthand, a
+period (\*.) is equivalent to cur.)
+The meanings of these names
+are straightforward: \*(lqfirst\*(rq is the first message in the
+folder; \*(lqlast\*(rq is the last
+message in the folder; \*(lqprev\*(rq is the
+message numerically previous to the current message; \*(lqnext\*(rq
+is the message numerically following the current message; \*(lqcur\*(rq
+(or \*(lq\*.\*(rq) is the current message in the folder.
+.pp
+The default in commands that take a \*(lqmsg\*(rq argument is
+always \*(lqcur\*(rq.
+.pp
+The word \*(lqmsgs\*(rq indicates that several messages may be
+specified.
+Such a specification consists of several message
+designations separated by spaces.
+A message designation is
+either a message name or a message range.
+A message range is a
+specification of the form name1\-name2 or name1:n, where name1 and
+name2 are message names and n is an integer.
+The first form
+designates all the messages from name1 to name2 inclusive; this
+must be a non-empty range.
+The second form specifies up to n
+messages, starting with name1 if name1 is a number, or first,
+cur, or next, and ending with name1 if name1 is last or
+prev.
+This interpretation of n is overridden if n is preceded
+by a plus sign or a minus sign;
++n always means up to n messages starting with
+name1, and \-n always means up to n messages ending with name1.
+Repeated specifications of the same message have the same effect
+as a single specification of
+the message.
+Examples of
+specifications are:
+
+.(b
+1 5 7\-11 22
+first 6 8 next
+first\-10
+last:5
+.)b
+.pp
+The message name \*(lqall\*(rq is a shorthand for \*(lqfirst\-last\*(rq,
+indicating all of the messages in the folder.
+.pp
+The limit on the number of messages in an expanded message
+list is generally 999\*-the maximum number of messages in a
+folder.
+However, the
+.i show
+command and the
+commands `\fIpick\0\-scan\fR' and `\fIpick\0\-show\fR'
+are constrained to have argument lists
+that are no more than 512 characters long.
+(Under Version 7 UNIX this limit is 4096.)
+.pp
+In commands that accept \*(lqmsgs\*(rq arguments, the default is
+either cur or all, depending on which makes more sense.
+.pp
+In all of the MH commands, a plus sign preceding an argument
+indicates a folder name.
+Thus, \*(lq+inbox\*(rq is the name of the
+user's standard inbox.
+If an explicit folder argument is given
+to an MH command, it will become the current folder (that is,
+the \*(lqCurrent-Folder:\*(rq entry
+in \*(lq\*.mh\(ruprofile\*(rq will be changed to this
+folder).
+In the case of the
+.i file
+and
+.i pick
+commands, which
+can have multiple output folders, a new source folder (other than
+the default current folder) is specified by \*(lq\-src\0+folder\*(rq.
+.uh "OTHER MH CONVENTIONS"
+.pp
+One very powerful feature of MH is that the MH commands may
+be issued from any current directory, and the proper path to
+the appropriate folder(s) will be taken from the user's profile.
+If the MH path is not appropriate for a specific folder or file,
+the automatic prepending of the MH path can be avoided by
+beginning a folder or file name with \fB/\fR.
+Thus any specific full
+path may be specified.
+.pp
+Arguments to the various programs may be given in any order,
+with the exception of a few switches whose arguments must follow
+immediately, such as \*(lq\-src\0+folder\*(rq for \fIpick\fR and \fIfile\fR.
+.pp
+Whenever an MH command prompts the user, the valid options
+will be listed in response to a <RETURN>.
+(The first of the
+listed options is the default if end-of-file is encountered, such
+as from a command file.) A valid response is any \fIunique\fR
+abbreviation of one of the listed options.
+.pp
+Standard UNIX documentation conventions are used in this report
+to describe MH command syntax.
+Arguments enclosed in brackets
+([ ]) are optional; exactly one of the arguments enclosed
+within braces ({ }) must be specified, and all other
+arguments are required.
+The use of ellipsis dots (...) indicates
+zero or more repetitions of the previous item.
+For example,
+\*(lq+folder ...\*(rq would indicate that one or more \*(lq+folder\*(rq arguments
+is required and \*(lq[+folder ...]\*(rq indicates that 0 or more
+\*(lq+folder\*(rq arguments may be given.
+.pp
+MH departs from UNIX standards by using switches that consist of
+more than one character, e.g. \*(lq\-header\*(rq.
+To minimize typing,
+only a unique abbreviation of a switch need be typed; thus, for
+\*(lq\-header\*(rq, \*(lq\-hea\*(rq is probably sufficient, depending on the
+other switches the command accepts.
+Each MH program
+accepts the switch \*(lq\-help\*(rq (which \fImust\fR be spelled out fully)
+and produces a syntax description and a list of switches.
+In the
+list of switches, parentheses indicate required characters.
+For example, all \*(lq\-help\*(rq switches will appear as \*(lq\-(help)\*(rq,
+indicating that no abbreviation is accepted.
+.pp
+Many MH switches have both on and off forms, such as
+\*(lq\-format\*(rq and \*(lq\-noformat\*(rq.
+In many of the descriptions in Sec. V,
+only one form is defined; the other form, often used to
+nullify profile switch settings, is assumed to be the opposite.
+.br
+.bp
+.uh "MH COMMANDS"
+.pp
+The MH package comprises 16 programs:
+
+.nf
+.in .5i
+.ta 1.5i
+^comp~^Compose a message
+^dist~^Redistribute a message
+^file~^Move messages between folders
+^folder~^Select/list status of folders
+^forw~^Forward a message
+^inc~^Incorporate new mail
+^next~^Show the next message
+^pick~^Select a set of messages by context
+^prev~^Show the previous message
+^prompter~^Prompting editor front end for composing messages
+^repl~^Reply to a message
+^rmf~^Remove a folder
+^rmm~^Remove messages
+^scan~^Produce a scan listing of selected messages
+^send~^Send a previously composed message
+^show~^Show messages
+.fi
+.re
+.pp
+These programs are described below.
+The form of the descriptions
+conforms to the standard
+form for the description of UNIX commands.
+.if t \{
+.ll 6.5i
+.lt 6.5i
+\}
+.fo '7th Edition'UNIX/32V(Rand)''
+.de SC
+.he '\\$1(1)'-%-'\\$1(1)'
+.bp
+.(x
+.ti .8i
+\\$1
+.)x
+..
+.de NA
+.b \\s-2NAME\\s0
+.ti .5i
+..
+.de SY
+.sp
+.b \\s-2SYNOPSIS\\s0
+.in 1i
+.ti .5i
+.na
+..
+.de DE
+.ad
+.sp
+.in 0
+.b \\s-2DESCRIPTION\\s0
+.sp
+.fi
+.in .5i
+..
+.de Fi
+.(b L
+.ti 0
+.b \\s-2Files\\s0
+.ta 2i
+..
+.de Pr
+.)b
+.(b L F
+.in 2.5i
+.ti 0
+.b "\\s-2Profile Components\\s0"
+.ti .5i
+..
+.de Ps
+.ti .5i
+..
+.de De
+.)b
+.(b L
+.in .5i
+.ti 0
+.b \\s-2Defaults\\s0
+..
+.de Co
+.)b
+.(b L F
+.ti 0
+.b \\s-2Context\\s0
+.br
+..
+.de En
+.)b
+.in 0
+..
+.SC COMP
+.NA
+comp \- compose a message
+
+.SY
+comp \%[\-editor\ editor] \%[\-form\ formfile] \%[file] \%[\-use]
+\%[\-nouse] \%[\-help]
+
+.DE
+\fIComp\fP is used to create a new message to be mailed.
+If
+\fIfile\fP is not specified, the file named \*(lqdraft\*(rq in the user's MH
+directory will be used.
+\fIComp\fR copies a message form to
+the file being composed and then invokes an editor on the
+file.
+The default editor is /bin/ned, which may be overridden with
+the `\-editor' switch or with a profile entry \*(lqEditor:\*(rq.
+(See Ref. 5 for a
+description of the NED text editing system.)
+The default
+message form contains the following elements:
+
+ To:
+ cc:
+ Subject:
+ ----------
+
+If the file named \*(lqcomponents\*(rq exists in the user's MH directory,
+it will be used instead of this form.
+If `\-form
+formfile' is specified, the specified formfile (from the MH
+directory) will be used as the skeleton.
+The line of dashes
+or a blank line must be left between the header and the
+body of the message for the message to be identified properly when it is
+sent (see \fIsend;\fR).
+The switch `\-use' directs \fIcomp\fR to
+continue editing an already started message.
+That is, if a
+\fIcomp\fR (or \fIdist\fR, \fIrepl\fR, or \fIforw\fR) is terminated without
+sending the message, the message can be edited again via
+\*(lqcomp \-use\*(rq.
+
+If the specified file (or draft) already exists, \fIcomp\fR will ask
+if you want to delete it before continuing.
+A reply of \fBNo\fR will abort the
+\fIcomp\fR, \fByes\fR will replace the existing draft with a blank
+skeleton, \fBlist\fR will display the draft, and \fBuse\fR will use it
+for further composition.
+
+Upon exiting from the editor, \fIcomp\fR will ask \*(lqWhat now?\*(rq.
+The valid
+responses are \fBlist\fR, to list the draft on the terminal; \fBquit\fR, to
+terminate the session and preserve the draft; \fBquit delete\fR, to terminate,
+then delete the draft; \fBsend\fR, to send the message; \fBsend verbose\fR, to
+cause the delivery process to be monitored; \fBedit <editor>\fR, to invoke
+<editor> for further editing; and \fBedit\fR, to re-edit using the
+same editor that was used on the preceding round unless a profile
+entry \*(lq<lasteditor>\-next: <editor>\*(rq names an alternative editor.
+
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`file' defaults to draft
+`\-editor' defaults to /bin/ned
+`\-nouse'
+.Co
+\fIComp\fR does not affect either the current folder or the current message.
+.En
+.SC DIST
+.NA
+dist \- redistribute a message to additional addresses
+.SY
+dist \%[+folder] \%[msg] \%[\-form\ formfile] \%[\-editor\ editor]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+.DE
+\fIDist\fR is similar to \fIforw\fR.
+It prepares the specified
+message for redistribution to addresses that (presumably) are
+not on the original address list.
+The file \*(lqdistcomps\*(rq in the
+user's MH directory, or a standard form, or the file specified by
+`\-form formfile' will be used as the blank components file to
+be prepended to the message being distributed.
+The standard form
+has the components \*(lqDistribute-to:\*(rq and \*(lqDistribute-cc:\*(rq.
+When
+the message is sent, \*(lqDistribution-Date:\0date\*(rq,
+\*(lqDistribution-From:\0name\*(rq, and
+\*(lqDistribution-Id:\0id\*(rq (if `\-msgid' is
+specified to \fIsend\fR;) will be prepended to the outgoing message.
+Only those addresses in \*(lqDistribute-To\*(rq, \*(lqDistribute-cc\*(rq, and
+\*(lqDistribute-Bcc\*(rq will be sent.
+Also, a \*(lqDistribute-Fcc:\0folder\*(rq
+will be honored (see \fIsend;\fR).
+
+\fISend\fR recognizes a message as a redistribution message by the
+existence of the field \*(lqDistribute-To:\*(rq, so don't try to
+redistribute a message with only a \*(lqDistribute-cc:\*(rq.
+
+If the `\-annotate' switch is given, each message being
+distributed will be annotated with the lines:
+
+ Distributed:\0\*(<<date\*(>>
+ Distributed:\0Distribute-to: names
+
+where each \*(lqto\*(rq list contains as many lines as required.
+This annotation
+will be done only if the message is sent directly from \fIdist\fR.
+If the
+message is not sent immediately from \fIdist\fR (i.e., if it is sent later
+via \fIsend;\fR),
+\*(lqcomp \-use\*(rq may be used to re-edit and send the constructed message, but
+the annotations won't take place.
+The '\-inplace' switch causes annotation to
+be done in place in order to preserve links to the annotated message.
+
+See \fIcomp\fR for a description of the `\-editor' switch and for options
+upon exiting from the editor.
+
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`+folder' defaults to the current folder
+`msg' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a +folder is specified, it will become the current
+folder, and the current message will be set to the message
+being redistributed.
+.En
+.SC FILE
+.NA
+file \- file message(s) in (an)other folder(s)
+.SY
+file \%[\-src\ +folder] \%[msgs] \%[\-link] \%[\-preserve] \%+folder\ ...
+\%[\-nolink] \%[\-nopreserve]
+\%[\-file\ file] \%[\-nofile] \%[\-help]
+.DE
+\fIFile\fR moves (\fImv\fR(I)) or links (\fIln\fR(I)) messages from a
+source folder into one or more destination folders.
+If you think
+of a message as a sheet of paper, this operation is not
+unlike filing the sheet of paper (or copies) in file cabinet
+folders.
+When a message is filed, it is linked into the
+destination folder(s) if possible, and is copied otherwise.
+As long
+as the destination folders are all on the same file system, multiple filing
+causes little storage overhead.
+This facility provides a good way to cross-file or multiply-index
+messages.
+For example, if a message is received from Jones about
+the ARPA Map Project, the command
+
+ file\0cur\0+jones\0+Map
+
+would allow the message to be found in either of the two
+folders `jones' or `Map'.
+
+The option `\-file file' directs \fIfile\fR to use the specified
+file as the source message to be filed, rather than a message from
+a folder.
+
+If a destination folder doesn't exist, \fIfile\fR will ask if you
+want to create one.
+A negative response will abort the file
+operation.
+
+`\-link' preserves the source folder copy of the message
+(i.e., it does a \fIln\fR(I) rather than a \fImv\fR(I)), whereas,
+`\-nolink' deletes the \*(lqfiled\*(rq messages from the source
+folder.
+Normally, when a message is filed, it is assigned the
+next highest number available in each of the destination folders.
+Use of the `\-preserve' switch will override this message
+\*(lqrenaming\*(rq, but name conflicts may occur, so
+use this switch cautiously.
+(See \fIpick\fR for more details on
+message numbering.)
+
+If `\-link' is not specified (or `\-nolink' is specified),
+the filed messages will be removed (unlink(II)) from the
+source folder.
+
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.Ps
+^Folder\-Protect:~^To set mode when creating a new folder
+.De
+`\-src +folder' defaults to the current folder
+`msgs' defaults to cur
+`\-nolink'
+`\-nopreserve'
+`\-nofile'
+.Co
+If `\-src +folder' is given, it will become the
+current folder for future MH commands.
+If neither `\-link' nor
+`all' are specified, the current message in the source
+folder will be set to the last message specified; otherwise, the
+current message won't be changed.
+.En
+.SC FOLDER
+.NA
+folder \- set/list current folder/message
+.SY
+folder \%[+folder] \%[msg] \%[\-all] \%[\-fast] \%[\-nofast] \%[\-up] \%[\-down]
+\%[\-header] \%[\-noheader] \%[\-total] \%[\-nototal] \%[\-pack] \%[\-nopack]
+\%[\-help]
+
+.ti .5i
+folders <equivalent to 'folder \-all'>
+.DE
+Since the MH environment is the shell, it is easy to lose
+track of the current folder from day to day.
+\fIFolder\fR will
+list the current folder, the number of messages in it, the
+range of the messages (low-high), and the current message within
+the folder, and will flag a selection list or extra files if they
+exist.
+An example of the output is:
+
+ inbox+ has 16 messages ( 3\- 22); cur= 5.
+
+If a `+folder' and/or `msg' are specified, they will
+become the current folder and/or message.
+An `\-all' switch
+will produce a line for each folder in the user's MH directory,
+sorted alphabetically.
+These folders are preceded by the read-only
+folders, which occur as \*.mh\(ruprofile \*(lqcur\-\*(rq entries.
+For example,
+
+.nf
+.ta 1.5i 2.1i 2.7i 3.5i
+^~Folder\ \ ^^~#\ of\ ^^messages~^^(~\ range\~ );\ ^cur msg (other files)
+^~/fsd/rs/m/tacc\ \ ^^has~35\ ^^messages~^^(~1\-\035);\ ^cur=\ 23.
+^~/rnd/phyl/Mail/EP\ \ ^^has~82\ ^^messages~^^(~1\-108);\ ^cur=\ 82.
+^~f\&f\ \ ^^has~4\ ^^messages~^^(~1\-\0\04);\ ^cur=\ \01.
+^~inbox+\ ^^has~16\ ^^messages~^^(~3\-\022);\ ^cur=\ \05.
+^~mh\ \ ^^has~76\ ^^messages~^^(~1\-\076);\ ^cur=\ 70.
+^~notes\ \ ^^has~2\ ^^messages~^^(~1\-\0\02);\ ^cur=\ \01.
+^~ucom\ \ ^^has~124\ ^^messages~^^(~1\-124);\ ^cur=\ \06; (select).
+
+^^^~TOTAL=\0339\ ^messages\0in\0\07\0Folders.
+.re
+.fi
+
+The \*(lq+\*(rq after inbox indicates that it is the current folder.
+The \*(lq(select)\*(rq indicates that the folder ucom has a selection
+list produced by \fIpick\fR.
+If \*(lqothers\*(rq had appeared in parentheses at
+the right of a line, it would indicate that there are files in
+the folder directory that don't belong under the MH file naming
+scheme.
+
+The header is output if either an `\-all' or a `\-header' switch
+is specified; it is suppressed by `\-noheader'.
+Also, if \fIfolder\fR
+is invoked by a name ending with \*(lqs\*(rq (e.g., \fIfolders\fR),
+`\-all' is assumed.
+A `\-total' switch will produce only the
+summary line.
+
+If `\-fast' is given, only the folder name (or names in the
+case of `\-all') will be listed.
+(This is faster because the
+folders need not be read.)
+
+The switches `\-up' and `\-down' change the folder to be the
+one above or below the current folder.
+That is, \*(lqfolder \-down\*(rq
+will set the folder to \*(lq<current\-folder>/select\*(rq, and if the
+current folder is a selection-list folder, \*(lqfolder \-up\*(rq will
+set the current folder to the parent of the selection-list.
+(See \fIpick\fR for details on selection-lists.)
+
+The `\-pack' switch will compress the message names in a folder, removing
+holes in message numbering.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^/bin/ls~^To fast-list the folders
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to the current folder
+`msg' defaults to none
+`\-nofast'
+`\-noheader'
+`\-nototal'
+`\-nopack'
+.Co
+If `+folder' and/or `msg' are given, they will become the
+current folder and/or message.
+.En
+.SC FORW
+.NA
+forw \- forward messages
+.SY
+forw \%[+folder] \%[msgs] \%[\-editor\ editor] \%[\-form\ formfile]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+.DE
+\fIForw\fR may be used to prepare a message containing other
+messages.
+It constructs the new message from the components file
+or `\-form formfile' (see \fIcomp\fR), with a body composed of the
+message(s) to be forwarded.
+An editor is invoked as in \fIcomp\fR,
+and after editing is complete, the user is prompted before the message
+is sent.
+
+If the `\-annotate' switch is given, each message being
+forwarded will be annotated with the lines
+
+ Forwarded: \*(<<date\*(>>
+ Forwarded: To: names
+ Forwarded: cc: names
+
+where each \*(lqTo:\*(rq and \*(lqcc:\*(rq list contains as many lines as required.
+This annotation will be done only if the message is sent directly
+from \fIforw\fR.
+If the message is not sent immediately from \fIforw\fR,
+\*(lqcomp \-use\*(rq may be used in a later session to re-edit and send
+the constructed message, but the annotations won't take place.
+The `\-inplace' switch permits annotating a message in place in
+order to preserve its links.
+
+See \fIcomp\fR for a description of the `\-editor' switch.
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^Current-Folder:~^To find the default current folder
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`+folder' defaults to the current folder
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a +folder is specified, it will become
+the current folder, and the current message will be set to
+the first message being forwarded.
+.En
+.SC INC
+.NA
+inc \- incorporate new mail
+.SY
+inc \%[+folder] \%[\-audit\ audit-file] \%[\-help]
+.DE
+\fIInc\fR incorporates mail from the user's incoming mail drop
+(\*.mail) into an MH folder.
+If `+folder' isn't specified,
+the folder named \*(lqinbox\*(rq in the user's MH directory will be used.
+The
+new messages being incorporated are assigned numbers starting
+with the next highest number in the folder.
+If the specified (or
+default) folder doesn't exist, the user will be queried prior to
+its creation.
+As the messages are processed, a \fIscan\fR listing
+of the new mail is produced.
+
+If the user's profile contains a \*(lqMsg\-Protect: nnn\*(rq entry, it
+will be used as the protection on the newly created messages,
+otherwise the MH default of 664 will be used.
+During all
+operations on messages, this initially assigned protection will
+be preserved for each message, so \fIchmod\fR(I) may be used to set a
+protection on an individual message, and its protection will be
+preserved thereafter.
+
+If the switch `\-audit audit-file' is specified (usually as a
+default switch in the profile), then \fIinc\fR will append a header
+line and a line per message to the end of the specified
+audit-file with the format:
+
+.nf
+.ti 1i
+\*(<<inc\*(>> date
+.ti 1.5i
+<scan line for first message>
+.ti 1.5i
+<scan line for second message>
+.ti 2.5i
+<etc.>
+.fi
+
+This is useful for keeping track of volume and source of incoming
+mail.
+Eventually, \fIrepl\fR, \fIforw\fR, \fIcomp\fR, and \fIdist\fR may also
+produce audits to this (or another) file, perhaps with
+\*(lqMessage-Id:\*(rq information to keep an exact correspondence history.
+\*(lqAudit-file\*(rq will be in the user's MH directory unless a full
+path is specified.
+
+\fIInc\fR will incorporate even illegally formatted messages into the
+user's MH folder, inserting a blank line prior to the offending
+component and printing a comment identifying the bad message.
+
+In all cases, the \*.mail file will be zeroed.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^$HOME/\*.mail~^The user's mail drop
+^<mh-dir>/audit-file~^Audit trace file (optional)
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Folder\-Protect:~^For protection on new folders
+.Ps
+^Msg\-Protect:~^For protection on new messages
+.De
+`+folder' defaults to \*(lqinbox\*(rq
+.Co
+The folder into which the message is
+being incorporated will become the
+current folder, and the first message incorporated will be the
+current message.
+This leaves the context ready for a \fIshow\fR
+of the first new message.
+.En
+.SC NEXT
+.NA
+next \- show the next message
+.SY
+next \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+.DE
+\fINext\fR performs a \fIshow\fR on the next message in the
+specified (or current) folder.
+Like \fIshow\fR, it passes any
+switches on to the program \fIl\fR, which is called to list the
+message.
+This command is exactly equivalent to \*(lqshow next\*(rq.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+.Co
+If a folder is specified, it will become the current folder, and the
+message that is shown (i.e., the next message in sequence)
+will become the current message.
+.En
+.SC PICK
+.NA
+pick \- select messages by content
+.SY
+.ta .4i 1.8i
+.nf
+.in .5i
+^pick~^^\0\-cc~^ \%[\-src\ +folder] \%[msgs] \%[\-help] \%[\-scan] \%[\-noscan]
+^^^\0\-date~^ \%[\-show] \%[\-noshow] \%[\-nofile] \%[\-nokeep]
+^^^\0\-from~^
+^^^\s+2\b'\(lt\(bv\(bv\(lk\(bv\(bv\(lb'\s0 \-search~\s+2\b'\(rt\(bv\(bv\(rk\(bv\(bv\(rb'\s0^ pattern
+^^^\0\-subject~^
+^^^\0\-to~^ \%[\-file \%[\-preserve] \%[\-link] \%+folder\ ... \%[\-nopreserve] \%[\-nolink] ]
+^^^\0\-\-component~^ \%[\-keep \%[\-stay] \%[\-nostay] \%[+folder\ ...]\ ]
+.fi
+
+.re
+.ti .5i
+typically:
+.in 1i
+pick\0\-from\0jones\0\-scan
+.br
+pick\0\-to\0holloway
+.br
+pick\0\-subject\0ned\0\-scan\0\-keep
+.DE
+\fIPick\fR searches messages within a folder for the specified
+contents, then performs several operations on the selected
+messages.
+
+A modified \fIgrep\fR(I) is used to perform the searching, so the
+full regular expression (see \fIed\fR(I)) facility is available
+within `pattern'.
+With `\-search', pattern is used directly,
+and with the others, the grep pattern constructed is:
+
+.ti +.5i
+\*(lq^component:\*.\*(**pattern\*(rq
+
+This means that the pattern specified for a `\-search' will be
+found everywhere in the message, including the header and the body,
+while the other search requests are limited to the single
+specified component.
+The expression `\-\-component pattern'
+is a shorthand for
+specifying `\-search \*(lqcomponent:\*.\*(**pattern\*(rq\ '; it is used to pick
+a component not in the set [cc date from subject to].
+An
+example is \*(lqpick \-\-reply\-to pooh \-show\*(rq.
+
+Searching is performed on a per-line basis.
+Within the header of
+the message, each component is treated as one long line, but in
+the body, each line is separate.
+Lower-case letters in the
+search pattern will match either lower or upper case in the
+message, while upper case will match only upper case.
+
+Once the search has been performed, the selected messages
+are scanned (see \fIscan\fR) if the `\-scan' switch is given, and
+then they are shown (see \fIshow\fR) if the `\-show' switch is
+given.
+After these two operations, the file operations (if
+requested) are performed.
+
+The `\-file' switch operates exactly like the \fIfile\fR command, with the
+same meaning for the `\-preserve' and `\-link' switches.
+
+The `\-keep' switch is similar to `\-file', but it produces a folder that
+is a subfolder of the folder being searched and defines it as
+the current folder (unless the `\-stay' flag is used).
+This
+subfolder contains the messages which matched the search
+criteria.
+All of the MH commands may be used with the sub-folder
+as the current folder.
+This gives the user considerable power
+in dealing with subsets of messages in a folder.
+
+The messages in a folder produced by `\-keep' will always have the
+same numbers as they have in the source folder (i.e., the
+`\-preserve' switch is automatic).
+This way, the message
+numbers are consistent with the folder from which the messages
+were selected.
+Messages are not removed from the source folder
+(i.e., the `\-link' switch is assumed).
+If a `+folder' is not
+specified, the standard name \*(lqselect\*(rq will be used.
+(This is the
+meaning of \*(lq(select)\*(rq when it appears in the output of the
+\fIfolder\fR command.) If `+folder' arguments are given to
+`\-keep', they will be used rather than \*(lqselect\*(rq for the names
+of the subfolders.
+This allows for several subfolders to be
+maintained concurrently.
+
+When a `\-keep' is performed, the subfolder becomes the current folder.
+This can be overridden by use
+of the `\-stay' switch.
+
+Here's an example:
+
+.nf
+\01 % folder +inbox
+\02 inbox+ has 16 messages ( 3\- 22); cur= 3.
+\03 % pick \-from dcrocker
+\04 6 hits.
+\05 [+inbox/select now current]
+\06 % folder
+\07 inbox/select+ has \06 messages ( 3\- 16); cur= 3.
+\08 % scan
+.ds p \\h'\\w'+'u'
+\09 \03+ 6/20 Dcrocker Re: ned file update issue...
+10 \06\*p 6/23 Dcrocker removal of files from /tm...
+11 \08\*p 6/27 Dcrocker Problems with the new ned...
+12 13\*p 6/28 d\h'\w'D'u-\w'd'u'crocker newest nned \*(<<I would ap...
+13 15\*p 7/\05 Dcrocker nned \*(<<Last week I asked...
+14 16\*p 7/\05 d\h'\w'D'u-\w'd'u'crocker message id format \*(<<I re...
+15 % show all | print
+16 [produce a full listing of this set of messages on the line printer.]
+17 % folder \-up
+18 inbox+ has 16 messages ( 3\- 22); cur= 3; (select).
+19 % folder \-down
+20 inbox/select+ has 6 messages ( 3\- 16); cur= 3.
+21 % rmf
+22 [+inbox now current]
+23 % folder
+24 inbox+ has 16 messages ( 3\- 22); cur= 3.
+.fi
+
+This is a rather lengthy example, but it shows the power of the
+MH package.
+In item 1, the current folder is set to inbox.
+In 3,
+all of the messages from dcrocker are found in inbox and linked
+into the folder \*(lqinbox/select\*(rq.
+(Since no action switch is
+specified, `\-keep' is assumed.) Items 6 and 7 show that this
+subfolder is now the current folder.
+Items 8 through 14 are a
+\fIscan\fR of the selected messages (note that they are all from dcrocker
+and are all in upper and lower case).
+Item 15 lists all of the messages to
+the high-speed printer.
+Item 17 directs \fIfolder\fR to set the
+current folder to the parent of the selection-list folder, which
+is now current.
+Item 18 shows that this has been done.
+Item 19 resets
+the current folder to the selection list, and 21 removes the
+selection-list folder and resets the current folder to the
+parent folder, as shown in 22 and 23.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Folder\-Protect:~^For protection on new folders
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`\-src +folder' defaults to current
+`msgs' defaults to all
+.fi
+`\-keep +select' is the default if no `\-scan', `\-show', or `\-file' is specified
+.Co
+If a `\-src +folder' is specified, it will
+become the current folder, unless a `\-keep' with 0 or 1
+folder arguments makes the selection-list subfolder the
+current folder.
+Each selection-list folder will have its
+current message set to the first of the messages linked into
+it unless the selection list already existed, in which case the
+current message won't be changed.
+.En
+.SC PREV
+.NA
+prev \- show the previous message
+.SY
+prev \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+.DE
+\fIPrev\fR performs a \fIshow\fR on the previous message in the specified
+(or current) folder.
+Like \fIshow\fR, it passes any switches on to the
+program \fIl\fR, which is called to list the message.
+This command
+is exactly equivalent to \*(lqshow prev\*(rq.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+.Co
+If a folder is specified, it will become current, and the
+message that is shown (i.e., the previous message in sequence)
+will become the current message.
+.En
+.SC PROMPTER
+.NA
+prompter \- prompting editor front end
+.SY
+This program is not called directly but takes the place
+of an editor and acts as an editor front end.
+
+.ti .5i
+prompter \%[\-erase\ chr] \%[\-kill\ chr] \%[\-help]
+.DE
+\fIPrompter\fR is an editor which allows rapid composition of
+messages.
+It is particularly useful to network and low-speed
+(less than 2400 baud) users of MH.
+It is an MH program in that
+it can have its own profile entry with switches, but it can't
+be invoked directly as all other MH commands can; it is an editor
+in that it is invoked by an \*(lq\-editor prompter\*(rq switch or by the
+profile entry \*(lqEditor: prompter\*(rq, but functionally it is merely
+a text-collector and not a true editor.
+
+\fIPrompter\fR expects to be called from \fIcomp\fR, \fIrepl\fR, \fIdist\fR, or
+\fIforw\fR, with a draft file as an argument.
+For example, \*(lqcomp
+\-editor prompter\*(rq will call \fIprompter\fR with the file \*(lqdraft\*(rq already set
+up with blank components.
+For each blank component it finds in
+the draft, it prompts the user and accepts a response.
+A
+<RETURN> will cause the whole component to be left out.
+A \*(lq\\\*(rq
+preceding a <RETURN> will continue the response on the next line,
+allowing for multiline components.
+
+Any component that is non-blank will be copied and echoed to the
+terminal.
+
+The start of the message body is prompted by a line of
+dashes.
+If the body is non-blank, the prompt is
+\*(lq--------Enter additional text\*(rq.
+Message-body typing is terminated with
+a <CTRL-D> (or <OPEN>).
+Control is returned to the calling
+program, where the user is asked \*(lqWhat now?\*(rq.
+See \fIcomp\fR for
+the valid options.
+
+The line editing characters for kill and erase may be
+specified by the user via the arguments \*(lq\-kill chr\*(rq and \*(lq\-erase
+chr\*(rq, where chr may be a character; or \*(lq\\nnn\*(rq, where nnn is the
+octal value for the character.
+(Again, these may come from the
+default switches specified in the user's profile.)
+
+A <DEL> during message-body typing is equivalent to
+<CTRL-D> for compatibility with NED.
+A <DEL> during
+component typing will abort the command that invoked
+\fIprompter\fR.
+.Fi
+None
+.Pr
+^prompter-next:~^To name the editor to be used on exit from \fIprompter\fR
+.De
+.Co
+None
+.En
+.SC REPL
+.NA
+repl \- reply to a message
+.SY
+repl \%[+folder] \%[msg] \%[\-editor\ editor] \%[\-inplace] \%[\-annotate]
+\%[\-help] \%[\-noinplace]
+\%[\-noannotate]
+.DE
+\fIRepl\fR aids a user in producing a reply to an existing
+message.
+In its simplest form (with no arguments), it will set up
+a message-form skeleton in reply to the current message in the
+current folder, invoke the editor, and send the composed
+message if so directed.
+The composed message is constructed as
+follows:
+
+.nf
+.in 1i
+To: <Reply-To> or <From>
+cc: <cc>, <To>
+Subject: Re: <Subject>
+In-reply-to: Your message of <Date>
+.ti +\w'In-reply-to: 'u
+<Message-Id>
+.in .5i
+.fi
+
+where field names enclosed in angle brackets (< >) indicate the
+contents of the named field from the message to which the reply
+is being made.
+Once the skeleton is constructed, an editor is
+invoked (as in \fIcomp\fR, \fIdist\fR, and \fIforw\fR).
+While in the editor,
+the message being replied to is available through a link named
+\*(lq@\*(rq.
+In NED, this means the replied-to message may be \*(lqused\*(rq
+with \*(lquse @\*(rq, or put in a window by \*(lqwindow @\*(rq.
+
+As in \fIcomp\fR, \fIdist\fR, and \fIforw\fR, the user will be queried
+before the message is sent.
+If `\-annotate' is
+specified, the replied-to message will be annotated with the
+single line
+
+.ti +.5i
+Replied: \*(<<Date\*(>>.
+
+The command
+\*(lqcomp \-use\*(rq may be used to pick up interrupted editing, as in
+\fIdist\fR and \fIforw\fR; the `\-inplace' switch annotates the message in place,
+so that all folders with links to it will see the annotation.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The constructed message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a `+folder' is specified, it will become the current
+folder, and the current message will be set to the replied-to
+message.
+.sp 2
+.En
+.SC RMF
+.NA
+rmf \- remove folder
+.SY
+rmf \%[+folder] \%[\-help]
+.DE
+\fIRmf\fR removes all of the files (messages) within the specified
+(or default) folder, and then removes the directory (folder).
+If
+there are any files within the folder which are not a part of MH,
+they will \fInot\fR be removed, and an error will be produced.
+If the
+folder is given explicitly or the current folder is a
+subfolder (i.e., a selection list from \fIpick\fR), it will be
+removed without confirmation.
+If no argument is specified and
+the current folder is not a selection-list folder, the
+user will be asked for confirmation.
+
+\fIRmf\fR irreversibly deletes messages that don't have other links,
+so use it with caution.
+
+If the folder being removed is a subfolder, the parent
+folder will become the new current folder, and \fIrmf\fR will
+produce a message telling the user this has happened.
+This
+provides an easy mechanism for selecting a set of messages,
+operating on the list, then removing the list and returning to
+the current folder from which the list was extracted.
+(See the
+example under \fIpick\fR.)
+
+The files that \fIrmf\fR will delete are cur, any file beginning
+with a comma, and files with purely numeric names.
+All others
+will produce error messages.
+
+\fIRmf\fR of a read-only folder will delete the \*(lqcur\-\*(rq entry from the
+profile without affecting the folder itself.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current, usually with confirmation
+.Co
+\fIRmf\fR will set the current folder to the parent folder if a
+subfolder is removed; or if the current folder is removed,
+it will make \*(lqinbox\*(rq current.
+Otherwise, it doesn't change the
+current folder or message.
+.En
+.SC RMM
+.NA
+rmm \- remove messages
+.SY
+rmm \%[+folder] \%[msgs] \%[\-help]
+.DE
+\fIRmm\fR removes the specified messages by renaming the message
+files with preceding commas.
+(This is the Rand-UNIX backup file
+convention.)
+
+The current message is not changed by \fIrmm\fR, so a \fInext\fR will
+advance to the next message in the folder as expected.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+.Co
+If a folder is given, it will become current.
+.En
+.SC SCAN
+.NA
+scan \- produce a one-line-per-message scan listing
+.SY
+scan \%[+folder] \%[msgs] \%[\-f\&f] \%[\-header] \%[\-help]
+\%[\-nof\&f] \%[\-noheader]
+.DE
+\fIScan\fR produces a one-line-per-message listing of the specified
+messages.
+Each \fIscan\fR line contains the message number (name),
+the date, the \*(lqFrom\*(rq field, the \*(lqSubject\*(rq field, and, if room
+allows, some of the body of the message.
+For example:
+
+.nf
+.ta .5i 1.2i 2.6i
+^ #~^^Date~^^ From~^Subject\ \ \ \ \[\*(<<Body]
+^15+~^^7/\05~^^Dcrocker~^nned \*(<<Last week I asked some of
+^16\ \-~^^7/\05~^^dcrocker~^message id format \*(<<I recommend
+^18~^^7/\06~^^Obrien~^Re: Exit status from mkdir
+^19~^^7/\07~^^Obrien~^"scan" listing format in MH
+.re
+.fi
+
+The `+' on message 15 indicates that it is the current message.
+The `\-' on message 16 indicates that it has been
+replied to, as indicated by a \*(lqReplied:\*(rq component produced by
+an `\-annotate' switch to the \fIrepl\fR command.
+
+If there is sufficient room left on the \fIscan\fR line after the
+subject, the line will be filled with text from the body,
+preceded by \*(<<.
+\fIScan\fR actually reads each of the specified
+messages and parses them to extract the desired fields.
+During parsing, appropriate error messages will be produced if
+there are format errors in any of the messages.
+
+The `\-header' switch produces a header line prior to the \fIscan\fR
+listing, and the `\-f\&f' switch will cause a form feed to be
+output at the end of the \fIscan\fR listing.
+See Appendix D.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+Defaults:
+`+folder' defaults to current
+`msgs' defaults to all
+`\-nof\&f'
+`\-noheader'
+.Co
+If a folder is given, it will become current.
+The current
+message is unaffected.
+.En
+.SC SEND
+.NA
+send \- send a message
+.SY
+send \%[file] \%[\-draft] \%[\-verbose] \%[\-format] \%[\-msgid]
+\%[\-help] \%[\-noverbose] \%[\-noformat] \%[\-nomsgid]
+.DE
+\fISend\fR will cause the specified file (default <mh-dir>/draft) to
+be delivered to each of the addresses in the \*(lqTo:\*(rq, \*(lqcc:\*(rq, and \*(lqBcc:\*(rq
+fields of the message.
+If `\-verbose' is specified, \fIsend;\fR
+will monitor the delivery of local and net mail.
+\fISend\fR with no
+argument will query whether the draft is the intended file, whereas
+`\-draft' will suppress this question.
+Once the message has
+been mailed (or queued) successfully, the file will be renamed
+with a leading comma, which allows it to be retreived until the
+next draft message is sent.
+If there are errors in the
+formatting of the message, \fIsend;\fR will abort with a (hopefully)
+helpful error message.
+
+If a \*(lqBcc:\*(rq field is encountered, its addresses will be used for
+delivery, but the \*(lqBcc:\*(rq field itself will be deleted from all
+copies of the outgoing message.
+
+Prior to sending the message, the fields \*(lqFrom: user\*(rq, and
+\*(lqDate: now\*(rq will be prepended to the message.
+If `\-msgid' is
+specified, then a \*(lqMessage-Id:\*(rq field will also be added to the
+message.
+If the message already contains a \*(lqFrom:\*(rq field, then a
+\*(lqSender: user\*(rq field will be added instead.
+(An already existing
+\*(lqSender:\*(rq field will be deleted from the message.)
+
+If the user doesn't specify `\-noformat', each of the entries in
+the \*(lqTo:\*(rq and \*(lqcc:\*(rq fields will be replaced with \*(lqstandard\*(rq format
+entries.
+This standard format is designed to be usable by all
+of the message handlers on the various systems around the
+ARPANET.
+
+If an \*(lqFcc: folder\*(rq is encountered, the message will be copied
+to the specified folder in the format in which it will appear to any
+receivers of the message.
+That is, it will have the prepended
+fields and field reformatting.
+
+If a \*(lqDistribute-To:\*(rq field is encountered, the message
+is handled as a redistribution message (see \fIdist\fR for
+details), with \*(lqDistribution-Date: now\*(rq and \*(lqDistribution-From: user\*(rq
+added.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.De
+`file' defaults to draft
+`\-noverbose'
+`\-format'
+`\-nomsgid'
+.Co
+\fISend\fR has no effect on the current message or folder.
+.En
+.SC SHOW
+.NA
+show \- show (list) messages
+.SY
+show \%[+folder] \%[msgs] \%[\-pr] \%[\-nopr] \%[\-draft] \%[\-help]
+\%[\fIl\fR\ or\ \fIpr\fR\ switches]
+.DE
+\fIShow\fR lists each of the specified messages to the standard
+output (typically, the terminal).
+The messages are listed exactly
+as they are, with no reformatting.
+A program called \fIl\fR is
+invoked to do the listing, and any switches not recognized by
+\fIshow\fR are passed along to \fIl\fR.
+
+If no \*(lqmsgs\*(rq are specified, the current message is used.
+If
+more than one message is specified, \fIl\fR will prompt for a
+<return> prior to listing each message.
+
+\fIl\fR will list each message, a page at a time.
+When the end of
+page is reached, \fIl\fR will ring the bell and wait for a <RETURN>
+or <CTRL-D>.
+If a <return> is entered, \fIl\fR will clear the
+screen before listing the next page, whereas <CTRL-D> will not.
+The switches to \fIl\fR are
+`\-p#' to indicate the page length in lines, and `\-w#' to
+indicate the width of the page in characters.
+
+If the standard output is not a terminal, no queries are made,
+and each file is listed with a one-line header and two lines of
+separation.
+
+If `\-pr' is specified, then \fIpr\fR(I) will be invoked rather than
+\fIl\fR, and the switches (other than `\-draft') will be passed
+along.
+\*(lqShow \-draft\*(rq will list the file <mh-dir>/draft if it
+exists.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^/bin/l~^Screen-at-a-time list program
+^/bin/pr~^\fIpr\fR(I)
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-nopr'
+.Co
+If a folder is given, it will become the current message.
+The last message
+listed will become the current message.
+.En
+\"
+\" On to the Appendices
+\"
+.fo ''-%-''
+.he ''''
+.(x
+.sp
+Appendix
+.)x _
+.de $c \" Major Heading printer
+.ce
+Appendix \\n+(ch
+.sp 2p
+.ce
+.b "\\s12\\$1\\s0" \" 12 Point Bold Header
+.(x
+\ \ \ \\n(ch.\\ \\ \\$2
+.)x
+.sp 45p \" 45 points or about 1/2 inch
+..
+.++ A
+.bp
+.$c "COMMAND SUMMARY\\**" "Command Summary"
+.(f
+\**All commands accept a \-help switch.
+.)f
+.in 1i
+.na
+.ti .5i
+comp \%[\-editor\ editor] \%[\-form\ formfile] \%[file] \%[\-use]
+\%[\-nouse] \%[\-help]
+
+.ti .5i
+dist \%[+folder] \%[msg] \%[\-form\ formfile] \%[\-editor\ editor]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+
+.ti .5i
+file \%[\-src\ +folder] \%[msgs] \%[\-link] \%[\-preserve] \%+folder\ ...
+\%[\-nolink] \%[\-nopreserve]
+\%[\-file\ file] \%[\-nofile] \%[\-help]
+
+.ti .5i
+folder \%[+folder] \%[msg] \%[\-all] \%[\-fast] \%[\-nofast] \%[\-up] \%[\-down]
+\%[\-header] \%[\-noheader] \%[\-total] \%[\-nototal] \%[\-pack] \%[\-nopack]
+\%[\-help]
+
+.ti .5i
+forw \%[+folder] \%[msgs] \%[\-editor\ editor] \%[\-form\ formfile]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+
+.ti .5i
+inc \%[+folder] \%[\-audit\ audit-file] \%[\-help]
+
+.ti .5i
+next \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+
+.ta .4i 1.8i
+.nf
+.in .5i
+^pick~^^\0\-cc~^ \%[\-src\ +folder] \%[msgs] \%[\-help] \%[\-scan] \%[\-noscan]
+^^^\0\-date~^ \%[\-show] \%[\-noshow] \%[\-nofile] \%[\-nokeep]
+^^^\0\-from~^
+^^^\s+2\b'\(lt\(bv\(bv\(lk\(bv\(bv\(lb'\s0 \-search~\s+2\b'\(rt\(bv\(bv\(rk\(bv\(bv\(rb'\s0^ pattern
+^^^\0\-subject~^
+^^^\0\-to~^ \%[\-file \%[\-preserve] \%[\-link] \%+folder\ ... \%[\-nopreserve] \%[\-nolink] ]
+^^^\0\-\-component~^ \%[\-keep \%[\-stay] \%[\-nostay] \%[+folder\ ...]\ ]
+.fi
+.re
+
+.ti .5i
+prev \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+
+.ti .5i
+prompter \%[\-erase\ chr] \%[\-kill\ chr] \%[\-help]
+
+.ti .5i
+repl \%[+folder] \%[msg] \%[\-editor\ editor] \%[\-inplace] \%[\-annotate]
+\%[\-help] \%[\-noinplace]
+\%[\-noannotate]
+
+.ti .5i
+rmf \%[+folder] \%[\-help]
+
+.ti .5i
+rmm \%[+folder] \%[msgs] \%[\-help]
+
+.ti .5i
+scan \%[+folder] \%[msgs] \%[\-f\&f] \%[\-header] \%[\-help]
+\%[\-nof\&f] \%[\-noheader]
+
+.ti .5i
+send \%[file] \%[\-draft] \%[\-verbose] \%[\-format] \%[\-msgid]
+\%[\-help] \%[\-noverbose] \%[\-noformat] \%[\-nomsgid]
+
+.ti .5i
+show \%[+folder] \%[msgs] \%[\-pr] \%[\-nopr] \%[\-draft] \%[\-help]
+\%[\fIl\fR\ or\ \fIpr\fR\ switches]
+.ad
+.in 0
+\".+c "MESSAGE FORMAT" "Message Format"
+.if t \{
+.ll 32P
+.lt 32P
+\}
+.bp
+.$c "MESSAGE FORMAT" "Message Format"
+.pp
+This section paraphrases the format of ARPANET text messages
+given in Ref. 6.
+
+.lp
+ASSUMPTIONS
+.np
+Messages
+are expected to consist of lines of text.
+Graphics and binary data are not handled.
+.np
+No data compression is accepted.
+All text is clear
+ASCII 7-bit data.
+
+.lp
+LAYOUT
+.lp
+A general \*(lqmemo\*(rq framework is used.
+A message consists of a
+block of information in a rigid format, followed by general
+text with no specified format.
+The rigidly formatted first
+part of a message is called the header, and the free-format
+portion is called the body.
+The header must always
+exist, but the body is optional.
+
+.lp
+THE HEADER
+.lp
+Each header item can be viewed as a single logical line of ASCII
+characters.
+If the text of a header item extends across several
+real lines, the continuation lines are indicated by leading
+spaces or tabs.
+.lp
+Each header item is called a component and is composed of a
+keyword or name, along with associated text.
+The keyword begins at the
+left margin, may contain spaces or tabs, may not exceed 63
+characters, and is terminated by a colon (:).
+Certain
+components (as identified by their keywords) must follow rigidly
+defined formats in their text portions.
+.lp
+The text for most formatted components (e.g., \*(lqDate:\*(rq and \*(lqMessage-Id:\*(rq)
+is produced automatically.
+The only ones entered by the
+user are address fields such as \*(lqTo:\*(rq, \*(lqcc:\*(rq, etc.
+ARPA addresses
+are assigned mailbox names and host computer specifications.
+The
+rough format is \*(lqmailbox at host\*(rq, such as \*(lqBorden at Rand-Unix\*(rq.
+Multiple addresses are separated by commas.
+A missing host is
+assumed to be the local host.
+
+.ne 10
+.lp
+THE BODY
+.lp
+A blank line signals that all following text up to the end of the file
+is the body.
+(A blank line is defined as a pair of
+<end-of-line> characters with \fIno\fR characters in between.)
+No formatting is expected or enforced within the body.
+.lp
+Within MH, a line consisting of dashes is accepted
+as the header delimiter.
+This is a cosmetic feature applying
+only to locally composed mail.
+.bp
+.$c "MESSAGE NAME BNF" "Message Name BNF"
+
+.ta 1.2i 1.8i 3.2i
+.nf
+.in 1i
+^msgs~^^:=~^^msgspec~^|
+^^^^msgs msgspec
+
+^msgspec~^^:=~^^msg~^|
+^^^^^msg-range~^|
+^^^^msg-sequence
+
+^msg~^^:=~^^msg-name~^|
+^^^^<number>^
+
+^msg-name~^^:=~^^\*(lqfirst\*(rq~^|
+^^^^^\*(lqlast\*(rq~^|
+^^^^^\*(lqcur\*(rq~^|
+^^^^^\*(lq\*.\*(rq~^|
+^^^^^\*(lqnext\*(rq~^|
+^^^^\*(lqprev\*(rq
+
+^msg-range~^^:=~^^msg\*(lq-\*(rqmsg~^|
+^^^^^\*(lqall\*(rq
+
+^msg-sequence~^^:=~^msg\*(lq:\*(rqsigned-number
+
+^signed-number~^^:=~^^\*(lq+\*(rq<number>~^|
+^^^^^\*(lq\--\*(rq<number>~^|
+^^^^<number>
+.re \" Reset Tabs
+.fi
+.sp
+.pp
+Where <number> is a decimal number in the range 1 to 999.
+.pp
+Msg-range specifies all of the messages in the given range
+and must not be empty.
+.pp
+Msg-sequence specifies up to <number> of messages, beginning
+with \*(lqmsg\*(rq (in the case of first, cur, next, or <number>),
+or ending with \*(lqmsg\*(rq (in the case of prev or last).
++<number> forces \*(lqstarting with msg\*(rq, and \-<number> forces
+\*(lqending with number\*(rq.
+In all cases, \*(lqmsg\*(rq must exist.
+.bp
+.$c "EXAMPLE OF SHELL COMMANDS" "Example of Shell Commands"
+.pp
+UNIX commands may be mixed with MH commands to obtain additional
+functions.
+These may be prepared as files (known as
+shell command files or
+shell scripts).
+The following example is a useful function that
+illustrate the possibilities.
+Other functions, such as copying,
+deleting, renaming, etc., can be achieved in a similar fashion.
+
+HARDCOPY
+.pp
+The command:
+
+.ti +.5i
+(scan\0\-f\&f\0\-header;\0show\0all\0\-pr\0\-f)\0|\0print
+
+produces a scan listing of the current folder, followed by a
+form feed, followed by a formatted listing of all messages
+in the folder, one per page.
+Omitting \*(lq\-pr\0\-f\*(rq will cause the
+messages to be concatenated, separated by a one-line header
+and two blank lines.
+.pp
+You can create variations on this theme, using \fIpick\fR.
+.re
+.fi
+.in 0
+.bp
+.ce
+.b \\s12REFERENCES\\s0
+.(x
+.sp
+REFERENCES
+.)x
+.sp 3
+.in .4i
+.ti 0
+1. Crocker, D. H., J. J. Vittal, K. T. Pogran, and D. A. Henderson, Jr.,
+\*(lqStandard for the Format of ARPA Network Test Messages,\*(rq \fIArpanet Request
+for Comments\fR, No. 733, Network Information Center 41952, Augmentation
+Research Center, Stanford Research Institute,
+November 1977.
+
+.ti 0
+2. Thompson, K., and D. M. Ritchie, \*(lqThe UNIX Time-sharing System,\*(rq
+\fICommunications of the ACM\fR, Vol. 17, July 1974, pp. 365-375.
+
+.ti 0
+3. McCauley, E. J., and P. J. Drongowski, \*(lqKSOS\-The Design of a Secure
+Operating System,\*(rq \fIAFIPS Conference Proceedings\fR,
+National Computer Conference,
+Vol. 48, 1979, pp. 345-353.
+
+.ti 0
+4. Crocker, David H., \fIFramework and Functions of the \*(lqMS\*(rq Personal
+Message System\fR, The Rand Corporation, R-2134-ARPA, December 1977.
+
+.ti 0
+5. Thompson, K., and D. M. Ritchie, \fIUNIX Programmer's Manual\fR, 6th ed.,
+Western Electric Company, May 1975 (available only to UNIX licensees).
+
+.ti 0
+6. Bilofsky, Walter, \fIThe CRT Text Editor NED\-Introduction and
+Reference Manual\fR, The Rand Corporation, R-2176-ARPA, December 1977.
+.bp 3
+.de $c
+.ce
+.b "\\s12\\$1\\s0" \" 12 Point Bold Header
+.(x y
+.sp
+\\$1
+.)x
+.sp 3
+..
+.pn 3
+.++ P
+.fo ''''
+.he ''-%-''
+.+c PREFACE
+.pp
+This report describes a system for dealing with messages transmitted on a
+computer. Such messages might originate with other users of the same
+computer or might come from an outside source through a network to which the user's
+computer is connected. Such computer-based message systems are
+becoming increasingly widely used, both within and outside the Department
+of Defense.
+.pp
+The message handling system MH was developed for two reasons.
+One was to investigate some
+research ideas concerning how a message system might take advantage of
+the architecture of the UNIX time-sharing operating system for
+Digital Equipment Corporation PDP-11 and VAX computers, and the special
+features of UNIX's command-level interface with the user (the
+\*(lqshell\*(rq). The other reason was to provide a better and more
+adaptable base than that of conventional designs
+on which to build a command and control message system.
+The effort has succeeded in both
+regards, although this report mainly describes the message system itself
+and how it fits in with UNIX. The main research results are being
+described and analyzed in a forthcoming Rand report.
+The system is currently being used as part
+of a tactical command and control \*(lqlaboratory,\*(rq which is also being described
+in a separate report.
+.pp
+The present report should be of interest to three groups of readers. First,
+it is a complete reference manual for the users of MH (although
+users outside of Rand must take into
+account differences from the local Rand operating system). Second, it should be
+of interest to those who have a general knowledge of computer-based
+message systems, both in civilian and military applications. Finally,
+it should be of interest to those who build large subsystems that
+interface with users, since it illustrates a new approach to such
+interfaces.
+.pp
+The MH system was developed by the first
+author, using an approach suggested by the other two authors.
+Valuable assistance was provided by Phyllis Kantar in the later
+stages of the system's implementation.
+Several colleagues
+contributed to the ideas included in this system, particularly
+Robert Anderson and David Crocker.
+In addition, valuable experience
+in message systems, and a valuable source of ideas, was available
+to us in the form of a previous message system for UNIX called
+MS, designed at Rand by David Crocker.
+.pp
+This report was prepared as part of the Rand project entitled \*(lqData
+Automation Research\*(rq, sponsored by Project AIR FORCE.
+.pn 5
+.+c SUMMARY
+.pp
+Electronic communication of text messages is becoming
+commonplace. Computer-based message systems\-software
+packages that provide tools for dealing with messages\-are used in many
+contexts. In particular, message systems are becoming
+increasingly important in command and control and intelligence
+applications.
+.pp
+This report describes a message handling system called MH.
+This system provides the user
+with tools to compose, send, receive, store, retrieve, forward, and
+reply to messages. MH has been built on the UNIX time-sharing system,
+a popular operating system developed for the DEC PDP-11 and VAX classes of
+computers.
+.pp
+A complete description of MH is given for users of
+the system. For those who do not intend to use the system, this description
+gives a general idea of what a message system is like. The system involves
+some new ideas about how large subsystems can be constructed. These design
+concepts and a comparison of MH with other message systems
+will be published in a forthcoming Rand report.
+.pp
+The interesting and unusual features of MH include the
+following: The user command interface to MH is the UNIX \*(lqshell\*(rq
+(the standard UNIX command interpreter). Each separable
+component of message handling, such as message composition or
+message display, is a separate command. Each program is driven from
+and updates a private user environment, which is stored as a file
+between program invocations. This private environment also contains
+information to \*(lqcustom tailor\*(rq MH to the individual's tastes. MH
+stores each message as a separate file under UNIX, and it utilizes the
+tree-structured UNIX file system to organize groups of files within
+separate directories or \*(lqfolders.\*(rq All of the UNIX facilities
+for dealing with files and directories, such as
+renaming, copying, deleting, cataloging, off-line printing, etc., are
+applicable to messages and directories of messages (folders). Thus,
+important capabilities needed in a message system are available in MH without
+the need (often seen in other message systems) for code that
+duplicates the facilities of the supporting operating system.
+It also allows users familiar with the shell to use MH with minimal
+effort.
+.he ''''
+.fo ''''
+.bp
+.ce
+.b \\s12CONTENTS\\s0
+.sp 3
+.xp y
+.xp x
+
+.bp \" Spare numbers for cut and paste work!
+.ft B
+
+1 1 1 1 1 1 1 1
+
+1 1 1 1 1 1 1 1
+
+1 1 1 1 1 1 1 1
+
+1 1 1 1 1 1 1 1
+
+2 2 2 2 2 2 2 2
+
+2 2 2 2 2 2 2 2
+
+2 2 2 2 2 2 2 2
+
+3 3 3 3 3 3 3
\ No newline at end of file
--- /dev/null
+.de $c \" Major Heading printer
+.ce
+.b "\\s12\\n+(ch.\\ \\$1\\s0" \" 12 Point Bold Header
+.(x
+
+\ \ \ \\n(ch.\\ \\ \\$1
+.)x
+.sp 45p \" 45 point space or about 1/2 inch
+..
+\".nr xs .15v \" Put index entries closer together
+.(x
+
+Section
+.)x _
+.de $0 \" Sub-Heading macro called AFTER printing the heading
+.(x
+.sp .3v
+.ti .5i
+\\$1
+.)x
+..
+.de $s \" Macro to print footnote separator
+\"\l'2i' \" No line drawn
+.if n \
+. sp 1.3 \" But extra space to make up for it.
+..
+.fc ^ ~ \" The characters ^ and ~ CANNOT BE USED
+\" throughout this document except as field
+\" delimiter & pad indicator!
+.he ''-%-''
+.ll 32P \" 32 Picas or about 5+1/3 inch Line Length
+.if n .ll 72m \" Use 72 ems for nroff
+.nr ss 30p \" 30 point space before section titles
+.nr fm 5v \" Rand likes bigger than normal [3v] bottom margins
+.nr bm 7v \" ditto
+.ds . \\fB.\\fP\\h'-(1m/4)' \" Bold period to stand out.
+.ds << <\\h!-(\\w'<'/2)!<
+.ds >> >\\h!-(\\w'>'/2)!>
+.ds ** \v'-3p'\s+1*\s0\v'+3p'
+.++ C
+.+c INTRODUCTION
+.pp
+Although people can travel cross-country in hours and can
+reach others by telephone in seconds, communications still depend
+heavily upon paper, most of which is distributed through the mails.
+.pp
+There are several major reasons for this continued dependence on
+written documents.
+First, a written document may be proofread
+and corrected prior to its distribution, giving the author
+complete control over his words.
+Thus, a written document is
+better than a telephone conversation in this respect.
+Second,
+a carefully written document is far less likely to be
+misinterpreted or poorly translated than a phone conversation.
+Third, a signature offers reasonable verification of authorship,
+which cannot be provided with media such as telegrams.
+.pp
+However, the need for
+.u fast ,
+accurate, and reproducible document distribution is
+obvious.
+One solution in widespread use is the telefax.
+Another
+that is rapidly gaining popularity is electronic mail.
+Electronic mail is similar to telefax in that the data to be sent
+are digitized, transmitted via phone lines, and
+turned back into a document at the receiver.
+The advantage of
+electronic mail is in its compression factor.
+Whereas a telefax
+must scan a page in very fine lines and send all of the black and
+white information, electronic mail assigns characters fixed
+codes which can be transmitted as a few bits of information.
+Telefax presently has the advantage of being able to transmit an
+arbitrary page, including pictures, but electronic mail is
+beginning to deal with this problem.
+Electronic mail also integrates well
+with current directions in office automation, allowing documents
+prepared with sophisticated equipment at one site to be quickly
+transferred and printed at another site.
+.pp
+Currently, most electronic mail is intraorganizational,
+with mail transfer remaining within one computer.
+As computer
+networking becomes more common, however, it is becoming more feasible to
+communicate with anyone whose computer can be linked to your
+own via a network.
+.pp
+The pioneering efforts on general-purpose electronic mail
+were by organizations using the Defense Department's ARPANET.[1]
+The capability to send messages between computers existed before
+the ARPANET was developed, but it was used only in limited ways.
+With the advent of the
+ARPANET, tools began to be developed which made it convenient for
+individuals or organizations to distribute messages
+over broad geographic areas, using
+diverse computer facilities.
+The interest and activity in
+message systems has now reached such proportions that steps
+have been taken within the DoD to coordinate and
+unify the development of military message systems.
+The use of electronic mail is expected to increase
+dramatically in the next few years.
+The utility of such systems
+in the command and control and intelligence environments is
+clear, and applications in these areas will probably lead the
+way.
+As the costs for sending and handling electronic messags
+continue their rapid decrease, such uses can be
+expected to spread rapidly into other areas and, of course, will
+not be limited to the DoD.
+.pp
+A message system provides tools that help users (individuals
+or organizations) deal with messages in various ways.
+Messages
+must be composed, sent, received, stored, retrieved,
+forwarded, and replied to.
+Today's best interactive computer
+systems provide a variety of word-processing and information
+handling capabilities.
+The message handling facilities should be
+well integrated with the rest of the system, so as to be a
+graceful extension of overall system capability.
+.pp
+The message system described in this report, MH, provides most of the
+features that can be found in other message systems and also
+incorporates some new ones.
+It has been built on the UNIX time-sharing
+system,[2] a popular operating system for the DEC PDP-11
+and VAX classes of computers.
+A \*(lqsecure\*(rq operating
+system similar to UNIX is currently being developed,[3]
+and that system will also run MH.
+.pp
+This report provides a complete description of MH and
+thus may serve as a user's manual, although parts of the report
+will be of interest to non-users as well.
+Sections 2 and 3, the
+Overview and Tutorial, present the key
+ideas of MH and will give those not familiar with message systems
+an idea of what such systems are like.
+.pp
+MH consists of a set of commands which use some special
+files and conventions.
+Section 4 covers the information
+a user needs to know in addition to the
+commands.
+The final section, Sec. 5, describes each of
+the MH commands in detail.
+A summary of the commands is given in
+Appendix A, and Appendixes B and C describe the ARPANET
+conventions for messages (we expect that many users of MH
+will be using the ARPANET) and the formal syntax of such
+messages, respectively.
+Finally, Appendix D provides
+an illustration of how MH commands may be used in
+conjunction with other UNIX facilities.
+.pp
+A novel approach has been taken in the design of MH.
+The
+design concept will be reported in detail in a forthcoming Rand
+report, but it can be described briefly as follows.
+Instead of creating a large subsystem that appears as a single
+command to the user, MH is a collection of separate commands
+which are run as separate programs.
+The file and directory
+system of UNIX are used directly.
+Messages are stored as
+individual files (datasets), and collections of them are grouped
+into directories.
+In contrast, most other message systems store
+messages in a complicated data structure within a monolithic
+file.
+With the MH approach, UNIX commands can be
+interleaved with commands invoking the functions of the message
+handler.
+Conversely, existing UNIX commands
+can be used in connection with messages.
+For
+example, all the usual UNIX editing, text-formatting, and printing
+facilities can be applied directly to individual messages.
+MH,
+therefore, consists of a relatively small amount of new code; it
+makes extensive use of other UNIX software to provide the
+capabilities found in other message systems.
+.pp
+The MH system was developed by the first
+author, using an approach suggested by the other two authors.
+Valuable assistance was provided by Phyllis Kantar in the later
+stages of the system's implementation.
+Several colleagues
+contributed to the ideas included in this system, particularly
+Robert Anderson and David Crocker.
+In addition, valuable experience
+in message systems, and a valuable source of ideas, was available
+to us in the form of a previous message system for UNIX called
+MS,[4] designed at Rand by David Crocker.
+.+c OVERVIEW
+.pp
+There are three main aspects of MH: the way messages are
+stored (the message database), the user's profile (which directs
+how certain actions of the message handler take place), and the
+commands for dealing with messages.
+.pp
+Under MH, each message is stored as a separate file.
+A user
+can take any action with a message that he could with an ordinary
+file in UNIX.
+A UNIX directory in which messages are stored is
+called a folder.
+Each folder contains some standard entries to support
+the message-handling functions.
+The messages in a folder have numerical
+names.
+These folders (directories)
+are entries in a particular directory path, described in
+the user profile, through which MH can find message folders.
+Using the UNIX \*(lqlink\*(rq facility, it is possible for one copy of a
+message to be \*(lqfiled\*(rq in more than one folder, providing a
+message index facility.
+Also, using the UNIX tree-structured
+file system, it is possible to have a folder within a folder.
+This two-level organization provides a \*(lqselection-list\*(rq
+facility, with the full power of the MH commands available on
+selected sublists of messages.
+.pp
+Each user of MH has a user profile, a file in his $HOME (initial
+login)
+directory called \*(lq\*.mh\(ruprofile\*(rq.
+This profile contains several
+pieces of information used by the MH commands: a
+path name to the directory that contains the message folders,
+information concerning which folder the user last referenced (the
+\*(lqcurrent\*(rq folder), and parameters that tailor MH commands
+to the individual user's requirements.
+It also contains
+most of the necessary state information concerning how
+the user is dealing with his messages, enabling MH to be
+implemented as a set of individual UNIX commands, in contrast to the
+usual approach of a monolithic subsystem.
+.pp
+In MH, incoming mail is appended
+to the end of a file called \*.mail in a user's $HOME
+directory.
+The user adds the new messages to his collection of MH messages
+by invoking the command
+.i inc .
+.i Inc
+(incorporate) adds the new
+messages to a folder called \*(lqinbox\*(rq, assigning them names which
+are consecutive integers starting with the next highest integer
+available in inbox.
+.i Inc
+also produces a
+.i scan
+summary of
+the messages thus incorporated.
+.pp
+There are four commands for examining the messages in a
+folder:
+.i show ,
+.i prev ,
+.i next ,
+and
+.i scan .
+.i Show
+displays a
+message in a folder,
+.i prev
+displays the message preceding the
+current message, and
+.i next
+displays the message following the
+current message.
+.i Scan
+summarizes the messages in a folder,
+producing one line per message, showing who the message is from,
+the date, the subject, etc.
+.pp
+The user may move a message from one folder to another with
+the command
+.i file .
+Messages may be removed from a folder
+by means of the command
+.i rmm .
+In addition, a user may query
+what the current folder is and may specify that a new folder
+become the current folder, through the command
+.i folder .
+.pp
+A set of messages based on content may be selected by
+use of the command
+.i pick .
+This command searches through
+messages in a folder and selects those that match a given
+criterion.
+A subfolder is created within the original folder,
+containing links to all the messages that satisfy the selection
+criteria.
+.pp
+A message folder (or subfolder) may be removed by means of
+the command
+.i rmf .
+.pp
+There are five commands enabling the user to create new
+messages and send them:
+.i comp ,
+.i dist ,
+.i forw ,
+.i repl ,
+and
+.i send .
+.i Comp
+provides the facility for the user to compose a
+new message;
+.i dist
+redistributes mail to additional addressees;
+.i forw
+enables the user to forward messages; and
+.i repl
+facilitates the generation of a reply to an incoming message.
+If
+a message is not sent directly by one of these commands, it may
+be sent at a later time using the command
+.i send .
+.pp
+All of the elements summarized above
+are described in more detail in the following sections.
+Many of the
+normal facilities of UNIX provide additional capabilities for
+dealing with messages in various ways.
+For example, it is
+possible to print messages
+on the line-printer without requiring any additional code within
+MH.
+Using standard UNIX facilities, any terminal output can be
+redirected to a file for repeated or future viewing.
+In general,
+the flexibility and capabilities of the UNIX interface with the
+user are preserved as a result of the integration of MH into the UNIX
+structure.
+.+c TUTORIAL
+.pp
+This tutorial provides a brief introduction to the MH commands.
+It should be sufficient
+to allow the user to read his mail, do some simple manipulations of
+it, and create and send messages.
+.pp
+A message has two major pieces: the
+header and the body.
+The body consists of the text of the message
+(whatever you care to type in).
+It follows the header and is separated from
+it by an empty line.
+(When you compose a message, the form that appears
+on your terminal shows a line of dashes after the header.
+This is for
+convenience and is replaced by an empty line when the message is
+sent.) The header is composed of several components, including the
+subject of the message and the person to whom it is addressed.
+Each component starts with a name
+and a colon; components must not start with a blank.
+The text of the
+component may take more than one line, but each continuation line must
+start with a blank.
+Messages typically have \*(lqto:\*(rq, \*(lqcc:\*(rq, and
+\*(lqsubject:\*(rq components.
+When composing a message, you should include
+the \*(lqto:\*(rq and \*(lqsubject:\*(rq components; the \*(lqcc:\*(rq (for people
+you want to send copies to) is not necessary.
+.pp
+The basic MH commands are
+.i inc ,
+.i scan ,
+.i show ,
+.i next ,
+.i prev ,
+.i rmm ,
+.i comp ,
+and
+.i repl .
+These are described below.
+
+.i inc
+.pp
+When you get the message \*(lqYou have mail\*(rq, type the command
+.i inc .
+You will get a \*(lqscan listing\*(rq such as:
+
+.nf
+.if t .ta .4i 1.0i 2i
+.if n .ta .4i 1.2i 3i
+^7+~^^\07/13~^^Cas~^revival of measurement work
+^8~^^10/\09~^^Norm~^NBS people and publications
+^9~^^11/26~^^To:norm~^question \*(<<Are there any functions
+.re
+.fi
+.pp
+This shows the messages you received since the last time you
+executed this command (
+.i inc
+adds these new messages to
+your inbox folder).
+You can see this list again, plus a list of any
+other messages you have, by using the
+.i scan
+command.
+
+.i scan
+.pp
+The scan listing shows the message number, followed by the
+date and the sender.
+(If you are the sender, the addressee in the \*(lqto:\*(rq
+component is displayed.
+You may send yourself a message by including
+your name among the \*(lqto:\*(rq or \*(lqcc:\*(rq addressees.)
+It also shows the message's subject; if
+the subject is short, the first part of the body of the message is
+included after the characters \*(<<.
+
+.ne 5
+.i show
+.pp
+This command shows the current message, that is,
+the first one of the new messages after an
+.i inc .
+If the message is not
+specified by name (number), it is
+generally the last message referred to by an MH command.
+For example,
+
+.ta 1i
+.ti .5i
+^\fIshow\fP\05~^will show message 5.
+.pp
+You can use the show command to copy a message or print a
+message.
+
+.(b L
+.in .5i
+.if t .ta 1i
+.if n .ta 1.5i
+^\fIshow\fR\0>\0\fIx\fR~^will copy the message to file x.
+.br
+^\fIshow\fR\0|\0\fIprint\fR~^will print the message, using the \fIprint\fR command.
+.br
+^\fInext\fR~^will show the message that follows the current message.
+.br
+^\fIprev\fR~^will show the message previous to the current message.
+.br
+^\fIrmm\fR~^will remove the current message.
+.br
+^\fIrmm\03\fR~^will remove message 3.
+.)b
+
+.ne 5
+.i comp
+.pp
+The
+.i comp
+command puts you in the editor to write or edit a message.
+Fill in or
+delete the \*(lqto:\*(rq, \*(lqcc:\*(rq, and \*(lqsubject:\*(rq fields, as appropriate, and
+type the body of the message.
+Then
+exit normally from the editor.
+You will be asked
+\*(lqWhat now?\*(rq.
+Type a carriage return to see the options.
+Typing \fBsend\fR
+will cause the message to be sent; typing \fBquit\fR will cause an exit
+from
+.i comp ,
+with the message draft saved.
+.pp
+If you quit without sending the message, it will be saved in a file
+called /usr/<name>/Mail/draft (where /usr/<name> is your $HOME directory).
+You can edit this file and send the message later, using the
+.i send
+command.
+
+.ne 4
+.i "comp\0\-editor\0prompter"
+.pp
+This command uses a different editor and is useful for preparing
+\*(lqquick and dirty\*(rq messages.
+It prompts you for each component of the
+header.
+Type the information for that component, or type a carriage
+return to omit the component.
+After that, type the body of the
+message.
+Backspacing is the only form of editing allowed with this editor.
+When the body is complete, type a carriage return followed by <CTRL-D>
+(<OPEN> on Ann Arbor terminals).
+This completes the initial preparation of the message; from then on, use
+the same procedures as with
+.i comp
+(above).
+
+.ne 5
+.i repl
+.br
+.i "repl\0n"
+.pp
+This command makes up an initial message form with a header
+that is appropriate for
+replying to an existing message.
+The message being answered is the
+current message if no message number is mentioned, or n if a number
+is specified.
+After the header is completed, you can finish the message as in
+.i comp
+(above).
+.pp
+This is enough information to get you going using MH.
+There are more commands,
+and the commands described here have more features.
+Subsequent sections
+explain MH in complete detail.
+The system is quite powerful if you
+want to use its sophisticated features, but the foregoing commands
+suffice for sending and receiving messages.
+.pp
+There are numerous additional capabilities you may wish to explore.
+For example, the
+.i pick
+command will select a subset of messages
+based on specified criteria such as sender or subject.
+Groups of
+messages may be designated, as described in Sec. V, under \*(lqMessage
+Naming\*(rq.
+The file \*(lq\*.mh\(ruprofile\*(rq can be used to tailor your use of
+the message system to your needs and preferences, as described in Sec. V,
+under \*(lqThe User Profile\*(rq.
+In general, you may
+learn additional features of the system selectively, according to your
+requirements,
+by studying the relevant sections of this manual.
+There is no need to
+learn all the details of the system at once.
+.+c "DETAILED DESCRIPTION"
+.pp
+This section describes the MH system in detail, including the components
+of the user profile, the conventions for message naming, and some of
+the other MH conventions.
+Readers who are
+generally familiar with computer systems will be able to follow
+the principal ideas, although some details may be meaningful only to
+those familiar with UNIX.
+.uh "THE USER PROFILE"
+.pp
+The first time an MH command is issued by a new user, the system
+prompts for a \*(lqpath\*(rq and creates an MH \*(lqprofile\*(rq.
+.pp
+Each MH user has a profile which contains current
+state information for the MH package and, optionally, tailoring
+information for each individual program.
+When a folder becomes
+the current folder, it is recorded in the user's profile.
+Other profile entries control the MH path (where folders and
+special files are kept), folder and message protections, editor
+selection, and default arguments for each MH program.
+.pp
+The MH profile is stored in the file \*(lq\*.mh\(ruprofile\*(rq in the
+user's $HOME directory.
+It has the format of a message without
+any body.
+That is, each profile entry is on one line, with a
+keyword followed by a colon (:) followed by text particular to
+the keyword.
+.br
+\(rh\ \ \&
+.i "This file must not have blank lines."
+.br
+The keywords
+may have any combination of upper and lower case.
+(See Appendix
+B for a description of message formats.)
+.pp
+For the average MH user, the only profile entry of
+importance is \*(lqPath\*(rq.
+Path specifies a directory in which MH
+folders and certain files such as \*(lqdraft\*(rq are found.
+The
+argument to this keyword must be a legal UNIX path that names an
+existing directory.
+If this path is unrooted (i.e., does not
+begin with a \fB/\fR), it will be presumed to start from the
+user's $HOME directory.
+All folder and message references within
+MH will relate to this path unless full path names are used.
+.pp
+Message protection defaults to 664, and folder protection to
+751.
+These may be changed by profile entries \*(lqMsg-Protect\*(rq
+and \*(lqFolder-Protect\*(rq, respectively.
+The argument to these
+keywords is an octal number which is used as the UNIX file mode.\**
+.(f
+\**See
+.i chmod (I)
+in the
+.i "UNIX Programmer's Manual" .[5]
+.)f
+.pp
+When an MH program starts running, it looks through the
+user's profile for an entry with a keyword matching the program's
+name.
+For example, when
+.i comp
+is run, it looks for a \*(lqcomp\*(rq
+profile entry.
+If one is found, the text of the profile entry is
+used as the default switch setting until all defaults are overridden
+by explicit switches passed to the program as arguments.
+Thus the profile
+entry \*(lqcomp:\0\-form\0standard.list\*(rq would direct
+.i comp
+to use the
+file \*(lqstandard.list\*(rq as the message skeleton.
+If an explicit
+form switch is given to the
+.i comp
+command, it will override the
+switch obtained from the profile.
+.pp
+In UNIX, a program may exist under several names, either by
+linking or aliasing.
+The actual invocation name is used by an MH
+program when scanning for its profile defaults.
+Thus, each MH program
+may have several names by which it can be invoked, and each name
+may have a different set of default switches.
+For example, if
+.i comp
+is invoked by the name
+.i icomp ,
+the profile entry
+\*(lqicomp\*(rq will control the default switches for this invocation of
+the
+.i comp
+program.
+This provides a powerful
+definitional facility for commonly used switch settings.
+.pp
+The default editor
+for editing within
+.i comp ,
+.i repl ,
+.i forw ,
+and
+.i dist ,
+is \*(lq/bin/ned\*(rq.\**
+.(f
+\**See Ref. 6 for a description of
+the NED text editor.
+.)f
+A different editor may be used by specifying
+the profile entry
+\*(lqEditor: \*(rq.
+The argument to \*(lqEditor\*(rq is the name of an
+executable program or shell command file which can be found via
+the user's $PATH defined search path, excluding the current
+directory.
+The \*(lqEditor:\*(rq profile specification
+may in turn be overridden by a \*(lq\-editor\0<editor>\*(rq
+profile switch associated with
+.i comp ,
+.i repl ,
+.i forw ,
+or
+.i dist .
+Finally, an explicit editor switch specified with any
+of these four commands will have ultimate precedence.
+.pp
+During message composition, more than one editor may be
+used.
+For example, one editor (such as
+.i prompter )
+may be used
+initially, and a second editor may be invoked later to revise
+the message being composed
+(see the discussion of
+.i comp
+in Section 5 for details).
+A profile entry \*(lq<lasteditor>\-next:\0<editor>\*(rq specifies the name of
+the editor to be used after a particular editor.
+Thus \*(lqcomp:\0\-e\0prompter\*(rq
+causes the initial text to be collected by
+.i prompter ,
+and the profile entry \*(lqprompter\-next:\0ed\*(rq names ed as the
+editor to be invoked for the next round of editing.
+.pp
+Some of the MH commands, such as
+.i show ,
+can be used on
+message folders owned by others, if those folders are readable.
+However,
+you cannot write in someone else's folder.
+All the MH command
+actions not requiring write permission may be used with
+a \*(lqread-only\*(rq folder.
+In a writable folder, a file named
+\*(lqcur\*(rq is used to contain its current message name.
+For read-only folders, the current message name is
+stored in the user's profile.
+.pp
+Table 1 lists examples of the currently defined profile
+entries, typical arguments, and the programs that reference the
+entries.
+.in .9i
+.ll -.9i
+.ta 2.3i
+.sp 30p
+.ce
+Table 1
+.sp 8p
+.ce
+P\s-2ROFILE\s0 C\s-2OMPONENTS\s0
+.hl \" ~12p preceding + 1v (12p) after
+.nf
+^^MH Programs that
+^Keyword and Argument~^\ Use Component\h'|\n(.lu-.9i'\v'2p'\l'|0'\v'-2' \" \l'..' does underlining
+.sp
+^Path:\0Mail~^All
+^Current-Folder:\0inbox~^Most
+^Editor:\0/bin/ed~^\fIcomp, dist, forw, repl\fR
+^Msg\-Protect:\0644~^\fIinc\fR
+^Folder\-Protect:\0711~^\fIfile, inc, pick\fR
+^<program>:\0default switches~^All
+^cur\-<read-onlyfolder>:\0172~^Most
+^prompter\-next:\0ed~^\fIcomp, dist, forw, repl\fR
+.hl
+.ll +.9i
+.in 0
+.fi
+.pp
+Path
+.u should
+be present.
+Folder is maintained
+automatically by many MH commands (see the \*(lqContext\*(rq sections of
+the individual commands in Sec. V).
+All other entries are optional,
+defaulting to the values described above.
+.uh "MESSAGE NAMING"
+.pp
+Messages may be referred to explicitly or implicitly when
+using MH commands.
+A formal syntax of message names is given in Appendix C, but the
+following description should be sufficient for most MH users.
+Some details of message naming that apply only to certain
+commands are included in the description of those
+commands.
+.pp
+Most of the MH commands accept arguments specifying one or
+more folders, and one or more messages to operate on.
+The use of
+the word \*(lqmsg\*(rq as an argument to a command means that exactly one
+message name may be specified.
+A message name may be a number,
+such as 1, 33, or 234, or it may be
+one of the \*(lqreserved\*(rq message names:
+first, last, prev, next, and cur.
+(As a shorthand, a
+period (\*.) is equivalent to cur.)
+The meanings of these names
+are straightforward: \*(lqfirst\*(rq is the first message in the
+folder; \*(lqlast\*(rq is the last
+message in the folder; \*(lqprev\*(rq is the
+message numerically previous to the current message; \*(lqnext\*(rq
+is the message numerically following the current message; \*(lqcur\*(rq
+(or \*(lq\*.\*(rq) is the current message in the folder.
+.pp
+The default in commands that take a \*(lqmsg\*(rq argument is
+always \*(lqcur\*(rq.
+.pp
+The word \*(lqmsgs\*(rq indicates that several messages may be
+specified.
+Such a specification consists of several message
+designations separated by spaces.
+A message designation is
+either a message name or a message range.
+A message range is a
+specification of the form name1\-name2 or name1:n, where name1 and
+name2 are message names and n is an integer.
+The first form
+designates all the messages from name1 to name2 inclusive; this
+must be a non-empty range.
+The second form specifies up to n
+messages, starting with name1 if name1 is a number, or first,
+cur, or next, and ending with name1 if name1 is last or
+prev.
+This interpretation of n is overridden if n is preceded
+by a plus sign or a minus sign;
++n always means up to n messages starting with
+name1, and \-n always means up to n messages ending with name1.
+Repeated specifications of the same message have the same effect
+as a single specification of
+the message.
+Examples of
+specifications are:
+
+.(b
+1 5 7\-11 22
+first 6 8 next
+first\-10
+last:5
+.)b
+.pp
+The message name \*(lqall\*(rq is a shorthand for \*(lqfirst\-last\*(rq,
+indicating all of the messages in the folder.
+.pp
+The limit on the number of messages in an expanded message
+list is generally 999\*-the maximum number of messages in a
+folder.
+However, the
+.i show
+command and the
+commands `\fIpick\0\-scan\fR' and `\fIpick\0\-show\fR'
+are constrained to have argument lists
+that are no more than 512 characters long.
+(Under Version 7 UNIX this limit is 4096.)
+.pp
+In commands that accept \*(lqmsgs\*(rq arguments, the default is
+either cur or all, depending on which makes more sense.
+.pp
+In all of the MH commands, a plus sign preceding an argument
+indicates a folder name.
+Thus, \*(lq+inbox\*(rq is the name of the
+user's standard inbox.
+If an explicit folder argument is given
+to an MH command, it will become the current folder (that is,
+the \*(lqCurrent-Folder:\*(rq entry
+in \*(lq\*.mh\(ruprofile\*(rq will be changed to this
+folder).
+In the case of the
+.i file
+and
+.i pick
+commands, which
+can have multiple output folders, a new source folder (other than
+the default current folder) is specified by \*(lq\-src\0+folder\*(rq.
+.uh "OTHER MH CONVENTIONS"
+.pp
+One very powerful feature of MH is that the MH commands may
+be issued from any current directory, and the proper path to
+the appropriate folder(s) will be taken from the user's profile.
+If the MH path is not appropriate for a specific folder or file,
+the automatic prepending of the MH path can be avoided by
+beginning a folder or file name with \fB/\fR.
+Thus any specific full
+path may be specified.
+.pp
+Arguments to the various programs may be given in any order,
+with the exception of a few switches whose arguments must follow
+immediately, such as \*(lq\-src\0+folder\*(rq for \fIpick\fR and \fIfile\fR.
+.pp
+Whenever an MH command prompts the user, the valid options
+will be listed in response to a <RETURN>.
+(The first of the
+listed options is the default if end-of-file is encountered, such
+as from a command file.) A valid response is any \fIunique\fR
+abbreviation of one of the listed options.
+.pp
+Standard UNIX documentation conventions are used in this report
+to describe MH command syntax.
+Arguments enclosed in brackets
+([ ]) are optional; exactly one of the arguments enclosed
+within braces ({ }) must be specified, and all other
+arguments are required.
+The use of ellipsis dots (...) indicates
+zero or more repetitions of the previous item.
+For example,
+\*(lq+folder ...\*(rq would indicate that one or more \*(lq+folder\*(rq arguments
+is required and \*(lq[+folder ...]\*(rq indicates that 0 or more
+\*(lq+folder\*(rq arguments may be given.
+.pp
+MH departs from UNIX standards by using switches that consist of
+more than one character, e.g. \*(lq\-header\*(rq.
+To minimize typing,
+only a unique abbreviation of a switch need be typed; thus, for
+\*(lq\-header\*(rq, \*(lq\-hea\*(rq is probably sufficient, depending on the
+other switches the command accepts.
+Each MH program
+accepts the switch \*(lq\-help\*(rq (which \fImust\fR be spelled out fully)
+and produces a syntax description and a list of switches.
+In the
+list of switches, parentheses indicate required characters.
+For example, all \*(lq\-help\*(rq switches will appear as \*(lq\-(help)\*(rq,
+indicating that no abbreviation is accepted.
+.pp
+Many MH switches have both on and off forms, such as
+\*(lq\-format\*(rq and \*(lq\-noformat\*(rq.
+In many of the descriptions in Sec. V,
+only one form is defined; the other form, often used to
+nullify profile switch settings, is assumed to be the opposite.
+.br
+.bp
+.uh "MH COMMANDS"
+.pp
+The MH package comprises 16 programs:
+
+.nf
+.in .5i
+.ta 1.5i
+^comp~^Compose a message
+^dist~^Redistribute a message
+^file~^Move messages between folders
+^folder~^Select/list status of folders
+^forw~^Forward a message
+^inc~^Incorporate new mail
+^next~^Show the next message
+^pick~^Select a set of messages by context
+^prev~^Show the previous message
+^prompter~^Prompting editor front end for composing messages
+^repl~^Reply to a message
+^rmf~^Remove a folder
+^rmm~^Remove messages
+^scan~^Produce a scan listing of selected messages
+^send~^Send a previously composed message
+^show~^Show messages
+.fi
+.re
+.pp
+These programs are described below.
+The form of the descriptions
+conforms to the standard
+form for the description of UNIX commands.
+.if t \{
+.ll 6.5i
+.lt 6.5i
+\}
+.fo '7th Edition'UNIX/32V(Rand)''
+.de SC
+.he '\\$1(1)'-%-'\\$1(1)'
+.bp
+.(x
+.ti .8i
+\\$1
+.)x
+..
+.de NA
+.b \\s-2NAME\\s0
+.ti .5i
+..
+.de SY
+.sp
+.b \\s-2SYNOPSIS\\s0
+.in 1i
+.ti .5i
+.na
+..
+.de DE
+.ad
+.sp
+.in 0
+.b \\s-2DESCRIPTION\\s0
+.sp
+.fi
+.in .5i
+..
+.de Fi
+.(b L
+.ti 0
+.b \\s-2Files\\s0
+.ta 2i
+..
+.de Pr
+.)b
+.(b L F
+.in 2.5i
+.ti 0
+.b "\\s-2Profile Components\\s0"
+.ti .5i
+..
+.de Ps
+.ti .5i
+..
+.de De
+.)b
+.(b L
+.in .5i
+.ti 0
+.b \\s-2Defaults\\s0
+..
+.de Co
+.)b
+.(b L F
+.ti 0
+.b \\s-2Context\\s0
+.br
+..
+.de En
+.)b
+.in 0
+..
+.SC COMP
+.NA
+comp \- compose a message
+
+.SY
+comp \%[\-editor\ editor] \%[\-form\ formfile] \%[file] \%[\-use]
+\%[\-nouse] \%[\-help]
+
+.DE
+\fIComp\fP is used to create a new message to be mailed.
+If
+\fIfile\fP is not specified, the file named \*(lqdraft\*(rq in the user's MH
+directory will be used.
+\fIComp\fR copies a message form to
+the file being composed and then invokes an editor on the
+file.
+The default editor is /bin/ned, which may be overridden with
+the `\-editor' switch or with a profile entry \*(lqEditor:\*(rq.
+(See Ref. 5 for a
+description of the NED text editing system.)
+The default
+message form contains the following elements:
+
+ To:
+ cc:
+ Subject:
+ ----------
+
+If the file named \*(lqcomponents\*(rq exists in the user's MH directory,
+it will be used instead of this form.
+If `\-form
+formfile' is specified, the specified formfile (from the MH
+directory) will be used as the skeleton.
+The line of dashes
+or a blank line must be left between the header and the
+body of the message for the message to be identified properly when it is
+sent (see \fIsend;\fR).
+The switch `\-use' directs \fIcomp\fR to
+continue editing an already started message.
+That is, if a
+\fIcomp\fR (or \fIdist\fR, \fIrepl\fR, or \fIforw\fR) is terminated without
+sending the message, the message can be edited again via
+\*(lqcomp \-use\*(rq.
+
+If the specified file (or draft) already exists, \fIcomp\fR will ask
+if you want to delete it before continuing.
+A reply of \fBNo\fR will abort the
+\fIcomp\fR, \fByes\fR will replace the existing draft with a blank
+skeleton, \fBlist\fR will display the draft, and \fBuse\fR will use it
+for further composition.
+
+Upon exiting from the editor, \fIcomp\fR will ask \*(lqWhat now?\*(rq.
+The valid
+responses are \fBlist\fR, to list the draft on the terminal; \fBquit\fR, to
+terminate the session and preserve the draft; \fBquit delete\fR, to terminate,
+then delete the draft; \fBsend\fR, to send the message; \fBsend verbose\fR, to
+cause the delivery process to be monitored; \fBedit <editor>\fR, to invoke
+<editor> for further editing; and \fBedit\fR, to re-edit using the
+same editor that was used on the preceding round unless a profile
+entry \*(lq<lasteditor>\-next: <editor>\*(rq names an alternative editor.
+
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`file' defaults to draft
+`\-editor' defaults to /bin/ned
+`\-nouse'
+.Co
+\fIComp\fR does not affect either the current folder or the current message.
+.En
+.SC DIST
+.NA
+dist \- redistribute a message to additional addresses
+.SY
+dist \%[+folder] \%[msg] \%[\-form\ formfile] \%[\-editor\ editor]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+.DE
+\fIDist\fR is similar to \fIforw\fR.
+It prepares the specified
+message for redistribution to addresses that (presumably) are
+not on the original address list.
+The file \*(lqdistcomps\*(rq in the
+user's MH directory, or a standard form, or the file specified by
+`\-form formfile' will be used as the blank components file to
+be prepended to the message being distributed.
+The standard form
+has the components \*(lqDistribute-to:\*(rq and \*(lqDistribute-cc:\*(rq.
+When
+the message is sent, \*(lqDistribution-Date:\0date\*(rq,
+\*(lqDistribution-From:\0name\*(rq, and
+\*(lqDistribution-Id:\0id\*(rq (if `\-msgid' is
+specified to \fIsend\fR;) will be prepended to the outgoing message.
+Only those addresses in \*(lqDistribute-To\*(rq, \*(lqDistribute-cc\*(rq, and
+\*(lqDistribute-Bcc\*(rq will be sent.
+Also, a \*(lqDistribute-Fcc:\0folder\*(rq
+will be honored (see \fIsend;\fR).
+
+\fISend\fR recognizes a message as a redistribution message by the
+existence of the field \*(lqDistribute-To:\*(rq, so don't try to
+redistribute a message with only a \*(lqDistribute-cc:\*(rq.
+
+If the `\-annotate' switch is given, each message being
+distributed will be annotated with the lines:
+
+ Distributed:\0\*(<<date\*(>>
+ Distributed:\0Distribute-to: names
+
+where each \*(lqto\*(rq list contains as many lines as required.
+This annotation
+will be done only if the message is sent directly from \fIdist\fR.
+If the
+message is not sent immediately from \fIdist\fR (i.e., if it is sent later
+via \fIsend;\fR),
+\*(lqcomp \-use\*(rq may be used to re-edit and send the constructed message, but
+the annotations won't take place.
+The '\-inplace' switch causes annotation to
+be done in place in order to preserve links to the annotated message.
+
+See \fIcomp\fR for a description of the `\-editor' switch and for options
+upon exiting from the editor.
+
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`+folder' defaults to the current folder
+`msg' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a +folder is specified, it will become the current
+folder, and the current message will be set to the message
+being redistributed.
+.En
+.SC FILE
+.NA
+file \- file message(s) in (an)other folder(s)
+.SY
+file \%[\-src\ +folder] \%[msgs] \%[\-link] \%[\-preserve] \%+folder\ ...
+\%[\-nolink] \%[\-nopreserve]
+\%[\-file\ file] \%[\-nofile] \%[\-help]
+.DE
+\fIFile\fR moves (\fImv\fR(I)) or links (\fIln\fR(I)) messages from a
+source folder into one or more destination folders.
+If you think
+of a message as a sheet of paper, this operation is not
+unlike filing the sheet of paper (or copies) in file cabinet
+folders.
+When a message is filed, it is linked into the
+destination folder(s) if possible, and is copied otherwise.
+As long
+as the destination folders are all on the same file system, multiple filing
+causes little storage overhead.
+This facility provides a good way to cross-file or multiply-index
+messages.
+For example, if a message is received from Jones about
+the ARPA Map Project, the command
+
+ file\0cur\0+jones\0+Map
+
+would allow the message to be found in either of the two
+folders `jones' or `Map'.
+
+The option `\-file file' directs \fIfile\fR to use the specified
+file as the source message to be filed, rather than a message from
+a folder.
+
+If a destination folder doesn't exist, \fIfile\fR will ask if you
+want to create one.
+A negative response will abort the file
+operation.
+
+`\-link' preserves the source folder copy of the message
+(i.e., it does a \fIln\fR(I) rather than a \fImv\fR(I)), whereas,
+`\-nolink' deletes the \*(lqfiled\*(rq messages from the source
+folder.
+Normally, when a message is filed, it is assigned the
+next highest number available in each of the destination folders.
+Use of the `\-preserve' switch will override this message
+\*(lqrenaming\*(rq, but name conflicts may occur, so
+use this switch cautiously.
+(See \fIpick\fR for more details on
+message numbering.)
+
+If `\-link' is not specified (or `\-nolink' is specified),
+the filed messages will be removed (unlink(II)) from the
+source folder.
+
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.Ps
+^Folder\-Protect:~^To set mode when creating a new folder
+.De
+`\-src +folder' defaults to the current folder
+`msgs' defaults to cur
+`\-nolink'
+`\-nopreserve'
+`\-nofile'
+.Co
+If `\-src +folder' is given, it will become the
+current folder for future MH commands.
+If neither `\-link' nor
+`all' are specified, the current message in the source
+folder will be set to the last message specified; otherwise, the
+current message won't be changed.
+.En
+.SC FOLDER
+.NA
+folder \- set/list current folder/message
+.SY
+folder \%[+folder] \%[msg] \%[\-all] \%[\-fast] \%[\-nofast] \%[\-up] \%[\-down]
+\%[\-header] \%[\-noheader] \%[\-total] \%[\-nototal] \%[\-pack] \%[\-nopack]
+\%[\-help]
+
+.ti .5i
+folders <equivalent to 'folder \-all'>
+.DE
+Since the MH environment is the shell, it is easy to lose
+track of the current folder from day to day.
+\fIFolder\fR will
+list the current folder, the number of messages in it, the
+range of the messages (low-high), and the current message within
+the folder, and will flag a selection list or extra files if they
+exist.
+An example of the output is:
+
+ inbox+ has 16 messages ( 3\- 22); cur= 5.
+
+If a `+folder' and/or `msg' are specified, they will
+become the current folder and/or message.
+An `\-all' switch
+will produce a line for each folder in the user's MH directory,
+sorted alphabetically.
+These folders are preceded by the read-only
+folders, which occur as \*.mh\(ruprofile \*(lqcur\-\*(rq entries.
+For example,
+
+.nf
+.ta 1.5i 2.1i 2.7i 3.5i
+^~Folder\ \ ^^~#\ of\ ^^messages~^^(~\ range\~ );\ ^cur msg (other files)
+^~/fsd/rs/m/tacc\ \ ^^has~35\ ^^messages~^^(~1\-\035);\ ^cur=\ 23.
+^~/rnd/phyl/Mail/EP\ \ ^^has~82\ ^^messages~^^(~1\-108);\ ^cur=\ 82.
+^~f\&f\ \ ^^has~4\ ^^messages~^^(~1\-\0\04);\ ^cur=\ \01.
+^~inbox+\ ^^has~16\ ^^messages~^^(~3\-\022);\ ^cur=\ \05.
+^~mh\ \ ^^has~76\ ^^messages~^^(~1\-\076);\ ^cur=\ 70.
+^~notes\ \ ^^has~2\ ^^messages~^^(~1\-\0\02);\ ^cur=\ \01.
+^~ucom\ \ ^^has~124\ ^^messages~^^(~1\-124);\ ^cur=\ \06; (select).
+
+^^^~TOTAL=\0339\ ^messages\0in\0\07\0Folders.
+.re
+.fi
+
+The \*(lq+\*(rq after inbox indicates that it is the current folder.
+The \*(lq(select)\*(rq indicates that the folder ucom has a selection
+list produced by \fIpick\fR.
+If \*(lqothers\*(rq had appeared in parentheses at
+the right of a line, it would indicate that there are files in
+the folder directory that don't belong under the MH file naming
+scheme.
+
+The header is output if either an `\-all' or a `\-header' switch
+is specified; it is suppressed by `\-noheader'.
+Also, if \fIfolder\fR
+is invoked by a name ending with \*(lqs\*(rq (e.g., \fIfolders\fR),
+`\-all' is assumed.
+A `\-total' switch will produce only the
+summary line.
+
+If `\-fast' is given, only the folder name (or names in the
+case of `\-all') will be listed.
+(This is faster because the
+folders need not be read.)
+
+The switches `\-up' and `\-down' change the folder to be the
+one above or below the current folder.
+That is, \*(lqfolder \-down\*(rq
+will set the folder to \*(lq<current\-folder>/select\*(rq, and if the
+current folder is a selection-list folder, \*(lqfolder \-up\*(rq will
+set the current folder to the parent of the selection-list.
+(See \fIpick\fR for details on selection-lists.)
+
+The `\-pack' switch will compress the message names in a folder, removing
+holes in message numbering.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^/bin/ls~^To fast-list the folders
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to the current folder
+`msg' defaults to none
+`\-nofast'
+`\-noheader'
+`\-nototal'
+`\-nopack'
+.Co
+If `+folder' and/or `msg' are given, they will become the
+current folder and/or message.
+.En
+.SC FORW
+.NA
+forw \- forward messages
+.SY
+forw \%[+folder] \%[msgs] \%[\-editor\ editor] \%[\-form\ formfile]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+.DE
+\fIForw\fR may be used to prepare a message containing other
+messages.
+It constructs the new message from the components file
+or `\-form formfile' (see \fIcomp\fR), with a body composed of the
+message(s) to be forwarded.
+An editor is invoked as in \fIcomp\fR,
+and after editing is complete, the user is prompted before the message
+is sent.
+
+If the `\-annotate' switch is given, each message being
+forwarded will be annotated with the lines
+
+ Forwarded: \*(<<date\*(>>
+ Forwarded: To: names
+ Forwarded: cc: names
+
+where each \*(lqTo:\*(rq and \*(lqcc:\*(rq list contains as many lines as required.
+This annotation will be done only if the message is sent directly
+from \fIforw\fR.
+If the message is not sent immediately from \fIforw\fR,
+\*(lqcomp \-use\*(rq may be used in a later session to re-edit and send
+the constructed message, but the annotations won't take place.
+The `\-inplace' switch permits annotating a message in place in
+order to preserve its links.
+
+See \fIcomp\fR for a description of the `\-editor' switch.
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^Current-Folder:~^To find the default current folder
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`+folder' defaults to the current folder
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a +folder is specified, it will become
+the current folder, and the current message will be set to
+the first message being forwarded.
+.En
+.SC INC
+.NA
+inc \- incorporate new mail
+.SY
+inc \%[+folder] \%[\-audit\ audit-file] \%[\-help]
+.DE
+\fIInc\fR incorporates mail from the user's incoming mail drop
+(\*.mail) into an MH folder.
+If `+folder' isn't specified,
+the folder named \*(lqinbox\*(rq in the user's MH directory will be used.
+The
+new messages being incorporated are assigned numbers starting
+with the next highest number in the folder.
+If the specified (or
+default) folder doesn't exist, the user will be queried prior to
+its creation.
+As the messages are processed, a \fIscan\fR listing
+of the new mail is produced.
+
+If the user's profile contains a \*(lqMsg\-Protect: nnn\*(rq entry, it
+will be used as the protection on the newly created messages,
+otherwise the MH default of 664 will be used.
+During all
+operations on messages, this initially assigned protection will
+be preserved for each message, so \fIchmod\fR(I) may be used to set a
+protection on an individual message, and its protection will be
+preserved thereafter.
+
+If the switch `\-audit audit-file' is specified (usually as a
+default switch in the profile), then \fIinc\fR will append a header
+line and a line per message to the end of the specified
+audit-file with the format:
+
+.nf
+.ti 1i
+\*(<<inc\*(>> date
+.ti 1.5i
+<scan line for first message>
+.ti 1.5i
+<scan line for second message>
+.ti 2.5i
+<etc.>
+.fi
+
+This is useful for keeping track of volume and source of incoming
+mail.
+Eventually, \fIrepl\fR, \fIforw\fR, \fIcomp\fR, and \fIdist\fR may also
+produce audits to this (or another) file, perhaps with
+\*(lqMessage-Id:\*(rq information to keep an exact correspondence history.
+\*(lqAudit-file\*(rq will be in the user's MH directory unless a full
+path is specified.
+
+\fIInc\fR will incorporate even illegally formatted messages into the
+user's MH folder, inserting a blank line prior to the offending
+component and printing a comment identifying the bad message.
+
+In all cases, the \*.mail file will be zeroed.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^$HOME/\*.mail~^The user's mail drop
+^<mh-dir>/audit-file~^Audit trace file (optional)
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Folder\-Protect:~^For protection on new folders
+.Ps
+^Msg\-Protect:~^For protection on new messages
+.De
+`+folder' defaults to \*(lqinbox\*(rq
+.Co
+The folder into which the message is
+being incorporated will become the
+current folder, and the first message incorporated will be the
+current message.
+This leaves the context ready for a \fIshow\fR
+of the first new message.
+.En
+.SC NEXT
+.NA
+next \- show the next message
+.SY
+next \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+.DE
+\fINext\fR performs a \fIshow\fR on the next message in the
+specified (or current) folder.
+Like \fIshow\fR, it passes any
+switches on to the program \fIl\fR, which is called to list the
+message.
+This command is exactly equivalent to \*(lqshow next\*(rq.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+.Co
+If a folder is specified, it will become the current folder, and the
+message that is shown (i.e., the next message in sequence)
+will become the current message.
+.En
+.SC PICK
+.NA
+pick \- select messages by content
+.SY
+.ta .4i 1.8i
+.nf
+.in .5i
+^pick~^^\0\-cc~^ \%[\-src\ +folder] \%[msgs] \%[\-help] \%[\-scan] \%[\-noscan]
+^^^\0\-date~^ \%[\-show] \%[\-noshow] \%[\-nofile] \%[\-nokeep]
+^^^\0\-from~^
+^^^\s+2\b'\(lt\(bv\(bv\(lk\(bv\(bv\(lb'\s0 \-search~\s+2\b'\(rt\(bv\(bv\(rk\(bv\(bv\(rb'\s0^ pattern
+^^^\0\-subject~^
+^^^\0\-to~^ \%[\-file \%[\-preserve] \%[\-link] \%+folder\ ... \%[\-nopreserve] \%[\-nolink] ]
+^^^\0\-\-component~^ \%[\-keep \%[\-stay] \%[\-nostay] \%[+folder\ ...]\ ]
+.fi
+
+.re
+.ti .5i
+typically:
+.in 1i
+pick\0\-from\0jones\0\-scan
+.br
+pick\0\-to\0holloway
+.br
+pick\0\-subject\0ned\0\-scan\0\-keep
+.DE
+\fIPick\fR searches messages within a folder for the specified
+contents, then performs several operations on the selected
+messages.
+
+A modified \fIgrep\fR(I) is used to perform the searching, so the
+full regular expression (see \fIed\fR(I)) facility is available
+within `pattern'.
+With `\-search', pattern is used directly,
+and with the others, the grep pattern constructed is:
+
+.ti +.5i
+\*(lq^component:\*.\*(**pattern\*(rq
+
+This means that the pattern specified for a `\-search' will be
+found everywhere in the message, including the header and the body,
+while the other search requests are limited to the single
+specified component.
+The expression `\-\-component pattern'
+is a shorthand for
+specifying `\-search \*(lqcomponent:\*.\*(**pattern\*(rq\ '; it is used to pick
+a component not in the set [cc date from subject to].
+An
+example is \*(lqpick \-\-reply\-to pooh \-show\*(rq.
+
+Searching is performed on a per-line basis.
+Within the header of
+the message, each component is treated as one long line, but in
+the body, each line is separate.
+Lower-case letters in the
+search pattern will match either lower or upper case in the
+message, while upper case will match only upper case.
+
+Once the search has been performed, the selected messages
+are scanned (see \fIscan\fR) if the `\-scan' switch is given, and
+then they are shown (see \fIshow\fR) if the `\-show' switch is
+given.
+After these two operations, the file operations (if
+requested) are performed.
+
+The `\-file' switch operates exactly like the \fIfile\fR command, with the
+same meaning for the `\-preserve' and `\-link' switches.
+
+The `\-keep' switch is similar to `\-file', but it produces a folder that
+is a subfolder of the folder being searched and defines it as
+the current folder (unless the `\-stay' flag is used).
+This
+subfolder contains the messages which matched the search
+criteria.
+All of the MH commands may be used with the sub-folder
+as the current folder.
+This gives the user considerable power
+in dealing with subsets of messages in a folder.
+
+The messages in a folder produced by `\-keep' will always have the
+same numbers as they have in the source folder (i.e., the
+`\-preserve' switch is automatic).
+This way, the message
+numbers are consistent with the folder from which the messages
+were selected.
+Messages are not removed from the source folder
+(i.e., the `\-link' switch is assumed).
+If a `+folder' is not
+specified, the standard name \*(lqselect\*(rq will be used.
+(This is the
+meaning of \*(lq(select)\*(rq when it appears in the output of the
+\fIfolder\fR command.) If `+folder' arguments are given to
+`\-keep', they will be used rather than \*(lqselect\*(rq for the names
+of the subfolders.
+This allows for several subfolders to be
+maintained concurrently.
+
+When a `\-keep' is performed, the subfolder becomes the current folder.
+This can be overridden by use
+of the `\-stay' switch.
+
+Here's an example:
+
+.nf
+\01 % folder +inbox
+\02 inbox+ has 16 messages ( 3\- 22); cur= 3.
+\03 % pick \-from dcrocker
+\04 6 hits.
+\05 [+inbox/select now current]
+\06 % folder
+\07 inbox/select+ has \06 messages ( 3\- 16); cur= 3.
+\08 % scan
+.ds p \\h'\\w'+'u'
+\09 \03+ 6/20 Dcrocker Re: ned file update issue...
+10 \06\*p 6/23 Dcrocker removal of files from /tm...
+11 \08\*p 6/27 Dcrocker Problems with the new ned...
+12 13\*p 6/28 d\h'\w'D'u-\w'd'u'crocker newest nned \*(<<I would ap...
+13 15\*p 7/\05 Dcrocker nned \*(<<Last week I asked...
+14 16\*p 7/\05 d\h'\w'D'u-\w'd'u'crocker message id format \*(<<I re...
+15 % show all | print
+16 [produce a full listing of this set of messages on the line printer.]
+17 % folder \-up
+18 inbox+ has 16 messages ( 3\- 22); cur= 3; (select).
+19 % folder \-down
+20 inbox/select+ has 6 messages ( 3\- 16); cur= 3.
+21 % rmf
+22 [+inbox now current]
+23 % folder
+24 inbox+ has 16 messages ( 3\- 22); cur= 3.
+.fi
+
+This is a rather lengthy example, but it shows the power of the
+MH package.
+In item 1, the current folder is set to inbox.
+In 3,
+all of the messages from dcrocker are found in inbox and linked
+into the folder \*(lqinbox/select\*(rq.
+(Since no action switch is
+specified, `\-keep' is assumed.) Items 6 and 7 show that this
+subfolder is now the current folder.
+Items 8 through 14 are a
+\fIscan\fR of the selected messages (note that they are all from dcrocker
+and are all in upper and lower case).
+Item 15 lists all of the messages to
+the high-speed printer.
+Item 17 directs \fIfolder\fR to set the
+current folder to the parent of the selection-list folder, which
+is now current.
+Item 18 shows that this has been done.
+Item 19 resets
+the current folder to the selection list, and 21 removes the
+selection-list folder and resets the current folder to the
+parent folder, as shown in 22 and 23.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Folder\-Protect:~^For protection on new folders
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`\-src +folder' defaults to current
+`msgs' defaults to all
+.fi
+`\-keep +select' is the default if no `\-scan', `\-show', or `\-file' is specified
+.Co
+If a `\-src +folder' is specified, it will
+become the current folder, unless a `\-keep' with 0 or 1
+folder arguments makes the selection-list subfolder the
+current folder.
+Each selection-list folder will have its
+current message set to the first of the messages linked into
+it unless the selection list already existed, in which case the
+current message won't be changed.
+.En
+.SC PREV
+.NA
+prev \- show the previous message
+.SY
+prev \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+.DE
+\fIPrev\fR performs a \fIshow\fR on the previous message in the specified
+(or current) folder.
+Like \fIshow\fR, it passes any switches on to the
+program \fIl\fR, which is called to list the message.
+This command
+is exactly equivalent to \*(lqshow prev\*(rq.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+.Co
+If a folder is specified, it will become current, and the
+message that is shown (i.e., the previous message in sequence)
+will become the current message.
+.En
+.SC PROMPTER
+.NA
+prompter \- prompting editor front end
+.SY
+This program is not called directly but takes the place
+of an editor and acts as an editor front end.
+
+.ti .5i
+prompter \%[\-erase\ chr] \%[\-kill\ chr] \%[\-help]
+.DE
+\fIPrompter\fR is an editor which allows rapid composition of
+messages.
+It is particularly useful to network and low-speed
+(less than 2400 baud) users of MH.
+It is an MH program in that
+it can have its own profile entry with switches, but it can't
+be invoked directly as all other MH commands can; it is an editor
+in that it is invoked by an \*(lq\-editor prompter\*(rq switch or by the
+profile entry \*(lqEditor: prompter\*(rq, but functionally it is merely
+a text-collector and not a true editor.
+
+\fIPrompter\fR expects to be called from \fIcomp\fR, \fIrepl\fR, \fIdist\fR, or
+\fIforw\fR, with a draft file as an argument.
+For example, \*(lqcomp
+\-editor prompter\*(rq will call \fIprompter\fR with the file \*(lqdraft\*(rq already set
+up with blank components.
+For each blank component it finds in
+the draft, it prompts the user and accepts a response.
+A
+<RETURN> will cause the whole component to be left out.
+A \*(lq\\\*(rq
+preceding a <RETURN> will continue the response on the next line,
+allowing for multiline components.
+
+Any component that is non-blank will be copied and echoed to the
+terminal.
+
+The start of the message body is prompted by a line of
+dashes.
+If the body is non-blank, the prompt is
+\*(lq--------Enter additional text\*(rq.
+Message-body typing is terminated with
+a <CTRL-D> (or <OPEN>).
+Control is returned to the calling
+program, where the user is asked \*(lqWhat now?\*(rq.
+See \fIcomp\fR for
+the valid options.
+
+The line editing characters for kill and erase may be
+specified by the user via the arguments \*(lq\-kill chr\*(rq and \*(lq\-erase
+chr\*(rq, where chr may be a character; or \*(lq\\nnn\*(rq, where nnn is the
+octal value for the character.
+(Again, these may come from the
+default switches specified in the user's profile.)
+
+A <DEL> during message-body typing is equivalent to
+<CTRL-D> for compatibility with NED.
+A <DEL> during
+component typing will abort the command that invoked
+\fIprompter\fR.
+.Fi
+None
+.Pr
+^prompter-next:~^To name the editor to be used on exit from \fIprompter\fR
+.De
+.Co
+None
+.En
+.SC REPL
+.NA
+repl \- reply to a message
+.SY
+repl \%[+folder] \%[msg] \%[\-editor\ editor] \%[\-inplace] \%[\-annotate]
+\%[\-help] \%[\-noinplace]
+\%[\-noannotate]
+.DE
+\fIRepl\fR aids a user in producing a reply to an existing
+message.
+In its simplest form (with no arguments), it will set up
+a message-form skeleton in reply to the current message in the
+current folder, invoke the editor, and send the composed
+message if so directed.
+The composed message is constructed as
+follows:
+
+.nf
+.in 1i
+To: <Reply-To> or <From>
+cc: <cc>, <To>
+Subject: Re: <Subject>
+In-reply-to: Your message of <Date>
+.ti +\w'In-reply-to: 'u
+<Message-Id>
+.in .5i
+.fi
+
+where field names enclosed in angle brackets (< >) indicate the
+contents of the named field from the message to which the reply
+is being made.
+Once the skeleton is constructed, an editor is
+invoked (as in \fIcomp\fR, \fIdist\fR, and \fIforw\fR).
+While in the editor,
+the message being replied to is available through a link named
+\*(lq@\*(rq.
+In NED, this means the replied-to message may be \*(lqused\*(rq
+with \*(lquse @\*(rq, or put in a window by \*(lqwindow @\*(rq.
+
+As in \fIcomp\fR, \fIdist\fR, and \fIforw\fR, the user will be queried
+before the message is sent.
+If `\-annotate' is
+specified, the replied-to message will be annotated with the
+single line
+
+.ti +.5i
+Replied: \*(<<Date\*(>>.
+
+The command
+\*(lqcomp \-use\*(rq may be used to pick up interrupted editing, as in
+\fIdist\fR and \fIforw\fR; the `\-inplace' switch annotates the message in place,
+so that all folders with links to it will see the annotation.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The constructed message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a `+folder' is specified, it will become the current
+folder, and the current message will be set to the replied-to
+message.
+.sp 2
+.En
+.SC RMF
+.NA
+rmf \- remove folder
+.SY
+rmf \%[+folder] \%[\-help]
+.DE
+\fIRmf\fR removes all of the files (messages) within the specified
+(or default) folder, and then removes the directory (folder).
+If
+there are any files within the folder which are not a part of MH,
+they will \fInot\fR be removed, and an error will be produced.
+If the
+folder is given explicitly or the current folder is a
+subfolder (i.e., a selection list from \fIpick\fR), it will be
+removed without confirmation.
+If no argument is specified and
+the current folder is not a selection-list folder, the
+user will be asked for confirmation.
+
+\fIRmf\fR irreversibly deletes messages that don't have other links,
+so use it with caution.
+
+If the folder being removed is a subfolder, the parent
+folder will become the new current folder, and \fIrmf\fR will
+produce a message telling the user this has happened.
+This
+provides an easy mechanism for selecting a set of messages,
+operating on the list, then removing the list and returning to
+the current folder from which the list was extracted.
+(See the
+example under \fIpick\fR.)
+
+The files that \fIrmf\fR will delete are cur, any file beginning
+with a comma, and files with purely numeric names.
+All others
+will produce error messages.
+
+\fIRmf\fR of a read-only folder will delete the \*(lqcur\-\*(rq entry from the
+profile without affecting the folder itself.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current, usually with confirmation
+.Co
+\fIRmf\fR will set the current folder to the parent folder if a
+subfolder is removed; or if the current folder is removed,
+it will make \*(lqinbox\*(rq current.
+Otherwise, it doesn't change the
+current folder or message.
+.En
+.SC RMM
+.NA
+rmm \- remove messages
+.SY
+rmm \%[+folder] \%[msgs] \%[\-help]
+.DE
+\fIRmm\fR removes the specified messages by renaming the message
+files with preceding commas.
+(This is the Rand-UNIX backup file
+convention.)
+
+The current message is not changed by \fIrmm\fR, so a \fInext\fR will
+advance to the next message in the folder as expected.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+.Co
+If a folder is given, it will become current.
+.En
+.SC SCAN
+.NA
+scan \- produce a one-line-per-message scan listing
+.SY
+scan \%[+folder] \%[msgs] \%[\-f\&f] \%[\-header] \%[\-help]
+\%[\-nof\&f] \%[\-noheader]
+.DE
+\fIScan\fR produces a one-line-per-message listing of the specified
+messages.
+Each \fIscan\fR line contains the message number (name),
+the date, the \*(lqFrom\*(rq field, the \*(lqSubject\*(rq field, and, if room
+allows, some of the body of the message.
+For example:
+
+.nf
+.ta .5i 1.2i 2.6i
+^ #~^^Date~^^ From~^Subject\ \ \ \ \[\*(<<Body]
+^15+~^^7/\05~^^Dcrocker~^nned \*(<<Last week I asked some of
+^16\ \-~^^7/\05~^^dcrocker~^message id format \*(<<I recommend
+^18~^^7/\06~^^Obrien~^Re: Exit status from mkdir
+^19~^^7/\07~^^Obrien~^"scan" listing format in MH
+.re
+.fi
+
+The `+' on message 15 indicates that it is the current message.
+The `\-' on message 16 indicates that it has been
+replied to, as indicated by a \*(lqReplied:\*(rq component produced by
+an `\-annotate' switch to the \fIrepl\fR command.
+
+If there is sufficient room left on the \fIscan\fR line after the
+subject, the line will be filled with text from the body,
+preceded by \*(<<.
+\fIScan\fR actually reads each of the specified
+messages and parses them to extract the desired fields.
+During parsing, appropriate error messages will be produced if
+there are format errors in any of the messages.
+
+The `\-header' switch produces a header line prior to the \fIscan\fR
+listing, and the `\-f\&f' switch will cause a form feed to be
+output at the end of the \fIscan\fR listing.
+See Appendix D.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+Defaults:
+`+folder' defaults to current
+`msgs' defaults to all
+`\-nof\&f'
+`\-noheader'
+.Co
+If a folder is given, it will become current.
+The current
+message is unaffected.
+.En
+.SC SEND
+.NA
+send \- send a message
+.SY
+send \%[file] \%[\-draft] \%[\-verbose] \%[\-format] \%[\-msgid]
+\%[\-help] \%[\-noverbose] \%[\-noformat] \%[\-nomsgid]
+.DE
+\fISend\fR will cause the specified file (default <mh-dir>/draft) to
+be delivered to each of the addresses in the \*(lqTo:\*(rq, \*(lqcc:\*(rq, and \*(lqBcc:\*(rq
+fields of the message.
+If `\-verbose' is specified, \fIsend;\fR
+will monitor the delivery of local and net mail.
+\fISend\fR with no
+argument will query whether the draft is the intended file, whereas
+`\-draft' will suppress this question.
+Once the message has
+been mailed (or queued) successfully, the file will be renamed
+with a leading comma, which allows it to be retreived until the
+next draft message is sent.
+If there are errors in the
+formatting of the message, \fIsend;\fR will abort with a (hopefully)
+helpful error message.
+
+If a \*(lqBcc:\*(rq field is encountered, its addresses will be used for
+delivery, but the \*(lqBcc:\*(rq field itself will be deleted from all
+copies of the outgoing message.
+
+Prior to sending the message, the fields \*(lqFrom: user\*(rq, and
+\*(lqDate: now\*(rq will be prepended to the message.
+If `\-msgid' is
+specified, then a \*(lqMessage-Id:\*(rq field will also be added to the
+message.
+If the message already contains a \*(lqFrom:\*(rq field, then a
+\*(lqSender: user\*(rq field will be added instead.
+(An already existing
+\*(lqSender:\*(rq field will be deleted from the message.)
+
+If the user doesn't specify `\-noformat', each of the entries in
+the \*(lqTo:\*(rq and \*(lqcc:\*(rq fields will be replaced with \*(lqstandard\*(rq format
+entries.
+This standard format is designed to be usable by all
+of the message handlers on the various systems around the
+ARPANET.
+
+If an \*(lqFcc: folder\*(rq is encountered, the message will be copied
+to the specified folder in the format in which it will appear to any
+receivers of the message.
+That is, it will have the prepended
+fields and field reformatting.
+
+If a \*(lqDistribute-To:\*(rq field is encountered, the message
+is handled as a redistribution message (see \fIdist\fR for
+details), with \*(lqDistribution-Date: now\*(rq and \*(lqDistribution-From: user\*(rq
+added.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.De
+`file' defaults to draft
+`\-noverbose'
+`\-format'
+`\-nomsgid'
+.Co
+\fISend\fR has no effect on the current message or folder.
+.En
+.SC SHOW
+.NA
+show \- show (list) messages
+.SY
+show \%[+folder] \%[msgs] \%[\-pr] \%[\-nopr] \%[\-draft] \%[\-help]
+\%[\fIl\fR\ or\ \fIpr\fR\ switches]
+.DE
+\fIShow\fR lists each of the specified messages to the standard
+output (typically, the terminal).
+The messages are listed exactly
+as they are, with no reformatting.
+A program called \fIl\fR is
+invoked to do the listing, and any switches not recognized by
+\fIshow\fR are passed along to \fIl\fR.
+
+If no \*(lqmsgs\*(rq are specified, the current message is used.
+If
+more than one message is specified, \fIl\fR will prompt for a
+<return> prior to listing each message.
+
+\fIl\fR will list each message, a page at a time.
+When the end of
+page is reached, \fIl\fR will ring the bell and wait for a <RETURN>
+or <CTRL-D>.
+If a <return> is entered, \fIl\fR will clear the
+screen before listing the next page, whereas <CTRL-D> will not.
+The switches to \fIl\fR are
+`\-p#' to indicate the page length in lines, and `\-w#' to
+indicate the width of the page in characters.
+
+If the standard output is not a terminal, no queries are made,
+and each file is listed with a one-line header and two lines of
+separation.
+
+If `\-pr' is specified, then \fIpr\fR(I) will be invoked rather than
+\fIl\fR, and the switches (other than `\-draft') will be passed
+along.
+\*(lqShow \-draft\*(rq will list the file <mh-dir>/draft if it
+exists.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^/bin/l~^Screen-at-a-time list program
+^/bin/pr~^\fIpr\fR(I)
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-nopr'
+.Co
+If a folder is given, it will become the current message.
+The last message
+listed will become the current message.
+.En
+\"
+\" On to the Appendices
+\"
+.fo ''-%-''
+.he ''''
+.(x
+.sp
+Appendix
+.)x _
+.de $c \" Major Heading printer
+.ce
+Appendix \\n+(ch
+.sp 2p
+.ce
+.b "\\s12\\$1\\s0" \" 12 Point Bold Header
+.(x
+\ \ \ \\n(ch.\\ \\ \\$2
+.)x
+.sp 45p \" 45 points or about 1/2 inch
+..
+.++ A
+.bp
+.$c "COMMAND SUMMARY\\**" "Command Summary"
+.(f
+\**All commands accept a \-help switch.
+.)f
+.in 1i
+.na
+.ti .5i
+comp \%[\-editor\ editor] \%[\-form\ formfile] \%[file] \%[\-use]
+\%[\-nouse] \%[\-help]
+
+.ti .5i
+dist \%[+folder] \%[msg] \%[\-form\ formfile] \%[\-editor\ editor]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+
+.ti .5i
+file \%[\-src\ +folder] \%[msgs] \%[\-link] \%[\-preserve] \%+folder\ ...
+\%[\-nolink] \%[\-nopreserve]
+\%[\-file\ file] \%[\-nofile] \%[\-help]
+
+.ti .5i
+folder \%[+folder] \%[msg] \%[\-all] \%[\-fast] \%[\-nofast] \%[\-up] \%[\-down]
+\%[\-header] \%[\-noheader] \%[\-total] \%[\-nototal] \%[\-pack] \%[\-nopack]
+\%[\-help]
+
+.ti .5i
+forw \%[+folder] \%[msgs] \%[\-editor\ editor] \%[\-form\ formfile]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+
+.ti .5i
+inc \%[+folder] \%[\-audit\ audit-file] \%[\-help]
+
+.ti .5i
+next \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+
+.ta .4i 1.8i
+.nf
+.in .5i
+^pick~^^\0\-cc~^ \%[\-src\ +folder] \%[msgs] \%[\-help] \%[\-scan] \%[\-noscan]
+^^^\0\-date~^ \%[\-show] \%[\-noshow] \%[\-nofile] \%[\-nokeep]
+^^^\0\-from~^
+^^^\s+2\b'\(lt\(bv\(bv\(lk\(bv\(bv\(lb'\s0 \-search~\s+2\b'\(rt\(bv\(bv\(rk\(bv\(bv\(rb'\s0^ pattern
+^^^\0\-subject~^
+^^^\0\-to~^ \%[\-file \%[\-preserve] \%[\-link] \%+folder\ ... \%[\-nopreserve] \%[\-nolink] ]
+^^^\0\-\-component~^ \%[\-keep \%[\-stay] \%[\-nostay] \%[+folder\ ...]\ ]
+.fi
+.re
+
+.ti .5i
+prev \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+
+.ti .5i
+prompter \%[\-erase\ chr] \%[\-kill\ chr] \%[\-help]
+
+.ti .5i
+repl \%[+folder] \%[msg] \%[\-editor\ editor] \%[\-inplace] \%[\-annotate]
+\%[\-help] \%[\-noinplace]
+\%[\-noannotate]
+
+.ti .5i
+rmf \%[+folder] \%[\-help]
+
+.ti .5i
+rmm \%[+folder] \%[msgs] \%[\-help]
+
+.ti .5i
+scan \%[+folder] \%[msgs] \%[\-f\&f] \%[\-header] \%[\-help]
+\%[\-nof\&f] \%[\-noheader]
+
+.ti .5i
+send \%[file] \%[\-draft] \%[\-verbose] \%[\-format] \%[\-msgid]
+\%[\-help] \%[\-noverbose] \%[\-noformat] \%[\-nomsgid]
+
+.ti .5i
+show \%[+folder] \%[msgs] \%[\-pr] \%[\-nopr] \%[\-draft] \%[\-help]
+\%[\fIl\fR\ or\ \fIpr\fR\ switches]
+.ad
+.in 0
+\".+c "MESSAGE FORMAT" "Message Format"
+.if t \{
+.ll 32P
+.lt 32P
+\}
+.bp
+.$c "MESSAGE FORMAT" "Message Format"
+.pp
+This section paraphrases the format of ARPANET text messages
+given in Ref. 6.
+
+.lp
+ASSUMPTIONS
+.np
+Messages
+are expected to consist of lines of text.
+Graphics and binary data are not handled.
+.np
+No data compression is accepted.
+All text is clear
+ASCII 7-bit data.
+
+.lp
+LAYOUT
+.lp
+A general \*(lqmemo\*(rq framework is used.
+A message consists of a
+block of information in a rigid format, followed by general
+text with no specified format.
+The rigidly formatted first
+part of a message is called the header, and the free-format
+portion is called the body.
+The header must always
+exist, but the body is optional.
+
+.lp
+THE HEADER
+.lp
+Each header item can be viewed as a single logical line of ASCII
+characters.
+If the text of a header item extends across several
+real lines, the continuation lines are indicated by leading
+spaces or tabs.
+.lp
+Each header item is called a component and is composed of a
+keyword or name, along with associated text.
+The keyword begins at the
+left margin, may contain spaces or tabs, may not exceed 63
+characters, and is terminated by a colon (:).
+Certain
+components (as identified by their keywords) must follow rigidly
+defined formats in their text portions.
+.lp
+The text for most formatted components (e.g., \*(lqDate:\*(rq and \*(lqMessage-Id:\*(rq)
+is produced automatically.
+The only ones entered by the
+user are address fields such as \*(lqTo:\*(rq, \*(lqcc:\*(rq, etc.
+ARPA addresses
+are assigned mailbox names and host computer specifications.
+The
+rough format is \*(lqmailbox at host\*(rq, such as \*(lqBorden at Rand-Unix\*(rq.
+Multiple addresses are separated by commas.
+A missing host is
+assumed to be the local host.
+
+.ne 10
+.lp
+THE BODY
+.lp
+A blank line signals that all following text up to the end of the file
+is the body.
+(A blank line is defined as a pair of
+<end-of-line> characters with \fIno\fR characters in between.)
+No formatting is expected or enforced within the body.
+.lp
+Within MH, a line consisting of dashes is accepted
+as the header delimiter.
+This is a cosmetic feature applying
+only to locally composed mail.
+.bp
+.$c "MESSAGE NAME BNF" "Message Name BNF"
+
+.ta 1.2i 1.8i 3.2i
+.nf
+.in 1i
+^msgs~^^:=~^^msgspec~^|
+^^^^msgs msgspec
+
+^msgspec~^^:=~^^msg~^|
+^^^^^msg-range~^|
+^^^^msg-sequence
+
+^msg~^^:=~^^msg-name~^|
+^^^^<number>^
+
+^msg-name~^^:=~^^\*(lqfirst\*(rq~^|
+^^^^^\*(lqlast\*(rq~^|
+^^^^^\*(lqcur\*(rq~^|
+^^^^^\*(lq\*.\*(rq~^|
+^^^^^\*(lqnext\*(rq~^|
+^^^^\*(lqprev\*(rq
+
+^msg-range~^^:=~^^msg\*(lq-\*(rqmsg~^|
+^^^^^\*(lqall\*(rq
+
+^msg-sequence~^^:=~^msg\*(lq:\*(rqsigned-number
+
+^signed-number~^^:=~^^\*(lq+\*(rq<number>~^|
+^^^^^\*(lq\--\*(rq<number>~^|
+^^^^<number>
+.re \" Reset Tabs
+.fi
+.sp
+.pp
+Where <number> is a decimal number in the range 1 to 999.
+.pp
+Msg-range specifies all of the messages in the given range
+and must not be empty.
+.pp
+Msg-sequence specifies up to <number> of messages, beginning
+with \*(lqmsg\*(rq (in the case of first, cur, next, or <number>),
+or ending with \*(lqmsg\*(rq (in the case of prev or last).
++<number> forces \*(lqstarting with msg\*(rq, and \-<number> forces
+\*(lqending with number\*(rq.
+In all cases, \*(lqmsg\*(rq must exist.
+.bp
+.$c "EXAMPLE OF SHELL COMMANDS" "Example of Shell Commands"
+.pp
+UNIX commands may be mixed with MH commands to obtain additional
+functions.
+These may be prepared as files (known as
+shell command files or
+shell scripts).
+The following example is a useful function that
+illustrate the possibilities.
+Other functions, such as copying,
+deleting, renaming, etc., can be achieved in a similar fashion.
+
+HARDCOPY
+.pp
+The command:
+
+.ti +.5i
+(scan\0\-f\&f\0\-header;\0show\0all\0\-pr\0\-f)\0|\0print
+
+produces a scan listing of the current folder, followed by a
+form feed, followed by a formatted listing of all messages
+in the folder, one per page.
+Omitting \*(lq\-pr\0\-f\*(rq will cause the
+messages to be concatenated, separated by a one-line header
+and two blank lines.
+.pp
+You can create variations on this theme, using \fIpick\fR.
+.re
+.fi
+.in 0
+.bp
+.ce
+.b \\s12REFERENCES\\s0
+.(x
+.sp
+REFERENCES
+.)x
+.sp 3
+.in .4i
+.ti 0
+1. Crocker, D. H., J. J. Vittal, K. T. Pogran, and D. A. Henderson, Jr.,
+\*(lqStandard for the Format of ARPA Network Test Messages,\*(rq \fIArpanet Request
+for Comments\fR, No. 733, Network Information Center 41952, Augmentation
+Research Center, Stanford Research Institute,
+November 1977.
+
+.ti 0
+2. Thompson, K., and D. M. Ritchie, \*(lqThe UNIX Time-sharing System,\*(rq
+\fICommunications of the ACM\fR, Vol. 17, July 1974, pp. 365-375.
+
+.ti 0
+3. McCauley, E. J., and P. J. Drongowski, \*(lqKSOS\-The Design of a Secure
+Operating System,\*(rq \fIAFIPS Conference Proceedings\fR,
+National Computer Conference,
+Vol. 48, 1979, pp. 345-353.
+
+.ti 0
+4. Crocker, David H., \fIFramework and Functions of the \*(lqMS\*(rq Personal
+Message System\fR, The Rand Corporation, R-2134-ARPA, December 1977.
+
+.ti 0
+5. Thompson, K., and D. M. Ritchie, \fIUNIX Programmer's Manual\fR, 6th ed.,
+Western Electric Company, May 1975 (available only to UNIX licensees).
+
+.ti 0
+6. Bilofsky, Walter, \fIThe CRT Text Editor NED\-Introduction and
+Reference Manual\fR, The Rand Corporation, R-2176-ARPA, December 1977.
+.bp 3
+.de $c
+.ce
+.b "\\s12\\$1\\s0" \" 12 Point Bold Header
+.(x y
+.sp
+\\$1
+.)x
+.sp 3
+..
+.pn 3
+.++ P
+.fo ''''
+.he ''-%-''
+.+c PREFACE
+.pp
+This report describes a system for dealing with messages transmitted on a
+computer. Such messages might originate with other users of the same
+computer or might come from an outside source through a network to which the user's
+computer is connected. Such computer-based message systems are
+becoming increasingly widely used, both within and outside the Department
+of Defense.
+.pp
+The message handling system MH was developed for two reasons.
+One was to investigate some
+research ideas concerning how a message system might take advantage of
+the architecture of the UNIX time-sharing operating system for
+Digital Equipment Corporation PDP-11 and VAX computers, and the special
+features of UNIX's command-level interface with the user (the
+\*(lqshell\*(rq). The other reason was to provide a better and more
+adaptable base than that of conventional designs
+on which to build a command and control message system.
+The effort has succeeded in both
+regards, although this report mainly describes the message system itself
+and how it fits in with UNIX. The main research results are being
+described and analyzed in a forthcoming Rand report.
+The system is currently being used as part
+of a tactical command and control \*(lqlaboratory,\*(rq which is also being described
+in a separate report.
+.pp
+The present report should be of interest to three groups of readers. First,
+it is a complete reference manual for the users of MH (although
+users outside of Rand must take into
+account differences from the local Rand environment). Second, it should be
+of interest to those who have a general knowledge of computer-based
+message systems, both in civilian and military environments. Finally,
+it should be of interest to those who build large subsystems that
+interface with users, since it illustrates a new approach to such
+interfaces.
+.pp
+This report was prepared as part of the Rand project entitled \*(lqData
+Automation Research\*(rq, sponsored by Project AIR FORCE.
+.pn 5
+.+c SUMMARY
+.pp
+Electronic communication of text messages is becoming
+commonplace. Computer-based message systems\-software
+packages that provide tools for dealing with messages\-are used in many
+contexts. In particular, message systems are becoming
+increasingly important in command and control and intelligence
+applications.
+.pp
+This report describes a message handling system called MH.
+This system provides the user
+with tools to compose, send, receive, store, retrieve, forward, and
+reply to messages. MH has been built on the UNIX time-sharing system,
+a popular operating system developed for the DEC PDP-11 and VAX classes of
+computers.
+.pp
+A complete description of MH is given for users of
+the system. For those who do not intend to use the system, this description
+gives a general idea of what a message system is like. The system involves
+some new ideas about how large subsystems can be constructed. These design
+concepts and a comparison of MH with other message systems
+will be published in a forthcoming Rand report.
+.pp
+The interesting and unusual features of MH include the
+following: The user command interface to MH is the UNIX \*(lqshell\*(rq
+(the standard UNIX command interpreter). Each separable
+component of message handling, such as message composition or
+message display, is a separate command. Each program is driven from
+and updates a private user environment, which is stored as a file
+between program invocations. This private environment also contains
+information to \*(lqcustom tailor\*(rq MH to the individual's tastes. MH
+stores each message as a separate file under UNIX, and it utilizes the
+tree-structured UNIX file system to organize groups of files within
+separate directories or \*(lqfolders.\*(rq All of the UNIX facilities
+for dealing with files and directories, such as
+renaming, copying, deleting, cataloging, off-line printing, etc., are
+applicable to messages and directories of messages (folders). Thus,
+important capabilities needed in a message system are available in MH without
+the need (often seen in other message systems) for code that
+duplicates the facilities of the supporting operating system.
+It also allows users familiar with the shell to use MH with minimal
+effort.
+.he ''''
+.fo ''''
+.bp
+.ce
+.b \\s12CONTENTS\\s0
+.sp 3
+.xp y
+.xp x
+
+.bp \" Spare numbers for cut and paste work!
+.ft B
+
+1 1 1 1 1 1 1 1
+
+1 1 1 1 1 1 1 1
+
+1 1 1 1 1 1 1 1
+
+1 1 1 1 1 1 1 1
+
+2 2 2 2 2 2 2 2
+
+2 2 2 2 2 2 2 2
+
+2 2 2 2 2 2 2 2
+
+3 3 3 3 3 3 3
\ No newline at end of file
--- /dev/null
+.de $c \" Major Heading printer
+.ce
+.b "\\s12\\n+(ch.\\ \\$1\\s0" \" 12 Point Bold Header
+.(x
+
+\\n(ch.\\ \\$1
+.)x
+.sp 45p \" 45 point space or about 1/2 inch
+..
+.de $0 \" Sub-Heading macro called AFTER printing the heading
+.(x
+
+.ti .5i
+\\$1
+.)x
+..
+.de $s \" Macro to print footnote separator
+\"\l'2i' \" No line drawn
+.if n \
+. sp 1.3 \" But extra space to make up for it.
+..
+.fc ^ ~ \" The characters ^ and ~ CANNOT BE USED
+\" throughout this document except as field
+\" delimiter & pad indicator!
+.he \*(rq-%-\*(rq
+.ll 32P \" 32 Picas or about 5+1/3 inch Line Length
+.nr ss 30p \" 30 point space before section titles
+.ds . \\fB.\\fP\\h'-(1m/4)' \" Bold period to stand out.
+.ds << <\\h!-(\\w'<'/2)!<
+.ds >> >\\h!-(\\w'>'/2)!>
+.ds ** \v'-3p'\s+1*\s0\v'+3p'
+.++ C
+.+c INTRODUCTION
+.pp
+Although people can travel cross-country in hours and can
+reach others by telephone in seconds, communications still depend
+heavily upon paper, most of which is distributed through the mails.
+.pp
+There are several major reasons for this continued dependence on
+written documents.
+First, a written document may be proofread
+and corrected prior to its distribution, giving the author
+complete control over his words.
+Thus, a written document is
+better than a telephone conversation in this respect.
+Second,
+a carefully written document is far less likely to be
+misinterpreted or poorly translated than a phone conversation.
+Third, a signature offers reasonable verification of authorship,
+which cannot be provided with media such as telegrams.
+.pp
+However, the need for
+.u fast ,
+accurate, and reproducible document distribution is
+obvious.
+One solution in widespread use is the telefax.
+Another
+that is rapidly gaining popularity is electronic mail.
+Electronic mail is similar to telefax in that the data to be sent
+are digitized, transmitted via phone lines, and
+turned back into a document at the receiver.
+The advantage of
+electronic mail is in its compression factor.
+Whereas a telefax
+must scan a page in very fine lines and send all of the black and
+white information, electronic mail assigns characters fixed
+codes which can be transmitted as a few bits of information.
+Telefax presently has the advantage of being able to transmit an
+arbitrary page, including pictures, but electronic mail is
+beginning to deal with this problem.
+Electronic mail also integrates well
+with current directions in office automation, allowing documents
+prepared with sophisticated equipment at one site to be quickly
+transferred and printed at another site.
+.pp
+Currently, most electronic mail is intraorganizational,
+with mail transfer remaining within one computer.
+As computer
+networking becomes more common, however, it is becoming more feasible to
+communicate with anyone whose computer can be linked to your
+own via a network.
+.pp
+The pioneering efforts on general-purpose electronic mail
+were by organizations using the Defense Department's ARPANET.[1]
+The capability to send messages between computers existed before
+the ARPANET was developed, but it was used only in limited ways.
+With the advent of the
+ARPANET, tools began to be developed which made it convenient for
+individuals or organizations to distribute messages
+over broad geographic areas, using
+diverse computer facilities.
+The interest and activity in
+message systems has now reached such proportions that steps
+have been taken within the DoD to coordinate and
+unify the development of military message systems.
+The use of electronic mail is expected to increase
+dramatically in the next few years.
+The utility of such systems
+in the command and control and intelligence environments is
+clear, and applications in these areas will probably lead the
+way.
+As the costs for sending and handling electronic messags
+continue their rapid decrease, such uses can be
+expected to spread rapidly into other areas and, of course, will
+not be limited to the DoD.
+.pp
+A message system provides tools that help users (individuals
+or organizations) deal with messages in various ways.
+Messages
+must be composed, sent, received, stored, retrieved,
+forwarded, and replied to.
+Today's best interactive computer
+systems provide a variety of word-processing and information
+handling capabilities.
+The message handling facilities should be
+well integrated with the rest of the system, so as to be a
+graceful extension of overall system capability.
+.pp
+The message system described in this report, MH, provides most of the
+features that can be found in other message systems and also
+incorporates some new ones.
+It has been built on the UNIX time-sharing
+system,[2] a popular operating system for the DEC PDP-11
+and VAX classes of computers.
+A \*(lqsecure\*(rq operating
+system similar to UNIX is currently being developed,[3]
+and that system will also run MH.
+.pp
+This report provides a complete description of MH and
+thus may serve as a user's manual, although parts of the report
+will be of interest to non-users as well.
+Sections 2 and 3, the
+Overview and Tutorial, present the key
+ideas of MH and will give those not familiar with message systems
+an idea of what such systems are like.
+.pp
+MH consists of a set of commands which use some special
+files and conventions.
+Section 4 covers the information
+a user needs to know in addition to the
+commands.
+The final section, Sec. 5, describes each of
+the MH commands in detail.
+A summary of the commands is given in
+Appendix A, and Appendixes B and C describe the ARPANET
+conventions for messages (we expect that many users of MH
+will be using the ARPANET) and the formal syntax of such
+messages, respectively.
+Finally, Appendix D provides
+some illustrations of how MH commands may be used in
+conjunction with other UNIX facilities.
+.pp
+A novel approach has been taken in the design of MH.
+The
+design concept will be reported in detail in a forthcoming Rand
+report, but it can be described briefly as follows.
+Instead of creating a large subsystem that appears as a single
+command to the user, MH is a collection of separate commands
+which are run as separate programs.
+The file and directory
+system of UNIX are used directly.
+Messages are stored as
+individual files (datasets), and collections of them are grouped
+into directories.
+In contrast, most other message systems store
+messages in a complicated data structure within a monolithic
+file.
+With the MH approach, UNIX commands can be
+interleaved with commands invoking the functions of the message
+handler.
+Conversely, existing UNIX commands
+can be used in connection with messages.
+For
+example, all the usual UNIX editing, text-formatting, and printing
+facilities can be applied directly to individual messages.
+MH,
+therefore, consists of a relatively small amount of new code; it
+makes extensive use of other UNIX software to provide the
+capabilities found in other message systems.
+.pp
+The MH system was developed by the first
+author, using an approach suggested by the other two authors.
+Valuable assistance was provided by Phyllis Kantar in the later
+stages of the system's implementation.
+Several colleagues
+contributed to the ideas included in this system, particularly
+Robert Anderson and David Crocker.
+In addition, valuable experience
+in message systems, and a valuable source of ideas, was available
+to us in the form of a previous message system for UNIX called
+MS,[4] designed at Rand by David Crocker.
+.+c OVERVIEW
+.pp
+There are three main aspects of MH: the way messages are
+stored (the message database), the user's profile (which directs
+how certain actions of the message handler take place), and the
+commands for dealing with messages.
+.pp
+Under MH, each message is stored as a separate file.
+A user
+can take any action with a message that he could with an ordinary
+file in UNIX.
+A UNIX directory in which messages are stored is
+called a folder.
+Each folder contains some standard entries to support
+the message-handling functions.
+The messages in a folder have numerical
+names.
+These folders (directories)
+are entries in a particular directory path, described in
+the user profile, through which MH can find message folders.
+Using the UNIX \*(lqlink\*(rq facility, it is possible for one copy of a
+message to be \*(lqfiled\*(rq in more than one folder, providing a
+message index facility.
+Also, using the UNIX tree-structured
+file system, it is possible to have a folder within a folder.
+This two-level organization provides a \*(lqselection-list\*(rq
+facility, with the full power of the MH commands available on
+selected sublists of messages.
+.pp
+Each user of MH has a user profile, a file in his $HOME (initial
+login)
+directory called \*(lq\*.mh\(ruprofile\*(rq.
+This profile contains several
+pieces of information used by the MH commands: a
+path name to the directory that contains the message folders,
+information concerning which folder the user last referenced (the
+\*(lqcurrent\*(rq folder), and parameters that tailor MH commands
+to the individual user's requirements.
+It also contains
+most of the necessary state information concerning how
+the user is dealing with his messages, enabling MH to be
+implemented as a set of individual UNIX commands, in contrast to the
+usual approach of a monolithic subsystem.
+.pp
+In MH, incoming mail is appended
+to the end of a file called \*.mail in a user's $HOME
+directory.
+The user adds the new messages to his collection of MH messages
+by invoking the command
+.i inc .
+.i Inc
+(incorporate) adds the new
+messages to a folder called \*(lqinbox\*(rq, assigning them names which
+are consecutive integers starting with the next highest integer
+available in inbox.
+.i Inc
+also produces a
+.i scan
+summary of
+the messages thus incorporated.
+.pp
+There are four commands for examining the messages in a
+folder:
+.i show ,
+.i prev ,
+.i next ,
+and
+.i scan .
+.i Show
+displays a
+message in a folder,
+.i prev
+displays the message preceding the
+current message, and
+.i next
+displays the message following the
+current message.
+.i Scan
+summarizes the messages in a folder,
+producing one line per message, showing who the message is from,
+the date, the subject, etc.
+.pp
+The user may move a message from one folder to another with
+the command
+.i file .
+Messages may be removed from a folder
+by means of the command
+.i rmm .
+In addition, a user may query
+what the current folder is and may specify that a new folder
+become the current folder, through the command
+.i folder .
+.pp
+A set of messages based on content may be selected by
+use of the command
+.i pick .
+This command searches through
+messages in a folder and selects those that match a given
+criterion.
+A subfolder is created within the original folder,
+containing links to all the messages that satisfy the selection
+criteria.
+.pp
+A message folder (or subfolder) may be removed by means of
+the command
+.i rmf .
+.pp
+There are five commands enabling the user to create new
+messages and send them:
+.i comp ,
+.i dist ,
+.i forw ,
+.i repl ,
+and
+.i send .
+.i Comp
+provides the facility for the user to compose a
+new message;
+.i dist
+redistributes mail to additional addressees;
+.i forw
+enables the user to forward messages; and
+.i repl
+facilitates the generation of a reply to an incoming message.
+If
+a message is not sent directly by one of these commands, it may
+be sent at a later time using the command
+.i send .
+.pp
+All of the elements summarized above
+are described in more detail in the following sections.
+Many of the
+normal facilities of UNIX provide additional capabilities for
+dealing with messages in various ways.
+For example, it is
+possible to print messages
+on the line-printer without requiring any additional code within
+MH.
+Using standard UNIX facilities, any terminal output can be
+redirected to a file for repeated or future viewing.
+In general,
+the flexibility and capabilities of the UNIX interface with the
+user are preserved as a result of the integration of MH into the UNIX
+structure.
+.+c TUTORIAL
+.pp
+This tutorial provides a brief introduction to the MH commands.
+It should be sufficient
+to allow the user to read his mail, do some simple manipulations of
+it, and create and send messages.
+.pp
+A message has two major pieces: the
+header and the body.
+The body consists of the text of the message
+(whatever you care to type in).
+It follows the header and is separated from
+it by an empty line.
+(When you compose a message, the form that appears
+on your terminal shows a line of dashes after the header.
+This is for
+convenience and is replaced by an empty line when the message is
+sent.) The header is composed of several components, including the
+subject of the message and the person to whom it is addressed.
+Each component starts with a name
+and a colon; components must not start with a blank.
+The text of the
+component may take more than one line, but each continuation line must
+start with a blank.
+Messages typically have \*(lqto:\*(rq, \*(lqcc:\*(rq, and
+\*(lqsubject:\*(rq components.
+When composing a message, you should include
+the \*(lqto:\*(rq and \*(lqsubject:\*(rq components; the \*(lqcc:\*(rq (for people
+you want to send copies to) is not necessary.
+.pp
+The basic MH commands are
+.i inc ,
+.i scan ,
+.i show ,
+.i next ,
+.i prev ,
+.i rmm ,
+.i comp ,
+and
+.i repl .
+These are described below.
+
+.i inc
+.pp
+When you get the message \*(lqYou have mail\*(rq, type the command
+.i inc .
+You will get a \*(lqscan listing\*(rq such as:
+
+.nf
+.ta .4i 1.2i 3i
+^7+~^^\07/13~^^Cas~^revival of measurement work
+^8~^^10/\09~^^Norm~^NBS people and publications
+^9~^^11/26~^^To:norm~^question \*(<<Are there any functions
+.re
+.fi
+.pp
+This shows the messages you received since the last time you
+executed this command (
+.i inc
+adds these new messages to
+your inbox folder).
+You can see this list again, plus a list of any
+other messages you have, by using the
+.i scan
+command.
+
+.i scan
+.pp
+The scan listing shows the message number, followed by the
+date and the sender.
+(If you are the sender, the addressee in the \*(lqto:\*(rq
+component is displayed.
+You may send yourself a message by including
+your name among the \*(lqto:\*(rq or \*(lqcc:\*(rq addressees.)
+It also shows the message's subject; if
+the subject is short, the first part of the body of the message is
+included after the characters \*(<<.
+
+.i show
+.pp
+This command shows the current message, that is,
+the first one of the new messages after an
+.i inc .
+If the message is not
+specified by name (number), it is
+generally the last message referred to by an MH command.
+For example,
+
+.ta 1i
+.ti .5i
+^\fIshow\fP\05~^will show message 5.
+.pp
+You can use the show command to copy a message or print a
+message.
+
+.(b L
+.in .5i
+.ta 1i
+^\fIshow\fR\0>\0\fIx\fR~^will copy the message to file x.
+.br
+^\fIshow\fR\0|\0\fIprint\fR~^will print the message, using the \fIprint\fR command.
+.br
+^\fInext\fR~^will show the message that follows the current message.
+.br
+^\fIprev\fR~^will show the message previous to the current message.
+.br
+^\fIrmm\fR~^will remove the current message.
+.br
+^\fIrmm\03\fR~^will remove message 3.
+.)b
+
+.i comp
+.pp
+The
+.i comp
+command puts you in the editor to write or edit a message.
+Fill in or
+delete the \*(lqto:\*(rq, \*(lqcc:\*(rq, and \*(lqsubject:\*(rq fields, as appropriate, and
+type the body of the message.
+Then
+exit normally from the editor.
+You will be asked
+\*(lqWhat now?\*(rq.
+Type a carriage return to see the options.
+Typing \fBsend\fR
+will cause the message to be sent; typing \fBquit\fR will cause an exit
+from
+.i comp ,
+with the message draft saved.
+.pp
+If you quit without sending the message, it will be saved in a file
+called /usr/<name>/Mail/draft (where /usr/<name> is your $HOME directory).
+You can edit this file and send the message later, using the
+.i send
+command.
+
+.ne 4
+.i "comp\0\-editor\0prompter"
+.pp
+This command uses a different editor and is useful for preparing
+\*(lqquick and dirty\*(rq messages.
+It prompts you for each component of the
+header.
+Type the information for that component, or type a carriage
+return to omit the component.
+After that, type the body of the
+message.
+Backspacing is the only form of editing allowed with this editor.
+When the body is complete, type a carriage return followed by <CTRL-D>
+(<OPEN> on Ann Arbor terminals).
+This completes the initial preparation of the message; from then on, use
+the same procedures as with
+.i comp
+(above).
+
+.ne 5
+.i repl
+.br
+.i "repl\0n"
+.pp
+This command makes up an initial message form with a header
+that is appropriate for
+replying to an existing message.
+The message being answered is the
+current message if no message number is mentioned, or n if a number
+is specified.
+After the header is completed, you can finish the message as in
+.i comp
+(above).
+.pp
+This is enough information to get you going using MH.
+There are more commands,
+and the commands described here have more features.
+Subsequent sections
+explain MH in complete detail.
+The system is quite powerful if you
+want to use its sophisticated features, but the foregoing commands
+suffice for sending and receiving messages.
+.pp
+There are numerous additional capabilities you may wish to explore.
+For example, the
+.i pick
+command will select a subset of messages
+based on specified criteria such as sender or subject.
+Groups of
+messages may be designated, as described in Sec. V, under \*(lqMessage
+Naming\*(rq.
+The file \*(lq\*.mh\(ruprofile\*(rq can be used to tailor your use of
+the message system to your needs and preferences, as described in Sec. V,
+under \*(lqThe User Profile\*(rq.
+In general, you may
+learn additional features of the system selectively, according to your
+requirements,
+by studying the relevant sections of this manual.
+There is no need to
+learn all the details of the system at once.
+.+c "DETAILED DESCRIPTION"
+.pp
+This section describes the MH system in detail, including the components
+of the user profile, the conventions for message naming, and some of
+the other MH conventions.
+Readers who are
+generally familiar with computer systems will be able to follow
+the principal ideas, although some details may be meaningful only to
+those familiar with UNIX.
+.uh "THE USER PROFILE"
+.pp
+The first time an MH command is issued by a new user, the system
+prompts for a \*(lqpath\*(rq and creates an MH \*(lqprofile\*(rq.
+.pp
+Each MH user has a profile which contains current
+state information for the MH package and, optionally, tailoring
+information for each individual program.
+When a folder becomes
+the current folder, it is recorded in the user's profile.
+Other profile entries control the MH path (where folders and
+special files are kept), folder and message protections, editor
+selection, and default arguments for each MH program.
+.pp
+The MH profile is stored in the file \*(lq\*.mh\(ruprofile\*(rq in the
+user's $HOME directory.
+It has the format of a message without
+any body.
+That is, each profile entry is on one line, with a
+keyword followed by a colon (:) followed by text particular to
+the keyword.
+.br
+\(rh\ \ \&
+.i "This file must not have blank lines."
+.br
+The keywords
+may have any combination of upper and lower case.
+(See Appendix
+B for a description of message formats.)
+.pp
+For the average MH user, the only profile entry of
+importance is \*(lqPath\*(rq.
+Path specifies a directory in which MH
+folders and certain files such as \*(lqdraft\*(rq are found.
+The
+argument to this keyword must be a legal UNIX path that names an
+existing directory.
+If this path is unrooted (i.e., does not
+begin with a \fB/\fR), it will be presumed to start from the
+user's $HOME directory.
+All folder and message references within
+MH will relate to this path unless full path names are used.
+.pp
+Message protection defaults to 664, and folder protection to
+751.
+These may be changed by profile entries \*(lqMsg-Protect\*(rq
+and \*(lqFolder-Protect\*(rq, respectively.
+The argument to these
+keywords is an octal number which is used as the UNIX file mode.\**
+.(f
+\**See
+.i chmod (I)
+in the
+.i "UNIX Programmer's Manual" .[5]
+.)f
+.pp
+When an MH program starts running, it looks through the
+user's profile for an entry with a keyword matching the program's
+name.
+For example, when
+.i comp
+is run, it looks for a \*(lqcomp\*(rq
+profile entry.
+If one is found, the text of the profile entry is
+used as the default switch setting until all defaults are overridden
+by explicit switches passed to the program as arguments.
+Thus the profile
+entry \*(lqcomp:\0\-form\0standard.list\*(rq would direct
+.i comp
+to use the
+file \*(lqstandard.list\*(rq as the message skeleton.
+If an explicit
+form switch is given to the
+.i comp
+command, it will override the
+switch obtained from the profile.
+.pp
+In UNIX, a program may exist under several names, either by
+linking or aliasing.
+The actual invocation name is used by an MH
+program when scanning for its profile defaults.
+Thus, each MH program
+may have several names by which it can be invoked, and each name
+may have a different set of default switches.
+For example, if
+.i comp
+is invoked by the name
+.i icomp ,
+the profile entry
+\*(lqicomp\*(rq will control the default switches for this invocation of
+the
+.i comp
+program.
+This provides a powerful
+definitional facility for commonly used switch settings.
+.pp
+The default editor
+for editing within
+.i comp ,
+.i repl ,
+.i forw ,
+and
+.i dist ,
+is \*(lq/bin/ned\*(rq.\**
+.(f
+\**See Ref. 6 for a description of
+the NED text editor.
+.)f
+A different editor may be used by specifying
+the profile entry
+\*(lqEditor: \*(rq.
+The argument to \*(lqEditor\*(rq is the name of an
+executable program or shell command file which can be found via
+the user's $PATH defined search path, excluding the current
+directory.
+The \*(lqEditor:\*(rq profile specification
+may in turn be overridden by a \*(lq\-editor\0<editor>\*(rq
+profile switch associated with
+.i comp ,
+.i repl ,
+.i forw ,
+or
+.i dist .
+Finally, an explicit editor switch specified with any
+of these four commands will have ultimate precedence.
+.pp
+During message composition, more than one editor may be
+used.
+For example, one editor (such as
+.i prompter )
+may be used
+initially, and a second editor may be invoked later to revise
+the message being composed
+(see the discussion of
+.i comp
+in Section 5 for details).
+A profile entry \*(lq<lasteditor>\-next:\0<editor>\*(rq specifies the name of
+the editor to be used after a particular editor.
+Thus \*(lqcomp:\0\-e\0prompter\*(rq
+causes the initial text to be collected by
+.i prompter ,
+and the profile entry \*(lqprompter\-next:\0ed\*(rq names ed as the
+editor to be invoked for the next round of editing.
+.pp
+Some of the MH commands, such as
+.i show ,
+can be used on
+message folders owned by others, if those folders are readable.
+However,
+you cannot write in someone else's folder.
+All the MH command
+actions not requiring write permission may be used with
+a \*(lqread-only\*(rq folder.
+In a writable folder, a file named
+\*(lqcur\*(rq is used to contain its current message name.
+For read-only folders, the current message name is
+stored in the user's profile.
+.pp
+Table 1 lists examples of the currently defined profile
+entries, typical arguments, and the programs that reference the
+entries.
+.in .9i
+.ll -.9i
+.ta 2.3i
+.sp 30p
+.ce
+Table 1
+.sp 8p
+.ce
+P\s-2ROFILE\s0 C\s-2OMPONENTS\s0
+.hl \" ~12p preceding + 1v (12p) after
+.nf
+^^MH Programs that
+^Keyword and Argument~^\ Use Component\h'|\n(.lu-.9i'\l'|0' \" \l'..' does underlining
+.sp
+^Path:\0Mail~^All
+^Current-Folder:\0inbox~^Most
+^Editor:\0/bin/ed~^\fIcomp, dist, forw, repl\fR
+^Msg\-Protect:\0644~^\fIinc\fR
+^Folder\-Protect:\0711~^\fIfile, inc, pick\fR
+^<program>:\0default switches~^All
+^cur\-<read-onlyfolder>:\0172~^Most
+^prompter\-next:\0ed~^\fIcomp, dist, forw, repl\fR
+.hl
+.ll +1i
+.in 0
+.fi
+.pp
+Path
+.u should
+be present.
+Folder is maintained
+automatically by many MH commands (see the \*(lqContext\*(rq sections of
+the individual commands in Sec. V).
+All other entries are optional,
+defaulting to the values described above.
+.uh "MESSAGE NAMING"
+.pp
+Messages may be referred to explicitly or implicitly when
+using MH commands.
+A formal syntax of message names is given in Appendix C, but the
+following description should be sufficient for most MH users.
+Some details of message naming that apply only to certain
+commands are included in the description of those
+commands.
+.pp
+Most of the MH commands accept arguments specifying one or
+more folders, and one or more messages to operate on.
+The use of
+the word \*(lqmsg\*(rq as an argument to a command means that exactly one
+message name may be specified.
+A message name may be a number,
+such as 1, 33, or 234, or it may be
+one of the \*(lqreserved\*(rq message names:
+first, last, prev, next, and cur.
+(As a shorthand, a
+period (\*.) is equivalent to cur.)
+The meanings of these names
+are straightforward: \*(lqfirst\*(rq is the first message in the
+folder; \*(lqlast\*(rq is the last
+message in the folder; \*(lqprev\*(rq is the
+message numerically previous to the current message; \*(lqnext\*(rq
+is the message numerically following the current message; \*(lqcur\*(rq
+(or \*(lq\*.\*(rq) is the current message in the folder.
+.pp
+The default in commands that take a \*(lqmsg\*(rq argument is
+always \*(lqcur\*(rq.
+.pp
+The word \*(lqmsgs\*(rq indicates that several messages may be
+specified.
+Such a specification consists of several message
+designations separated by spaces.
+A message designation is
+either a message name or a message range.
+A message range is a
+specification of the form name1\-name2 or name1:n, where name1 and
+name2 are message names and n is an integer.
+The first form
+designates all the messages from name1 to name2 inclusive; this
+must be a non-empty range.
+The second form specifies up to n
+messages, starting with name1 if name1 is a number, or first,
+cur, or next, and ending with name1 if name1 is last or
+prev.
+This interpretation of n is overridden if n is preceded
+by a plus sign or a minus sign;
++n always means up to n messages starting with
+name1, and \-n always means up to n messages ending with name1.
+Repeated specifications of the same message have the same effect
+as a single specification of
+the message.
+Examples of
+specifications are:
+
+.(b
+1 5 7\-11 22
+first 6 8 next
+first\-10
+last:5
+.)b
+.pp
+The message name \*(lqall\*(rq is a shorthand for \*(lqfirst\-last\*(rq,
+indicating all of the messages in the folder.
+.pp
+The limit on the number of messages in an expanded message
+list is generally 999\*-the maximum number of messages in a
+folder.
+However, the
+.i show
+command and the
+commands `\fIpick\0\-scan\fR' and `\fIpick\0\-show\fR'
+are constrained to have argument lists
+that are no more than 512 characters long.
+(Under Version 7 UNIX this limit is 4096.)
+.pp
+In commands that accept \*(lqmsgs\*(rq arguments, the default is
+either cur or all, depending on which makes more sense.
+.pp
+In all of the MH commands, a plus sign preceding an argument
+indicates a folder name.
+Thus, \*(lq+inbox\*(rq is the name of the
+user's standard inbox.
+If an explicit folder argument is given
+to an MH command, it will become the current folder (that is,
+the \*(lqCurrent-Folder:\*(rq entry
+in \*(lq\*.mh\(ruprofile\*(rq will be changed to this
+folder).
+In the case of the
+.i file
+and
+.i pick
+commands, which
+can have multiple output folders, a new source folder (other than
+the default current folder) is specified by \*(lq\-src\0+folder\*(rq.
+.uh "OTHER MH CONVENTIONS"
+.pp
+One very powerful feature of MH is that the MH commands may
+be issued from any current directory, and the proper path to
+the appropriate folder(s) will be taken from the user's profile.
+If the MH path is not appropriate for a specific folder or file,
+the automatic prepending of the MH path can be avoided by
+beginning a folder or file name with \fB/\fR.
+Thus any specific full
+path may be specified.
+.pp
+Arguments to the various programs may be given in any order,
+with the exception of a few switches whose arguments must follow
+immediately, such as \*(lq\-src\0+folder\*(rq for \fIpick\fR and \fIfile\fR.
+.pp
+Whenever an MH command prompts the user, the valid options
+will be listed in response to a <RETURN>.
+(The first of the
+listed options is the default if end-of-file is encountered, such
+as from a command file.) A valid response is any \fIunique\fR
+abbreviation of one of the listed options.
+.pp
+Standard UNIX documentation conventions are used in this report
+to describe MH command syntax.
+Arguments enclosed in brackets
+([ ]) are optional; exactly one of the arguments enclosed
+within braces ({ }) must be specified, and all other
+arguments are required.
+The use of ellipsis dots (...) indicates
+zero or more repetitions of the previous item.
+For example,
+\*(lq+folder ...\*(rq would indicate that one or more \*(lq+folder\*(rq arguments
+is required and \*(lq[+folder ...]\*(rq indicates that 0 or more
+\*(lq+folder\*(rq arguments may be given.
+.pp
+MH departs from UNIX standards by using switches that consist of
+more than one character, e.g. \*(lq\-header\*(rq.
+To minimize typing,
+only a unique abbreviation of a switch need be typed; thus, for
+\*(lq\-header\*(rq, \*(lq\-hea\*(rq is probably sufficient, depending on the
+other switches the command accepts.
+Each MH program
+accepts the switch \*(lq\-help\*(rq (which \fImust\fR be spelled out fully)
+and produces a syntax description and a list of switches.
+In the
+list of switches, parentheses indicate required characters.
+For example, all \*(lq\-help\*(rq switches will appear as \*(lq\-(help)\*(rq,
+indicating that no abbreviation is accepted.
+.pp
+Many MH switches have both on and off forms, such as
+\*(lq\-format\*(rq and \*(lq\-noformat\*(rq.
+In many of the descriptions in Sec. V,
+only one form is defined; the other form, often used to
+nullify profile switch settings, is assumed to be the opposite.
+.(b L
+.uh "MH COMMANDS"
+.pp
+The MH package comprises 16 programs:
+
+.nf
+.in .5i
+.ta 1.5i
+^comp~^Compose a message
+^dist~^Redistribute a message
+^file~^Move messages between folders
+^folder~^Select/list status of folders
+^forw~^Forward a message
+^inc~^Incorporate new mail
+^next~^Show the next message
+^pick~^Select a set of messages by context
+^prev~^Show the previous message
+^prompter~^Prompting editor front end for composing messages
+^repl~^Reply to a message
+^rmf~^Remove a folder
+^rmm~^Remove messages
+^scan~^Produce a scan listing of selected messages
+^send~^Send a previously composed message
+^show~^Show messages
+.fi
+.re
+.)b
+.pp
+These programs are described below.
+The form of the descriptions
+conforms to the standard
+form for the description of UNIX commands.
+.ll 6.5i
+.lt 6.5i
+.nr Us 0 1
+.fo '7th Edition'UNIX/32V(Rand)'\\\\\\\\n+(Us'
+.de SC
+.he '\\$1(1)'-%-'\\$1(1)'
+.nr Us 0 1
+.bp
+.(x
+.ti .8i
+\\$1
+.)x
+..
+.de NA
+.b \\s-2NAME\\s0
+.ti .5i
+..
+.de SY
+.sp
+.b \\s-2SYNOPSIS\\s0
+.in 1i
+.ti .5i
+.na
+..
+.de DE
+.ad
+.sp
+.in 0
+.b \\s-2DESCRIPTION\\s0
+.sp
+.fi
+.in .5i
+..
+.de Fi
+.(b L
+.ti 0
+.b \\s-2Files\\s0
+.ta 2i
+..
+.de Pr
+.)b
+.(b L F
+.in 2.5i
+.ti 0
+.b "\\s-2Profile Components\\s0"
+.ti .5i
+..
+.de Ps
+.ti .5i
+..
+.de De
+.)b
+.(b L
+.in .5i
+.ti 0
+.b \\s-2Defaults\\s0
+..
+.de Co
+.)b
+.(b L F
+.ti 0
+.b \\s-2Context\\s0
+.br
+..
+.de En
+.)b
+.in 0
+..
+.SC COMP
+.NA
+comp \- compose a message
+
+.SY
+comp [\-editor editor] [\-form formfile] [file] [\-use] [\-nouse] [\-help]
+
+.DE
+\fIComp\fP is used to create a new message to be mailed.
+If
+\fIfile\fP is not specified, the file named \*(lqdraft\*(rq in the user's MH
+directory will be used.
+\fIComp\fR copies a message form to
+the file being composed and then invokes an editor on the
+file.
+The default editor is /bin/ned, which may be overridden with
+the `\-editor' switch or with a profile entry \*(lqEditor:\*(rq.
+(See Ref. 5 for a
+description of the NED text editing system.)
+The default
+message form contains the following elements:
+
+ To:
+ cc:
+ Subject:
+ ----------
+
+If the file named \*(lqcomponents\*(rq exists in the user's MH directory,
+it will be used instead of this form.
+If `\-form
+formfile' is specified, the specified formfile (from the MH
+directory) will be used as the skeleton.
+The line of dashes
+or a blank line must be left between the header and the
+body of the message for the message to be identified properly when it is
+sent (see \fIsend;\fR).
+The switch `\-use' directs \fIcomp\fR to
+continue editing an already started message.
+That is, if a
+\fIcomp\fR (or \fIdist\fR, \fIrepl\fR, or \fIforw\fR) is terminated without
+sending the message, the message can be edited again via
+\*(lqcomp \-use\*(rq.
+
+If the specified file (or draft) already exists, \fIcomp\fR will ask
+if you want to delete it before continuing.
+A reply of \fBNo\fR will abort the
+\fIcomp\fR, \fByes\fR will replace the existing draft with a blank
+skeleton, \fBlist\fR will display the draft, and \fBuse\fR will use it
+for further composition.
+
+Upon exiting from the editor, \fIcomp\fR will ask \*(lqWhat now?\*(rq.
+The valid
+responses are \fBlist\fR, to list the draft on the terminal; \fBquit\fR, to
+terminate the session and preserve the draft; \fBquit delete\fR, to terminate,
+then delete the draft; \fBsend\fR, to send the message; \fBsend verbose\fR, to
+cause the delivery process to be monitored; \fBedit <editor>\fR, to invoke
+<editor> for further editing; and \fBedit\fR, to re-edit using the
+same editor that was used on the preceding round unless a profile
+entry \*(lq<lasteditor>\-next: <editor>\*(rq names an alternative editor.
+
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`file' defaults to draft
+`\-editor' defaults to /bin/ned
+`\-nouse'
+.Co
+\fIComp\fR does not affect either the current folder or the current message.
+.En
+.SC DIST
+.NA
+dist \- redistribute a message to additional addresses
+.SY
+dist [+folder] [msg] [\-form formfile] [\-editor editor]
+[\-annotate] [\-noannotate]
+[\-inplace] [\-noinplace]
+[\-help]
+.DE
+\fIDist\fR is similar to \fIforw\fR.
+It prepares the specified
+message for redistribution to addresses that (presumably) are
+not on the original address list.
+The file \*(lqdistcomps\*(rq in the
+user's MH directory, or a standard form, or the file specified by
+`\-form formfile' will be used as the blank components file to
+be prepended to the message being distributed.
+The standard form
+has the components \*(lqDistribute-to:\*(rq and \*(lqDistribute-cc:\*(rq.
+When
+the message is sent, \*(lqDistribution-Date:\0date\*(rq,
+\*(lqDistribution-From:\0name\*(rq, and
+\*(lqDistribution-Id:\0id\*(rq (if `\-msgid' is
+specified to \fIsend\fR;) will be prepended to the outgoing message.
+Only those addresses in \*(lqDistribute-To\*(rq, \*(lqDistribute-cc\*(rq, and
+\*(lqDistribute-Bcc\*(rq will be sent.
+Also, a \*(lqDistribute-Fcc:\0folder\*(rq
+will be honored (see \fIsend;\fR).
+
+\fISend\fR recognizes a message as a redistribution message by the
+existence of the field \*(lqDistribute-To:\*(rq, so don't try to
+redistribute a message with only a \*(lqDistribute-cc:\*(rq.
+
+If the `\-annotate' switch is given, each message being
+distributed will be annotated with the lines:
+
+ Distributed:\0\*(<<date\*(>>
+ Distributed:\0Distribute-to: names
+
+where each \*(lqto\*(rq list contains as many lines as required.
+This annotation
+will be done only if the message is sent directly from \fIdist\fR.
+If the
+message is not sent immediately from \fIdist\fR (i.e., if it is sent later
+via \fIsend;\fR),
+\*(lqcomp \-use\*(rq may be used to re-edit and send the constructed message, but
+the annotations won't take place.
+The '\-inplace' switch causes annotation to
+be done in place in order to preserve links to the annotated message.
+
+See \fIcomp\fR for a description of the `\-editor' switch and for options
+upon exiting from the editor.
+
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`+folder' defaults to the current folder
+`msg' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a +folder is specified, it will become the current
+folder, and the current message will be set to the message
+being redistributed.
+.En
+.SC FILE
+.NA
+file \- file message(s) in (an)other folder(s)
+.SY
+file [\-src +folder] [msgs] [\-link] [\-preserve] +folder\ ...
+[\-nolink] [\-nopreserve] [\-help]
+.DE
+\fIFile\fR moves (\fImv\fR(I)) or links (\fIln\fR(I)) messages from a
+source folder into one or more destination folders.
+If you think
+of a message as a sheet of paper, this operation is not
+unlike filing the sheet of paper (or copies) in file cabinet
+folders.
+When a message is filed, it is linked into the
+destination folder(s) if possible, and is copied otherwise.
+As long
+as the destination folders are all on the same file system, multiple filing
+causes little storage overhead.
+This facility provides a good way to cross-file or multiply-index
+messages.
+For example, if a message is received from Jones about
+the ARPA Map Project, the instruction
+
+ file\0cur\0+jones\0+Map
+
+would allow the message to be found in either of the two
+folders `jones' or `Map'.
+
+If a destination folder doesn't exist, \fIfile\fR will ask if you
+want to create one.
+A negative response will abort the file
+operation.
+
+`\-link' preserves the source folder copy of the message
+(i.e., it does a \fIln\fR(I) rather than a \fImv\fR(I)), whereas,
+`\-nolink' deletes the \*(lqfiled\*(rq messages from the source
+folder.
+Normally, when a message is filed, it is assigned the
+next highest number available in each of the destination folders.
+Use of the `\-preserve' switch will override this message
+\*(lqrenaming\*(rq, but name conflicts may occur, so
+use this switch cautiously.
+(See \fIpick\fR for more details on
+message numbering.)
+
+If `\-link' is not specified (or `\-nolink' is specified),
+the filed messages will be removed (unlink(II)) from the
+source folder.
+
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.Ps
+^Folder\-Protect:~^To set mode when creating a new folder
+.De
+`\-src +folder' defaults to the current folder
+`msgs' defaults to cur
+`\-nolink'
+`\-nopreserve'
+.Co
+If `\-src +folder' is given, it will become the
+current folder for future MH commands.
+If neither `\-link' nor
+`all' are specified, the current message in the source
+folder will be set to the last message specified; otherwise, the
+current message won't be changed.
+.En
+.SC FOLDER
+.NA
+folder \- set/list current folder/message
+.SY
+folder [+folder] [msg] [\-all] [\-fast] [\-nofast] [\-up] [\-down]
+[\-header] [\-noheader] [\-total] [\-nototal] [\-help]
+
+.ti .5i
+folders <equivalent to 'folder \-all'>
+.DE
+Since the MH environment is the shell, it is easy to lose
+track of the current folder from day to day.
+\fIFolder\fR will
+list the current folder, the number of messages in it, the
+range of the messages (low-high), and the current message within
+the folder, and will flag a selection list or extra files if they
+exist.
+An example of the output is:
+
+ inbox+ has 16 messages ( 3\- 22); cur= 5.
+
+But it is well to note here that \\n(Us is \n(Us.
+
+If a `+folder' and/or `msg' are specified, they will
+become the current folder and/or message.
+An `\-all' switch
+will produce a line for each folder in the user's MH directory,
+sorted alphabetically.
+These folders are preceded by the read-only
+folders, which occur as \*.mh\(ruprofile \*(lqcur\-\*(rq entries.
+For example,
+
+.nf
+.ta 1.5i 2.1i 2.7i 3.5i
+^~Folder\ \ ^^~#\ of\ ^^messages~^^(~\ range\~ );\ ^cur msg (other files)
+^~/fsd/rs/m/tacc\ \ ^^has~35\ ^^messages~^^(~1\-\035);\ ^cur=\ 23.
+^~/rnd/phyl/Mail/EP\ \ ^^has~82\ ^^messages~^^(~1\-108);\ ^cur=\ 82.
+^~ff\ \ ^^has~4\ ^^messages~^^(~1\-\0\04);\ ^cur=\ \01.
+^~inbox+\ ^^has~16\ ^^messages~^^(~3\-\022);\ ^cur=\ \05.
+^~mh\ \ ^^has~76\ ^^messages~^^(~1\-\076);\ ^cur=\ 70.
+^~notes\ \ ^^has~2\ ^^messages~^^(~1\-\0\02);\ ^cur=\ \01.
+^~ucom\ \ ^^has~124\ ^^messages~^^(~1\-124);\ ^cur=\ \06; (select).
+
+^^^~TOTAL=\0339\ ^messages\0in\0\07\0Folders.
+.re
+.fi
+
+The \*(lq+\*(rq after inbox indicates that it is the current folder.
+The \*(lq(select)\*(rq indicates that the folder ucom has a selection
+list produced by \fIpick\fR.
+If \*(lqothers\*(rq had appeared in parentheses at
+the right of a line, it would indicate that there are files in
+the folder directory that don't belong under the MH file naming
+scheme.
+
+The header is output if either an `\-all' or a `\-header' switch
+is specified; it is suppressed by `\-noheader'.
+Also, if \fIfolder\fR
+is invoked by a name ending with \*(lqs\*(rq (e.g., \fIfolders\fR),
+`\-all' is assumed.
+A `\-total' switch will produce only the
+summary line.
+
+If `\-fast' is given, only the folder name (or names in the
+case of `\-all') will be listed.
+(This is faster because the
+folders need not be read.)
+
+The switches `\-up' and `\-down' change the folder to be the
+one above or below the current folder.
+That is, \*(lqfolder \-down\*(rq
+will set the folder to \*(lq<current\-folder>/select\*(rq, and if the
+current folder is a selection-list folder, \*(lqfolder \-up\*(rq will
+set the current folder to the parent of the selection-list.
+(See \fIpick\fR for details on selection-lists.)
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^/bin/ls~^To fast-list the folders
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to the current folder
+`msg' defaults to none
+`\-nofast'
+`\-noheader'
+`\-nototal'
+.Co
+If `+folder' and/or `msg' are given, they will become the
+current folder and/or message.
+.En
+.SC FORW
+.NA
+forw \- forward messages
+.SY
+forw [+folder] [msgs] [\-editor editor] [\-form formfile]
+[\-annotate] [\-noannotate]
+[\-inplace] [\-noinplace]
+[\-help]
+.DE
+\fIForw\fR may be used to prepare a message containing other
+messages.
+It constructs the new message from the components file
+or `\-form formfile' (see \fIcomp\fR), with a body composed of the
+message(s) to be forwarded.
+An editor is invoked as in \fIcomp\fR,
+and after editing is complete, the user is prompted before the message
+is sent.
+
+If the `\-annotate' switch is given, each message being
+forwarded will be annotated with the lines
+
+ Forwarded: \*(<<date\*(>>
+ Forwarded: To: names
+ Forwarded: cc: names
+
+where each \*(lqTo:\*(rq and \*(lqcc:\*(rq list contains as many lines as required.
+This annotation will be done only if the message is sent directly
+from \fIforw\fR.
+If the message is not sent immediately from \fIforw\fR,
+\*(lqcomp \-use\*(rq may be used in a later session to re-edit and send
+the constructed message, but the annotations won't take place.
+The `\-inplace' switch permits annotating a message in place in
+order to preserve its links.
+
+See \fIcomp\fR for a description of the `\-editor' switch.
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^Current-Folder:~^To find the default current folder
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`+folder' defaults to the current folder
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a +folder is specified, it will become
+the current folder, and the current message will be set to
+the first message being forwarded.
+.En
+.SC INC
+.NA
+inc \- incorporate new mail
+.SY
+inc [+folder] [\-audit audit-file] [\-help]
+.DE
+\fIInc\fR incorporates mail from the user's incoming mail drop
+(\*.mail) into an MH folder.
+If `+folder' isn't specified,
+the folder named \*(lqinbox\*(rq in the user's MH directory will be used.
+The
+new messages being incorporated are assigned numbers starting
+with the next highest number in the folder.
+If the specified (or
+default) folder doesn't exist, the user will be queried prior to
+its creation.
+As the messages are processed, a \fIscan\fR listing
+of the new mail is produced.
+
+If the user's profile contains a \*(lqMsg\-Protect: nnn\*(rq entry, it
+will be used as the protection on the newly created messages,
+otherwise the MH default of 664 will be used.
+During all
+operations on messages, this initially assigned protection will
+be preserved for each message, so \fIchmod\fR(I) may be used to set a
+protection on an individual message, and its protection will be
+preserved thereafter.
+
+If the switch `\-audit audit-file' is specified (usually as a
+default switch in the profile), then \fIinc\fR will append a header
+line and a line per message to the end of the specified
+audit-file with the format:
+
+.nf
+.ti 1i
+\*(<<inc\*(>> date
+.ti 1.5i
+<scan line for first message>
+.ti 1.5i
+<scan line for second message>
+.ti 2.5i
+<etc.>
+.fi
+
+This is useful for keeping track of volume and source of incoming
+mail.
+Eventually, \fIrepl\fR, \fIforw\fR, \fIcomp\fR, and \fIdist\fR may also
+produce audits to this (or another) file, perhaps with
+\*(lqMessage-Id:\*(rq information to keep an exact correspondence history.
+\*(lqAudit-file\*(rq will be in the user's MH directory unless a full
+path is specified.
+
+\fIInc\fR will incorporate even illegally formatted messages into the
+user's MH folder, inserting a blank line prior to the offending
+component and printing a comment identifying the bad message.
+
+In all cases, the \*.mail file will be zeroed.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^$HOME/\*.mail~^The user's mail drop
+^<mh-dir>/audit-file~^Audit trace file (optional)
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Folder\-Protect:~^For protection on new folders
+.Ps
+^Msg\-Protect:~^For protection on new messages
+.De
+`+folder' defaults to \*(lqinbox\*(rq
+.Co
+The folder into which the message is
+being incorporated will become the
+current folder, and the first message incorporated will be the
+current message.
+This leaves the context ready for a \fIshow\fR
+of the first new message.
+.En
+.SC NEXT
+.NA
+next \- show the next message
+.SY
+next [+folder] [\-switches for \fIl\fR] [\-help]
+.DE
+\fINext\fR performs a \fIshow\fR on the next message in the
+specified (or current) folder.
+Like \fIshow\fR, it passes any
+switches on to the program \fIl\fR, which is called to list the
+message.
+This command is exactly equivalent to \*(lqshow next\*(rq.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+.Co
+If a folder is specified, it will become the current folder, and the
+message that is shown (i.e., the next message in sequence)
+will become the current message.
+.En
+.SC PICK
+.NA
+pick \- select messages by content
+.SY
+.ta .4i 1.8i
+.nf
+.in .5i
+^pick~^^\0\-cc~^ [\-src +folder] [msgs] [\-help] [\-scan] [\-noscan]
+^^^\0\-date~^ [\-show] [\-noshow] [\-nofile] [\-nokeep]
+^^^\0\-from~^
+^^^\s+2\b'\(lt\(bv\(bv\(lk\(bv\(bv\(lb'\s0 \-search~\s+2\b'\(rt\(bv\(bv\(rk\(bv\(bv\(rb'\s0^ pattern
+^^^\0\-subject~^
+^^^\0\-to~^ [\-file [\-preserve] [\-link] +folder ... [\-nopreserve] [\-nolink] ]
+^^^\0\-\-component~^ [\-keep [\-stay] [\-nostay] [+folder ...] ]
+.fi
+
+.re
+.ti .5i
+typically:
+.in 1i
+pick\0\-from\0jones\0\-scan
+.br
+pick\0\-to\0holloway
+.br
+pick\0\-subject\0ned\0\-scan\0\-keep
+.DE
+\fIPick\fR searches messages within a folder for the specified
+contents, then performs several operations on the selected
+messages.
+
+A modified \fIgrep\fR(I) is used to perform the searching, so the
+full regular expression (see \fIed\fR(I)) facility is available
+within `pattern'.
+With `\-search', pattern is used directly,
+and with the others, the grep pattern constructed is:
+
+.ti +.5i
+\*(lq^component:\*.\*(**pattern\*(rq
+
+This means that the pattern specified for a `\-search' will be
+found everywhere in the message, including the header and the body,
+while the other search requests are limited to the single
+specified component.
+The expression `\-\-component pattern'
+is a shorthand for
+specifying `\-search \*(lqcomponent:\*.\*(**pattern\*(rq\ '; it is used to pick
+a component not in the set [cc date from subject to].
+An
+example is \*(lqpick \-\-reply\-to pooh \-show\*(rq.
+
+Searching is performed on a per-line basis.
+Within the header of
+the message, each component is treated as one long line, but in
+the body, each line is separate.
+Lower-case letters in the
+search pattern will match either lower or upper case in the
+message, while upper case will match only upper case.
+
+Once the search has been performed, the selected messages
+are scanned (see \fIscan\fR) if the `\-scan' switch is given, and
+then they are shown (see \fIshow\fR) if the `\-show' switch is
+given.
+After these two operations, the file operations (if
+requested) are performed.
+
+The `\-file' switch operates exactly like the \fIfile\fR command, with the
+same meaning for the `\-preserve' and `\-link' switches.
+
+The `\-keep' switch is similar to `\-file', but it produces a folder that
+is a subfolder of the folder being searched and defines it as
+the current folder (unless the `\-stay' flag is used).
+This
+subfolder contains the messages which matched the search
+criteria.
+All of the MH commands may be used with the sub-folder
+as the current folder.
+This gives the user considerable power
+in dealing with subsets of messages in a folder.
+
+The messages in a folder produced by `\-keep' will always have the
+same numbers as they have in the source folder (i.e., the
+`\-preserve' switch is automatic).
+This way, the message
+numbers are consistent with the folder from which the messages
+were selected.
+Messages are not removed from the source folder
+(i.e., the `\-link' switch is assumed).
+If a `+folder' is not
+specified, the standard name \*(lqselect\*(rq will be used.
+(This is the
+meaning of \*(lq(select)\*(rq when it appears in the output of the
+\fIfolder\fR command.) If `+folder' arguments are given to
+`\-keep', they will be used rather than \*(lqselect\*(rq for the names
+of the subfolders.
+This allows for several subfolders to be
+maintained concurrently.
+
+When a `\-keep' is performed, the subfolder becomes the current folder.
+This can be overridden by use
+of the `\-stay' switch.
+
+Here's an example:
+
+.nf
+\01 % folder +inbox
+\02 inbox+ has 16 messages ( 3\- 22); cur= 3.
+\03 % pick \-from dcrocker
+\04 6 hits.
+\05 [+inbox/select now current]
+\06 % folder
+\07 inbox/select+ has \06 messages ( 3\- 16); cur= 3.
+\08 % scan
+.ds + \\h'\\w!+!'
+\09 \03+ 6/20 Dcrocker Re: ned file update issue...
+10 \06\*+ 6/23 Dcrocker removal of files from /tm...
+11 \08\*+ 6/27 Dcrocker Problems with the new ned...
+12 13\*+ 6/28 dcrocker newest nned \*(<<I would ap...
+13 15\*+ 7/\05 Dcrocker nned \*(<<Last week I asked...
+14 16\*+ 7/\05 dcrocker message id format \*(<<I re...
+15 % show all | print
+16 [produce a full listing of this set of messages on the line printer.]
+17 % folder \-up
+18 inbox+ has 16 messages ( 3\- 22); cur= 3; (select).
+19 % folder \-down
+20 inbox/select+ has 6 messages ( 3\- 16); cur= 3.
+21 % rmf
+22 [+inbox now current]
+23 % folder
+24 inbox+ has 16 messages ( 3\- 22); cur= 3.
+.fi
+
+This is a rather lengthy example, but it shows the power of the
+MH package.
+In item 1, the current folder is set to inbox.
+In 3,
+all of the messages from dcrocker are found in inbox and linked
+into the folder \*(lqinbox/select\*(rq.
+(Since no action switch is
+specified, `\-keep' is assumed.) Items 6 and 7 show that this
+subfolder is now the current folder.
+Items 8 through 14 are a
+\fIscan\fR of the selected messages (note that they are all from dcrocker
+and are all in upper and lower case).
+Item 15 lists all of the messages to
+the high-speed printer.
+Item 17 directs \fIfolder\fR to set the
+current folder to the parent of the selection-list folder, which
+is now current.
+Item 18 shows that this has been done.
+Item 19 resets
+the current folder to the selection list, and 21 removes the
+selection-list folder and resets the current folder to the
+parent folder, as shown in 22 and 23.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Folder\-Protect:~^For protection on new folders
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`\-src +folder' defaults to current
+`msgs' defaults to all
+.fi
+`\-keep +select' is the default if no `\-scan', `\-show', or `\-file' is specified
+.Co
+If a `\-src +folder' is specified, it will
+become the current folder, unless a `\-keep' with 0 or 1
+folder arguments makes the selection-list subfolder the
+current folder.
+Each selection-list folder will have its
+current message set to the first of the messages linked into
+it unless the selection list already existed, in which case the
+current message won't be changed.
+.En
+.SC PREV
+.NA
+prev \- show the previous message
+.SY
+prev [+folder] [\-switches for \fIl\fR] [\-help]
+.DE
+\fIPrev\fR performs a \fIshow\fR on the previous message in the specified
+(or current) folder.
+Like \fIshow\fR, it passes any switches on to the
+program \fIl\fR, which is called to list the message.
+This command
+is exactly equivalent to \*(lqshow prev\*(rq.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+.Co
+If a folder is specified, it will become current, and the
+message that is shown (i.e., the previous message in sequence)
+will become the current message.
+.En
+.SC PROMPTER
+.NA
+prompter \- prompts the editor front end
+.SY
+This program is not called directly but takes the place
+of an editor and acts as an editor front end.
+
+.ti .5i
+prompter [\-erase chr] [\-kill chr] [\-help]
+.DE
+\fIPrompter\fR is an editor which allows rapid composition of
+messages.
+It is particularly useful to network and low-speed
+(less than 2400 baud) users of MH.
+It is an MH program in that
+it can have its own profile entry with switches, but it can't
+be invoked directly as all other MH commands can; it is an editor
+in that it is invoked by an \*(lq\-editor prompter\*(rq switch or by the
+profile entry \*(lqEditor: prompter\*(rq, but functionally it is merely
+a text-collector and not a true editor.
+
+\fIPrompter\fR expects to be called from \fIcomp\fR, \fIrepl\fR, \fIdist\fR, or
+\fIforw\fR, with a draft file as an argument.
+For example, \*(lqcomp
+\-editor prompter\*(rq will call \fIprompter\fR with the file \*(lqdraft\*(rq already set
+up with blank components.
+For each blank component it finds in
+the draft, it prompts the user and accepts a response.
+A
+<RETURN> will cause the whole component to be left out.
+A \*(lq\\\*(rq
+preceding a <RETURN> will continue the response on the next line,
+allowing for multiline components.
+
+Any component that is non-blank will be copied and echoed to the
+terminal.
+
+The start of the message body is prompted by a line of
+dashes.
+If the body is non-blank, the prompt is
+\*(lq--------Enter additional text\*(rq.
+Message-body typing is terminated with
+a <CTRL-D> (or <CLOSE>).
+Control is returned to the calling
+program, where the user is asked \*(lqWhat now?\*(rq.
+See \fIcomp\fR for
+the valid options.
+
+During \fIprompter\fR execution, the line-deletion character is
+redefined to be <CTRL-F> (<OPEN> on a NED Ann Arbor terminal)
+rather than @, to facilitate the typing of ARPANET addresses such as
+\*(lqKierr @ PARC\*(rq.
+The standard UNIX character-deletion code is
+changed from # to <CTRL-A>, but the destructive backspace key
+will continue to work normally.
+These two characters may be
+specified by the user via the arguments \*(lq\-kill chr\*(rq and \*(lq\-erase
+chr\*(rq, where chr may be a character; or \*(lq\\nnn\*(rq, where nnn is the
+octal value for the character.
+(Again, these may come from the
+default switches specified in the user's profile.)
+
+A <DEL> during message-body typing is equivalent to
+<CTRL-D> for compatibility with NED.
+A <DEL> during
+component typing will abort the command that invoked
+\fIprompter\fR.
+.Fi
+None
+.Pr
+^prompter-next:~^To name the editor to be used on exit from \fIprompter\fR
+.De
+`\-editor' defaults to /bin/ned
+`\-kill \\006'
+`\-erase \\001'
+.Co
+None
+.En
+.SC REPL
+.NA
+repl \- reply to a message
+.SY
+repl [+folder] [msg] [\-editor editor] [\-inplace] [\-annotate]
+[\-help] [\-noinplace] [\-noannotate]
+.DE
+\fIRepl\fR aids a user in producing a reply to an existing
+message.
+In its simplest form (with no arguments), it will set up
+a message-form skeleton in reply to the current message in the
+current folder, invoke the editor, and send the composed
+message if so directed.
+The composed message is constructed as
+follows:
+
+.nf
+.in 1i
+To: <Reply-To> or <From>
+cc: <cc>, <To>
+Subject: Re: <Subject>
+In-reply-to: Your message of <Date>
+.ti +\w'In-reply-to: 'u
+<Message-Id>
+.in .5i
+.fi
+
+where field names enclosed in angle brackets (< >) indicate the
+contents of the named field from the message to which the reply
+is being made.
+Once the skeleton is constructed, an editor is
+invoked (as in \fIcomp\fR, \fIdist\fR, and \fIforw\fR).
+While in the editor,
+the message being replied to is available through a link named
+\*(lq@\*(rq.
+In NED, this means the replied-to message may be \*(lqused\*(rq
+with \*(lquse @\*(rq, or put in a window by \*(lqwindow @\*(rq.
+
+As in \fIcomp\fR, \fIdist\fR, and \fIforw\fR, the user will be queried
+before the message is sent.
+If the `\-annotate' switch is
+specified, the replied-to message will be annotated with the
+single line
+
+.ti +.5i
+Replied: \*(<<Date\*(>>
+
+only if the message is sent directly.
+The command
+\*(lqcomp \-use\*(rq may be used to pick up interrupted editing, as in
+\fIdist\fR and \fIforw\fR; the `\-inplace' switch annotates the message in place,
+so that all folders with links to it will see the annotation.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The constructed message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a `+folder' is specified, it will become the current
+folder, and the current message will be set to the replied-to
+message.
+.En
+.SC RMF
+.NA
+rmf \- remove folder
+.SY
+rmf [+folder] [\-help]
+.DE
+\fIRmf\fR removes all of the files (messages) within the specified
+(or default) folder, and then removes the directory (folder).
+If
+there are any files within the folder which are not a part of MH,
+they will \fInot\fR be removed, and an error will be produced.
+If the
+folder is given explicitly or the current folder is a
+subfolder (i.e., a selection list from \fIpick\fR), it will be
+removed without confirmation.
+If no argument is specified and
+the current folder is not a selection-list folder, the
+user will be asked for confirmation.
+
+\fIRmf\fR irreversibly deletes messages that don't have other links,
+so use it with caution.
+
+If the folder being removed is a subfolder, the parent
+folder will become the new current folder, and \fIrmf\fR will
+produce a message telling the user this has happened.
+This
+provides an easy mechanism for selecting a set of messages,
+operating on the list, then removing the list and returning to
+the current folder from which the list was extracted.
+(See the
+example under \fIpick\fR.)
+
+The files that \fIrmf\fR will delete are cur, any file beginning
+with a comma, and files with purely numeric names.
+All others
+will produce error messages.
+
+\fIRmf\fR of a read-only folder will delete the \*(lqcur\-\*(rq entry from the
+profile without affecting the folder itself.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current, usually with confirmation
+.Co
+\fIRmf\fR will set the current folder to the parent folder if a
+subfolder is removed; or if the current folder is removed,
+it will make \*(lqinbox\*(rq current.
+Otherwise, it doesn't change the
+current folder or message.
+.En
+.SC RMM
+.NA
+rmm \- remove messages
+.SY
+rmm [+folder] [msgs] [\-help]
+.DE
+\fIRmm\fR removes the specified messages by renaming the message
+files with preceding commas.
+(This is the Rand-UNIX backup file
+convention.)
+
+The current message is not changed by \fIrmm\fR, so a \fInext\fR will
+advance to the next message in the folder as expected.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+.Co
+If a folder is given, it will become current.
+.En
+.SC SCAN
+.NA
+scan \- produce a one-line-per-message scan listing
+.SY
+scan [+folder] [msgs] [\-ff] [\-header] [\-help]
+[\-noff] [\-noheader]
+.DE
+\fIScan\fR produces a one-line-per-message listing of the specified
+messages.
+Each \fIscan\fR line contains the message number (name),
+the date, the \*(lqFrom\*(rq field, the \*(lqSubject\*(rq field, and, if room
+allows, some of the body of the message.
+For example:
+
+.nf
+.ta .5i 1.2i 2.6i
+^ #~^^Date~^^ From~^Subject\ \ \ \ \[\*(<<Body]
+^15+~^^7/\05~^^Dcrocker~^nned \*(<<Last week I asked some of
+^16\ \-~^^7/\05~^^dcrocker~^message id format \*(<<I recommend
+^18~^^7/\06~^^Obrien~^Re: Exit status from mkdir
+^19~^^7/\07~^^Obrien~^"scan" listing format in MH
+.re
+.fi
+
+The `+' on message 15 indicates that it is the current message.
+The `\-' on message 16 indicates that it has been
+replied to, as indicated by a \*(lqReplied:\*(rq component produced by
+an `\-annotate' switch to the \fIrepl\fR command.
+
+If there is sufficient room left on the \fIscan\fR line after the
+subject, the line will be filled with text from the body,
+preceded by \*(<<.
+\fIScan\fR actually reads each of the specified
+messages and parses them to extract the desired fields.
+During parsing, appropriate error messages will be produced if
+there are format errors in any of the messages.
+
+The `\-header' switch produces a header line prior to the \fIscan\fR
+listing, and the `\-ff' switch will cause a form feed to be
+output at the end of the \fIscan\fR listing.
+See Appendix D.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+Defaults:
+`+folder' defaults to current
+`msgs' defaults to all
+`\-noff'
+`\-noheader'
+.Co
+If a folder is given, it will become current.
+The current
+message is unaffected.
+.En
+.SC SEND
+.NA
+send \- send a message
+.SY
+send [file] [\-draft] [\-verbose] [\-format] [\-msgid]
+[\-help] [\-noverbose] [\-noformat] [\-nomsgid]
+.DE
+\fISend\fR will cause the specified file (default <mh-dir>/draft) to
+be delivered to each of the addresses in the \*(lqTo:\*(rq, \*(lqcc:\*(rq, and \*(lqBcc:\*(rq
+fields of the message.
+If `\-verbose' is specified, \fIsend;\fR
+will monitor the delivery of local and net mail.
+\fISend\fR with no
+argument will query whether the draft is the intended file, whereas
+`\-draft' will suppress this question.
+Once the message has
+been mailed (or queued) successfully, the file will be renamed
+with a leading comma, which allows it to be retreived until the
+next draft message is sent.
+If there are errors in the
+formatting of the message, \fIsend;\fR will abort with a (hopefully)
+helpful error message.
+
+If a \*(lqBcc:\*(rq field is encountered, its addresses will be used for
+delivery, but the \*(lqBcc:\*(rq field itself will be deleted from all
+copies of the outgoing message.
+
+Prior to sending the message, the fields \*(lqFrom: user\*(rq, and
+\*(lqDate: now\*(rq will be prepended to the message.
+If `\-msgid' is
+specified, then a \*(lqMessage-Id:\*(rq field will also be added to the
+message.
+If the message already contains a \*(lqFrom:\*(rq field, then a
+\*(lqSender: user\*(rq field will be added instead.
+(An already existing
+\*(lqSender:\*(rq field will be deleted from the message.)
+
+If the user doesn't specify `\-noformat', each of the entries in
+the \*(lqTo:\*(rq and \*(lqcc:\*(rq fields will be replaced with \*(lqstandard\*(rq format
+entries.
+This standard format is designed to be usable by all
+of the message handlers on the various systems around the
+ARPANET.
+
+If an \*(lqFcc: folder\*(rq is encountered, the message will be copied
+to the specified folder in the format in which it will appear to any
+receivers of the message.
+That is, it will have the prepended
+fields and field reformatting.
+
+If a \*(lqDistribute-To:\*(rq field is encountered, the message
+is handled as a redistribution message (see \fIdist\fR for
+details), with \*(lqDistribution-Date: now\*(rq and \*(lqDistribution-From: user\*(rq
+added.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.De
+`file' defaults to draft
+`\-noverbose'
+`\-format'
+`\-nomsgid'
+.Co
+\fISend\fR has no effect on the current message or folder.
+.En
+.SC SHOW
+.NA
+show \- show (list) messages
+.SY
+show [+folder] [msgs] [\-pr] [\-nopr] [\-draft] [\-help]
+[\fIl\fR or \fIpr\fR switches]
+.DE
+\fIShow\fR lists each of the specified messages to the standard
+output (typically, the terminal).
+The messages are listed exactly
+as they are, with no reformatting.
+A program called \fIl\fR is
+invoked to do the listing, and any switches not recognized by
+\fIshow\fR are passed along to \fIl\fR.
+
+If no \*(lqmsgs\*(rq are specified, the current message is used.
+If
+more than one message is specified, \fIl\fR will prompt for a
+<return> prior to listing each message.
+
+\fIl\fR will list each message, a page at a time.
+When the end of
+page is reached, \fIl\fR will ring the bell and wait for a <RETURN>
+or <CTRL-D>.
+If a <return> is entered, \fIl\fR will clear the
+screen before listing the next page, whereas <CTRL-D> will not.
+The switches to \fIl\fR are
+`\-p#' to indicate the page length in lines, and `\-w#' to
+indicate the width of the page in characters.
+
+If the standard output is not a terminal, no queries are made,
+and each file is listed with a one-line header and two lines of
+separation.
+
+If `\-pr' is specified, then \fIpr\fR(I) will be invoked rather than
+\fIl\fR, and the switches (other than `\-draft') will be passed
+along.
+\*(lqShow \-draft\*(rq will list the file <mh-dir>/draft if it
+exists.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^/bin/l~^Screen-at-a-time list program
+^/bin/pr~^\fIpr\fR(I)
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-nopr'
+.Co
+If a folder is given, it will become the current message.
+The last message
+listed will become the current message.
+.En
+.fo ''-%-''
+.he ''''
+\".AH COMMAND SUMMARY*
+.(x
+
+
+APPENDICES
+.)x _
+.++ A
+\".+c "COMMAND SUMMARY\**"
+.bp
+.ll 32P
+.lt 32P
+.ce
+COMMAND SUMMARY\**
+.(f
+\**All commands accept a \-help switch.
+.)f
+.(x
+
+A.\ COMMAND\ SUMMARY
+.)x
+.sp 3
+.nr ch +1
+.nf
+comp [file] [\-editor editor] [\-form formfile]
+ [\-use] [\-nouse]
+
+dist [+folder] [msg] [\-form formfile] [\-editor editor]
+ [\-annotate] [\-noannotate]
+ [\-inplace] [\-noinplace]
+
+file [\-src +folder][msgs] [\-link] [\-preserve] +folder ...
+ [\-nolink] [\-nopreserve]
+
+folder [+folder] [msg] [\-all] [\-fast] [\-nofast] [\-up] [\-down]
+ [\-header] [\-noheader] [\-total] [\-nototal]
+
+forw [+folder] [msgs] [\-editor editor] [\-form formfile]
+ [\-annotate] [\-noannotate]
+ [\-inplace] [\-noinplace]
+
+inc [+folder] [\-audit audit-file]
+
+next [+folder] [\-switches for \fIl\fR]
+
+pick {\-cc } [\-src +folder] [msgs]
+ {\-date } [\-scan] [\-noscan] [\-show] [\-noshow]
+ {\-from }
+ {\-search } pattern [\-nofile] [\-nokeep]
+ {\-subject }
+ {\-to } [\-file [\-preserve] [\-nopreserve] [\-link]
+ {\-\-component} [\-nolink] +folder ... ]
+ [\-keep [\-stay] [+folder ...] [\-nostay] ]
+
+prev [+folder] [\-switches for \fIl\fR]
+
+prompter [\-erase chr] [\-kill chr]
+
+repl [+folder] [msg] [\-editor editor] [\-annotate] [\-noannotate]
+ [\-inplace] [\-noinplace]
+
+rmf [+folder]
+
+rmm [+folder] [msgs]
+
+scan [+folder] [msgs] [\-ff] [\-header]
+ [\-noff] [\-noheader]
+
+send [file] [\-draft] [\-verbose] [\-format] [\-msgid]
+ [\-noverbose] [\-noformat] [\-nomsgid]
+
+show [+folder] [msgs] [\-pr] [\-nopr] [\-draft]
+ [\fIl\fR or \fIpr\fR switches]
+.fi
+.he ''-%-''
+.fo ''''
+.+c "MESSAGE FORMAT"
+.pp
+This section paraphrases the format of ARPANET text messages
+given in Ref. 6.
+.lp
+ASSUMPTIONS
+.np
+Messages
+are expected to consist of lines of text.
+Graphics and binary data are not handled.
+.np
+No data compression is accepted.
+All text is clear
+ASCII 7-bit data.
+.lp
+LAYOUT
+.lp
+A general \*(lqmemo\*(rq framework is used.
+A message consists of a
+block of information in a rigid format, followed by general
+text with no specified format.
+The rigidly formatted first
+part of a message is called the header, and the free-format
+portion is called the body.
+The header must always
+exist, but the body is optional.
+.lp
+THE HEADER
+.lp
+Each header item can be viewed as a single logical line of ASCII
+characters.
+If the text of a header item extends across several
+real lines, the continuation lines are indicated by leading
+spaces or tabs.
+.lp
+Each header item is called a component and is composed of a
+keyword or name, along with associated text.
+The keyword begins at the
+left margin, may contain spaces or tabs, may not exceed 63
+characters, and is terminated by a colon (:).
+Certain
+components (as identified by their keywords) must follow rigidly
+defined formats in their text portions.
+.lp
+The text for most formatted components (e.g., \*(lqDate:\*(rq and \*(lqMessage-Id:\*(rq)
+is produced automatically.
+The only ones entered by the
+user are address fields such as \*(lqTo:\*(rq, \*(lqcc:\*(rq, etc.
+ARPA addresses
+are assigned mailbox names and host computer specifications.
+The
+rough format is \*(lqmailbox at host\*(rq, such as \*(lqBorden at Rand-Unix\*(rq.
+Multiple addresses are separated by commas.
+A missing host is
+assumed to be the local host.
+.ne 10
+.lp
+THE BODY
+.lp
+A blank line signals that all following text up to the end of the file
+is the body.
+(A blank line is defined as a pair of
+<end-of-line> characters with \fIno\fR characters in between.)
+No formatting is expected or enforced within the body.
+.lp
+Within MH, a line consisting of dashes is accepted
+as the header delimiter.
+This is a cosmetic feature applying
+only to locally composed mail.
+.+c "MESSAGE NAME BNF"
+
+.ta 1.2i 1.8i 3.2i
+.nf
+.in 1i
+^msgs~^^:=~^^msgspec~^|
+^^^^msgs msgspec
+
+^msgspec~^^:=~^^msg~^|
+^^^^^msg-range~^|
+^^^^msg-sequence
+
+^msg~^^:=~^^msg-name~^|
+^^^^<number>^
+
+^msg-name~^^:=~^^\*(lqfirst\*(rq~^|
+^^^^^\*(lqlast\*(rq~^|
+^^^^^\*(lqcur\*(rq~^|
+^^^^^\*(lq\*.\*(rq~^|
+^^^^^\*(lqnext\*(rq~^|
+^^^^\*(lqprev\*(rq
+
+^msg-range~^^:=~^^msg\*(lq-\*(rqmsg~^|
+^^^^^\*(lqall\*(rq
+
+^msg-sequence~^^:=~^msg\*(lq:\*(rqsigned-number
+
+^signed-number~^^:=~^^\*(lq+\*(rq<number>~^|
+^^^^^\*(lq\--\*(rq<number>~^|
+^^^^<number>
+.re \" Reset Tabs
+.fi
+.sp
+.pp
+Where <number> is a decimal number in the range 1 to 999.
+.pp
+Msg-range specifies all of the messages in the given range
+and must not be empty.
+.pp
+Msg-sequence specifies up to <number> of messages, beginning
+with \*(lqmsg\*(rq (in the case of first, cur, next, or <number>),
+or ending with \*(lqmsg\*(rq (in the case of prev or last).
++<number> forces \*(lqstarting with msg\*(rq, and \-<number> forces
+\*(lqending with number\*(rq.
+In all cases, \*(lqmsg\*(rq must exist.
+
+.+c "EXAMPLES OF SHELL COMMANDS"
+.pp
+UNIX commands may be mixed with MH commands to obtain additional
+functions.
+These may be prepared as files (known as
+shell command files or
+shell scripts).
+The following two examples are useful functions that
+illustrate the possibilities.
+Other functions, such as copying,
+deleting, renaming, etc., can be achieved in a similar fashion.
+
+HARDCOPY
+.pp
+The command:
+
+.ti +.5i
+(scan\0\-ff\0\-header;\0show\0all\0\-pr\0\-f)\0|\0print
+
+produces a scan listing of the current folder, followed by a
+form feed, followed by a formatted listing of all messages
+in the folder, one per page.
+Omitting \*(lq\-pr\0\-f\*(rq will cause the
+messages to be concatenated, separated by a one-line header
+and two blank lines.
+.pp
+You can create variations on this theme, using \fIpick\fR.
+
+
+RENUMBERING
+.pp
+To compact the message numbers within the folder called inbox,
+use the commands:
+
+.in 5
+.nf
+.ta 3i
+^file\0\-src\0+inbox\0all\0+temp~^/* file and renumber */
+^file\0all\0\-src\0+temp\0+inbox~^/* move 'em back */
+^rmf\0+temp~^/* remove \*(lqtemp\*(rq */
+^folder\0+inbox~^/* reset \*(lqcurrent\*(rq folder */
+.re
+.fi
+.in 0
+.+c REFERENCES
+.in .4i
+.ti 0
+1. Crocker, D. H., J. J. Vittal, K. T. Pogran, and D. A. Henderson, Jr.,
+\*(lqStandard for the Format of ARPA Network Test Messages,\*(rq \fIArpanet Request
+for Comments\fR, No. 733, Network Information Center 41952, Augmentation
+Research Center, Stanford Research Institute,
+November 1977.
+
+.ti 0
+2. Thompson, K., and D. M. Ritchie, \*(lqThe UNIX Time-sharing System,\*(rq
+\fICommunications of the ACM\fR, Vol. 17, July 1974, pp. 365-375.
+
+.ti 0
+3. McCauley, E. J., and P. J. Drongowski, \*(lqKSOS\-The Design of a Secure
+Operating System,\*(rq \fIAFIPS Conference Proceedings\fR,
+National Computer Conference,
+Vol. 48, 1979, pp. 345-353.
+
+.ti 0
+4. Crocker, David H., \fIFramework and Functions of the \*(lqMS\*(rq Personal
+Message System\fR, The Rand Corporation, R-2134-ARPA, December 1977.
+
+.ti 0
+5. Thompson, K., and D. M. Ritchie, \fIUNIX Programmer's Manual\fR, 6th ed.,
+Western Electric Company, May 1975 (available only to UNIX licensees).
+
+.ti 0
+6. Bilofsky, Walter, \fIThe CRT Text Editor NED\-Introduction and
+Reference Manual\fR, The Rand Corporation, R-2176-ARPA, December 1977.
+.de $c
+.ce
+.b "\\s12\\$1\\s0" \" 12 Point Bold Header
+.(x y
+
+\\$1
+.)x
+.sp 3
+..
+.hx
+.tp
+.nf
+.sp 15
+.ps 18
+.vs 24
+.ft B
+.ce 2
+THE MH MESSAGE HANDLING SYSTEM:
+USER'S MANUAL
+.ps
+.vs
+.ft
+.sp .75i
+.ps 12
+.ft B
+.ce
+PREPARED FOR THE AIR FORCE
+.ps
+.ft
+.sp 1i
+.ps 14
+.vs 17
+.ft B
+.ce 3
+BRUCE S. BORDEN
+R. STOCKTON GAINES
+NORMAN Z. SHAPIRO
+.ps
+.ft
+.vs
+.sp |-3.5i
+.ps 16
+.vs 20
+.ft B
+.ce 2
+R-2367-PAF
+OCTOBER 1979
+.ps
+.ft
+.vs
+.pn 3
+.af % i
+.+c PREFACE
+.pp
+This report describes a system for dealing with messages transmitted on a
+computer. Such messages might originate with other users of the same
+computer or might come from an outside source through a network to which the user's
+computer is connected. Such computer-based message systems are
+becoming increasingly widely used, both within and outside the Department
+of Defense.
+.pp
+The message handling system MH was developed for two reasons.
+One was to investigate some
+research ideas concerning how a message system might take advantage of
+the architecture of the UNIX time-sharing operating system for
+Digital Equipment Corporation PDP-11 and VAX computers, and the special
+features of UNIX's command-level interface with the user (the
+\*(lqshell\*(rq). The other reason was to provide a better and more
+adaptable base than that of conventional designs
+on which to build a command and control message system.
+The effort has succeeded in both
+regards, although this report mainly describes the message system itself
+and how it fits in with UNIX. The main research results are being
+described and analyzed in a forthcoming Rand report.
+The system is currently being used as part
+of a tactical command and control \*(lqlaboratory,\*(rq which is also being described
+in a separate report.
+.pp
+The present report should be of interest to three groups of readers. First,
+it is a complete reference manual for the users of MH (although
+users outside of Rand must take into
+account differences from the local Rand environment). Second, it should be
+of interest to those who have a general knowledge of computer-based
+message systems, both in civilian and military environments. Finally,
+it should be of interest to those who build large subsystems that
+interface with users, since it illustrates a new approach to such
+interfaces.
+.pp
+This report was prepared as part of the Rand project entitled \*(lqData
+Automation Research\*(rq, sponsored by Project AIR FORCE.
+.+c SUMMARY
+.pp
+Electronic communication of text messages is becoming
+commonplace. Computer-based message systems\-software
+packages that provide tools for dealing with messages\-are used in many
+contexts. In particular, message systems are becoming
+increasingly important in command and control and intelligence
+applications.
+.pp
+This report describes a message handling system called MH.
+This system provides the user
+with tools to compose, send, receive, store, retrieve, forward, and
+reply to messages. MH has been built on the UNIX time-sharing system,
+a popular operating system developed for the DEC PDP-11 and VAX classes of
+computers.
+.pp
+A complete description of MH is given for users of
+the system. For those who do not intend to use the system, this description
+gives a general idea of what a message system is like. The system involves
+some new ideas about how large subsystems can be constructed. These design
+concepts and a comparison of MH with other message systems
+will be published in a forthcoming Rand report.
+.pp
+The interesting and unusual features of MH include the
+following: The user command interface to MH is the UNIX \*(lqshell\*(rq
+(the standard UNIX command interpreter). Each separable
+component of message handling, such as message composition or
+message display, is a separate command. Each program is driven from
+and updates a private user environment, which is stored as a file
+between program invocations. This private environment also contains
+information to \*(lqcustom tailor\*(rq MH to the individual's tastes. MH
+stores each message as a separate file under UNIX, and it utilizes the
+tree-structured UNIX file system to organize groups of files within
+separate directories or \*(lqfolders.\*(rq All of the UNIX facilities
+for dealing with files and directories, such as
+renaming, copying, deleting, cataloging, off-line printing, etc., are
+applicable to messages and directories of messages (folders). Thus,
+important capabilities needed in a message system are available in MH without
+the need (often seen in other message systems) for code that
+duplicates the facilities of the supporting operating system.
+It also allows users familiar with the shell to use MH with minimal
+effort.
+.de $c
+.ce
+.b "\\s12\\$1\\s0" \" 12 Point Bold Header
+.sp 3
+..
+.pn 1
+.af % i
+.
\ No newline at end of file
--- /dev/null
+.ll 32P
+.nf
+.sp |2.5i
+.ps 18
+.vs 24
+.ft B
+.ce 2
+THE MH MESSAGE HANDLING SYSTEM:
+USER'S MANUAL
+.vs
+.sp .75i
+.ps 12
+.ce
+PREPARED FOR THE AIR FORCE
+.sp 1i
+.ps 14
+.vs 17
+.ce 3
+BRUCE S. BORDEN
+R. STOCKTON GAINES
+NORMAN Z. SHAPIRO
+.vs
+.sp 3.5i
+.ps 16
+.vs 20
+.ft B
+.ce 2
+R-2367-PAF
+OCTOBER 1979
--- /dev/null
+.de RA
+.mk v
+\kh\c
+.ft B
+.ps \\$1
+.vs \\$1+2
+RAND\kH
+.br
+.ps \\$1/4
+SANTA MONICA, CA. 90406
--- /dev/null
+if -r anno rm anno
+load -s anno annotate subs.a strings.a -O /rnd/borden/libg.a /rnd/borden/libh.a
+if -r anno.out mv anno.out anno
+: fini
+
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "mh.h"
+
+/* anno [+folder] [msgs] [switches] -component component [-text [text]]
+ *
+ * prepends Component: <<date stamp>>
+ * text
+ */
+
+int fout;
+struct msgs *mp;
+int inplace; /* preserve links in anno */
+
+struct swit switches[] {
+ "all", -3, /* 0 */
+ "component", 0, /* 1 */
+ "inplace", 0, /* 2 */
+ "noinplace", 0, /* 3 */
+ "text", 0, /* 4 */
+ "help", 4, /* 5 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ register int i, msgnum;
+ register char *cp, *ap;
+ char *folder, *maildir, *msgs[128], *component, *text;
+ char *arguments[50], **argp;
+ int msgp;
+
+ fout = dup(1);
+#ifdef NEWS
+ m_news();
+#endif
+ folder = msgp = component = text = 0;
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("anno: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: printf("\"-all\" changed to \"all\"\n");
+ goto leave;
+ /* -component */
+ case 1: if(component) {
+ printf("Only one component.\n");
+ goto leave;
+ }
+ if(!(component = *argp++)) {
+ printf("anno: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 2: inplace = 1; continue; /* -inplace */
+ case 3: inplace = 0; continue; /* -noinplace */
+ case 4: if(text) { /* -text */
+ printf("Only one text switch.\n");
+ goto leave;
+ }
+ text = *argp++; continue;
+ case 5: /* -help */
+help("anno [+folder] [msgs] [switches] -component component [-text [text]]", switches);
+ goto leave;
+ }
+ if(*cp == '+')
+ if(folder) {
+ printf("Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ else
+ msgs[msgp++] = cp;
+ }
+ if(!component) {
+ usage:
+ printf("usage: anno [+folder] [msgs] [switches] -component component [-text [text]] \n");
+ goto leave;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ printf("Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ printf("No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ printf("anno: feta cheese and garlic\n"); /* never get here */
+ goto leave;
+ }
+ m_replace("folder", folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ for(i = mp->lowsel; i <= mp->hghsel; i++)
+ if(mp->msgstats[i] & SELECTED)
+ annotate(m_name(i), component, text ? text : "");
+ leave:
+ m_update();
+ flush();
+}
+
+
+/*
+ * if(*cp == '\"' )
+ * if(astrp > 1)
+ * goto usage;
+ * else
+ * if(!(ap = rmquote(cp + 1)))
+ * goto usage;
+ * astrings[astrp++] = ap;
+*rmquote(cp)
+*char *cp;
+*{
+ * int i;
+ *
+ * if(cp[i = length(cp) -1] != '\"') {
+ * printf("rmquote: string doesn't end with \"\n");
+ * return(0);
+ * }
+ * cp[i] = 0;
+ * return(cp);
+*}
+ if(*cp == '=' ) {
+ if(astrp > 1)
+ goto usage;
+ else
+ astrings[astrp++] = cp + 1;
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <stdio.h>
+#include <pwd.h>
+
+char *
+getenv(key)
+ char *key;
+{
+ register char *r;
+ register struct passwd *p;
+
+ if(strcmp(key, "USER") == 0 || strcmp(key, "HOME") == 0)
+ if((p = getpwuid(getruid())) == NULL)
+ return NULL;
+ else
+ return strcmp(key, "USER") == 0 ?
+ p->pw_name : p->pw_dir;
+ return NULL;
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+
+#ifdef OLDNCP
+struct netopen /* Format of open request */
+{
+ long no_lskt; /* Local socket */
+ long no_fskt; /* Foreign socket */
+ short no_flags; /* Flag bits */
+ short no_rel; /* Local socket relative to this file */
+ short no_imp; /* Imp number */
+ char no_host; /* Host within Imp */
+ char no_net; /* Network number (!) */
+ char no_bsize; /* Byte size */
+};
+#else
+struct netopen /* Format of open request */
+{
+ long no_lskt; /* Local socket */
+ long no_fskt; /* Foreign socket */
+ short no_flags; /* Flag bits */
+ short no_rel; /* Local socket relative to this file */
+ short no_imp; /* Imp number */
+ char no_host; /* Host within Imp */
+ char no_net; /* Network number (!) */
+ char no_bsize; /* Byte size */
+};
+#endif
+
+#define NO_ABS 01 /* Absolute local socket number for a connect */
+#define NO_REL 02 /* Relative to another file */
+
+#define NIMPS 20 /* number of imp devices */
+#define MAX_IMPS 10 /* number of imp devices, starting from imp1 */
+
+#define HOSTTBL "/etc/nethosts"
+
+/* Op codes */
+#define NET_CNCT 0
+#define NET_RD 1
+#define NET_WRT 2
+#define NET_CLS 3
+#define NET_LSN 4
+#define NET_SICP 5
+#define NET_UICP 6
+#define NET_RST 7
+#define NET_STRT 8
+#define NET_LOG 9
+#define NET_RSTAT 10
+#define NET_WSTAT 11
+#define NET_SRVR 12
+#define NET_DUMP 13
+#define NET_FLOW 255
+
+/* ioctl commands for imp device*/
+#define IMPCONCT (('I'<<8)|NET_CNCT) /* Connect */
+#define IMPLISTN (('I'<<8)|NET_LSN ) /* Listen */
+#define IMPSICP (('I'<<8)|NET_SICP) /* Server ICP */
+#define IMPUICP (('I'<<8)|NET_UICP) /* User ICP */
+#define IMPRST (('I'<<8)|NET_RST ) /* Reset */
+#define IMPSTRT (('I'<<8)|NET_STRT) /* Start NCP */
+#define IMPLOG (('I'<<8)|NET_LOG ) /* Set log flags */
+#define IMPRSTAT (('I'<<8)|NET_RSTAT) /* Read socket status */
+#define IMPWSTAT (('I'<<8)|NET_WSTAT) /* Write socket status */
+#define IMPRDST (('I'<<8)|100 ) /* Get read status */
+#define IMPWRTST (('I'<<8)|101 ) /* Get write status */
+
+/* Structure for IMPSTAT ioctl */
+struct sockstat {
+ long sck_lskt;
+ long sck_fskt;
+ short sck_imp;
+ char sck_host;
+ char sck_net;
+};
+
+long hostnum();
+char *hos
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+int glbtype 0;
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+
+struct buf {
+
+ int fildes;
+ int nleft;
+ char *nextp;
+ char buff[512];
+
+};
+
+int pich;
+
+
+getpw(uid, buf)
+char *buf;
+{
+ auto pbuf[259];
+ register n, c;
+ register char *bp;
+
+ if (pich == 0) pich = open("/etc/passwd",0);
+ if (pich < 0) return(1);
+ seek(pich,0,0);
+ pbuf->fildes = pich;
+ pbuf->nleft = 0;
+ uid =& 0377; /* not for harv unix */
+
+ for(;;) {
+ bp = buf;
+ while((c=pwgetc(&pbuf)) != '\n') {
+ if (c <= 0) return(1);
+ *bp++ = c;
+ }
+ *bp++ = '\0';
+ bp = buf;
+ n = 3;
+ while(--n)
+ while((c = *bp++) != ':')
+ if (c == '\n') return(1);
+ while((c = *bp++) != ':') {
+ if (c < '0' || c > '9') continue;
+ n = n * 10 + c - '0';
+ }
+ if (n == uid) return(0);
+ }
+ return(1);
+}
+
+pwgetc(buf)
+struct buf *buf;
+{
+ register struct buf *bp;
+
+ bp = buf;
+ if (--bp->nleft < 0) {
+ bp->nleft = read(bp->fildes,bp->buff,512)-1;
+ if (bp->nleft < 0) return(-1);
+ bp->nextp = bp->buff;
+ }
+ return(*bp->nextp++);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "libg.h"
+#include "../h/stat.h"
+getwho(i)
+{
+ register char *st;
+ struct inode i_buf;
+
+ st = ttyname(i);
+ if (st == NULSTR) return(-1);
+ stat(cat("/dev/",st),&i_buf);
+ return(i_buf.i_uid&0377);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+
+getfstn(uid)
+{
+ return("first name");
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+
+getldate(uid)
+{
+ static int logout_date[2];
+
+ return(logout_date);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "libg.h"
+
+char *getlogn(uid)
+{
+ static char name[20];
+ register char *np, *bp;
+
+ if (getubuf(uid)<=0) return(NULSTR);
+
+ np = name; bp = u_buf;
+ while( (*np++ = *bp++) != ':');
+ *--np = '\0';
+ return(name);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+
+getlstn(uid)
+{
+ return("last name");
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../h/stat.h"
+/* this subr returns owner of tty attached to file handle # 2 */
+/* on harv/unix, this may not be the real uid, because */
+/* we have the command "alias" which spawns a sub-shell with */
+/* a new real uid. luid (login uid) is used by the harvard shell */
+/* to find the "save.txt" file (via getpath(getluid())) for $a - $z */
+/* shell macros, and elsewhere by certain accounting routines. */
+
+getluid()
+{
+ struct inode ibuf;
+ if (fstat(2,&ibuf) < 0 &&
+ fstat(1,&ibuf) < 0) return(getruid());
+ if ((ibuf.i_mode & IFMT) != IFCHR) return(getruid());
+ return(ibuf.i_uid&0377);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+
+getmnem(uid)
+{
+ return("mnemonic");
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "libg.h"
+
+getpath(uid)
+{
+ static char path[50];
+ register char *pp, *bp;
+ register int n;
+
+ if (getubuf(uid) <= 0) return(NULSTR);
+ pp = path; bp = u_buf;
+ for(n=0; n<5; n++) while(*bp++ != ':');
+ while((*pp++ = *bp++) != ':');
+ *--pp = '\0';
+ return(p
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+
+getpriv(uid)
+{
+ return(0);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "libg.h"
+
+char *getpswd(uid)
+{
+ static char pswd[9];
+ register char *bp, *np;
+
+ bp = u_buf; np = pswd;
+
+ if (getubuf(uid) <= 0) return(NULSTR);
+ while(*bp++ != ':');
+ --bp;
+ while((*np++ = *bp++) != ':');
+ *--np = '\0';
+ return(pswd);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* break up uid into effective and real */
+/* more compatible with 16-bit uid's */
+/* getuid and setuid are std. bell routines */
+geteuid()
+{
+ return((getuid()>>8)&0377);
+}
+getruid()
+{
+ return(getuid()&0377);
+}
+seteuid(euid)
+{
+ return(setuid(euid<<8|getuid()&0377));
+}
+setruid(ruid)
+{
+ return(setuid(ruid&0377|getuid()&0177600));
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+
+gettype(uid)
+{
+ /* return account type */
+ return(0);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "libg.h"
+
+getubuf(uid)
+{
+ if (uid != last_uid || uid == 0)
+ if (getpw(uid,u_buf)) return(0);
+ last_uid = uid;
+ return(1);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "libg.h"
+
+getunum(name)
+char *name;
+{
+ register char *bp, *np;
+ register c;
+ int inptr[259];
+ int uid;
+
+ if (pich <= 0)
+ pich = open("/etc/passwd",0);
+ if (pich < 0) return(-1);
+ seek(pich,0,0);
+ inptr[0] = pich;
+ inptr[1] = inptr[2] = 0;
+ uid = 0;
+ if (u_buf[0] != 0) goto test; /* first test what is presently in
+ the buffer */
+
+ for(;;) {
+
+ bp = u_buf;
+ while((c=getc(inptr)) != '\n') {
+ if (c <= 0) return(-1);
+ *bp++ = c;
+ }
+ *bp++ = '\0';
+
+ test: bp = u_buf;
+ np = name;
+ while(*bp++ == *np++);
+ --bp; --np;
+ if (*bp++ == ':' &&
+ *np++ == '\0') {
+ while(*bp++ != ':');
+ while(*bp != ':')
+ uid = uid * 10 + *bp++ - '0';
+ last_uid = uid;
+ return(uid);
+ }
+ }
+ return(-1);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "libg.h"
+
+/* this routine returns the file name within "/dev" */
+/* corresponding to the internal tty #, which */
+/* is in turn used by ttynum and getwho */
+/* this routine is obviously very system dependent. */
+
+/* ttyname is set up so that, in conjunction */
+/* with getwho, the following simple "who" program will work: */
+/* for (i = 0; ttnam = ttyname(i); i++) */
+/* if (luid = getwho(i)) printf("%s %s\n",ttnam,getlogn(luid)); */
+
+/* also, ttynum(ttyname(n)) should equal n if 0 <= n <= 31 */
+
+char *ttyname(num)
+{
+ register char *tty;
+ tty = "ttyx";
+ if (num < 0 || num > 31) return(NULSTR);
+ if (num == 0) return("tty8");
+ if (num < 9) {
+ tty[3] = num + ('0' - 1);
+ return(tty);
+ }
+ tty[3] = num - ('a' - 9);
+ return(tty);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../h/stat.h"
+
+ttynum(name)
+char *name;
+{
+ /* this routine returns the internal number */
+ /* of the given tty name (string) */
+ /* if the name="tty" or "", the number is that */
+ /* of the user's tty. */
+ /* this is obviously very system dependent */
+ register int major, minor, flags;
+ struct inode ibuf;
+ struct { char low, high; };
+
+ if (*name == '\0' || equal(name,"tty")) {
+ if (fstat(2,&ibuf) < 0 &&
+ fstat(1,&ibuf) < 0) return(-1);
+ }
+ else
+ if (stat(cat("/dev/",name),&ibuf) < 0 &&
+ stat(cat("/dev/tty",name),&ibuf) < 0) return(-1);
+ flags = ibuf.i_mode;
+ if ((flags & IFMT) != IFCHR) return(-1);
+ minor = ibuf.i_addr[0].low;
+ major = ibuf.i_addr[0].high;
+ if (major == 0)
+ return(minor);
+ else
+ if (major == 1)
+ return(minor+1);
+ else
+ return (-1);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+any(chr,stg)
+char chr, *stg;
+{
+ register char c, *s;
+
+ c = chr;
+ for (s = stg; *s;)
+ if (*s++ == c) return (1);
+ return (0);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#define NSTR 25
+char **brkstring(strg,brksep,brkterm) /* returns pointer to static table of substring ptrs */
+char *strg;
+char *brksep, *brkterm;
+{
+
+ register char c, *bp, *sp;
+ static char *broken[NSTR+1]; /* static array of substring start addresses */
+ int bi;
+
+ sp = strg; /* scan string, replacing separators with zeroes */
+
+ for (bi=0; bi<NSTR; bi++) { /* and entering start addrs in "broken" */
+ while (brkany(c = *sp, brksep)) *sp++ = 0;
+ if (!c || brkany(c, brkterm)) {
+ *sp=0;
+ broken[bi] = 0;
+ return(broken); /* terminator found, finish up */
+ }
+
+ broken[bi] = sp; /* set next start addr */
+
+ while ((c = *++sp) && !brkany(c,brksep) && !brkany(c,brkterm));
+
+ }
+ broken[NSTR] = 0; /* reached limit of NSTR substrings */
+ return (broken);
+}
+
+brkany (chr,strg) /* returns 1 if chr in strg, 0 otherwise */
+char chr,*strg;
+{
+ register char *sp;
+
+ for (sp=strg; *sp; sp++)
+ if (chr == *sp) return (1);
+ return (0);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char cat_buf[80];
+
+
+char *cat(s1,s2)
+char *s1, *s2;
+{
+ register char *r1, *r2, *bp;
+ r1 = s1; r2 = s2;
+ bp = cat_buf;
+ while(*bp++ = *r1++);
+ bp--;
+ while(*bp++ = *r2++);
+ return(cat_buf);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* returns date in format dd-mon-yy@hh:mm:ss\0 */
+cdate(dataddr)
+long *dataddr;
+{
+ register char *cp;
+
+ cp = ctime(dataddr);
+ cp[1] = cp[8];
+ cp[2] = cp[9];
+ cp[3] = '-';
+ cp[7] = '-';
+ cp[8] = cp[22];
+ cp[9] = cp[23];
+ cp[10] = '@';
+ cp[19] = 0;
+ return(cp+1);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+copy(from,to)
+char *from, *to;
+{
+ register char *rfrom, *rto;
+
+ rfrom = from;
+ rto = to;
+ while(*rto++ = *rfrom++);
+ return(rto-1);
+};
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/** Version of date.c in s1 modified to be a subroutine
+* it is called with a string and returns a pointer to ints.
+* ie, ip = date(string);
+* returns 0 if it fails.
+* only error message is bad conversion if string is illegal.
+* The only legal format is ########[ps]
+* where the int field is fixed input and 'p' forces PM by adding 12 hours
+* and 's' would force standard savings time
+*/
+int timbuf[2];
+char *cbp;
+int *cpx;
+int dmsize[];
+date(string)
+char *string;
+{
+ extern int timezone, *localtime();
+
+ cbp = string;
+ if(gtime()) {
+ write(2, "bad conversion\n", 15);
+ return(0);
+ }
+ if (*cbp != 's') {
+ /* convert to Greenwich time, on assumption of Standard time. */
+ dpadd(timbuf, timezone);
+ /* Now fix up to local daylight time. */
+ if ((cpx = localtime(timbuf))[8])
+ dpadd(timbuf, -1*60*60);
+ }
+ return(timbuf);
+}
+
+gtime()
+{
+ register int i;
+ register int y, t;
+ int d, h, m;
+ extern int *localtime();
+ int nt[2];
+
+ t = gpair();
+ if(t<1 || t>12)
+ goto bad;
+ d = gpair();
+ if(d<1 || d>31)
+ goto bad;
+ h = gpair();
+ if(h == 24) {
+ h = 0;
+ d++;
+ }
+ m = gpair();
+ if(m<0 || m>59)
+ goto bad;
+ y = gpair();
+ if (y<0) {
+ time(nt);
+ y = localtime(nt)[5];
+ }
+ if (*cbp == 'p')
+ h =+ 12;
+ if (h<0 || h>23)
+ goto bad;
+ timbuf[0] = 0;
+ timbuf[1] = 0;
+ y =+ 1900;
+ for(i=1970; i<y; i++)
+ gdadd(dysize(i));
+ /* Leap year */
+ if (dysize(y)==366 && t >= 3)
+ gdadd(1);
+ while(--t)
+ gdadd(dmsize[t-1]);
+ gdadd(d-1);
+ gmdadd(24, h);
+ gmdadd(60, m);
+ gmdadd(60, 0);
+ return(0);
+
+bad:
+ return(1);
+}
+
+gdadd(n)
+{
+ register char *t;
+
+ t = timbuf[1]+n;
+ if(t < timbuf[1])
+ timbuf[0]++;
+ timbuf[1] = t;
+}
+
+gmdadd(m, n)
+{
+ register int t1;
+
+ timbuf[0] =* m;
+ t1 = timbuf[1];
+ while(--m)
+ gdadd(t1);
+ gdadd(n);
+}
+
+gpair()
+{
+ register int c, d;
+ register char *cp;
+
+ cp = cbp;
+ if(*cp == 0)
+ return(-1);
+ c = (*cp++ - '0') * 10;
+ if (c<0 || c>100)
+ return(-1);
+ if(*cp == 0)
+ return(-1);
+ if ((d = *cp++ - '0') < 0 || d > 9)
+ return(-1);
+ cbp = cp;
+ return (c+d);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#define ECHO 010
+/* set, clear echo on file handle # 2 */
+
+int tt_mode[3];
+noecho()
+{
+ gtty(2,tt_mode);
+ tt_mode[2] =& ~ECHO;
+ return(stty(2,tt_mode));
+}
+
+doecho()
+{
+ gtty(2,tt_mode);
+ tt_mode[2] =| ECHO;
+ return(stty(2,tt_mo
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+equal(s1,s2)
+char *s1, *s2;
+{
+ register char *r1, *r2;
+ r1 = s1; r2 = s2;
+ while (*r1++ == *r2)
+ if (*r2++ == 0) return (1);
+ return(0);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+error(s)
+char *s;
+{
+ register char *p;
+
+ flush();
+ write(2, "?", 1);
+ for (p = s; *p++; );
+ --p;
+ write(2, s, p-s);
+ write(2, "?\n", 2);
+ exit(-1);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+errtype(file, errmsg)
+char *file, *errmsg;
+{
+ register char *r1, *r2;
+ char errlin[80];
+ register char *r3;
+
+ r3 = errlin;
+ r1 = r3;
+ r2 = file;
+ while (*r1++ = *r2++);
+ r1[-1] = ':';
+ r2 = errmsg;
+ while (*r1++ = *r2++);
+ r1[-1] = '\n';
+ write(2, r3, r1-r3);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#
+#include "../h/errors.h"
+
+char *SRHLIST[] { /* upper case!! */
+ "",
+ "%",
+ "/bin/",
+ "/usr/bin/",
+ 0
+};
+
+char **srhlist SRHLIST;
+
+execvsrh(argv)
+char **argv;
+{
+ return(excvsrh(argv[0], argv));
+}
+
+excvsrh(prog, argv)
+char *prog, **argv;
+{
+ extern errno;
+ register char **r1, *r2, *r3;
+ static char command[50];
+
+ for (r1 = srhlist; r2 = *r1++; ) {
+ r3 = command;
+ if(*r2 == '%') {
+ r2 = getpath(getruid()&0377);
+ while(*r3++ = *r2++);
+ --r3;
+ r2 = "/bin/";
+ }
+ while (*r3++ = *r2++);
+ --r3;
+ r2 = prog;
+ while (*r3++ = *r2++);
+ if (execvsh(command, argv) != 0) break;
+ }
+ errtype(prog, errno==E2BIG?"arg list too long":"not found");
+ return(-1);
+}
+execlsrh(arg1,arg2,arg3)
+char *arg1,*arg2,*arg3;
+{
+ return(excvsrh(arg1, &arg1));
+}
+
+exclsrh(prog, arg1, arg2)
+char *prog, *arg1, *arg2;
+{
+ return(excvsrh(prog, &arg1));
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#
+#include "../h/errors.h"
+#define NSHARGS 25 /* limit on number of args to shell command file */
+execvsh(name,args)
+char *name, **args;
+{
+ extern errno;
+ register char **v1, **v2;
+ char *shvec[NSHARGS];
+
+ v2 = args;
+ for (v1 = v2; *v1; )
+ if (*v1++ == -1) *--v1 = 0;
+ execv(name, v2);
+ /* return 0 if not found, -1 if not executable */
+ if (errno == ENOENT || errno == EACCES)
+ return (0);
+ else if (errno != ENOEXEC)
+ return(-1);
+ v1 = shvec;
+ *v1++ = "sh";
+ *v1++ = name;
+ *v2++ = "/bin/sh";
+ while (*v1++ = *v2++) {
+ if (v1 >= &shvec[NSHARGS]) {
+ errno = E2BIG;
+ return(-1);
+ }
+ }
+ execv(args[0], shvec);
+ return(-1);
+}
+
+execlsh(name,arg0,arg1,arg2)
+char *name, *arg0, *arg1, *arg2;
+{
+ return(execvsh(name,&arg0));
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../h/iobuf.h"
+#define NBUFFED 256 /* limit on fmt buffer */
+
+extern struct iobuf fout;
+int fmtlen;
+
+fmt(fmtstrng, arg1, arg2, arg3)
+char *fmtstrng;
+{
+ int svfildes, svnleft, svnextp;
+
+ flush();
+ svfildes = fout.b_fildes;
+ svnleft = fout.b_nleft;
+ svnextp = fout.b_nextp;
+
+ /* a very illegal file handle */
+ fout.b_fildes = 99;
+ /* use last half of fout buffer */
+ fout.b_nleft = NBUFFED;
+ fout.b_nextp = &fout.b_buff[512-NBUFFED];
+ printf("%r", &fmtstrng); /* and pass the buck ... */
+ fmtlen = fout.b_nextp - &fout.b_buff[512-NBUFFED];
+ putchar(0);
+
+ fout.b_fildes = svfildes;
+ fout.b_nleft = svnleft;
+ fout.b_nextp = svnextp;
+
+ return(&fout.b_buff[512-NBUFFED]);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../h/iobuf.h"
+
+/* this is the counterpart to fopen which leaves
+ * the file opened for both read and write
+ * fseek may then be used to position at the end of the
+ * file (or wherever) before reading/writing
+ */
+fopen2(filename, abufp)
+char *filename;
+struct iobuf *abufp;
+{
+ register struct iobuf *bufp;
+
+ bufp = abufp;
+ bufp->b_nleft = 0;
+ bufp->b_nextp = 0;
+ if ((bufp->b_fildes = open(filename, 2)) < 0) return(-1);
+ return(0);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "/h/stat.h"
+#include "/h/iobuf.h"
+/* used for input using getc/getw */
+/* does equivalent to requested seek */
+/* by doing seek by blocks if necessary, */
+/* and then adjusting nleft/nextp in iobuf */
+/* first arg is iobuf pointer, others are identical to seek or lseek */
+struct { int hiword, loword; };
+struct { char lobyte, hibyte; };
+
+fseek(bp, offs, dir)
+struct iobuf *bp;
+{
+ long loff;
+
+ loff = offs;
+ if (dir%3 == 0) loff.hiword = 0;
+ return(lfseek(bp, loff, dir));
+}
+
+lfseek(abp, aloff, adir)
+struct iobuf *abp;
+long aloff;
+{
+ register byteoff, blockoff;
+ long loff;
+ register struct iobuf *bp;
+ int dir;
+ struct inode statb;
+ long lsize;
+
+ bp = abp;
+ dir = adir;
+ loff = aloff;
+
+ if (dir >= 3) {
+ loff =<< 9;
+ dir =- 3;
+ }
+ switch(dir) {
+ case 1:
+ /* relative seek */
+ if (bp->b_nleft >= 0) {
+ if (bp->b_nextp) {
+ byteoff = bp->b_nextp-bp->b_buff;
+ loff =+ byteoff;
+ bp->b_nleft =+ byteoff;
+ }
+ break;
+ }
+ /* negative nleft means must be at e.o.f */
+ /* drop into rel.-to-end seek */
+ case 2:
+ if (fstat(bp->b_fildes, &statb) < 0)
+ return(-1);
+ lsize.hiword.hibyte = 0;
+ lsize.hiword.lobyte = statb.i_size0;
+ lsize.loword = statb.i_size1;
+ /* adjust loff by size of file */
+ loff =+ lsize;
+ dir = 0; /* now have offset rel.-to-beg. */
+ case 0:
+ /* rel.-to-beginning of file seek */
+ bp->b_nleft = 0;
+ break;
+ default:
+ return(-1);
+ }
+
+ bp->b_nextp = bp->b_buff;
+ blockoff = loff>>9;
+ byteoff = loff;
+ byteoff =& 0777;
+ if (dir != 1 || blockoff != 0) {
+ /* must do the seek */
+ if (seek(bp->b_fildes, blockoff, dir+3) < 0)
+ return(-1);
+ bp->b_nleft = read(bp->b_fildes, &bp->b_buff, 512);
+ }
+ bp->b_nleft =- byteoff;
+ bp->b_nextp =+ byteoff;
+ retur
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char *tim_ptr;
+int dmsize[];
+int timezone;
+int no_add;
+
+char *gd_months[] {
+ "january", "february", "march", "april",
+ "may", "june", "july", "august",
+ "september", "october", "november", "december",
+ 0,
+};
+
+
+long gdate(str)
+{
+ long tim, now, ghours(), secs;
+ int day, month, year, *nowp;
+ register int i;
+ register char *monp;
+
+ time(&now);
+ nowp = localtime(&now);
+ tim_ptr = str;
+ if(*tim_ptr == '+') {
+ tim_ptr++;
+ return(now + ghours());
+ }
+ day = gd_gdec();
+ if(*tim_ptr == '-') {
+ tim_ptr++;
+ if(*tim_ptr >= 'A' && *tim_ptr <= 'z') {
+ monp = gd_head();
+ if((month = swmtch(monp, &gd_months)) < 0) {
+ printf("Month \"%s\" Nonexistant.\n", monp);
+ return(0l);
+ }
+ if(*tim_ptr == '-') {
+ tim_ptr++;
+ year = gd_gdec();
+ } else
+ year = nowp[5];
+ } else {
+ month = nowp[4];
+ year = nowp[5];
+ }
+ if(*tim_ptr == ' ' || *tim_ptr == '@') {
+ tim_ptr++;
+ secs = ghours();
+ } else
+ secs = nowp[0]+ nowp[1]*60l + nowp[2]*3600l;
+ tim = 0l;
+ if(year<1900) year =+ 1900;
+ for(i = 1970; i < year; i++)
+ tim =+ dysize(i);
+ if(dysize(year) == 366 && month >= 3)
+ tim++;
+ while(month--)
+ tim =+ dmsize[month];
+ tim =+ day - 1;
+ tim =* 24l*60l*60l;
+ tim =+ secs;
+ tim =+ timezone;
+ nowp = localtime(&tim);
+ if(nowp[8])
+ tim =- 1*60l*60l;
+ return(tim);
+ }
+ tim_ptr = str;
+ secs = ghours();
+ secs =- nowp[0] + nowp[1]*60l + nowp[2]*3600l;
+ if(secs < 0 && no_add == 0)
+ secs =+ 24 * 60l * 60l;
+ return(now + secs);
+}
+
+
+long ghours()
+{
+ register char *cp;
+ register int h, m;
+ int s;
+
+ cp = tim_ptr;
+ s = m = 0;
+ h = gd_gdec();
+ if(tim_ptr - cp == 4 && *tim_ptr != ':') {
+ m = h % 100;
+ h = h / 100;
+ } else {
+ if(*tim_ptr == ':') {
+ tim_ptr++;
+ m = gd_gdec();
+ if(*tim_ptr == ':') {
+ tim_ptr++;
+ s = gd_gdec();
+ }
+ }
+ }
+ if(*tim_ptr == 'p') {
+ tim_ptr++;
+ h =+ 12;
+ }
+ return(h*3600l + m*60l + s);
+}
+
+
+gd_gdec()
+{
+ register int c, i;
+
+ i = 0;
+ c = *tim_ptr;
+ while(c >= '0' && c <= '9') {
+ i = i*10 + c - '0';
+ c = *++tim_ptr;
+ }
+ return(i);
+}
+
+
+gd_head()
+{
+ static char buf[20];
+ register char *c2, c;
+
+ c2 = buf;
+ while(((c = *tim_ptr) >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z')) {
+ if(c <= 'Z')
+ c =+ 'a' - 'A';
+ if(c2 < &buf[18])
+ *c2++ = c;
+ tim_ptr++;
+ }
+ *c2 = 0;
+ return(buf);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char copy_space[128];
+int copy_size; /* if this is non-zero, assume represents */
+ /* actual size of copy_space */
+char *copy_ptr;
+char *
+getcopy(str)
+char *str;
+{
+ static char *cpend;
+ register char *r1, *r2;
+
+ if (cpend == 0) {
+ /* first time through */
+ cpend = copy_space+ (copy_size? copy_size: sizeof copy_space);
+ copy_ptr = copy_space;
+ }
+ r2 = str;
+ for (r1 = copy_ptr; r1 < cpend; ) {
+ if ((*r1++ = *r2++) == 0) {
+ r2 = copy_ptr;
+ copy_ptr = r1;
+ return(r2);
+ }
+ }
+ write(2, "getcopy out of space\n", 21);
+ exit(-1);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../h/iobuf.h"
+/* return one line using getc, caller must supply iobuf pointer, */
+/* line buffer, and max. count */
+/* returns actual char count */
+
+getl(bufp,line,cnt)
+struct iobuf *bufp;
+char line[];
+int cnt;
+{
+ register char *lp;
+ register c, cc;
+
+ lp = line;
+ cc = cnt;
+ while ((c = getc(bufp)) >= 0) {
+ *lp++ = c;
+ if (--cc <= 0 || c == '\n') break;
+ }
+ return(cnt-cc);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* return one line using getchar, caller must supply line buf and max. cnt */
+/* return actual char cnt */
+
+getline(line,cnt)
+char line[];
+int cnt;
+{
+ register char *lp;
+ register c, cc;
+
+ lp = line;
+ cc = cnt;
+ while ((c = getchar()) > 0) {
+ *lp++ = c;
+ if (--cc <= 0 || c == '\n') break;
+ }
+ return(cnt-cc);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#
+/* glob match subroutine --
+
+ "*" in params matches r.e ".*"
+ "?" in params matches r.e. "."
+ "[...]" in params matches character class
+ "[...a-z...]" in params matches a through z.
+*/
+
+glbmtch(as, ap)
+char *as, *ap;
+{
+ register char *s, *p;
+ register scc;
+ int c, cc, ok, lc;
+
+ s = as;
+ p = ap;
+ if ((scc = *s++) && (scc =& 0177) == 0) scc = 0200;
+ switch (c = *p++) {
+ case '[':
+ ok = 0;
+ lc = 077777;
+ while (cc = *p++) {
+ if (cc==']') {
+ if (ok) return(glbmtch(s, p));
+ else return(0);
+ } else if (cc=='-') {
+ if (lc<=scc && scc<=(c = *p++)) ok++;
+ } else if (scc == (lc=cc)) ok++;
+ }
+ return(0);
+ default:
+ if (c!=scc) return(0);
+ case '?':
+ if (scc) return(glbmtch(s, p));
+ return(0);
+ case '*':
+ return(umatch(--s, p));
+ case '\0':
+ return(!scc);
+ }
+}
+
+umatch(s, p)
+char *s, *p;
+{
+ if(*p==0) return(1);
+ while(*s) if (glbmtch(s++,p)) return(1);
+ return(0);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../h/stat.h"
+#include "../h/dirent.h"
+
+struct dirinfo {
+ struct dirent dir;
+ char null;
+ int dotino;
+ int dotdotino;
+};
+
+char *rootlist[] {
+ "/",
+ "/rnd/",
+ "/mnt/",
+ "/sys/",
+ "/bak/",
+ "/fsd/",
+ 0
+};
+gwd()
+{
+ return(fullpath(0));
+}
+
+fullpath(str)
+char *str;
+{
+ static char wdbuf[128];
+ struct dirinfo d;
+ register char *wp, *cp, **cpp;
+ int fino;
+ char *savewp, *markwp;
+ int dotdev;
+ struct inode statb;
+
+ wp = &wdbuf + 1;
+ *--wp = 0;
+ markwp = 0;
+ if (str) {
+ wp = prepend(str, wp);
+ if (*wp == '/') return(wp);
+ *--wp = 0;
+ markwp = wp;
+ }
+ fino = 0;
+
+ for (;;) {
+ wp = scandir(&d, fino, wp);
+ if (d.dotino != d.dotdotino) {
+ fino = d.dotino;
+ chdir("..");
+ continue;
+ }
+ savewp = wp;
+ if (d.dotino != ROOTINO) break; /* error */
+ stat(".", &statb);
+ dotdev = statb.i_dev;
+ for (cpp = rootlist; cp = *cpp++; ) {
+ if (stat(cp, &statb) < 0) continue;
+ if (statb.i_dev == dotdev) {
+ wp = prepend(cp, wp);
+ break;
+ }
+ }
+ break;
+ }
+ chdir(savewp);
+ if (markwp) *markwp = '/';
+ return(wp);
+}
+
+scandir(dp, fileino, endwhere)
+struct dirinfo *dp;
+char *endwhere;
+{
+ register struct dirinfo *d;
+ register char *cp, *wp;
+ int fh;
+
+ d = dp;
+ d->dotino = 0;
+ d->dotdotino = 0;
+ if (fileino == 0) wp = endwhere;
+ else wp = 0;
+ fh = open(".", 0);
+ if (fh < 0) return(wp);
+ while ((!d->dotino || !d->dotdotino || !wp) &&
+ read(fh, &d->dir, sizeof d->dir) == sizeof d->dir) {
+ if (d->dir.d_ino == NULLINO) continue;
+ if (!d->dotino && equal(d->dir.d_name, "."))
+ d->dotino = d->dir.d_ino;
+ else if (!d->dotdotino && equal(d->dir.d_name, ".."))
+ d->dotdotino = d->dir.d_ino;
+ else if (!wp && d->dir.d_ino == fileino) {
+ /* ensure name is null term'd */
+ d->null = 0;
+ wp = endwhere;
+ /* separate with '/' */
+ if (*wp) *--wp = '/';
+ wp = prepend(d->dir.d_name, wp);
+ }
+ }
+ close(fh);
+ return(wp);
+}
+
+prepend(prefix, endwhere)
+char *prefix, *endwhere;
+{
+ register char *cp, *wp;
+
+ for (cp = prefix; *cp++; );
+ --cp;
+ for (wp = endwhere; cp > prefix; *--wp = *--cp);
+ return(wp);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#
+/* inputf is roughly complementary to printf,
+except input comes from getchar (may be
+user supplied, must return 0 at eof). in addition
+all args must be pointers (addresses). the first arg
+is the format string. '%' is used as the escape char as in
+printf. the general format is %w.dc where w and d are decimal
+character counts, and c is one of (d, o, i, f, e, s, c, x).
+the args are all assumed to be pointers to the appropriate
+typed args -- note all floating point is assumed to be float
+unless the %e format is used (extended float). if w is omitted
+the field ends with the first field delimeter (typically, space, comma,
+and newline -- these can be specified by following the specification
+by a list of chars before the next '%'). d represents the default
+number of decimal places for 'f' and 'e' if no explicit
+decimal point. for 's' w is the width of the field, and d is
+the maximum number of chars after stripping off delimeters
+on either end. s and c are approximately identical, except
+that s returns a pointer into a static buffer, and c returns char
+by char into the program itself, which means a 'd' specification
+for c is essential, and in fact 1 is assumed as a default (as opposed
+to infinity for s). if a w field is specified, the input data
+is assumed to be in a fixed format, with exactly w columns
+devoted to the designated field. this means that data in this format
+does not have to be separated by blanks, etc. chars in the format
+string before the first '%' are output before any requests
+to the subroutine for chars. e.g.:
+ inputf("-> %i%e%s\n",&integ, &dbl, &charptr);
+would read an integer into integ, a double into dbl, and a string
+terminated only by a <nl> into a static buffer, returning its start
+addr in charptr, after prompting with "-> ". */
+#define DFTSEP ",; \t\n\r" /* default field separators */
+#define NEXTCHR getchar() /* character input routine */
+#define SCBLEN 100 /* max. no. of chars in static char buff */
+struct { float *fltp; };
+struct { double *dblp; };
+inputf(format,arg1,arg2,arg3)
+char *format;
+{
+ register char *fp, *cp, cc;
+ int **ap;
+ int fld, val, wv, dv, radix;
+ char formc, negflg, negexp, *fsp, *scp;
+ static char scbuf[SCBLEN], fldsep[10];
+ double dval;
+
+ ap = &arg1;
+ fp = format;
+ scp = scbuf; /* init static string pointer */
+
+ while ((cc = *fp++) && cc != '%') putchar(cc);
+ flush();
+
+ fld = 0; /* used as return value when error found */
+ while (cc) {
+ fld--;
+ wv = 0; dv = 0; /* init w.d fields */
+ while (numeric(cc = *fp++)) wv = wv*10 + cc - '0';
+ if (cc == '.')
+ while (numeric(cc = *fp++)) dv = dv*10 + cc - '0';
+ if (!wv) wv--; if (!dv) dv--; /* zero --> minus one */
+ formc = cc; /* save format character */
+ fsp = cp = fldsep; /* collect terminators */
+ while (*cp++ = *fp)
+ if (*fp++ == '%') {
+ fp--;
+ *--cp = 0;
+ break;
+ }
+ if (!*fsp) fsp = DFTSEP;
+ switch (formc) {
+ case 'o':
+ radix = 8;
+ goto ido;
+ case 'd':
+ case 'i':
+ radix = 10;
+ ido:
+ val = 0;
+ negflg = 0;
+ while ((cc = NEXTCHR) && (cc == ' ' || cc == '-') && --wv)
+ if (cc == '-') negflg++;
+ if (!cc) return (fld); /* return error if eof found */
+ if (formc == 'i' && cc == '0') radix = 8;
+ if (wv) do {
+ if (numeric (cc)) {
+ val = val*radix + cc - '0';
+ } else if (any(cc,fsp))
+ break;
+ } while (--wv && (cc = NEXTCHR));
+ if (negflg) val = -val;
+ **ap++ = val;
+ break;
+ case 'c':
+ if (dv < 0)
+ if (wv < 0) dv = 1;
+ else dv = wv;
+ cp = *ap++;
+ goto casecs;
+ case 's':
+ cp = scp;
+ val = scbuf + SCBLEN - 1 - cp; /* calc max. limit on input */
+ if (dv<0 || dv>val)
+ if ((dv = val) <= 0) return (fld);
+ casecs:
+ while ((cc = NEXTCHR) && cc == ' ' && --wv);
+ if (!cc) return (fld); /* return error if eof found */
+ if (wv) do {
+ if (any(cc,fsp)) break;
+ if (!dv--) return (fld); /* too big */
+ *cp++ = cc;
+ } while (--wv && (cc = NEXTCHR));
+ if (dv || formc == 's') *cp++ = 0;
+ if (formc == 'c') break;
+ **ap++ = scp;
+ scp = cp;
+ break;
+ case 'x':
+ while ((cc = NEXTCHR) && cc == ' ' && --wv);
+ if (wv)
+ while (!any(cc,fsp) && --wv && (cc = NEXTCHR));
+ break;
+ case 'f':
+ case 'e':
+ dval = 0.;
+ negflg = 0;
+ val = 0; /* used for explicit exponent */
+ radix = 0100000; /* used for decimal place count */
+ while ((cc = NEXTCHR) && (cc == ' ' || cc == '-') && --wv)
+ if (cc == '-') negflg++;
+ if (!cc) return (fld); /* return error if eof found */
+ if (wv) do {
+ if (numeric(cc)) {
+ dval = dval*10. + (cc-'0');
+ radix++;
+ } else if (cc == '.') {
+ radix = 0;
+ dv = -1;
+ } else if (any(cc,fsp)) break;
+ else if (cc == 'e') {
+ negexp = 0;
+ while ((cc = NEXTCHR) && !numeric(cc) && --wv)
+ if (cc == '-') negexp++;
+ if (!cc) return (fld); /* return error if eof found */
+ if (wv) do {
+ if (numeric(cc))
+ val = val*10 + cc-'0';
+ else if (any(cc,fsp)) break;
+ } while (--wv && (cc = NEXTCHR));
+ if (negexp) val = -val;
+ break;
+ }
+ } while (--wv && (cc = NEXTCHR));
+ if (dv > 0) radix = dv;
+ if (radix > 0) val =- radix;
+ if (val >= 0)
+ while (--val >= 0) dval = dval*10.;
+ else
+ while (++val <= 0) dval = dval/10.;
+ if (negflg) dval = -dval;
+ if (formc == 'f')
+ *ap->fltp = dval;
+ else
+ *ap->dblp = dval;
+ ap++;
+ break;
+ default:
+ write(2,"bad format specification",20);
+ exit(fld);
+ }
+ cc = *fp++;
+ }
+ return (0);
+}
+numeric(chr)
+{
+ return (chr >= '0' && chr <=
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* return length of a string, not counting the null terminator */
+length(str)
+char *str;
+{
+ register char *cp;
+
+ for (cp = str; *cp++; );
+ return(cp-str-1);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+makename(prefix,suffix)
+char *prefix, *suffix;
+{
+ static char tmpname[15];
+ register char *cp1, *cp2;
+ register int pid;
+
+ pid = getpid();
+ cp1 = tmpname;
+ for (cp2 = prefix; *cp1++ = *cp2++; );
+ cp1--;
+ do *cp1++ = pid%10 + '0'; while (pid =/ 10);
+ for (cp2 = suffix; *cp1++ = *cp2++; );
+ if (cp1 > &tmpname + 1) error("strs too long to makename");
+ return (tmpname);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+prndec(ch, d)
+{
+ char buf[8];
+ register char *cp;
+ register int i, j;
+
+ i = d;
+ cp = &buf[8];
+ *--cp = 0;
+ j = 0;
+ if(i < 0) {
+ i =- i;
+ j =+ 10;
+ }
+ do {
+ *--cp = (i % 10) + '0';
+ i =/ 10;
+ j++;
+ } while(i);
+ if(j > 10) {
+ j =- 9;
+ *--cp = '-';
+ }
+ write(ch, cp, j);
+ return(j);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../h/errors.h"
+
+subshell(str)
+char *str;
+{
+ register s2, s3;
+ char *a2, *a3;
+ register pid;
+ char st[2];
+ /* if str is non null, exec it as a command to the shell */
+ /* and return immediately */
+ /* if str is the null string, simply spawn a sub-shell */
+
+ if (str == 0 || *str == 0) {
+ a2 = 0;
+ a3 = 0;
+ } else {
+ a2 = "-c";
+ a3 = str;
+ }
+ pid = fork();
+ if (pid == 0) {
+ execl("/bin/sh", "-", a2, a3, 0);
+ error("no shell!");
+ }
+ if (pid == -1) {
+ type(2, errno == EAGAIN? "system": "your");
+ type(2, " process limit reached\n");
+ return(-1);
+ }
+ s2 = signal(2,1);
+ s3 = signal(3,1);
+ while(pid != wait(&st));
+ signal(2,s2);
+ signal(3,s3);
+ return(st[1]);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* switch match, or any unambiguous abbreviation */
+/* exact match always wins, even if shares same root */
+/* returns subscript in zero-terminated tbl[] of strings */
+/* returns -1 if no match, -2 if ambiguous */
+
+swmtch(string,tbl)
+char *tbl[],*string;
+{
+ register char *sp, *tcp, c;
+ char **tp;
+ int firstone;
+
+ firstone = -1;
+
+ for (tp=tbl; tcp = *tp; tp++) {
+ for (sp = string; *sp == *tcp++; ) {
+ if (*sp++ == 0) return(tp-tbl); /* exact match */
+ }
+ if (*sp != 0) {
+ if (*sp != ' ') continue; /* no match */
+ if (*--tcp == 0) return(tp-tbl); /* exact match */
+ }
+ if (firstone == -1) firstone = tp-tbl; /* possible match */
+ else firstone = -2; /* ambiguous */
+ }
+
+ return (firstone);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+
+extern errno;
+
+main()
+{
+ execl("foo", "foo", 0);
+ printf("errno=%d\n", errno);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+type(ch, s)
+char *s;
+{
+ register char *p;
+
+ for (p = s; *p++; );
+ --p;
+ write(ch, s, p-s);
+ return(p-s);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#define MSGRETTIME (5*24*60*60) /* How long to keep trying */
+#define MAILQDIR "/usr/spool/netmail/"
+#define MAILDROP "/usr/spool/mail/"
+#define TMAILQDIR "/usr/spool/mailt/"
+#define MAILLOCKDIR "/usr/spool/locks/"
+#define MAILALIASES "/etc/MailAliases"
+
+/* Exit codes from net mailer */
+#define NM_OK 0 /* Delivered */
+#define NM_BAD 1 /* Not delivered to some addresses (perm failure) */
+#define NM_MORE 2 /* Some addresses not yet processed (temp failure) */
+#define NM_BADMORE 3 /* Both of above */
--- /dev/null
+if -r resp rm resp
+load -s resp replsubs annotate subs.a strings.a -O /rnd/borden/libg.a /rnd/borden/libh.a /rnd/borden/libg.a
+if -r resp.out mv resp.out resp
+: fini
+
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "mh.h"
+#include "/rnd/borden/h/iobuf.h"
+#include "/rnd/borden/h/signals.h"
+#define NOUSE 0
+
+/* #define TEST 1 */
+
+char draft[],
+ sysed[],
+
+char *anyl[] {
+ "no", 0,
+ "yes", 0,
+ "list", 0,
+ 0
+};
+char *aleqs[] {
+ "list", 0, /* 0 */
+ "edit [<editor>]", 0, /* 1 */
+ "quit [delete]", 0, /* 2 */
+ "send [verbose]", 0, /* 3 */
+ 0
+};
+
+int *vec[MAXARGS], fout, anot;
+int ccme 1;
+char *maildir;
+struct msgs *mp;
+char *ed;
+int inplace; /* preserve links in anno */
+
+struct swit switches[] {
+ "annotate", 0, /* 0 */
+ "noannotate", 0, /* 1 */
+ "ccme", -1, /* 2 */
+ "noccme", -1, /* 3 */
+ "editor editor", 0, /* 4 */
+ "inplace", 0, /* 5 */
+ "noinplace", 0, /* 6 */
+ "help", 4, /* 7 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *nfolder, *msg;
+ register char *cp, *ap;
+ register int cur;
+ char *arguments[50], **argp;
+
+ fout = dup(1);
+#ifdef NEWS
+ m_news();
+#endif
+ msg = anot = folder = 0;
+
+ ap = cp = argv[0];
+ while(*cp)
+ if(*cp++ == '/')
+ ap = cp;
+ if((cp = m_find(ap)) != -1) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("resp: -%s unknown\n", cp);
+ goto leave;
+ case 0: anot = 1; continue; /* -annotate */
+ case 1: anot = 0; continue; /* -noannotate */
+ case 2: ccme = 1; continue; /* -ccme */
+ case 3: ccme = 0; continue; /* -noccme */
+ case 4: if(!(ed = *argp++)) { /* -editor */
+ printf("resp: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 5: inplace = 1; continue; /* -inplace */
+ case 6: inplace = 0; continue; /* -noinplace */
+ /* -help */
+ case 7: help("resp [+folder] [msg] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ printf("Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else if(msg) {
+ printf("Only one message per response.\n");
+ goto leave;
+ } else
+ msg = cp;
+ }
+ if(!msg)
+ msg = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = getcpy(m_maildir(folder));
+ if(chdir(maildir) < 0) {
+ printf("Can't chdir to: "); flush();
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ printf("Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ printf("No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!m_convert(msg))
+ goto leave;
+ if(mp->numsel == 0) {
+ printf("resp: shark's fin soup\n"); /* never get here */
+ goto leave;
+ }
+ if(mp->numsel > 1) {
+ printf("Only one message at a time.\n");
+ goto leave;
+ }
+ m_replace(pfolder, folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ repl(getcpy(m_name(mp->lowsel)));
+ leave:
+ m_update();
+ flush();
+}
+
+
+repl(msg)
+{
+ register char *cp;
+ register int i,j;
+ struct iobuf in;
+ char name[NAMESZ], field[512], *replto, *from, *cc, *sub, *date, *to;
+ char *drft, *msgid;
+ int state, out, status, intr;
+ int pid, wpid;
+ char **argp, *address;
+
+ if(fopen(msg, &in) < 0) {
+ printf("Can't open \"%s\"\n", msg);
+ return;
+ }
+ drft = m_maildir(draft);
+ if((out = open(drft, 0)) >= 0) {
+ cp = concat("\"", drft, "\" exists; delete? ", 0);
+ while((i = gans(cp, anyl)) == 2)
+ showfile(drft);
+ if(!i)
+ return;
+ free(cp);
+ close(out);
+ }
+ if((out = creat(drft, m_gmprot())) < 0) {
+ printf("Can't create \"%s\".\n", drft);
+ return;
+ }
+
+ state = FLD;
+ replto = msgid = to = from = cc = sub = date = 0;
+
+ for(;;) {
+
+ switch(state = m_getfld(state, name, field, sizeof field, &in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(uleq(name, "from"))
+ from = niceadd(field, from);
+ if(uleq(name, "cc"))
+ cc = niceadd(field, cc);
+ if(uleq(name, "subject"))
+ sub = niceadd(field, sub);
+ if(uleq(name, "date"))
+ date = niceadd(field, date);
+ if(uleq(name, "to"))
+ to = niceadd(field, to);
+ if(uleq(name, "message-id"))
+ msgid = niceadd(field, msgid);
+ if(uleq(name, "reply-to"))
+ replto = niceadd(field, replto);
+ /* if(uleq(name, "sender"))
+ sender = niceadd(field, sender); */
+ if(state == FLDEOF)
+ goto done;
+ break;
+
+ case BODY:
+ case BODYEOF:
+ case FILEEOF:
+ goto done;
+
+ default:
+ printf("getfld returned %d\n", state);
+ return;
+ }
+
+ }
+
+done:
+
+ /* if(!(address = addr(sender)))
+ if(!(address = addr(from)))
+ address = addr(replto);
+ */
+ address = (replto ? addr(replto) : addr(from));
+ if(!ccme)
+ to = 0;
+ if(!(from || replto || to)) {
+ printf("No one to respond to!!!\n");
+ return;
+ }
+ close(in.b_fildes);
+ if(replto)
+ rtrim(replto);
+ if(from)
+ rtrim(from);
+ type(out, "To: "); /* To: */
+ if(cp = (replto ? replto : from))
+ type(out, cp);
+ if(to) {
+ if(cp)
+ type(out, ",\n ");
+ if(address)
+ to = fix(to, address);
+ type(out, to);
+ }
+ if(cc) { /* cc */
+ type(out, "cc: ");
+ if(address)
+ cc = fix(cc, address);
+ type(out, cc);
+ }
+ if(sub) { /* Subject: Re: */
+ type(out, "Subject: ");
+ if(*sub == ' ') sub++;
+ if((sub[0] != 'R' && sub[0] != 'r') ||
+ (sub[1] != 'E' && sub[1] != 'e') ||
+ sub[2] != ':')
+ type(out, "Re: ");
+ type(out, sub);
+ } /* In-response-to: */
+ type(out, "In-response-to: Message from ");
+ type(out, from);
+ if(date) {
+ date[length(date)-1] = '.';
+ if(*date == ' ') date++;
+ type(out, ", ");
+ type(out, date);
+ }
+ type(out, "\n");
+ if(msgid) {
+ type(out, " ");
+ if(*msgid == ' ') msgid++;
+ type(out, msgid);
+ }
+ type(out, "\t\t");
+ type(out, maildir);
+ type(out, "/");
+ type(out, msg);
+ type(out, "\n----------\n");
+ close(out);
+
+ if(m_edit(&ed, drft, NOUSE, msg) < 0)
+ return;
+#ifdef TEST
+ printf("!! Test Version of SEND Being Run !!\n");
+ printf(" Send verbose !\n\n");
+#endif
+
+ for(;;) {
+ if(!(argp = getans("\nWhat now? ", aleqs))) {
+ unlink("@");
+ return;
+ }
+ switch(smatch(*argp, aleqs)) {
+ case 0: showfile(drft); /* list */
+ break;
+ case 1: if(*++argp) /* edit */
+ ed = *argp;
+ if(m_edit(&ed, drft, NOUSE, msg) == -1)
+ return;
+ break;
+ case 2: if(*++argp && *argp[0] == 'd') /* quit */
+ if(unlink(drft) == -1) {
+ printf("Can't unlink %s ", drft);
+ perror("");
+ }
+ return;
+ case 3: if(*++argp) cp = *argp; else cp = ""; /* send */
+
+ if(!mp->msgflags&READONLY) { /* annotate first */
+ if(anot > 0) {
+ while((pid = fork()) == -1) sleep(5);
+ if(pid) {
+ while(wpid=wait()!= -1 && wpid!= pid);
+ if(stat(drft, field) == -1)
+ annotate(msg, "Responded", "");
+ return;
+ }
+ }
+ }
+ if(!m_send(cp, drft))
+ return;
+ default:printf("resp: illegal option\n"); /*##*/
+ break;
+ }
--- /dev/null
+if -r sndmsg.out rm sndmsg.out
+load sndmsg subs.a strings.a -O /rnd/borden/libg.a /rnd/borden/libh.a
+if ! -r sndmsg.out /rnd/borden/bin/skip {
+: strip sndmsg.out
+if $1x = x /rnd/borden/bin/skip {
+cp sndmsg.out /etc/ms.2.78/xsnd
+rm sndmsg.out
+: }
+: fini
+
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "mh.h";
+#include "/rnd/borden/h/iobuf.h"
+#include "/rnd/borden/h/stat.h"
+
+/*#define DEBUG 1 /* Comment out normally */
+
+/* Include a -msgid switch to .mh_profile to cause a
+ * Message-Id component to be added to outgoing mail.
+ */
+
+char *anoyes[]; /* Std no/yes gans array */
+struct swit switches[] {
+ "debug", -1, /* 0 */
+ "format", 0, /* 1 */
+ "noformat", 0, /* 2 */
+ "msgid", 0, /* 3 */
+ "nomsgid", 0, /* 4 */
+ "verbose", 0, /* 5 */
+ "noverbose", 0, /* 6 */
+ "help", 4, /* 7 */
+ 0, 0
+};
+struct iobuf in, pin, pout, fout, fccout;
+int format 1; /* re-formatting is the default */
+
+char *logn, *parptr, *nmsg, fccfile[256];
+
+main(argc, argv)
+char *argv[];
+{
+ int debug;
+ register char *cp, *msg;
+ register int state;
+ char *to, *cc, *bcc, *dist_to, *dist_cc, *dist_bcc;
+ char *tolist, *cclist, *adrlist, *sender, *fcc, *dist_fcc;
+ char name[NAMESZ], field[512];
+ int specfld, dist, fcconly;
+ int from, loc, net, verbose, msgid;
+ int toseen, ccseen;
+ char *ap;
+ char *arguments[50], **argp;
+
+ fout.b_fildes = dup(1);
+ msgid = from = loc = net = to = cc = bcc = dist = fcc = dist_fcc =
+ dist_to = dist_cc = dist_bcc = fcconly = debug =
+ toseen = ccseen = 0;
+ state = FLD;
+ msg = 0;
+ copyip(argv+1, arguments);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:printf("sndmsg: -%s unknown\n", cp);
+ goto leave;
+ case 0: verbose++; debug++; continue; /* -debug */
+ case 1: format = 1; continue; /* -format */
+ case 2: format = 0; continue; /* -noformat */
+ case 3: msgid = 1; continue; /* -msgid */
+ case 4: msgid = 0; continue; /* -nomsgid */
+ case 5: loc = 1; net = 1; continue; /* -verbose */
+ case 6: loc = 0; net = 0; continue; /* -noverbose */
+ case 7: help("sndmsg [file] [switches]",
+ switches);
+ goto leave;
+ }
+ if(msg) {
+ printf("Only one message at a time!\n");
+ goto leave;
+ } else
+ msg = cp;
+ }
+ if(!msg) {
+ printf("No Message specified.\n");
+ goto leave;
+ }
+ if(fopen(msg, &in) < 0) {
+ printf("Can't open \"%s\" for reading.\n", msg);
+ goto leave;
+ }
+
+ state = FLD;
+
+ for(;;)
+ switch(state = m_getfld(state, name, field, sizeof field, &in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(!dist && uleq(name, "to"))
+ to = add(field, to);
+ else if(!dist && uleq(name, "cc"))
+ cc = add(field, cc);
+ else if(!dist && uleq(name, "bcc"))
+ bcc = add(field, bcc);
+ else if(!dist && uleq(name, "fcc"))
+ fcc = add(field, fcc);
+ else if(uleq(name, "distribute-to"))
+ { dist++; /* use presence of field as flag */
+ dist_to = add(field, dist_to);
+ }
+ else if(uleq(name, "distribute-cc"))
+ dist_cc = add(field, dist_cc);
+ else if(uleq(name, "distribute-bcc"))
+ dist_bcc = add(field, dist_bcc);
+ else if(uleq(name, "distribute-fcc"))
+ dist_fcc = add(field, dist_fcc);
+ else if(uleq(name, "from"))
+ from++;
+
+ if(state == FLDEOF)
+ goto done;
+ continue;
+
+ case BODY:
+ case BODYEOF:
+ goto done;
+
+ default:
+ printf("getfld returned %d\n", state);
+ goto leave;
+ }
+
+done:
+ if (dist)
+ { to = dist_to;
+ cc = dist_cc;
+ bcc = dist_bcc;
+ fcc = dist_fcc;
+ }
+ if (!(to || cc))
+ if(!fcc) {
+ printf("Message %s has no addresses!!\n", msg);
+ goto leave;
+ } else
+ fcconly++;
+ pin.b_fildes = dup(2);
+ pout.b_fildes = 3;
+
+ if(to)
+ if(parse(to, 'c'))
+ goto leave;
+ if(cc)
+ if(parse(cc, 'c'))
+ goto leave;
+ if(bcc)
+ if(parse(bcc, 'c'))
+ goto leave;
+
+ compress();
+ adrlist = parptr; parptr = 0;
+ if(verbose) {
+ printf("Address List:\n%s", adrlist);
+ flush();
+ }
+
+ if(to)
+ if(parse(to, 'r', dist ? "Distribute-To: " : "To: "))
+ goto leave;
+ tolist = parptr; parptr = 0;
+ if(cc)
+ if(parse(cc, 'r', dist ? "Distribute-cc: " : "cc: "))
+ goto leave;
+ cclist = parptr; parptr = 0;
+
+ if(verbose) {
+ if (tolist) printf(tolist);
+ if (cclist) printf(cclist);
+ flush();
+ }
+ if(fcc) {
+ if(*fcc == ' ')
+ fcc++;
+ for(cp = fcc; *cp && *cp != '\n'; cp++) ;
+ *cp = 0;
+ if(debug)
+ printf("fcc: \"%s\"\n", fcc); flush();
+ if((fccout.b_fildes = filemsg(fcc)) == -1)
+ goto leave;
+ }
+ copy("\n", copy((logn = getlogn(getruid())), field));
+ if(parse(field, 'r', dist ? "Distributed-By: " :
+ (from ? "Sender: ":"From: ")))
+ goto leave;
+ sender = parptr; parptr = 0;
+ seek(in.b_fildes, 0, 0);
+ if(debug)
+ pout.b_fildes = 1; /* Send msg to std output for debugging */
+ else if(fcconly)
+ pout.b_fildes = 0; /* Flush send output if only an fcc */
+ cputc('s', &pout);
+ if(loc)
+ cputc('l', &pout);
+ if(net)
+ cputc('n', &pout);
+ cputc('\n', &pout);
+ puts(logn, &pout);
+ cputc('\n', &pout);
+ puts(adrlist, &pout);
+ puts("!\n", &pout);
+ puts2(sender, &pout);
+ puts2(dist ? "Distribution-Date: " : "Date: ", &pout);
+ puts2(gd(), &pout);
+ if(msgid) {
+ puts2(dist ? "Distribution-ID: " : "Message-ID: ", &pout);
+ puts2(gmid(), &pout);
+ }
+ seek(in.b_fildes, 0, 0);
+ in.b_nleft = in.b_nextp = 0;
+
+ state = FLD;
+
+ for(;;)
+ switch(state = m_getfld(state, name, field, sizeof field, &in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ specfld = 0;
+ if(format && uleq(name,dist ? "distribute-to":"to")) {
+ if(!toseen) {
+ toseen++;
+ specfld++;
+ if (tolist)
+ puts2(tolist,&pout);
+ }
+ } else if (format && uleq(name,dist ?"distribute-cc":"cc")) {
+ if(!ccseen) {
+ ccseen++;
+ specfld++;
+ if (cclist)
+ puts2(cclist,&pout);
+ }
+ } else if (uleq(name,dist ? "distribute-bcc" : "bcc") ||
+ uleq(name,dist ? "distributed-by" : "sender") ||
+ uleq(name,dist ? "distribution-date" : "date") ||
+ uleq(name,dist ? "distribution-id" : "message-id") ||
+ uleq(name,dist ? "distribution-fcc" : "fcc")) {
+ specfld++; /* Ignore these if present */
+ } else {
+ puts2(name, &pout);
+ puts2(":", &pout);
+ puts2(field, &pout);
+ }
+ while(state == FLDPLUS) { /* read rest of field */
+ state=m_getfld(state, name, field, sizeof field, &in);
+ if (specfld) continue;
+ /* puts2(name, &pout);
+ puts2(":", &pout); */
+ puts2(field, &pout);
+ }
+ if(state == FLDEOF)
+ goto endit;
+ continue;
+ case BODY:
+ case BODYEOF:
+ if(field[0]) {
+ puts2("\n", &pout);
+ puts2(field, &pout);
+ }
+
+ while(state == BODY) {
+ state=m_getfld(state, name, field, sizeof field, &in);
+ puts2(field, &pout);
+ }
+ if(state == BODYEOF)
+ goto endit;
+ default:
+ printf("Error from getfld=%d\n", state);
+ goto leave;
+ }
+endit:
+ if(pout.b_fildes)
+ fflush(&pout);
+ if(fccout.b_fildes) {
+ fflush(&fccout);
+ close(fccout.b_fildes);
+ }
+ if(!debug && !fcconly) {
+ write(3, "", 1);
+ if((state = read(2, &field, sizeof field)) != 1 || field[0]) {
+ printf("Error from adrparse.\n");
+ goto leave;
+ }
+ }
+ if(fccout.b_fildes)
+ printf("Filed: %s:%s\n", fcc, nmsg);
+ if(!debug) {
+ if(!fcconly) {
+ printf("Message %s sent.\n", msg);
+ flush();
+ }
+ cp = copy(msg, field);
+ /* for(cp = field; *cp++; ) ; */
+ cp[1] = 0;
+ do
+ *cp = cp[-1];
+ while(--cp >= field && *cp != '/');
+ *++cp = ','; /* New backup convention */
+ unlink(field);
+ if(link(msg, field) == -1 || unlink(msg) == -1)
+ printf("Can't rename %s to %s\n", msg, field);
+ }
+ m_update();
+ flush();
+ done(0);
+leave:
+ printf("[Message NOT Delivered!]\n");
+ if(fccout.b_fildes)
+ unlink(fccfile);
+ m_update();
+ flush();
+ done(1);
+}
+
+
+parse(ptr, type, fldname)
+char *fldname;
+{
+ register int i;
+ register int l;
+ char line[128];
+
+ putc(type, &pout);
+ puts("\n", &pout);
+ puts(ptr, &pout);
+ fflush(&pout);
+ write(3, "", 1);
+ l = 0;
+
+ while((i = getl(&pin, line, (sizeof line) - 1)) > 0) {
+ line[i] = 0;
+ if(line[0] == 0)
+ { if (type == 'r')
+ { if (l > 0)
+ parptr = add("\n",parptr);
+ }
+ return(0);
+ }
+ else if(line[0] == '?') {
+ printf("Adrparse: %s", line);
+ return(1);
+ }
+ if (type == 'r')
+ { line[--i] = 0;
+ if (l+i > 70)
+ { parptr = add("\n",parptr);
+ l = 0;
+ }
+ if (l == 0)
+ { parptr = add(fldname,parptr);
+ l =+ length(fldname);
+ }
+ else
+ { parptr = add(", ",parptr);
+ l =+ 2;
+ }
+ parptr = add(line+1, parptr);
+ l =+ i;
+ }
+ else
+ parptr = add(line, parptr);
+ }
+ printf("Error from adrparse.\n");
+ return(1);
+}
+
+gmid()
+{
+ static char bufmid[128];
+ long now;
+ register char *cp, *c2;
+ register int *ip;
+
+ cp = bufmid;
+ *cp++ = '<';
+ cp = copy(locv(0, getruid()), cp);
+ *cp++ = '.';
+ time(&now);
+ cp = copy(locv(now), cp);
+ cp = copy("@Rand-Unix>\n", cp);
+ *cp = 0;
+ return(bufmid);
+}
+
+#ifdef COMMENT
+gmid()
+{
+ static char bufmid[128];
+ long now;
+ register char *cp, *c2;
+
+ cp = bufmid;
+ cp = copy("<[Rand-Unix]", cp);
+ time(&now);
+ c2 = cdate(&now);
+ c2[9] = ' ';
+ c2[18] = 0;
+ cp = copy(c2, cp);
+ *cp++ = '.';
+ cp = copy(logn, cp);
+ *cp++ = '>';
+ *cp++ = '\n';
+ *cp = 0;
+ return(bufmid);
+}
+#endif
+
+gd()
+{
+ register char *t, *p;
+ register int *i;
+ static bufgd[32];
+ extern char *tzname[];
+ long now;
+
+ time(&now);
+ t = ctime(&now);
+ p = bufgd;
+
+ *p++ = t[8];
+ *p++ = t[9];
+ *p++ = ' ';
+ *p++ = t[4];
+ *p++ = t[5];
+ *p++ = t[6];
+ *p++ = ' ';
+ *p++ = t[20];
+ *p++ = t[21];
+ *p++ = t[22];
+ *p++ = t[23];
+ *p++ = ' ';
+ *p++ = 'a';
+ *p++ = 't';
+ *p++ = ' ';
+ *p++ = t[11];
+ *p++ = t[12];
+ *p++ = t[14];
+ *p++ = t[15];
+ *p++ = '-';
+ i = localtime(&now);
+ t = tzname[i[8]];
+ *p++ = *t++;
+ *p++ = *t++;
+ *p++ = *t++;
+ *p++ = '\n';
+ *p++ = 0;
+ return(bufgd);
+}
+
+
+getl(iob, buf, size)
+{
+ register char *cp;
+ register int cnt, c;
+
+ cp = buf; cnt = size;
+
+ while((c = getc(iob)) >= 0) {
+ *cp++ = c;
+ --cnt;
+ if(c == 0 || c == '\n' || cnt == 0)
+ break;
+ }
+ return(size - cnt);
+}
+
+
+compress()
+{
+ register char *f1, *f2, *f3;
+
+#ifdef DEBUG
+ printf("compress:\n%s-----\n", parptr);
+#endif
+ for(f1 = parptr; *f1; ) {
+ for(f2 = f1; *f2++ != '\n'; ) ;
+ while(*f2) {
+ if(eqqq(f1, f2)) {
+ for(f3 = f2; *f3++ != '\n'; ) ;
+ copy(f3, f2);
+ } else
+ while(*f2++ != '\n') ;
+ }
+ while(*f1++ != '\n') ;
+ }
+}
+
+
+eqqq(s1, s2)
+{
+ register char *c1, *c2;
+
+ c1 = s1; c2 = s2;
+ while(*c1 != '\n' && *c2 != '\n')
+ if((*c1++|040) != (*c2++|040))
+ return(0);
+ return((*c1|040) == (*c2|040));
+}
+
+
+filemsg(folder)
+char *folder;
+{
+ register int i;
+ register char *fp;
+ struct inode stbuf;
+ struct msgs *mp;
+
+ fp = m_maildir(folder);
+ if(stat(fp, &stbuf) < 0) {
+ nmsg = concat("Create folder \"",
+ fp, "\"? ", 0);
+ if(!gans(nmsg, anoyes))
+ return(-1);
+ if(!makedir(fp)) {
+ printf("Can't create folder.\n");
+ return(-1);
+ }
+ }
+ if(chdir(fp) < 0) {
+ perror(concat("Can't chdir to ", fp, 0));
+ return(-1);
+ }
+ if(!(mp = m_gmsg())) {
+ printf("Can't read folder %s\n", folder);
+ return(-1);
+ }
+ nmsg = m_name(mp->hghmsg + 1);
+ copy(nmsg, copy("/", copy(m_maildir(fp), fccfile)));
+ if((i = creat(fccfile, m_gmprot())) == -1)
+ printf("Can't create %s\n", fccfile);
+ return(i);
+}
+
+
+puts2(str, iob)
+{
+ puts(str, &fccout);
+ puts(str, i
\ No newline at end of file
--- /dev/null
+/*
+ * Type definitions for the strings(3) subroutines.
+ */
+
+char *strcat();
+char *strncat();
+char *strcpy();
+char *strncpy();
+int strcmp();
+int strncmp();
+char *index();
+char *rindex();
--- /dev/null
+/* USE THIS FILE AS AN EXAMPLE ONLY */
+/* You must fill in your own stuff in your whoami.h, which you already have */
+
+#define sysname "youruucpname"
+
+/* Omit these if not on the ARPANET */
+#define HOSTNAME "ARPA-NAME" /* Arpa STANDARD host name for us */
+#define HOSTNUM nnn /* Short style host number */
+#define HOSTHOST nnn /* For long style host/imp numbers */
+#define HOSTIMP nnn /* ditto */
+
+/* HOSTNUM = (HOSTHOST<<6)|HOSTIMP which only works if host is 0-3 */
+/* since result must fit in a byte. */
--- /dev/null
+2/16/81 progs Dave Yost:
+ Fixed folder so that it checks value from m_gmsg and complains
+ if the folder is unreadable. All other commands that call it
+ do this, so it was simply an error of omission.
+
+2/16/81 subs Dave Yost:
+ m_gmsg.c was testing return value of malloc against -1.
+ Tsk.
+
+2/16/81 subs Phyllis Kantar
+ trimcpy.c was scanning profile fields from the left and
+ truncating ('\0') at the first newline. It now zaps
+ the trailing newline and replaces embedded NL's with blanks.
+
+2/23/81 progs phyl:
+ Fixed annotation so that it annotates only "To:" and "cc:"
+ In forw.c doano():
+ Changed
+ if(uleq(name, "to") || uleq(name, "cc") == 0) {
+ to:
+ if(uleq(name, "to") || uleq(name, "cc") ) {
+
+ Similarly for dist.c
+ Changed /etc/mh/distcomps to read "Distribute*"
+ instead of "Distribution*"
+
+ Also, fixed bug in annotate.c:
+ fprintf(tmp, "%s: %*s", comp, cp-sp, sp);
+ should be
+ fprintf(tmp, "%s: %*.*s", comp, cp-sp, cp-sp, sp);
+
+ Note: none of these fixes affects repl
+
+
+
+3/23/81 progs jdg/day: changed deliver.c to check for effective uid and gid
+ while it is preventing forgery of mail. Needed for uucp, when
+ uucico is invoked by a real person instead of uucp itself.
+
+4/7/81 progs Dave-Yost
+ Fixed scansub.c to check for HOSTNAME instead of "rand-unix".
+ A little portability, please.
+
+4/13/81 progs Dave-Yost
+ Changed deliver to put out a date format like
+ Monday, 13 Apr 1981 20:46-PST
+ instead of
+ 13 Apr 1981 at 2046-PST
+
+4/13/81 subs Dave Yost
+ modified m_edit.c to exec the editor with altmsg as an extra
+ argument, in case the editor can use it as an alt file.
+
+5/7/81 progs Dave-Yost
+ Changed conflict.c and conflict.8 to ignore /usr/spool/mail
+ files starting with '.'.
+
+5/7/81 progs Dave-Yost
+ conflict isn't smart about the fact that there can be
+ more than one login name on the same uid. This should
+ be fixed.
+
+5/29/81 progs Phyl
+ Changed /usr/news/.mh_receive to grep for
+
+ '^[Tt][Oo]:.*news\.'
+
+ instead of
+
+ '[Tt][Oo]:'
+
+ However, 'news' will still break when there are multiple news folders
+ in the 'To:' field(s)!
+
+7/2/81 progs Phyl:
+ Changed inc.c and scansub.c so that mail is not lost when
+ the message number exceeds 999.
+
+7/2/81 progs day:
+ mh.h has #define MAXFOLDER 999 and hopefully all occurrences
+ of that magic number have been changed to MAXFOLDER.
+
+7/2/81 progs day:
+ Fixed pick and file so they won't go beyond 999 (MAXFOLDER)
+ into a folder. file.c and pick.c had virtually identical
+ copies of the same routine to file a message. Took it out and
+ put it into subs as m_file(), and changed it to have
+ several arguments so there are no connections via globals.
+ Also created ../folder.h which is included by pick.c, file.c,
+ and ../subs/m_file.c.
+
+7/2/81 progs day:
+ Changed the message-name parser (../subs/m_convert.c) to
+ limit message number arguments to 999 (MAXFOLDER). Thus if you
+ say 'scan 800-10000', this will be interpreted as 'scan 800-999'
+
+7/2/81 progs day:
+ Some very minor changes to satisfy lint.
+
+7/6/81 progs day:
+ Did a make install of all the stuff changed in the last
+ few days.
+
+7/9/81 progs phyl:
+ fixed inc so that "inc -nochangecur" doesn't display a spurious '+'
+ on the 1st incorporated msg.
+
+7/24/81 progs phyl:
+
+ Fixed rmail to match graphics. On the Vax, it failed to construct
+ a From: field when the next hop is Arpanet if there was a remote
+ uucp hop remaining.
+
+8/10/81 progs phyl:
+
+ Fixed rmail to block uucp-to-arpanet mail when the originating
+ host is not a Rand sysname. It also returns mail to the sender
+ when this condition occurs.
+
+ rmail now recognizes "at" as well as "@".
+
+ rmail no longer compares headers against a list of legal headers;
+ rather it tests for proper form "<63-chars-or-less>:"
+
+ m_getfld.c now tests for ':' BEFORE it tests for header length
+ exceeded.
+
+8/10/81 progs strings day:
+
+ remove hostname.c from mh/strings.a. It was used only by
+ deliver.c for constructing a msgid; now it uses
+ HOSTNAME (from <whoami.h>)
+
+8/10/81 Dave Yost
+ Put rhosts[] decl in mh.h and added rhosts.c to strings.a
+ rmail is only thing that references it just now.
+
+8/11/81 Dave Yost
+ Added rand proprietary notice to all .c, .h, and Makefiles.
+ Ownership and date on all files left unchanged.
+
+8/11/81 Dave Yost
+ Combined */Log into this file
+
+8/13/81 Phyl
+ Added uucp addresses to deliver's debug printout.
+ (Didn't install).
+
+8/18/81 Phyl
+ Fixed adrparse so that it accepts multiple "at"s in an address:
+ a!b!c at d at e at f ==> (a!b!c at d at e) at f
+
+ Changed deliver to set a new process group when it is called
+ with the -deliver switch--so that if it sends an interrupt to pid
+ 0, it's parent (e.g., srvrftp) won't get blown away.
+ Note that deliver now must be loaded with the jobs library (-ljobs),
+ to access setpgrp(). I added "#define VMUNIX" to mh.h,
+ and #ifdef'd the call to setpgrp.
+
+ Fixed deliver to allow 120 secs (instead of only 30)
+ for a user's .mh_receive to complete.
+
+8/26/81 Mike
+ Fixed "folder" so you can now have up to 300 folders.
+
+9/24/81 phyl
+ fixed scansub.c to incorporate illegal messages correctly:
+ Bug: If the bad message has the bobo in its last line,
+ then inc says [No mail incorporated]
+ FIX: if (state == BODYEOF || state == FILEEOF)
+ -------------------
+ Bug: spurious chars printed in the body of the bad msg.
+ FIX: a) \n after the bad component
+ b) if(scnout && state != FILEEOF)
+ -------------------
+
+10/1/81 phyl
+ fixed mhl bug; it no longer bombs on "mhl: -option " profile
+ arguments:
+ procargs(ap); /* Old */
+ procargs(profargs); /* New */
+
+10/13/81 obrien
+ changed scansub to replace '\f' with blank
+
+11/4/81 day
+ Fixed pick to say '1 hit' instead of `1 hits'.
+
+11/18/81 phyl
+ Accidently did a "make" in /usr/src/cmd/mh on Nov 18. Most
+ programs reloaded because the new "#define VMUNIX" in mh.h caused
+ strings.a to be remade. Did not install any of it. err file moved
+ to err.Nov18
+
+1/6/82 phyl
+ o Added scansub dependencies to Makefile
+ o Added rmail.c and scansub.c to CFILES in Makefile
+ o Alphabetized dependency list in Makefile
+ o ??Are all the Nov 18 binaries suspect? The Aug 18 .o files?
+ o I ask because--
+ Nov 18 prompter had strange behavior (didn't respond to <DEL>,
+ didn't display error messages) which disappeared when
+ recompiled.
+
+1/7/82 phyl
+ o Added cs-rand to rhosts.c.
+ o Re-make all of MH (save old .o files in DOT.o.01072;
+ save old executables in SAVE.01072)
+
+1/20/82 phyl
+ Fixed scansub.c to terminate a short message body with ">>"
+ on the scan line.
+
+1/25/82 phyl
+ Changed deliver.c, repl.c, send.c to require all 5 characters
+ for -debug switch.
+
+ (didn't "make")
+
+2/19/82 phyl
+ mh.h: added SELECT_EMPTY flag
+
+2/22/82 day
+ mh.h change char to extern char for strings in strings/strings.a
+ progs: install my new inc, scan, and scansub with -time and -numdate
+ progs: change show.c so it includes mhl.c and calls it if
+ showproc is mhl, rather than execing it.
+
+3/10/82 phyl
+ Changed adrparse to return 0 in case of error, instead of exiting.
+ Changed repl to test for adrparse's return value and do the
+ right thing. It constructs a reply skeleton, omitting the
+ offending addresses from the header. Instead, unparsable
+ addresses are listed in the skeleton body. Note, repl
+ normally takes the sender:'s (or from:'s) host as the default
+ to append to hostless addressees. In the new version,
+ if the sender (or from) field was unparsable, the default
+ host is "?????".
+ Changed deliver to test for adrparse's 0 return value, and exit.
+
+4/22/82 phyl
+ Changed the functions msg_convert() and msg_conv() to convert()
+ and conv(), respectively, to maintain 8-char uniqueness.
+ Linked new source into /usr/dist/1.7
+
+4/23/82 phyl
+ scansub.c: renamed the structure tag 'zone' to 'tzone'
+ for compatibility with lesser C compilers (?). (Anyway,
+ it wouldn't load on the 11/45 under 2.8bsd without that change.)
+ Delete unused reference to locv().
+ Linked new source into /usr/dist/1.7
+
+5/8/82 phyl, guyton
+ scansub.c: no longer reads the full message when called
+ by scan.
+ Linked new source into /usr/dist/1.7
+
+5/8/82 phyl
+ rmail: now tacks on Arpa-style date to dateless uucp mail.
+ Takes date from oldest uucp-From line. Assumes uudate is
+ in ctime() format.
+
+5/10/82 phyl
+ Fixed bug in deliver that caused mail addresses uuhost1!joe,
+ uuhost2!joe to look like duplicates. Fix: if uuaddress, compare
+ host names instead of host numbers.
+
+5/12/82
+ Fixed news.
+
+ Until now it couldn't handle "cc: news.topic", or "To: news.topicA,
+ news.topicB", or news topics that aren't explicitly in the message
+ header, or ...).
+
+ Deliver: fixed it so that aliasing keeps a handle on the
+ 1st (local) alias. Now deliver can pass this string to
+ /usr/news/.mh_receive as an argument, rather than have .mh_receive
+ grep through the message for the news topic.
+ Deliver: changed aliasing so that, once it finds a match to an
+ alias whose form is <string>*, it *continues* comparing addresses.
+
+ Deliver: changed it to fflush(stdout) after every printf() sans '\n'.
+
+6/3/82 phyl
+ All references to anoyes were changed from char *
+ to extern struct swit.
+
+ mh.h: delete hostname, layout; add mailproc; change mypath
+ from extern char * to char *.
+
+ progs/Makefile: move "chmod 777 MHTMP" down to installroot.
+
+ Deliver: a bug that caused the temp files in /usr/tmp/mh
+ to hang around whenever there was a local delivery error
+ was fixed.
+
+ if(!debug && rmflg > 1) ==> if(!debug && rmflg > 0)
+
+ m_gmsg.c: WAS FIXED TO USE FREAD INSTEAD OF READ on the mail
+ dir
\ No newline at end of file
--- /dev/null
+ MHL Design
+
+Mhl is a formatted message listing program. It can be used as a
+replacement for "c" (the default message lister). As with c, each of
+the messages specified as arguments (or stdin) will be output. If more
+than one message file is specified, the user will be prompted prior to
+each one, and a <return> or <eot> will begin the output, with <return>
+clearing the screen (if appropriate), and <eot> suppressing the screen
+clear. An <interrupt> will abort the current message ouput, prompting
+for the next message (if there is one), and a <quit> will terminate the
+program (without core dump).
+
+NOTE: This is a preliminary document and the design is VERY young.
+
+Syntax: mhl [switches] [files]
+
+As in all MH programs, mhl looks for a line "mhl: args" in the user's
+profile, and thus allows tailored defaults. The switches are:
+
+ -clear /* Clear screen each page */
+ -noclear /* Don't clear screen each page */
+ -folder folder /* Use this "folder" name */
+ -form formfile /* Name of the format file */
+ -length /* Screen length */
+ -width /* Screen width */
+ -help /* Standard help message */
+
+All of the functions these switches perform are affected or controlled
+by information elsewhere. That is, the format file can specify "clear",
+in which case, the command line switches will override. Also, the
+length and width can be specified in the format file, or default to
+40x80. The folder is used in constructing a message name (see special
+component "MessageName" below). If it is not specified in a switch, it
+is taken from the environment variable "mhfolder", which show, next,
+prev, and pick initialize appropriately.
+
+If the form file is not specified, it is taken from the file
+"mhl.format" in the user's MH directory, and if that file doesn't exist,
+it is taken from "/etc/mh/mhl.format". (Same evaluation hierarchy as the
+compose form file.)
+
+Mhl operates in two phases: 1) read and parse the format file, and 2)
+process each message (file). During phase 1, an internal description of
+the format is produced as a structured list. In phase 2, this list is
+walked for each message, outputing message information under the format
+constraints from the format file.
+
+The "mhl.format" file contains information controlling screen clearing,
+screen size, wraparound control, transparent text, component ordering,
+and component formatting. Also, a list of components to ignore may be
+specified, and a couple of "special" components are defined to provide
+added functionality. Message output will be in the order specified by
+the order in the format file.
+
+
+Each line of mhl.format has one of the formats:
+
+ ;comment
+ :cleartext
+ variable[,variable...]
+ component:[variable,...]
+
+A line beginning with a ";" is a comment, and is ignored. A line
+beginning with a ":" is clear text, and is output exactly as is. (A line
+containing only a ":" produces a blank line in the output.) A line
+beginning with "component:" defines the format for the specified
+component, and finally, remaining lines define the global environment.
+
+For example, the line:
+
+width=80,length=40,clearscreen,overflowtext=***,overflowoffset=5
+
+defines the screen size to be 80 columns by 40 rows, specifies that the
+screen should be cleared prior to each page, that the overflow
+indentation is 5, and that overflow text should be flagged with "***".
+
+Following are all of the current variables and their argmuments. If
+they follow a component, they apply only to that component, otherwise,
+their affect is global. Since the whole format is parsed before any
+output processing, the last global switch setting for a variable applies
+to the whole message.
+
+width=# Screen width, component width
+length=# Screen length, component line limit
+offset=# Positions to indent text
+overflowtext=t Text to use at the beginning of an overflow line
+overflowoffset=# Positions to indent overflow lines
+compwidth=# Positions to indent component text after first line
+nocomponent Don't output "component: " for this component
+uppercase Output text of this component in all upper case
+center Center component on line (works for one-line components
+ only)
+clearscreen Clear the screen (form feed) prior to each page
+leftadjust Strip off leading spaces & tabs on each line of text
+compress Change newlines in text to spaces
+
+Where "=#" indicates a number must be specified, and "=t" indicates that
+arbitrary text up to end of line or "," is required. The variables
+without arguments are ON indicators, with the default in all cases OFF.
+The variables "nocomponent", center, leftadjust and compress have no
+affect globally, and clearscreen only affects the global environment.
+
+A line of the form:
+
+ignores=component,...
+
+specifies a list of components which are never output.
+
+The component "MessageName" (case is unimportant) will output the actual
+message name (file name) preceded by "folder:" if one is specified or
+found in the environment.
+
+The component "Extras" will output all of the components of the message
+which were not matched by explicit components, or included in the ignore
+list. If this component is not specified, an ignore list is not needed
+since all non-specified components will be ignored.
+
+If "nocomponent" is NOT specified, then the component name will be output
+as it appears in the format file.
+
+The current default format is:
+
+width=80,length=40,overflowtext=***,overflowoffset=5
+ignores=msgid,message-id
+Date:leftadjust,offset=40
+To:leftadjust
+Cc:leftadjust
+:
+From:leftadjust
+Subject:leftadjust
+:
+extras:leftadjust,nocomponent
+:
+body:nocomponent
+
+
+Future work:(?)
+
+ o Fancier address formatting (to, cc, from)
+ o Tests for "am i in this address list?" and what to do if yes/no
+ o Currently only one component per line--should be generalized
+ o Clear text and components intermixed on a line
+ o Intelligent fill/justify per component?
+
+
+
+May 1980
+Bruce
\ No newline at end of file
--- /dev/null
+ HOW TO GENERATE AN MH
+
+ASSUMPTIONS/RESTRICTIONS:
+
+ All of the code is written for Version 7 C, and assumes the
+existence of appropriate Version 7 /usr/include files. It also uses the
+Version 7 stdio package, which is somewhat different from the
+Phototypesetter stdio!
+
+ There is moderate usage of Version 7 UNIX features, including:
+
+ ftime() system call
+ execlp() & execvp() environment exec calls
+ getenv() environment access
+
+also, login has to be changed to add the environment entry "USER=name".
+This is used during scan listings to see if the message "From" should be
+replaced by "To:name". This string is NOT used to determine the "From:
+name" stamp on outgoing mail.
+
+ All of these usages ARE replaceable by subroutines which do the
+same thing, only slower. That is, a line of the form:
+
+ homedir = getenv("HOME");
+
+should be replaced by something like:
+
+ homedir = gethome();
+
+and the routine gethome() written to return the home directory by
+looking through /etc/passwd for the line matching the process' getuid().
+This goes for the environment variable "USER" as well.
+
+The routines execlp() & execvp() are simply fancy exec's, which use the
+"PATH" environment variable to determine the search path by which to
+find the executable image. They can be replaced by routines which use a
+default search list. They also call a shell to execute the file in the
+same way the shell handles shell scripts.
+
+
+
+PROCEDURE:
+
+
+1) Read the MH directory tree onto a file system.
+ On our system it lives in the directory "/usr/src/cmd/mh".
+
+2) Edit mh.h, and define ARPANET if you are on the ARPANET.
+ If not, don't define it. If ARPANET is not defined and if you want to
+ assign your host a name for address formatting, change HOSTNAME in
+ adrparse.h. If you are on VMUNIX, define that in mh.h and set up the
+ JOBSLIB define in progs/Makefile.
+
+3) Examine the C header files in the "Extras" directory. Copy them to
+ /usr/include or support/ and modify them for your installation.
+ If you are going to use mh over uucp and/or ARPANET links, you must edit
+ your /usr/include/whoami.h to be sure the defines for sysname (uucp) and
+ HOSTNAME & HOSTNUM (ARPANET) are correct. If you are not on the
+ ARPANET, delete HOSTNAME and HOSTNUM from whoami.h.
+
+4) Examine all of the files in the "strings" directory. These contain
+ site-dependent strings, such as pathnames for programs used by MH. Most
+ of the files contain short descriptions of what the strings are.
+ 'showproc.c' refers to a program which is found as support/l.c and which
+ is installed as 'c' linked to 'l'. You may want to use Berkeley's
+ 'more' or some other program here. The BINDIR and MHDIR entries in
+ Makefile and */Makefile must agree with the contents of strings/*.c.
+ Also, the 'file' command in support/news/mh_receive should have the same
+ path as is in strings/fileproc.c. Make sure BINDIR (/usr/local as
+ distributed) is put into everyone's PATH by login or by shell startup
+ files.
+ Note: if you are installing mh `unofficially', and you don't have
+ permissions to make directories in /usr/spool/ and /etc/, then make
+ sure the paths in the strings/*.c files and in support/mailsys.h
+ are directories you have permission to make if they don't exist already.
+ In particular, /usr/spool/locks/ must be on the same file system as
+ /usr/spool/mail so that links can be made. Try /usr/tmp/locks if
+ you can't mkdir /usr/spool/locks/.
+
+5) Install support/putenv.c into your system libc.a, or if you don't
+ want it as part of your standard C library, move it into subs. (Both
+ options work equally well for MH!)
+
+6) Copy the file "support/MailAliases" to /etc. Then you should look at
+ it and see if you want to add any mail aliases.
+
+7) In the top level directory, utter:
+
+ make all
+
+ This will make both of the libraries: strings.a and subs.a, and all
+ of the executable modules.
+ (Ignore the possible error message "nm: sysname.o--no name list")
+
+
+8) For the 'news' facility of mh to work, you must:
+ Create a user called 'news' who belongs to the group 'mail',
+ with password '--none--' in /etc/passwd and /etc/group.
+ Creat a home directory for news: "/usr/news".
+ cd /usr/news
+ /etc/chown news * .??*
+
+9)
+ make onceonly This renames conflicting bell
+ programs, and makes requisite
+ directories.
+
+ make install This puts all of the programs,
+ misc files, and man pages
+ into appropriate directories.
+
+10) As SU:
+ cd progs; make installroot
+
+ - If /etc/chown isn't found, try linking /bin/chown to /etc/chown
+
+ - If [ isn't found, try linking /bin/test to /bin/[
+
+ - If "true" isn't found, create the executable NULL file /bin/true.
+
+That's it. Take a close look at the Makefile--it does LOTS of work.
+Especially note that it renames the V7 `file' program to `filetype'
+because for historical and other reasons, mh has its own `file' command.
+Also, MH has its own versions of `mail' and `rmail'. If you don't want
+to install everything in standard places, run "make install" with the
+variables MHDIR=newdir and BINDIR=newdir pointing wherever you wish. If
+you do this, you probably have to change some of the path names in the
+strings files. For most of them, you can get away with adding profile
+entries to change where the default paths are sought.
+
+If you don't have `make':
+
+ You'll have to use the make file as a template for commands to give
+ by hand. Basically each section of the make file defines the
+ sequence of shell commands needed to create the object before the
+ `:'. The list immediately after the `:' specifies the dependencies
+ for the object--that is, those objects which either must be made
+ first, or those modules that if they've changed, the object must be
+ rebuilt. The following lines (up to the next object) are simply
+ shell commands to be executed. Make knows how to create .o's from
+ .c's, and the "CFLAGS= -O" at the beginning tells it to include
+ optimization when it does a c compile.
+
+If you don't have stdio (i.e. some version 7 C compiler):
+
+ Punt. I recently converted the whole package from the old
+ getc/putc/iobuf subroutines--including lots of upgrades/
+ improvements, it took me about a week. Expect it to take a couple
+ of weeks for someone good to convert back. Basically, convert the
+ subroutines, then once you've converted one module (start with show
+ or comp), you'll find all the rest VERY similar. Some day I may
+ split out all of the system dependencies, but don't hold your
+ breath.
+
+
+
+As a last resort:
+
+ Feel free to send mail to me, but please don't expect me to spend
+hours helping. Collect your questions/problems, and get in touch and
+I'll see what I can do. I can be reached:
+
+ via ARPANET: Borden at Rand-UNIX
+
+ Mail: The Rand Corporation
+ 1700 Main Street
+ Santa Monica, CA 90406
+
+Bruce Borden
+April, 1980
+
+
+ If you are accessible via the arpanet or via uucp mail, please
+contact the secretary to the Director of the Information Systems Lab at
+Rand, and get on our mh-bugs electronic mailing list. 213/393-0411
+
+Dave Yost
+Februar
\ No newline at end of file
--- /dev/null
+This file contains some notes on features/bugs/etc which are
+not documented in the "MH User's Manual", as well as some notes
+on future directions. See MHgenerate for more info. Some of
+these notes assume VAX/V7 UNIX--as noted by {V/V7}.
+
+0) Directories:
+ support contains files which get copied to /etc/mh, as
+ well as some miscellaneous Rand support programs
+ subs contains support subroutines--built into subs.a
+ strings contains c files which define all of the default
+ names and paths used by the package->strings.a
+ Extras old and un-supported code--much of it not
+ converted to V7. Look at libg/libh for help in
+ getting around V7 features.
+ DOC contains the MH User's Manual document in nroff/
+ troff form. This requires the Phototypesetter or
+ V7 version of nroff/troff, AND the Berkeley -me
+ macros.
+
+1) Undocumented Feature: The paths to the various programs which
+ MH exec's are kept in variables named something like "lsproc".
+ (See the strings directory.) While reading in the user's
+ profile, (m_getdefs()) a component matching one of these exec
+ path names, will cause the default string to be replaced by
+ the profile entry argument. Thus, the profile entry "lsproc:
+ /usr/foo/bin/newls" will cause all MH programs using "lsproc"
+ to get a new ls. At least for now, there is no way to specify
+ switches. This mapping is arranged by the "procs" structure
+ in m_getdefs.c--keep it up to date if new exec procs are
+ added.
+
+2) Collision: Take a close look at the "onceonly" entry of the
+ Makefile. Bell already has a program named `file', which the
+ makefile will rename to `filetype', which is what it tries to
+ indicate. If you really want to, you might rename the MH
+ command `file', but I have yet to hear of an even vaguely
+ reasonable alternative.
+
+3) Different Approach: Using the Berkeley C shell (csh),
+ "multiple links to the same file with different profile
+ entries" is better served with aliases.
+
+4) Collision: {V/V7} BELL mail cannot co-exist with MH--IF THEY
+ SHARE THE SAME MAILBOXES, otherwise they co-exist fine! If
+ you use the standard (VAX) mail directory /usr/spool/mail for
+ MH, you should also install the MH version of the mail
+ program. It is much nicer, and integrates with MH cleanly.
+ The advantage of using /usr/spool/mail is that login will
+ notify of new mail.
+
+5) Feature: If you add a line like:
+
+ 30 1 * * * /etc/mh/conflict -mail admin
+
+ to crontab, then every morning at 1:30 AM, the alias file will
+ be checked against the /etc/passwd file to see that
+ inconsistencies haven't been introduced. In particular, a
+ line in the alias file may be "tom: jones" (because Tom Jones
+ likes to be called Tom), but if tom is also a valid user name,
+ tom will no longer receive any mail! This program also prints
+ any mail drops in /usr/spool/mail which don't belong to a
+ valid user (i.e. a deleted or renamed user id).
+
+ "convlict -mail name" will check the consistency and mail
+ the specified user a short status message.
+
+ This program also checks to see if there are any users who do
+ not belong to any group, or any user in a group which is missing
+ from the passwd file. This latter is an inconsistency on all
+ systems, whereas the former is not required except at Rand, and
+ won't be compiled without the "-DRAND" cc flag in the makefile.
+
+6) Hidden Feature: At the request of some of the Rand staff,
+ there is the ability to invoke a user-specified deletion-
+ program to implement message deletion, rather than getting the
+ default comma renaming convention (see next item). If a
+ user's profile contains the line: "Delete-prog: path", the
+ specified path will be called with a list of files needing
+ deletion. All this code works...
+
+7) Feature: When a message (draft or in a folder) is "removed",
+ it is really renamed with a leading comma. E.g. foo -> ,foo.
+ At Rand we have a program called the midnight skulker which
+ goes through the whole system and removes all backup (starting
+ with comma), a.out, and core files. This backup convention
+ gives users a chance to undo spurious removes, at least all
+ day. You may want to replace these renames with a simple
+ unlink(), or each user may get this effect by specifying
+ "Delete-prog: /bin/rm" in his/her profile.
+
+8) Feature: NEWS. The news facility is undocumented in the MH
+ manual, because it is a very new addition to the package. SO,
+ here it is...
+
+ The directory /usr/news should be created--it will
+ contain the folders for news topics, and various support
+ files. The news items are strictly MH folders, and users
+ can utilize all of the MH commands on them. The news
+ program is similar to "show", but it shows `unseen' news
+ as the default, keeping a separate entry in the users
+ profile for each news topic indicating the highest item
+ the user has seen. These entries look like
+ "news-<topic>: highest-seen".
+
+ Rather than read through the news folders to determine
+ the number of entries, a file with name .<topic> (i.e.
+ period followed by the topic name) is kept with length
+ equal to highest message number. Thus, to determine if a
+ user hasn't seen some news, the news directory
+ (/usr/news) is read, and for each non-period beginning
+ file (i.e. each folder), stat the associated period
+ beginning file, and compare its length with the users
+ profile news entry for the same name. If the user has no
+ entry, or it is less than the length of the period-file,
+ then show him the remainder of the news in each such
+ topic.
+
+ The program `l' is used to display each message, and the
+ highest item profile entry is updated prior to each
+ individual message displayed, so <del> will leave the
+ user's profile in the proper state for the next news
+ request.
+
+ Add a user to the system called news, with home directory
+ /usr/news and add the line:
+
+ news.*: news
+
+ to /etc/MailAlias. Thus, to add news to a topic, it is
+ only necessary to mail to news.topic, and it will happen.
+ To make the automatic filing into folders happen, copy
+ the file support/news-mh_receiv to /usr/news/.mh_receive.
+ This is a shell script which will get invoked whenever
+ mail is sent to the user news (see next "undocumented
+ feature").
+
+ Problems: I have yet to write the program which packs
+ news folders. Items can be readily removed (as long as
+ they are not the last item in the folder), but if the
+ folder is packed (after some months/years the item
+ numbers will reach the 999 limit), it is necessary to go
+ through everyones .mh_profile files and reset the
+ highest-seen numbers. Not hard to write, I just haven't
+ done it yet. Also, the receive shell script should be
+ recoded in C to speed it up considerably.
+
+9) Undocumented Feature: If a user has an executable program or
+ shell script named ".mh_receive" in his home directory, then
+ it will be executed by the mail deliverer RATHER than
+ appending mail items to the user's mail file
+ (/usr/spool/mail/name). This program will be called with:
+
+ execlp(prog, prog, tmpfil, mail, home, 0);
+
+ where prog is the receive program, tmpfil is a file in
+ /usr/tmp which is the mail to be received, mail is the path of
+ the user's mail drop (/usr/spool/mail/name), and home is the
+ $HOME directory of the user. File descriptor 3 will have
+ tmpfil opened on it read only. These are all the RECEIVER'S
+ parameters, not the sender's. Also, the environment is set up
+ with appropriate values for HOME and USER.
+
+ Eventually, the goal is to have received mail LINKED into
+ user's inbox folders, rather than appended to their mailboxes.
+ This will facilitate the sending of mail to large distribution
+ lists (Rand is always tight on space!) Have a look at the news
+ .mh_receive file for an example of this facility.
+
+ Warning: appropriate interlocks are implemented in "deliver"
+ to prevent collisions when it appends to mailboxes, but it is
+ up to the users's .mh_receive program to provide its own
+ interlocks!
+
+10) New Program: "mhl" is a custom MH list program which displays
+ messages according to a format specification. See MHL.Design
+ for further details. See Extras/mhl.bsb for an added example.
+
+11) New Program: "ali" is a mail alias checker. It takes a list
+ of names, and produces the alias list for the names. It also
+ indicates any names which are not valid local names or aliases.
+
+
+
+
+Bruce Borden
+Mar
\ No newline at end of file
--- /dev/null
+#
+# Proprietary Rand Corporation, 1981.
+# Further distribution of this software
+# subject to the terms of the Rand
+# license agreement.
+#
+
+#
+
+# The following two must match entries in */Makefile
+BINDIR = /usr/local
+MHDIR = /etc/mh
+
+all:
+ cd subs; make
+ cd strings; make
+ cd progs; make progs
+
+uninstall:
+ cd progs; make uninstall
+ cd support; make uninstall
+ cd man; make uninstall
+ -rm -rf $(MHDIR)
+ -mv /usr/man/man1/bellmail.1 /usr/man/man1/mail.1
+ -mv /bin/bellmail /bin/mail
+ rm -f /bin/rmail
+ ln /bin/mail /bin/rmail
+ -mv /usr/man/man1/filetype.1 /usr/man/man1/file.1
+ -mv /usr/bin/filetype /usr/bin/file
+ -mv /bin/filetype /bin/file
+
+onceonly:
+ -@if [ ! -f /usr/bin/filetype -a ! -f /bin/filetype -a -f /bin/file ] ; then \
+ mv /bin/file /bin/filetype;echo "/bin/file => /bin/filetype" ; else true ; fi
+ -@if [ ! -f /bin/filetype -a ! -f /usr/bin/filetype -a -f /usr/bin/file ] ; then \
+ mv /usr/bin/file /usr/bin/filetype;echo "/usr/bin/file => /usr/bin/filetype" ; else true ; fi
+ -@if [ ! -f /usr/man/man1/filetype.1 -a -f /usr/man/man1/file.1 ] ; then \
+ mv /usr/man/man1/file.1 /usr/man/man1/filetype.1;echo "/usr/man/man1/file.1 => /usr/man/man1/filetype.1" ; else true ; fi
+ -@if [ ! -f /bin/bellmail -a -f /bin/mail ] ; then \
+ mv /bin/mail /bin/bellmail;echo "/bin/mail => /bin/bellmail" ; else true ; fi
+ -@if [ ! -f /usr/man/man1/bellmail.1 -a -f /usr/man/man1/mail.1 ] ; then \
+ mv /usr/man/man1/mail.1 /usr/man/man1/bellmail.1;echo "/usr/man/man1/mail.1 => /usr/man/man1/bellmail.1" ; else true ; fi
+ -@if [ -f $(BINDIR)/comp ] ; then \
+ echo "Collision on $(BINDIR)/comp" ; else true ; fi
+# -@if [ -f $(BINDIR)/dist ] ; then \
+ echo "Collision on $(BINDIR)/dist" ; else true ; fi
+# -@if [ -f $(BINDIR)/file ] ; then \
+ echo "Collision on $(BINDIR)/file" ; else true ; fi
+ -@if [ -f $(BINDIR)/folder ] ; then \
+ echo "Collision on $(BINDIR)/folder" ; else true ; fi
+ -@if [ -f $(BINDIR)/forw ] ; then \
+ echo "Collision on $(BINDIR)/forw" ; else true ; fi
+ -@if [ -f $(BINDIR)/inc ] ; then \
+ echo "Collision on $(BINDIR)/inc" ; else true ; fi
+# -@if [ -f $(BINDIR)/mail ] ; then \
+ echo "Collision on $(BINDIR)/mail" ; else true ; fi
+ -@if [ -f $(BINDIR)/news ] ; then \
+ echo "Collision on $(BINDIR)/news" ; else true ; fi
+ -@if [ -f $(BINDIR)/next ] ; then \
+ echo "Collision on $(BINDIR)/next" ; else true ; fi
+ -@if [ -f $(BINDIR)/pick ] ; then \
+ echo "Collision on $(BINDIR)/pick" ; else true ; fi
+ -@if [ -f $(BINDIR)/prev ] ; then \
+ echo "Collision on $(BINDIR)/prev" ; else true ; fi
+ -@if [ -f $(BINDIR)/prompter ] ; then \
+ echo "Collision on $(BINDIR)/prompter" ; else true ; fi
+ -@if [ -f $(BINDIR)/repl ] ; then \
+ echo "Collision on $(BINDIR)/repl" ; else true ; fi
+ -@if [ -f $(BINDIR)/rmf ] ; then \
+ echo "Collision on $(BINDIR)/rmf" ; else true ; fi
+ -@if [ -f $(BINDIR)/rmm ] ; then \
+ echo "Collision on $(BINDIR)/rmm" ; else true ; fi
+ -@if [ -f $(BINDIR)/scan ] ; then \
+ echo "Collision on $(BINDIR)/scan" ; else true ; fi
+ -@if [ -f $(BINDIR)/send ] ; then \
+ echo "Collision on $(BINDIR)/send" ; else true ; fi
+ -@if [ -f $(BINDIR)/show ] ; then \
+ echo "Collision on $(BINDIR)/show" ; else true ; fi
+ -@if [ -f $(MHDIR) -o -d $(MHDIR) ] ; then \
+ echo "$(MHDIR) already exists!"; else true ; fi
+
+install:
+ cd progs; make install
+ cd support; make install
+ cd man; make install
+
+pinstall:
+ cd progs; make pinstall
+
+distribution:
+ cd support; make distribution
+ cd subs; make distribution
+ cd strings; make distribution
+ cd progs; make distribution
+
+clean:
+ cd support; make clean
+ cd subs; make clean
+ cd strings; make clean
+ cd progs; make clean
--- /dev/null
+To install mh, read the file 'MHgenerate'
+
+The documentation is somewhat in transition.
+In the DOC directory you will find the original Rand
+report on mh, but since then we have generated man pages
+which will be found in the 'man' directory and are
+more current.
--- /dev/null
+11/14/79
+ Allow complex boolean expressions in "pick"
+
+11/14/79
+ Add profile switches that will "answer" prompts,
+ sa "Draft exists, delete?"
+
+11/14/79
+ Have the stand-alone "anno" prompt for component and text.
+
+3/19/80
+ More elaborate "<command> -help". (But see objections in
+ /r/phyl/Mail/MH/2)
+
+10/6/80
+ MH should be able to pass the terminal type to the editor.
+
+10/23/80
+ Mail sent to mailing list aliases should also be sent to "news"
+ (Complex problem--but see BSB's msg /r/phyl/Mail/MH/134)
+
+11/21/80
+ Allow a "delete-after: <date>" component to MH; have a
+ daemon go thru everyone's MH folders and delete stale
+ messages. (see /r/phyl/Mail/MH/45...)
+
+11/21/81
+ Add a -noformat option to mhl--to get rid of " at RAND-UNIX"
+ when the message is listed.
+
+1/13/81
+ Have a file "/etc/Newsgroups" with lists of people
+ who should see certain news, so that systems personnel
+ can decide who should see certain topics and not have to
+ alter .mh_profiles.
+
+1/15/81
+ "ali -user" to give the reverse info from "ali aliasname";
+ viz, given a user, what aliases will send mail to him.
+
+1/20/81
+ "repl -form formfile"
+
+ or
+
+ There could .mh_profile entries that specify the
+ defaults for the various components for messages,
+ and all programs like comp & forw could look to
+ those instead of looking to a 'compform' or the like.
+
+ Examples:
+ From-Component: dave-yost
+ Fcc-Component: inbox
+
+1/26/81
+ Link messages instead of copying them
+
+1/29/81
+ Have "news -folder" change your current folder to the 1st unread
+ news folder, thus allowing you to use all the usual MH commands on it.
+
+2/3/81
+ "news -inc"
+
+2/9/81
+ "All plain files that now reside in 'Mail' should live in a
+ subdirectory like 'Mail/M'. Now I can unprotect the 'Mail'
+ directory, so that I can selectively grant snoop permission on any
+ folder without fear of making my other miscellaneous files like
+ 'draft' vulnerable. All I have to do is protect 'Mail/M'." --Dave
+
+2/16/81 FROM BERKELEY
+
+
+ Date: 3 Feb 1981 15:57:05-PST
+ From: CSVAX.kas at Berkeley
+ Message-ID: <601.350091987@CSVAX.Berkeley>
+ To: Day@Rand-Unix, Urban@Rand-Unix
+ Subject: Re: Updated MH to run in 4bsd environment
+ In-reply-to: Your message of 27 Jan 1981 2011-PST (Tuesday).
+ Fcc: mh
+
+ I have finished making the new version of MH run in our 4bsd
+ environment. That is, our version of MH runs compatibly with
+ the standard v7 mail program, the Berkeley Mail, UNIX sndmsg, msg,
+ and others. Some of the things I encountered may be of use to
+ you in making your distribution of MH easier to install in 4bsd systems.
+
+ So here they are:
+
+ ali.c Changed to use a #define for the MailAlias file.
+ Should really have created a new strings file for it.
+
+ annotate.c Now uses the character defined by CBACKUP instead of ,
+ for the backup convention. We have a line of the form:
+
+ 40 4 * * * find / -name '#*' -atime +3 -exec rm -f {} \;
+
+ in /usr/lib/crontab and it seemed easier to make MH
+ obey that than to convince users to use ,
+
+ conflict.c Used to reference ``struct dir'' which in our system at
+ least is defined in /usr/include/sys/dir.h as
+ ``struct direct''
+
+ dist.c Changed to use CBACKUP, instead of comma
+
+ folder.c Removed fflush(stdout) after each line of output. This makes
+ the program appear to run faster.
+
+ forw.c Changed to use CBACKUP, not comma
+
+ inc.c Changed to call a program unixtomh (described later) which
+ reads mail in standard unix format and converts it to MH
+ format. Now has -file filename flag to read messages
+ from a file (many users already have mbox files full of
+ unix format mail. they can do inc -file mbox +mbox to
+ convert this to an MH folder). Also has -keep to
+ prefer close(creat(mailboxname, 0600)) to unlink to
+ help users preserve a non-publically readable mode on
+ their mail drop.
+
+ mail.c Renamed mhmail.c to avoid confusion
+
+ mhl.c Changed to use termlib to clear terminal screen correctly.
+ Fixed its argument processing so it won't try to open flag
+ arguments as files.
+
+ news.c s/struct dir/struct direct/
+
+ rmf.c Uses CBACKUP instead of comma
+
+ rmm.c Uses CBACKUP instead of comma
+
+ scan.c Has -reverse flag to look at headers newest first. A user
+ with a HUGE inbox demanded this.
+
+ send.c Uses CBACKUP instead of comma
+
+ unixtomh.c Created program to read unix format mail and put it in MH
+ format. This is invoked by inc.
+
+ mh.h Although this is the wrong place to do it, added CBACKUP
+ #define to give backup character. Should really be in
+ strings.
+
+ mailsys.h Changed path names to end with / to satisfy the assumption
+ in inc.c that they look that way.
+
+ deliver.c Now makes temporary file in /tmp, not /usr/tmp/mh,
+ doesn't check validity of network addressees,
+ Only outputs From: and Date: in fcc copy of message,
+ invokes /etc/delivermail on all recipients to actually
+ deliver the mail, removed putdate() routine in favor
+ of shared (with unixtomh) version in subs, and now
+ uses #define MAILALIASES.
+
+ Also, a couple of minor notes: we do not have a strings.h file in
+ /usr/include, which I assume gave the return types of routines like
+ rindex() and friends. A number of files include system files as, eg:
+
+ #include <types.h>
+ #include <stat.h>
+
+ this requires that you give the preprocessor flag -I/usr/include/sys
+ for it to be found. This creates problems for the make depend stuff
+ since include files are not necessarily in /usr/include. I got around
+ this by simply editing out the header file dependencies from the
+ Makefiles.
+
+ Finally, to get around the conflict between /usr/bin/file and the MH file
+ command, I made a program fakefile which examines its arguments. If any
+ begin with +, it invokes MH file, else /usr/bin/file. This seems to
+ work fine.
+
+ I have everything sccs'd so I can send you sccs source, diffs, new source
+ or whatever if you like.
+
+ Kurt Shoens
+
+
+2/17/81
+ Sort folders by time-received.
+
+2/17/81
+ Whenever a news topic is created, a suitable message to news.everyone
+ should announce that fact and try to sell users on the new topic.
+
+2/18/81
+ "... I've been hacking up an MH to
+ put the attributes in the file names, format n-aaa, where n is
+ the message number, and the a's are the attribute characters,
+ initially, only 's' for 'seen' being implemented. This is VERY
+ efficient, and only runs into the original problems Norm pointed
+ out...the name is difficult to guess from an environment which
+ does not allow wild-cards, such as inside the editor.
+
+ "Personally, I think the advantage gained is well worth the
+ messiness. I would like to be able to say "scan unseen",
+ or "file seen +handled", etc. This can't be done in ANY
+ other fashion under UNIX without losing lots of other important
+ features, such as preservation on copy."
+
+ /Bruce
+
+2/18/81
+ Allow personal alias files.
+
+ Except---
+ "No personal aliases because there ain't no way to reply!
+ The 733 syntax is totally botched on "file inclusion".
+ There should be a meta-syntax for using a file as an
+ address, which deliver programs ALL AROUND THE NET could
+ use for replies."
+ /B
+
+ But---
+ "You could have personal aliases if they were expanded into the
+ message."
+ --dave
+
+2/19/81
+ "Screw -time and -numdate. How about a -display <string> option,
+ where <string> is a printf-like format that dictates exactly the
+ way you want the scan to look. Something like:
+
+ scan -display '%3(num) %2(mo)/%2(day)/%2(yr) \
+ %2(hour):%2(min)-(timezone) \
+ %10(from) %40(subject)%(incl)(body)'
+
+ "It has been suggested that the 'ls' command should have an option
+ like this, too."
+
+ --dave
+
+2/19/81
+ Scan and inc should display control characters in readable form.
+ (Except, for example, ^G, ^I)
+
+2/23/81
+ encrypted mail
+
+2/23/81
+ Integrate MH file naming conventions with Unix naming conventions.
+ So, for example, when in the editor, you could reference
+ "last" or "+junk/14"
+
+2/24/81
+ "Replied-to" Subject fields should somehow keep track of
+ the "generation" of the replied-to message.
+
+2/26/81 Dave Clemans, SDC
+
+ Because the ISC system is a UNIX V6 variant, and MH is set up for
+ V7, there are a few differences:
+
+ Because of name conflicts between MH programs and ISC programs,
+ mail
+ news
+ file
+ are in the directory /misc/bin. The version of file in /misc/bin
+ is a preprocessor; if its argument list has an argument with a '+'
+ as its first character, it calls /usr/bin/file.msg, otherwise it
+ calls /bin/file.
+
+ MH wants to look at a few environment variables, which don't exist
+ on UNIX V6. They are simulated using the global shell variables of
+ the SDC-extended "Harvard" shell. For people who use the "Harvard"
+ shell (hsh), this procedure is handled automatically. For people
+ who use the Berkeley C shell (csh) or people who use the ISC shell,
+ a special command has to be run at least once, and possible every
+ time that you log in, depending on how often you change things.
+ What follows is a short description of that command:
+
+ /misc/bin/mhsetup <login name> <home directory> <search path>
+
+ Environment Variable
+ <login name> is your actual login name USER
+ <home directory> is your login directory HOME
+ <search path> is the PWB/UNIX style path PATH
+
+ There also has been a few extensions made to MH at SDC. A short
+ list of these are:
+
+ a. Registered mail: send has a -register and a -noregister switch.
+ A receipt is sent back to the sending user when the receiving
+ user types "inc" and a registered message is received. (Done by
+ adding a "Registered" component to the message)
+
+ b. Fcc: Multiple folder names are accepted in this component and
+ handled correctly.
+
+ c. Personal mailing lists: In addition to the mailing lists
+ accepted by the /etc/MailAliases file, users can maintain
+ private mailing lists. These are referenced by addresses of the
+ form "<path", where path is the name of the mailing list. It is
+ looked for first in the current directory, and then in the users
+ Mail directory. It should have the same format as a list of
+ addresses typed in by hand.
+
+ d. Automatic forwarding: If a user has accounts on multiple
+ machines, but only uses one of them on a regular basis, it is
+ possible to have all messages from those other machines
+ automatically forwarded to the machine that is used regularly.
+ The same database hook used by this is also used to provide full
+ names in addresses:
+ (i.e., Full Name <user at host>)
+ (Done by having a file with one line for each user, of the format:
+ <user> <flag> <address> :<Full Name>
+ <user> is the local user name
+ <flag> says whether or not to forward
+ <address> is the forwarding address
+ <Full Name> is the users full name)
+
+ e. Msg/Sndmsg: There are msg/sndmsg programs in /misc/bin that
+ look very similar to normal ARPAnet msg/sndmsg programs, but
+ which interface to MH.
+
+ f. Repl: repl has "-fccme" and "-nofccme" switches for making file
+ copies of replies to messages.
+
+ g. Next/Prev: next and prev have "-pr" and "-nopr" switches. They
+ have the same effect as the "-pr" and "-nopr" switches in show.
+
+ The "onstruct is recognized and handled correctly. The only
+ transport mechanism available currently is the Berkeley network (from
+ 2BSD).
+ (Hooks do exist to add others, specifically UUCP). Currently defined
+ host names are:
+ sdc-70 the R&D 11/70 system
+ sdc-net the 11/45 network support machine
+
+ Two other host names exist for sending mail into the ISC mail system.
+ These are "sdc-70x" and "local".
+
+ For any problems, or for more information, send a message to dgc
+ dgc
+
+ Dave Clemans
+ -----
+
+3/2/81
+ repl -use
+
+3/17/81
+ Delayed mail delivery: add a "Deliver-date:" header containing
+ the delivery date...
+
+3/18/81
+ "send" in the background
+
+4/5/81
+ Mail to terminals
+
+ "... the sender would decide which of the four possible
+ options to select:
+ 1. mail only
+ 2. send to terminal only
+ 3. send to terminal and also mail
+ 4. send to terminal if possible, otherwise mail
+
+ "Furthermore, messages added to your mailbox would indicate whether
+ they were sent as mail or tty messages, so you could discard
+ messages which were intended to be displayed on the the terminal."
+
+ --greep
+
+4/17/81
+ Automatic mail agents, per Dave Farber
+
+4/23/81
+ <command> -nochangedir
+
+5/7/81
+ bcc recipients should SEE the bcc header in their copy of
+ the message
+
+
+5/14/81
+ Repl should have an option that includes
+ the replied-to message in the body of the
+ new message, indented one tabstop, so you
+ can intersperse answers with original text.
+ (But see objections in mail subsequent to the
+ suggestion)
+
+5/26/81
+ scan -name; folder -name
+ to return full path names of message files
+
+6/1/81
+ You should be able to anti-alias a login id,
+ making the user unknown for mail delivery purposes.
+ username:<NUL>
+
+7/30/81
+ Scansub should insert ">>" if msg body all fits on the scan line.
+
+7/30/81
+ Speed MH up by having 2 interfaces: a monolithic environment
+ for speed in commonly used commands, and the current MH
+ environment for generality.
+
+8/4/81
+ Move all the scattered mail alias files to /usr/MailLists.
+ Also move /etc/MailAliases and /etc/mh to /usr.
+
+8/17/81
+ add a -noreorder switch to request that MH process the msg
+ list in the GIVEN order, not in sorted order.
+
+8/20/81
+ There should be a common LOGFILE to be written by srvrftp,
+ rmail, and deliver.
+
+8/20/81
+ An environment variable should be set so that MH can choose
+ an editor based on your terminal type.
+
+
+
+
+MAIL ROUTING
+
+ Modularize the delivery process so that new networks can
+ be easily incorporated (e.g., SU-DSN is on the arpanet as well as
+ the ethernet)
+
+ Host table lookup: "joe at destination"
+
+ Etc...
+
+9/12/81
+ From: wales at UCLA-Security (Rich Wales)
+ Subject: mail security and mailing to files/pipes
+
+9/16/81
+ From: greep at SU-DSN
+
+ How about an option in comp (along with "list", "edit", "quit", and
+ "send") to get a new shell? Sometimes I'm in the middle of composing
+ a message and realize there's some program I want to run.
+
+11/3/81
+ From: Dave-Yost at RAND-UNIX
+ Subject: 'message does not exist'
+
+ If I do something with cur and the message pointed to doesn't
+ exist, I think mh should automatically look for the next message.
+ Or at least it should be something I can opt for with an entry in
+ .mh_profile.
+
+ This I don't need:
+ % show # look at the current message
+ % rmm # decide to junk it
+ % ... # do some other work
+ % show # show current message if not deleted, else next
+ Message 18 doesn't exist.
+
+ --dave
+
+11/4/81
+ From: Dave-Yost at RAND-UNIX
+ Subject: mh vs mail or msg or ms or Berkmail or ...
+
+ I'll tell ya, I'm a fan of mh and everything, but
+ mh has GOT to be optionally available as a
+ monolithic program within which you give mh
+ commands.
+
+ (See /r/phyl/Mail/MH for discussion)
+
+11/24/81
+ SUBJECT: An mh argument to specify the profile file
+ From: norm at RAND-UNIX
+
+ What the world needs is for every mh command to have an optional
+ flag, say "-profile", which introduces an alternative file to be
+ used, for all purposes, instead of .mh_profile.
+
+ This capability has a number of obvious and less obvious
+ consequences that would make mh a much more powerful system and
+ seems to have little adverse impact when not used.
+
+
+1/24/82
+ Subject: mail aliases and automatic forwarding
+
+ MH should provide facilities for a user to
+ forward/unforward his mail somewhere easily.
+ This does NOT mean telling him that all he has
+ to do is write a shell procedure and install it
+ in his .mh_receive file. The MH command I am
+ proposing would do that for you, and do the
+ appropriate locking against race conditions.
+ You need to be able to divert your incoming mail,
+ and to set up other aliases to your login name--
+ in this case, the command should send a message
+ to a system administrator requresting the alias.
+
+ Bell mail allows a user to write, for example,
+ Forward to harpo!ber
+ in the beginning of your mail spool file to
+ forward mail. (Brian also points out that that is
+ also the ONLY aliasing that they provide.)
+ I don't think this is such a good idea, since
+ it requires knowledge of where the mail spool file is,
+ and is susceptible to a race condition if incoming mail
+ comes in while you are messing with the spool
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+struct mailname {
+ struct mailname *m_next;
+ char *m_text,
+ *m_headali, /***/
+ *m_mbox,
+ *m_at,
+ *m_host,
+ *m_hs, *m_he;
+ long m_hnum;
+ char m_nohost;
+} *getm();
+
+char *adrformat(), *getname(), *stdhost();
+
+struct hosts {
+ struct hosts *nh_next;
+ char *nh_name;
+ long nh_num;
+} hosts;
+
+#ifdef ARPANET
+long gethnum();
+#else
+#define HOSTNAME "(local)"
+#define HOSTNUM 0
+#endif
+/* If on the ARPANET, whoami.h should have these defined. */
+/* If not on the ARPANET, delete HOSTNAME, HOSTNUM from whoami.h */
--- /dev/null
+#
+# Proprietary Rand Corporation, 1981.
+# Further distribution of this software
+# subject to the terms of the Rand
+# license agreement.
+#
+
+# Remove the -DRAND elsewhere!
+# In ../mh.h: define ARPANET if you are on the arpanet.
+# In ../mh.h: define VMUNIX if you are running a berkeley system
+LIBJOBS=#-ljobs
+
+CFLAGS = -O $(A) # -m -DRAND
+# The following two must match entry in ../Makefile
+BINDIR = /usr/local
+MHDIR = /etc/mh
+MHTMP = /usr/tmp/mh
+LOCKDIR = /usr/spool/locks
+NETDIR = /usr/spool/netmail
+
+SUBS = ../subs/subs.a
+STRINGS = ../strings/strings.a
+
+LINT = lint
+
+# The 'dist' program is not ready yet, and so is not listed in the CMDS
+# See also ../man/Makefile
+CMDS = \
+ali \
+comp \
+file \
+folder \
+forw \
+inc \
+mail \
+mhpath \
+next \
+news \
+pick \
+prev \
+prompter \
+repl \
+rmf \
+rmm \
+scan \
+send \
+show
+
+MISC = \
+conflict \
+deliver \
+install-mh \
+mhl
+
+PROGS = $(CMDS) $(MISC) rmail
+
+CFILES = \
+adrformat.c \
+adrparse.c \
+ali.c \
+comp.c \
+conflict.c \
+deliver.c \
+dist.c \
+file.c \
+folder.c \
+forw.c \
+inc.c \
+install-mh.c \
+mail.c \
+mhl.c \
+mhpath.c \
+news.c \
+next.c \
+pick.c \
+prompter.c \
+repl.c \
+rmail.c \
+rmf.c \
+rmm.c \
+scan.c \
+scansub.c \
+send.c \
+show.c
+
+progs: $(PROGS)
+
+ali: ali.o $(SUBS)
+ $(CC) -o ali ali.o $(SUBS)
+
+comp: comp.o $(SUBS) $(STRINGS)
+ $(CC) -o comp comp.o $(SUBS) $(STRINGS)
+
+conflict: conflict.o $(SUBS)
+ $(CC) -o conflict conflict.o $(SUBS)
+
+deliver: deliver.o adrparse.o adrformat.o $(SUBS) $(STRINGS)
+ $(CC) -o deliver deliver.o adrparse.o adrformat.o $(SUBS) $(STRINGS)\
+ $(JOBSLIB)
+
+dist: dist.o annotate.o $(SUBS) $(STRINGS)
+ $(CC) -o dist dist.o annotate.o $(SUBS) $(STRINGS)
+
+file: file.o $(SUBS) $(STRINGS)
+ $(CC) -o file file.o $(SUBS) $(STRINGS)
+
+folder: folder.o $(SUBS) $(STRINGS)
+ $(CC) -o folder folder.o $(SUBS) $(STRINGS)
+
+forw: forw.o annotate.o $(SUBS) $(STRINGS)
+ $(CC) -o forw forw.o annotate.o $(SUBS) $(STRINGS)
+
+inc: inc.o scansub.o $(SUBS) $(STRINGS)
+ $(CC) -o inc inc.o scansub.o $(SUBS) $(STRINGS)
+
+install-mh: install-mh.o $(SUBS) $(STRINGS)
+ $(CC) -o install-mh install-mh.o $(SUBS) $(STRINGS)
+
+mail: mail.o $(SUBS) $(STRINGS)
+ $(CC) -o mail mail.o $(SUBS) $(STRINGS)
+
+mhpath: mhpath.o $(SUBS) $(STRINGS)
+ $(CC) -o mhpath mhpath.o $(SUBS) $(STRINGS)
+
+mhl: mhl.o $(SUBS) $(STRINGS)
+ $(CC) -o mhl mhl.o $(SUBS) $(STRINGS)
+
+news: news.o $(SUBS) $(STRINGS)
+ $(CC) -o news news.o $(SUBS) $(STRINGS)
+
+next: nexthdr.o next.o $(SUBS) $(STRINGS)
+ $(CC) -o next nexthdr.o next.o $(SUBS) $(STRINGS)
+
+pick: pick.o grep.o $(SUBS) $(STRINGS)
+ $(CC) -o pick pick.o grep.o $(SUBS) $(STRINGS)
+
+prev: prevhdr.o next.o $(SUBS) $(STRINGS)
+ $(CC) -o prev prevhdr.o next.o $(SUBS) $(STRINGS)
+
+prompter: prompter.o $(SUBS) $(STRINGS)
+ $(CC) -o prompter prompter.o $(SUBS) $(STRINGS)
+
+repl: repl.o annotate.o adrparse.o adrformat.o $(SUBS) $(STRINGS)
+ $(CC) -o repl repl.o annotate.o adrparse.o adrformat.o $(SUBS) $(STRINGS)
+
+rmail: rmail.o $(SUBS) $(STRINGS)
+ $(CC) -o rmail rmail.o $(SUBS) $(STRINGS)
+
+rmf: rmf.o $(SUBS) $(STRINGS)
+ $(CC) -o rmf rmf.o $(SUBS) $(STRINGS)
+
+rmm: rmm.o $(SUBS) $(STRINGS)
+ $(CC) -o rmm rmm.o $(SUBS) $(STRINGS)
+
+scan: scan.o scansub.o $(SUBS) $(STRINGS)
+ $(CC) -o scan scan.o scansub.o $(SUBS) $(STRINGS)
+
+send: send.o $(SUBS) $(STRINGS)
+ $(CC) -o send send.o $(SUBS) $(STRINGS)
+
+show: show.o $(SUBS) $(STRINGS)
+ $(CC) -o show show.o $(SUBS) $(STRINGS)
+
+lint:
+ -$(LINT) ali.c -v ../subs/subs-lc | tee ali.lint
+ -$(LINT) comp.c -v ../subs/subs-lc | tee comp.lint
+ -$(LINT) conflict.c -v ../subs/subs-lc | tee conflict.lint
+ -$(LINT) deliver.c adrparse.c adrformat.c -v ../subs/subs-lc | tee deliver.lint
+ -$(LINT) dist.c -v ../subs/subs-lc | tee dist.lint
+ -$(LINT) file.c -v ../subs/subs-lc | tee file.lint
+ -$(LINT) folder.c -v ../subs/subs-lc | tee folder.lint
+ -$(LINT) forw.c annotate.c -v ../subs/subs-lc | tee forw.lint
+ -$(LINT) inc.c scansub.c -v ../subs/subs-lc | tee inc.lint
+ -$(LINT) install-mh.c -v ../subs/subs-lc | tee install.lint
+ -$(LINT) mail.c -v ../subs/subs-lc | tee mail.lint
+ -$(LINT) mhl.c -v ../subs/subs-lc | tee mhl.lint
+ -$(LINT) mhpath.c -v ../subs/subs-lc | tee mhpath.lint
+ -$(LINT) news.c -v ../subs/subs-lc | tee news.lint
+ -$(LINT) pick.c -v ../subs/subs-lc | tee pick.lint
+ -$(LINT) prevhdr.c next.c -v ../subs/subs-lc | tee prev.lint
+ -$(LINT) prompter.c -v ../subs/subs-lc | tee prompter.lint
+ -$(LINT) repl.c replsubs.c -v ../subs/subs-lc | tee repl.lint
+ -$(LINT) rmf.c -v ../subs/subs-lc | tee rmf.lint
+ -$(LINT) rmm.c -v ../subs/subs-lc | tee rmm.lint
+ -$(LINT) scan.c scansub.c -v ../subs/subs-lc | tee scan.lint
+ -$(LINT) show.c -v ../subs/subs-lc | tee show.lint
+
+install: strip installprogs
+ -mkdir $(MHTMP)
+ chmod 777 $(MHTMP)
+ -mkdir $(MHDIR)
+ -mkdir $(LOCKDIR)
+ -mkdir $(NETDIR)
+ -chmod a+x $(MISC)
+ -cd $(MHDIR); rm -f $(MISC)
+ -cp $(MISC) $(MHDIR)
+ echo Now become root and \'make installroot\'
+
+installprogs:
+ -chmod a+x $(PROGS)
+ -cd $(BINDIR); rm -f $(CMDS) folders
+ -cp $(CMDS) $(BINDIR)
+ -cd $(BINDIR); ln folder folders
+
+installroot:
+ -cd $(BINDIR); chmod a+x $(CMDS)
+ -cd $(MHDIR); chmod a+x $(MISC)
+ /etc/chown root $(NETDIR)
+ chmod 755 $(NETDIR)
+ -rm -f /bin/rmail
+ /etc/chown root $(LOCKDIR)
+ chmod 777 $(LOCKDIR)
+ -cp rmail /bin
+# Setuid and Setgid:
+ -chmod 6755 /bin/rmail
+# Sticky Bit & Setgid: (?Setuid? PK)
+ -/etc/chown root $(MHDIR)/deliver;chmod 5755 $(MHDIR)/deliver
+# Sticky Bit:
+ -chmod 1755 $(BINDIR)/comp
+ -chmod 1755 $(BINDIR)/inc
+ -chmod 1755 $(BINDIR)/next
+ -chmod 1755 $(BINDIR)/prompter
+ -chmod 1755 $(BINDIR)/show
+
+uninstall:
+ -rmdir $(MHTMP)
+ -cd $(MHDIR); rm -f $(MISC)
+ -cd $(BINDIR); rm -f $(CMDS) folders
+
+strip:
+ -strip $(PROGS)
+
+chmod:
+ chmod a+x $(PROGS)
+
+pinstall:
+ -install -s comp $(BINDIR)/comp
+ -install -s file $(BINDIR)/file
+ -install -s folder $(BINDIR)/folder
+ -install -s forw $(BINDIR)/forw
+ -install -s inc $(BINDIR)/inc
+ -install -s mhl $(MHDIR)/mhl
+ -install -s mhpath $(BINDIR)/mhpath
+ -install -s next $(BINDIR)/next
+ -install -s pick $(BINDIR)/pick
+ -install -s prev $(BINDIR)/prev
+ -install -s prompter $(BINDIR)/prompter
+ -install -s repl $(BINDIR)/repl
+ -install -s rmf $(BINDIR)/rmf
+ -install -s rmm $(BINDIR)/rmm
+ -install -s scan $(BINDIR)/scan
+ -install -s send $(BINDIR)/send
+ -install -s show $(BINDIR)/show
+
+distribution: clean rmprogs
+
+rmprogs:
+ -rm -f $(PROGS)
+
+clean:
+ -rm -f *.o *.lint
+
+depend:
+ ../misc/depend.sh $(CFILES)
+
+
+###DEPENDENCIES Follow. Do not delete this line
+adrformat.o: /usr/include/stdio.h
+adrformat.o: ../mh.h
+adrformat.o: ../adrparse.h
+adrformat.o: /usr/include/ctype.h
+adrparse.o: /usr/include/stdio.h
+adrparse.o: /usr/include/whoami.h
+adrparse.o: ../mh.h
+adrparse.o: ../adrparse.h
+adrparse.o: /usr/include/imp.h
+adrparse.o: /usr/include/ctype.h
+ali.o: ../mh.h
+ali.o: /usr/include/stdio.h
+ali.o: /usr/include/ctype.h
+ali.o: /usr/include/pwd.h
+ali.o: /usr/include/sys/types.h
+comp.o: ../mh.h
+comp.o: /usr/include/stdio.h
+comp.o: /usr/include/strings.h
+comp.o: /usr/include/signal.h
+conflict.o: /usr/include/stdio.h
+conflict.o: /usr/include/ctype.h
+conflict.o: /usr/include/pwd.h
+conflict.o: /usr/include/grp.h
+conflict.o: /usr/include/sys/types.h
+conflict.o: /usr/include/sys/dir.h
+conflict.o: ../mh.h
+conflict.o: /usr/include/mailsys.h
+deliver.o: /usr/include/whoami.h
+deliver.o: ../mh.h
+deliver.o: ../adrparse.h
+deliver.o: /usr/include/stdio.h
+deliver.o: /usr/include/ctype.h
+deliver.o: /usr/include/pwd.h
+deliver.o: /usr/include/sys/types.h
+deliver.o: /usr/include/sys/timeb.h
+deliver.o: /usr/include/sys/stat.h
+deliver.o: /usr/include/signal.h
+deliver.o: /usr/include/strings.h
+deliver.o: /usr/include/mailsys.h
+deliver.o: /usr/include/time.h
+dist.o: ../mh.h
+dist.o: /usr/include/stdio.h
+dist.o: /usr/include/signal.h
+dist.o: /usr/include/strings.h
+dist.o: /usr/include/sys/types.h
+dist.o: /usr/include/sys/stat.h
+file.o: ../mh.h
+file.o: ../folder.h
+file.o: /usr/include/stdio.h
+folder.o: ../mh.h
+folder.o: /usr/include/stdio.h
+folder.o: /usr/include/sys/types.h
+folder.o: /usr/include/sys/stat.h
+folder.o: /usr/include/strings.h
+forw.o: ../mh.h
+forw.o: /usr/include/stdio.h
+forw.o: /usr/include/signal.h
+forw.o: /usr/include/strings.h
+forw.o: /usr/include/sys/types.h
+forw.o: /usr/include/sys/stat.h
+inc.o: ../mh.h
+inc.o: /usr/include/stdio.h
+inc.o: /usr/include/sys/types.h
+inc.o: /usr/include/sys/stat.h
+inc.o: /usr/include/errno.h
+inc.o: /usr/include/strings.h
+inc.o: /usr/include/signal.h
+inc.o: scansub.h
+install-mh.o: ../mh.h
+install-mh.o: /usr/include/stdio.h
+install-mh.o: /usr/include/sys/types.h
+install-mh.o: /usr/include/sys/stat.h
+mail.o: ../mh.h
+mail.o: /usr/include/stdio.h
+mail.o: /usr/include/signal.h
+mhl.o: /usr/include/ctype.h
+mhl.o: /usr/include/signal.h
+mhl.o: /usr/include/setjmp.h
+mhl.o: /usr/include/sgtty.h
+mhl.o: /usr/include/stdio.h
+mhl.o: ../mh.h
+mhpath.o: ../mh.h
+mhpath.o: /usr/include/stdio.h
+mhpath.o: /usr/include/strings.h
+mhpath.o: /usr/include/ctype.h
+news.o: ../mh.h
+news.o: /usr/include/stdio.h
+news.o: /usr/include/sys/types.h
+news.o: /usr/include/sys/stat.h
+news.o: /usr/include/sys/dir.h
+news.o: /usr/include/strings.h
+news.o: /usr/include/sys/timeb.h
+next.o: ../mh.h
+next.o: /usr/include/stdio.h
+next.o: /usr/include/strings.h
+pick.o: ../mh.h
+pick.o: ../folder.h
+pick.o: /usr/include/stdio.h
+pick.o: /usr/include/signal.h
+pick.o: /usr/include/sys/types.h
+pick.o: /usr/include/sys/stat.h
+prompter.o: ../mh.h
+prompter.o: /usr/include/stdio.h
+prompter.o: /usr/include/errno.h
+prompter.o: /usr/include/sgtty.h
+prompter.o: /usr/include/signal.h
+prompter.o: /usr/include/strings.h
+repl.o: /usr/include/whoami.h
+repl.o: ../mh.h
+repl.o: /usr/include/stdio.h
+repl.o: /usr/include/signal.h
+repl.o: /usr/include/strings.h
+repl.o: /usr/include/sys/types.h
+repl.o: /usr/include/sys/stat.h
+repl.o: ../adrparse.h
+rmail.o: ../mh.h
+rmail.o: /usr/include/whoami.h
+rmail.o: /usr/include/stdio.h
+rmail.o: /usr/include/sys/types.h
+rmail.o: /usr/include/sys/timeb.h
+rmail.o: /usr/include/time.h
+rmf.o: ../mh.h
+rmf.o: /usr/include/stdio.h
+rmf.o: /usr/include/strings.h
+rmm.o: ../mh.h
+rmm.o: /usr/include/stdio.h
+rmm.o: /usr/include/strings.h
+scan.o: ../mh.h
+scan.o: /usr/include/stdio.h
+scan.o: /usr/include/strings.h
+scan.o: scansub.h
+scansub.o: ../mh.h
+scansub.o: /usr/include/whoami.h
+scansub.o: /usr/include/stdio.h
+scansub.o: /usr/include/ctype.h
+scansub.o: /usr/include/time.h
+scansub.o: ../adrparse.h
+scansub.o: scansub.h
+send.o: ../mh.h
+send.o: /usr/include/stdio.h
+send.o: /usr/include/sys/types.h
+send.o: /usr/include/stat.h
+send.o: /usr/include/strings.h
+send.o: /usr/include/signal.h
+show.o: ../mh.h
+show.o: /usr/include/stdio.h
+show.o: /usr/include/st
\ No newline at end of file
--- /dev/null
+This directory contains Dave Yost's test versions
+of some mh commands.
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* THIS command is included wholesale by show.c, which calls
+ * its `main' rather than execing it when showproc is "mhl"
+ */
+
+#include <ctype.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sgtty.h>
+#ifndef INCLUDED_BY_SHOW
+#include <stdio.h>
+#include "../mh.h"
+#endif INCLUDED_BY_SHOW
+char *calloc();
+extern char *index();
+extern char *sprintf();
+
+char *ignores[25];
+char **igp = ignores; /* List of ignored components */
+char *parptr, *parse();
+char *fmtfile; /* User specified format file */
+char *folder; /* Name of folder messages are in */
+char *profargs[32]; /* Args extracted from profile */
+int ofilec; /* Count of real output file args */
+int ofilen; /* Number of output file */
+int ontty; /* Output to char device */
+int clearflg; /* Overrides format screen clear */
+int row, column; /* For character output routine */
+int alength, awidth; /* -length and -width args */
+char *oneline();
+int sigcatch();
+int exitstat;
+jmp_buf env;
+
+extern char _sobuf[]; /* MLW standard out buffer */
+char *strcpy();
+
+/* Defines for c_flags (see below) */
+#define NOCOMPONENT 01 /* Don't show component name */
+#define UPPERCASE 02 /* Display in all upper case */
+#define CENTER 04 /* Center line within width */
+#define CLEARTEXT 010 /* Clear text line--simply copy to output */
+#define PROCESSED 020 /* This item processed already */
+#define EXTRA 040 /* This message comp is an "extra" */
+#define HDROUTPUT 0100 /* This comp's hdr has been output */
+#define CLEARSCR 0200 /* Clear screen before each file */
+#define LEFTADJUST 0400 /* Left adjust mult lines of component */
+#define COMPRESS 01000 /* Compress text--ignore <lf's> */
+
+struct comp {
+ struct comp *c_next; /* Chain to next */
+ char *c_name, /* Component name */
+ *c_text, /* Text associated with component */
+ *c_ovtxt; /* Line overflow indicator text */
+ int c_offset, /* Left margin indent */
+ c_ovoff, /* Line overflow indent */
+ c_width, /* Width of field */
+ c_cwidth, /* Component width (default strlen(comp)) */
+ c_length; /* Length in lines */
+ short c_flags; /* Special flags (see above) */
+
+} *msghd, *msgtl, *fmthd, *fmttl,
+ /* Global contains global len/wid info */
+ global = { NULL, NULL, NULL, "", 0, 0, 80, 0, 40, 0 },
+ holder = { NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, NOCOMPONENT };
+
+/* Defines for putcomp subrutine mode arg */
+#define ONECOMP 0 /* Display only control comp name */
+#define BOTHCOMP 1 /* Display both comp names (conditionally) */
+
+/*ARGSUSED*/
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct comp *comp;
+ register char *cp, **ap;
+ FILE *fp;
+ char line[256], name[64];
+ int out();
+
+ invo_name = argv[0];
+ setbuf(stdout, _sobuf);
+ VOID signal(SIGQUIT, out);
+ ontty = gtty(1, (struct sgttyb *)name) != -1;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(getcpy(cp), " ", "\n");
+ VOID copyip(ap, profargs);
+/* procargs(ap);*/
+ procargs(profargs);
+ }
+ procargs(argv + 1);
+ if(!folder)
+ folder = getenv("mhfolder");
+ if(fmtfile) {
+ if((fp = fopen(m_maildir(fmtfile), "r")) == NULL) {
+ fprintf(stderr, "mhl: Can't open format file: %s\n",
+ fmtfile);
+ done(1);
+ }
+ } else if((fp = fopen(m_maildir(mhlformat), "r")) == NULL &&
+ (fp = fopen(mhlstdfmt, "r")) == NULL) {
+ fprintf(stderr, "mhl: Can't open default format file.\n");
+ done(1);
+ }
+ while(fgets(line, sizeof line, fp)) {
+ if(line[0] == ';') /* Comment line */
+ continue;
+
+ line[strlen(line)-1] = 0; /* Zap the <lf> */
+
+ if(line[0] == ':') { /* Clear text line */
+ comp = (struct comp *) calloc(1, sizeof (struct comp));
+ comp->c_text = getcpy(line+1);
+ comp->c_flags = CLEARTEXT;
+ comp->c_ovoff = -1;
+ comp->c_cwidth = -1;
+ goto fmtqueue;
+ }
+
+ parptr = line;
+ strcpy(name, parse());
+/*** printf("%s %c %s\n", name, *parptr, parptr+1); */
+ switch(*parptr) {
+
+ case '\0':
+ case ',':
+ case '=':
+ if(uleq(name, "ignores")) {
+ igp = copyip(brkstring(getcpy(++parptr), ",", NULLCP), igp);
+ continue;
+ }
+ parptr = line;
+ while(*parptr) {
+ if(evalvar(&global)) {
+ fmterr: fprintf(stderr, "mhl: format file syntax error: %s\n",
+ line);
+ done(1);
+ }
+ if(*parptr)
+ parptr++;
+ }
+ continue;
+
+ case ':':
+ comp = (struct comp *) calloc(1, sizeof (struct comp));
+ comp->c_name = getcpy(name);
+ comp->c_cwidth = -1;
+ comp->c_ovoff = -1;
+ while(*parptr == ':' || *parptr == ',') {
+ parptr++;
+ if(evalvar(comp))
+ goto fmterr;
+ }
+ fmtqueue: if(!fmthd)
+ fmthd = fmttl = comp;
+ else {
+ fmttl->c_next = comp;
+ fmttl = comp;
+ }
+ continue;
+
+ default:
+ goto fmterr;
+
+ }
+ }
+ if(clearflg == 1)
+ global.c_flags |= CLEARSCR;
+ else if(clearflg == -1)
+ global.c_flags &= ~CLEARSCR;
+ if(awidth) global.c_width = awidth;
+ if(alength) global.c_length = alength;
+ if(global.c_width < 5) global.c_width = 10000;
+ if(global.c_length < 5) global.c_length = 10000;
+ VOID fclose(fp);
+ if(!ofilec)
+ process(NULLCP);
+ else {
+ for(ap = profargs; *ap; ap++)
+ if(**ap)
+ process(*ap);
+ for(ap = argv+1; *ap; ap++)
+ if(**ap)
+ process(*ap);
+ }
+ done(exitstat);
+}
+
+
+evalvar(sp)
+ register struct comp *sp;
+{
+ register char *cp;
+ int c;
+ char name[32];
+
+ if(!*parptr)
+ return 0;
+ strcpy(name, parse());
+/***printf("evalvar: %s %c %s\n", name, *parptr, parptr+1); */
+ if(uleq(name, "width")) {
+ if(!*parptr++ == '=' || !*(cp = parse())) {
+missing: fprintf(stderr, "mhl: missing arg to variable %s\n",
+ name);
+ return 1;
+ }
+ sp->c_width = atoi(cp);
+ return 0;
+ }
+ if(uleq(name, "compwidth")) {
+ if(!*parptr++ == '=' || !*(cp = parse())) goto missing;
+ sp->c_cwidth = atoi(cp);
+ return 0;
+ }
+ if(uleq(name, "length")) {
+ if(!*parptr++ == '=' || !*(cp = parse())) goto missing;
+ sp->c_length = atoi(cp);
+ return 0;
+ }
+ if(uleq(name, "overflowtext")) {
+ if(!*parptr++ == '=') goto missing;
+ cp = parptr;
+ while(*parptr && *parptr != ':' && *parptr != ',') parptr++;
+ c = *parptr;
+ *parptr = 0;
+ sp->c_ovtxt = getcpy(cp);
+ *parptr = c;
+ return 0;
+ }
+ if(uleq(name, "offset")) {
+ if(!*parptr++ == '=' || !*(cp = parse())) goto missing;
+ sp->c_offset = atoi(cp);
+ return 0;
+ }
+ if(uleq(name, "overflowoffset")) {
+ if(!*parptr++ == '=' || !*(cp = parse())) goto missing;
+ sp->c_ovoff = atoi(cp);
+ return 0;
+ }
+ if(uleq(name, "nocomponent")) {
+ sp->c_flags |= NOCOMPONENT;
+ return 0;
+ }
+ if(uleq(name, "uppercase")) {
+ sp->c_flags |= UPPERCASE;
+ return 0;
+ }
+ if(uleq(name, "center")) {
+ sp->c_flags |= CENTER;
+ return 0;
+ }
+ if(uleq(name, "clearscreen")) {
+ sp->c_flags |= CLEARSCR;
+ return 0;
+ }
+ if(uleq(name, "leftadjust")) {
+ sp->c_flags |= LEFTADJUST;
+ return 0;
+ }
+ if(uleq(name, "compress")) {
+ sp->c_flags |= COMPRESS;
+ return 0;
+ }
+ return 1;
+}
+
+
+char *
+parse()
+{
+ static char result[64];
+ register char *cp;
+ register int c;
+
+ cp = result;
+ while(c = *parptr)
+ if(isalnum(c) || c == '.' || c == '-' || c == '_') {
+ *cp++ = c;
+ parptr++;
+ } else
+ break;
+ *cp = 0;
+ return result;
+}
+
+struct swit switches[] = {
+ "clear", 0, /* 0 */
+ "noclear", 0, /* 1 */
+ "folder folder", 0, /* 2 */
+ "form formfile", 0, /* 3 */
+ "length of page", 0, /* 4 */
+ "width of line", 0, /* 5 */
+ "help", 4, /* 6 */
+ 0, 0
+};
+
+procargs(ap)
+ register char **ap;
+{
+ register char *cp;
+
+ while(cp = *ap++)
+ if(*cp == '-') switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ done(1);
+ /* unknown */
+ case -1:fprintf(stderr, "mhl: -%s unknown\n", cp);
+ done(1);
+ /* -form format */
+ case 0: clearflg = 1; /* -clear */
+ ap[-1] = "";
+ break;
+
+ case 1: clearflg = -1; /* -noclear */
+ ap[-1] = "";
+ break;
+
+ case 2: if(!(folder = *ap++) || *folder == '-') {
+ missing: fprintf(stderr, "mhl: Missing arg for %s\n", ap[-2]);
+ done(1);
+ }
+ ap[-2] = ""; ap[-1] = "";
+ break;
+
+ case 3: if(!(fmtfile = *ap++) || *fmtfile == '-')
+ goto missing;
+ ap[-2] = ""; ap[-1] = "";
+ break;
+ /* length */
+ case 4: if(!(cp = *ap++) || *cp == '-')
+ goto missing;
+ alength = atoi(cp);
+ ap[-2] = ""; ap[-1] = "";
+ break;
+ /* width */
+ case 5: if(!(cp = *ap++) || *cp == '-')
+ goto missing;
+ awidth = atoi(cp);
+ ap[-2] = ""; ap[-1] = "";
+ break;
+ /* -help */
+ case 6: help("mhl [switches] [files]", switches);
+ done(0);
+
+ } else
+ ofilec++;
+}
+
+FILE *fp;
+
+process(fname)
+ char *fname;
+{
+ register int state;
+ register struct comp *comp, *c2, *c3;
+ char *cp, **ip, name[NAMESZ], buf[BUFSIZ];
+
+ if(setjmp(env)) {
+ discard(stdout);
+ putchar('\n');
+ goto out;
+ }
+ VOID signal(SIGINT, sigcatch);
+ if(fname) {
+ if((fp = fopen(fname, "r")) == NULL) {
+ fprintf(stderr, "mhl: Can't open ");
+ perror(fname);
+ exitstat++;
+ VOID signal(SIGINT, SIG_IGN);
+ return;
+ }
+ } else
+ fp = stdin;
+ if(ontty) {
+ strcpy(buf, "\n");
+ if(ofilec > 1) {
+ if(ofilen)
+ printf("\n\n\n");
+ printf("Press <return> to list \"");
+ if(folder) printf("%s:", folder);
+ printf("%s\"...", fname);
+ VOID fflush(stdout);
+ strcpy(buf, "");
+ VOID read(1, buf, sizeof buf);
+ }
+ if(index(buf, '\n')) {
+ if(global.c_flags & CLEARSCR)
+ printf("\014\200");
+ } else
+ printf("\n");
+ } else if(ofilec > 1) {
+ if(ofilen)
+ printf("\n\n\n");
+ printf(">>> ");
+ if(folder) printf("%s: ", folder);
+ printf("%s\n\n", fname);
+ }
+
+ ofilen++;
+ row = column = 0;
+ msghd = 0;
+ for(state = FLD ; ;) {
+ state = m_getfld(state, name, buf, sizeof buf, fp);
+ switch(state) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ for(ip = ignores; *ip; ip++)
+ if(uleq(name, *ip)) {
+ while(state == FLDPLUS)
+ state = m_getfld(state, name, buf, sizeof buf, fp);
+ goto next;
+ }
+ for(c3 = msghd; c3; c3 = c3->c_next)
+ if(uleq(name, c3->c_name))
+ break;
+ if(c3) {
+ comp = c3;
+ comp->c_text = add(buf, comp->c_text);
+ } else {
+ comp = (struct comp *) calloc(1, sizeof (struct comp));
+ comp->c_name = getcpy(name);
+ comp->c_text = getcpy(buf);
+ comp->c_cwidth = -1;
+ comp->c_ovoff = -1;
+ }
+ while(state == FLDPLUS) {
+ state = m_getfld(state, name, buf, sizeof buf, fp);
+ comp->c_text = add(buf, comp->c_text);
+ }
+ for(c2 = fmthd; c2; c2 = c2->c_next)
+ if(uleq(c2->c_name, comp->c_name))
+ goto goodun;
+ comp->c_flags |= EXTRA;
+ goodun: if(!c3) {
+ if(!msghd)
+ msghd = msgtl = comp;
+ else {
+ msgtl->c_next = comp;
+ msgtl = comp;
+ }
+ }
+ if(state == FLDEOF)
+ goto doit;
+ continue;
+
+ default:
+ case LENERR:
+ case FMTERR:
+ fprintf(stderr, "Message format error!\n");
+ exitstat++;
+ return;
+
+ case BODY:
+ case BODYEOF:
+ case FILEEOF:
+ doit:
+ for(comp = fmthd; comp; comp = comp->c_next) {
+ if(comp->c_flags & CLEARTEXT) {
+ putcomp(comp, comp, ONECOMP);
+ continue;
+ }
+ if(uleq(comp->c_name, "messagename")) {
+ cp = concat(fname, "\n", NULLCP);
+ if(folder) {
+ holder.c_text = concat(folder, ":", cp, NULLCP);
+ free(cp);
+ } else
+ holder.c_text = cp;
+ putcomp(comp, &holder, ONECOMP);
+ free(holder.c_text);
+ holder.c_text = 0;
+ }
+ if(uleq(comp->c_name, "extras")) {
+ for(c2 = msghd; c2; c2 = c2->c_next)
+ if(c2->c_flags & EXTRA)
+ putcomp(comp, c2, BOTHCOMP);
+ continue;
+ }
+ if(uleq(comp->c_name, "body")) {
+ holder.c_text = buf;
+ putcomp(comp, &holder, ONECOMP);
+ holder.c_text = 0;
+ while(state == BODY) {
+ state = m_getfld(state, name, buf, sizeof buf, fp);
+ holder.c_text = buf;
+ putcomp(comp, &holder, ONECOMP);
+ holder.c_text = 0;
+ }
+ continue;
+ }
+ for(c2 = msghd; c2; c2 = c2->c_next)
+ if(uleq(c2->c_name, comp->c_name)) {
+ putcomp(comp, c2, ONECOMP);
+ break;
+ }
+ }
+ out:
+ if(fp)
+ VOID fclose(fp);
+ fp = NULL;
+ if(holder.c_text) cndfree(holder.c_text);
+ holder.c_text = 0;
+ for(c2 = msghd; c2; c2 = comp) {
+ comp = c2->c_next;
+ cndfree(c2->c_name);
+ cndfree(c2->c_text);
+ free( (char *)c2);
+ }
+ msghd = msgtl = NULL;
+ for(c2 = fmthd; c2; c2 = c2->c_next)
+ c2->c_flags &= ~HDROUTPUT;
+ VOID signal(SIGINT, SIG_IGN);
+ return;
+ }
+next: ;
+ }
+}
+
+int lm; /* Left Margin for putstr */
+int llim; /* line limit for this component */
+int wid; /* width limit for this comp */
+int ovoff; /* overflow offset for this comp */
+char *ovtxt; /* overflow text for this comp */
+int term; /* term from last oneline() */
+char *onelp; /* oneline() text pointer */
+
+putcomp(cc, c2, flag)
+ register struct comp *cc, *c2;
+ int flag;
+{
+ register char *cp;
+ int count, cchdr = 0;
+
+#ifdef DEBUGCOMP
+ printf("%s(%o):%s:%s", cc->c_name, cc->c_flags, c2->c_name,
+ c2->c_text);
+#endif
+ onelp = NULL;
+ lm = 0;
+ llim = cc->c_length? cc->c_length : -1;
+ wid = cc->c_width? cc->c_width : global.c_width;
+ ovoff = cc->c_ovoff >= 0 ? cc->c_ovoff : global.c_ovoff;
+ ovoff += cc->c_offset;
+ ovtxt = cc->c_ovtxt ? cc->c_ovtxt : global.c_ovtxt;
+ if(!ovtxt) ovtxt = "";
+ if(wid < ovoff + strlen(ovtxt) + 5) {
+ fprintf(stderr, "mhl: component: %s width too small for overflow.\n",
+ cc->c_name);
+ done(1);
+ }
+ if(cc->c_flags & CLEARTEXT) {
+ putstr(cc->c_text);
+ putstr("\n");
+ return;
+ }
+ if(cc->c_flags & CENTER) {
+ count = global.c_width;
+ if(cc->c_width) count = cc->c_width;
+ count -= cc->c_offset;
+ count -= strlen(c2->c_text);
+ if(!(cc->c_flags&HDROUTPUT) && !(cc->c_flags&NOCOMPONENT))
+ count -= strlen(cc->c_name) + 2;
+ lm = cc->c_offset+(count/2);
+ } else if(cc->c_offset)
+ lm = cc->c_offset;
+ if(!(cc->c_flags & HDROUTPUT) && !(cc->c_flags & NOCOMPONENT)) {
+ putstr(cc->c_name); putstr(": ");
+ cc->c_flags |= HDROUTPUT;
+ cchdr++;
+ if((count = cc->c_cwidth - strlen(cc->c_name) - 2) > 0)
+ while(count--) putstr(" ");
+ }
+ if(flag == BOTHCOMP && !(c2->c_flags & HDROUTPUT) &&
+ !(c2->c_flags & NOCOMPONENT)) {
+ putstr(c2->c_name); putstr(": ");
+ c2->c_flags |= HDROUTPUT;
+ }
+ if(cc->c_flags & UPPERCASE)
+ for(cp = c2->c_text; *cp; cp++)
+ if(islower(*cp))
+ *cp -= 'a' - 'A';
+ count = 0;
+ if(cchdr)
+ count = (cc->c_cwidth>=0) ? cc->c_cwidth : strlen(cc->c_name)+2;
+ count += cc->c_offset;
+ putstr(oneline(c2->c_text, cc->c_flags));
+/*** if(cc->c_flags & COMPRESS) printf("-1-"); /***/
+ if(term == '\n')
+ putstr("\n");
+ while(cp = oneline(c2->c_text, cc->c_flags)) {
+/*** if(cc->c_flags & COMPRESS) printf("-2-"); /***/
+ if(*cp) {
+ lm = count;
+ putstr(cp);
+ if(term == '\n')
+ putstr("\n");
+ } else
+ if(term == '\n')
+ putstr("\n");
+ }
+ c2->c_flags |= PROCESSED;
+}
+
+putstr(string)
+ register char *string;
+{
+ if(!column && lm > 0)
+ while(lm > 0)
+ if(lm >= 8) {
+ putch('\t');
+ lm -= 8;
+ } else {
+ putch(' ');
+ lm--;
+ }
+ lm = 0;
+ while(*string)
+ putch(*string++);
+}
+
+putch(ch)
+{
+ char buf[32];
+
+ if(llim == 0)
+ return;
+ switch(ch) {
+ case '\n':
+ if(llim > 0) llim--;
+ column = 0;
+ row++;
+ if(ontty && row == global.c_length) {
+ putchar('\007');
+ VOID fflush(stdout);
+ buf[0] = 0;
+ VOID read(1, buf, sizeof buf);
+ if(index(buf, '\n')) {
+ if(global.c_flags & CLEARSCR) {
+ putchar('\014');
+ putchar('\200');
+ }
+ row = 0;
+ } else {
+ putchar('\n');
+ row = global.c_length / 3;
+ }
+ return;
+ }
+ break;
+ case '\t':
+ column |= 07;
+ column++;
+ break;
+
+ case '\010':
+ column--;
+ break;
+
+ case '\r':
+ column = 0;
+ break;
+
+ default:
+ if(ch >= ' ')
+ column++;
+ }
+ if(column >= wid) {
+ putch('\n');
+ if(ovoff > 0)
+ lm = ovoff;
+ if(ovtxt)
+ putstr(ovtxt);
+ else
+ putstr("");
+ putch(ch);
+ return;
+ }
+ putchar(ch);
+}
+
+
+char *
+oneline(stuff, flgs)
+ char *stuff;
+{
+ register char *ret;
+ register char *cp;
+ int spc;
+
+ if(!onelp)
+ onelp = stuff;
+ if(!*onelp) {
+ onelp = 0;
+ return NULL;
+ }
+ ret = onelp;
+ term = 0;
+ if(flgs & COMPRESS) {
+ cp = ret;
+ spc = 0;
+ while(*onelp) {
+ if(*onelp == '\n' || *onelp == '\t' || *onelp == ' '){
+ if(*onelp == '\n' && !onelp[1]) {
+ term = '\n';
+ break;
+ } else if(!spc) {
+ *cp++ = ' ';
+ spc++;
+ }
+ } else {
+ *cp++ = *onelp;
+ spc = 0;
+ }
+ onelp++;
+ }
+ *onelp = 0;
+ *cp = 0;
+ } else {
+ while(*onelp && *onelp != '\n') onelp++;
+ if(*onelp == '\n') {
+ term = '\n';
+ *onelp++ = 0;
+ }
+ if(flgs&LEFTADJUST)
+ while(*ret == ' ' || *ret == '\t') ret++;
+ }
+ return ret;
+}
+
+
+sigcatch()
+{
+ longjmp(env, 1);
+}
+
+
+out()
+{
+ putchar('\n');
+ VOID fflush(stdout);
+ exit(-1);
+}
+
+discard(io)
+register FILE *io;
+{
+ struct sgttyb sg;
+
+ if (ioctl(fileno (io), TIOCGETP, &sg) >= 0)
+ ioctl(fileno (io), TIOCSETP, &sg);
+ io->_cnt = BUFSIZ;
+ io->_ptr
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <strings.h>
+
+int vecp;
+int header = 1;
+char *vec[MAXARGS];
+struct msgs *mp;
+/* The minimum match numbers below are all at least 2 as
+/* a kludge to avoid conflict between switches intended for
+/* "show" and those that it passes on to pr, mhl, c, ...
+/**/
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "draft", 2, /* 1 */
+ "header", 2, /* 2 */
+ "noheader", 3, /* 3 */
+ "format", 2, /* 4 */
+ "noformat", 3, /* 5 */
+ "pr", 2, /* 6 */
+ "nopr", 3, /* 7 */
+ "help", 4, /* 8 */
+ 0, 0
+};
+
+extern char _sobuf[]; /* MLW standard out buffer */
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100];
+ register int msgnum;
+ register char *cp, **ap;
+ int msgp, drft, pr, format;
+ char *arguments[50], **argp;
+
+ invo_name = argv[0];
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ folder = (char *) 0;
+ pr = msgp = 0;
+ format = 1;
+ vecp = 1;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:vec[vecp++] = --cp; continue;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: drft = 1; continue; /* -draft */
+ case 2: header = 1; continue; /* -header */
+ case 3: header = 0; continue; /* -noheader */
+ case 4: format = 1; continue; /* -format */
+ case 5: format = 0; continue; /* -noformat */
+ case 6: pr = 1; continue; /* -pr */
+ case 7: pr = 0; vecp = 1; continue;/* -nopr */
+ case 8: /* -help */
+ help("show [+folder] [msgs] [switches] [switches for \"type\" or \"pr\" ]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = path(cp+1, TFOLDER);
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!m_find("path")) free(path("./", TFOLDER));
+ if(drft)
+ maildir = m_maildir("");
+ else {
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ }
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(drft) {
+ vec[vecp++] = draft;
+ goto doit;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(msgp)
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "show: potato pancakes.\n"); /* never get here */
+ goto leave;
+ }
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "show: more than %d messages for show-exec\n", MAXARGS-2);
+ goto leave;
+ }
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ vec[vecp++] = getcpy(m_name(msgnum));
+ m_replace(pfolder, folder);
+ if(mp->hghsel != mp->curmsg)
+ m_setcur(mp->hghsel);
+ if(vecp == 2 && header) {
+ printf("(Message %s:%s)\n", folder, vec[1]);
+ }
+doit:
+ VOID fflush(stdout);
+ vec[vecp] = 0;
+ {
+ register char *proc;
+ if(pr)
+ proc = prproc;
+ else if(format) {
+ putenv("mhfolder", folder);
+ if (!showproc) {
+ mhl(vecp, vec);
+ m_update();
+ done(0);
+ }
+ proc = showproc;
+ } else {
+ proc = "/bin/cat";
+ /* THIS IS INEFFICIENT */
+ /* what we really should do in this case is
+ /* copy it out ourself to save the extra exec */
+ }
+ m_update();
+ vec[0] = r1bindex(proc, '/');
+ execv(proc, vec);
+ perror(proc);
+ }
+ done(0);
+ leave:
+ m_update();
+ done(0);
+}
+
+#define switches mhlswitches
+#define INCLUDED_BY_SHOW
+#define main(a,b) mhl(a,b)
+
+#include "mhl.c"
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+
+struct st_fold {
+ char *f_name;
+ int f_reused;
+ struct msgs *f_mp;
+};
--- /dev/null
+#
+# Proprietary Rand Corporation, 1981.
+# Further distribution of this software
+# subject to the terms of the Rand
+# license agreement.
+#
+
+DESTMAN = /usr/man
+
+# 'dist.1' is not ready yet.
+MAN1 = \
+ali.1 \
+comp.1 \
+file.1 \
+folder.1 \
+forw.1 \
+inc.1 \
+mail.1 \
+mh.1 \
+mhl.1 \
+mhpath.1 \
+news.1 \
+next.1 \
+pick.1 \
+prev.1 \
+prompter.1 \
+repl.1 \
+rmail.1 \
+rmf.1 \
+rmm.1 \
+scan.1 \
+send.1 \
+show.1
+
+MAN5 = \
+mh-alias.5 \
+mh-mail.5 \
+netmail.5 \
+mh-profile.5
+
+MAN8 = \
+conflict.8 \
+deliver.8 \
+mailer.8
+
+install: uninstall
+ -cp $(MAN1) $(DESTMAN)/man1
+ -cp $(MAN5) $(DESTMAN)/man5
+ -cp $(MAN8) $(DESTMAN)/man8
+
+uninstall:
+ -cd $(DESTMAN)/man1; rm -f $(MAN1)
+ -cd $(DESTMAN)/man5; rm -f $(MAN5)
+ -cd $(DESTMAN)/man8; rm -f $(MAN8)
--- /dev/null
+.TH ALI 1 RAND
+.SH NAME
+ali \- list mail aliases
+.SH SYNOPSIS
+.B ali
+[
+.B \-l
+] name ...
+.SH DESCRIPTION
+.I Ali
+searches the mail alias file for each of the given
+\fIname\fRs.
+It creates a list of users for whom those
+\fIname\fRs
+are aliases, and writes that list on standard output.
+If the
+.B \-l
+option is specified, each username appears on a separate line;
+otherwise, the names are separated by commas and printed on
+as few lines as possible. Usernames are not repeated on the
+output list.
+.PP
+Each
+.I name
+is processed as described in mh-alias(5). After
+processing, any resulting names that do not appear
+in the password file are printed with an error message.
+.SH FILES
+/etc/passwd
+.br
+/etc/MailAliases
+.br
+/etc/group
+.SH SEE ALSO
+deliver(8),mh-alias(5)
--- /dev/null
+.TH COMP 1 RAND
+.SH NAME
+comp \- compose a message
+
+.SH SYNOPSIS
+.B comp
+\%[
+.B \-editor\ \fReditor] \%[
+.B \-form\ \fRformfile] \%[file] \%[
+.B \-use
+] \%[
+.B \-nouse
+] \%[
+.B \-help
+]
+
+.SH DESCRIPTION
+\fIComp\fP is used to create a new message to be mailed.
+If
+\fIfile\fP is not specified, the file named ``draft'' in the user's MH
+directory will be used.
+\fIComp\fR copies a message form to
+the file being composed and then invokes an editor on the
+file.
+The default editor is /bin/e, which may be overridden with
+the `\-editor' switch or with a profile entry ``Editor:''.
+
+The default
+message form contains the following elements:
+
+ To:
+ cc:
+ Subject:
+ ----------
+
+If the file named ``components'' exists in the user's MH directory,
+it will be used instead of this form.
+If `\-form
+formfile' is specified, the specified formfile (from the MH
+directory) will be used as the skeleton.
+The line of dashes
+or a blank line must be left between the header and the
+body of the message for the message to be identified properly when it is
+sent (see \fIsend(1)\fR).
+The switch `\-use' directs \fIcomp\fR to
+continue editing an already started message.
+That is, if a
+\fIcomp\fR (or \fIdist\fR, \fIrepl\fR, or \fIforw\fR) is terminated without
+sending the message, the message can be edited again via
+``comp \-use''.
+
+If the specified file (or draft) already exists, \fIcomp\fR will ask
+if you want to delete it before continuing.
+A reply of \fBNo\fR will abort the
+\fIcomp\fR, \fByes\fR will replace the existing draft with a blank
+skeleton, \fBlist\fR will display the draft, and \fBuse\fR will use it
+for further composition.
+
+Upon exiting from the editor, \fIcomp\fR will ask ``What now?''.
+The valid
+responses are \fBlist\fR, to list the draft on the terminal; \fBquit\fR, to
+terminate the session and preserve the draft; \fBquit delete\fR, to terminate,
+then delete the draft; \fBsend\fR, to send the message; \fBsend verbose\fR, to
+cause the delivery process to be monitored; \fBedit <editor>\fR, to invoke
+<editor> for further editing; and \fBedit\fR, to re-edit using the
+same editor that was used on the preceding round unless a profile
+entry ``<lasteditor>\-next: <editor>'' names an alternative editor.
+
+See \fImh-profile(5)\fR for further information
+about the how editors are used by MH.
+.SH FILES
+.ta 2.4i
+/etc/mh/components The message skeleton
+.br
+or <mh-dir>/components Rather than the standard
+.br
+$HOME/\*.mh\(ruprofile The user profile
+.br
+<mh-dir>/draft The default message file
+.br
+/usr/bin/send To send the composed message
+.SH PROFILE\ ELEMENTS
+Path: To determine the user's MH directory
+.br
+Editor: To override the default editor
+.br
+<lasteditor>\-next: To name an editor to be used
+ after exit from <lasteditor>
+sendproc: Program to use to send the message
+.SH SEE ALSO
+send(1), dist(1), repl(1)
+.SH DEFAULTS
+`file' defaults to draft
+.br
+`\-editor' defaults to /bin/e
+.br
+`\-nouse'
+.SH CONTEXT
+\fIComp\fR does not affect either the current folder or the current messa
\ No newline at end of file
--- /dev/null
+.TH CONFLICT 8 RAND
+.SH NAME
+conflict \- Search for alias/password conflicts
+.SH SYNOPSIS
+.B /etc/mh/conflict
+[\fB\-mail\fR\ name]
+.SH DESCRIPTION
+.I Conflict
+is a program which checks to see that inconsistencies between
+the Rand MH alias file (
+.I mh-alias(5)
+) and the
+.I password(5)
+file have not been introduced. In particular, a line in the
+alias file may be "tom: jones" (because the user "jones" likes to be
+called Tom), but if "tom" is also a valid user name for someone else, then
+that user will no longer receive any mail; his mail will be received
+by "jones" instead!
+.PP
+.I Conflict
+also checks for mailboxes in /usr/spool/mail which do not belong
+to a valid user.
+It assumes that no user name will start with `.',
+and thus ignores files in /usr/spool/mail which
+begin with `.'.
+It also checks for entries in the
+.I group(5)
+file which do not belong to a valid user, and for users who do
+not belong to any group in the group file. This last test is
+local to Rand, and will not be performed unless the \-DRAND flag
+was set at compile time.
+.PP
+If the
+.I \-mail
+flag is set, then the results will be sent to the specified
+.I name.
+Otherwise, the results are sent to the standard output.
+.PP
+.I Conflict
+should be run under
+.I Cron(1),
+or whenever system accounting takes place.
+.SH FILES
+/etc/MailAliases
+.br
+/etc/passwd
+.br
+/etc/group
+.br
+/usr/spool/mail/*
+.SH SEE ALSO
+mh-alias(5), passwd(5), group(5), ali(1)
--- /dev/null
+.TH DELIVER 8 RAND
+.SH NAME
+deliver \- deliver a message
+.SH SYNOPSIS
+.B /etc/mh/deliver
+[\fB\-deliver\fR user]
+[\fB\-verbose\fR] [\fB\-format\fR] [\fB\-msgid\fR]
+[\fB\-help\fR] [\fB\-noverbose\fR] [\fB\-noformat\fR] [\fB\-nomsgid\fR] file
+.SH DESCRIPTION
+.I Deliver
+is the program called by
+.I send(1)
+to deliver the message in
+.I file
+to a local or remote user. In fact,
+all of the functions attributed to
+.I send
+on its manual page are peformed by
+.I deliver,
+with
+.I send
+acting as a relatively simple preprocessor. Thus, it is
+.I deliver
+which parses the various header fields, appends From: and
+Date: lines, and maintains the correct locking on maildrop
+files.
+.I Deliver
+will not normally be called directly by the user.
+.PP
+.I Deliver
+searches the ``To:'', ``Bcc:'', and ``Fcc:'' header lines of
+the specified message for destination addresses, checks these
+addresses for validity, and formats them so as to conform to
+Arpanet Mail protocol, unless the
+.I \-noformat
+flag is set. This will normally cause ``AT local-site'' to
+be appended to each local destination address, as well
+as any local return addresses.. Destinations are
+of three types:
+.PP
+LOCAL MAIL (e.g. ``To: root''): The message is appended to the
+appropriate mailbox. The specified name may be mapped
+into a different user name if it matches an entry in the
+file /etc/MailAlias. See mh-alias(5) for additional details on the
+aliasing system..
+If the recipient user's home directory contains an
+executable or shell file named .mh\(rureceive, that program will be
+called via
+
+ execlp (prog, prog, tmpfil, mail, home, alias, 0)
+
+where prog is the receive program, tmpfil is a file in
+/usr/tmp which is the mail to be received, mail is the path of
+the user's mail drop (/usr/spool/mail/name), home is the
+$HOME directory of the user, and alias is the string that matched
+the first in a sequence of local aliases. File descriptor 3 will have
+tmpfil opened on it read only. These are all the RECEIVER'S
+parameters, not the sender's. Also, the environment is set up
+with appropriate values for HOME and USER.
+.PP
+ARPANET MAIL (e.g. ``To: root@bbn-unix''): A copy of the message is
+left as a uniquely-named file
+in the Arpanet mail queue directory (/usr/spool/netmail/),
+with the text prepended
+by a list of the network addresses of the recipients. The
+format of this queue file is given in
+.I netmail(5).
+The file is picked up by an Arpanet mailer daemon (
+.I mailer(8)
+)
+for later processing.
+.PP
+UUCP MAIL (e.g. ``To: ucbvax!root''): Uux(1) is forked with the
+.I file
+as
+its standard input, so as to execute mail(1) at the remote site.
+Thus, a message with a field such as given in the example would
+be given as standard input with a command line of
+
+ uux \- ucbvax!rmail root
+
+Rmail is assumed to be linked to mail(1) (or an equivalent program
+such as the UC Berkeley or Bell mail programs)
+so as to correctly deliver the
+message at the remote site.
+.PP
+It is possible to have all three types of destinations in the various
+destination fields of the message; each destination is processed
+separately. It is also possible to mix destinations from the
+two delivery networks. For example, one might specify a destination
+of ``csvax!root@Berkeley''. However, there is an ambiguity here as
+to whether
+.I deliver
+should attempt to use the Arpanet to send the message to Berkeley
+with ``csvax!root'' as the recipient, or whether it should use uux
+to tell csvax to deliver mail to ``root@Berkeley''. The choice
+is determined by a compile-time constant which tells whether
+or not the local machine is on the Arpanet. If it is, the message
+is sent via the Arpanet to the remote host, which presumably
+forwards the message via uux. Otherwise the at-sign is given
+no special treatment,
+and the message is sent via uux.
+.PP
+If the
+.B \-deliver
+flag is set,
+.I deliver
+will attempt to send the message to the appropriate user
+with no formatting or header processing. As this is primarily
+for the use of the
+.I rmail(1)
+command, use of this flag is restricted to the super-user.
+.ta 2.4i
+.SH FILES
+/usr/spool/mail/* Recipient mail drop
+.br
+/usr/spool/locks/* Lockout for the mail drop
+.br
+/usr/spool/netmail/* Arpanet mail queue
+.br
+/usr/spool/mailt/* Arpanet temp mail queue
+.br
+/usr/tmp/mh/locsXXXX.tmpTemporary local output file
+.br
+/usr/tmp/mh/uulcXXXX.tmpTemporary uucp output file
+.br
+/etc/MailAliases Alias list
+.SH PROFILE COMPONENTS
+fileproc: Used for Fcc: processing
+.SH SEE ALSO
+\fIThe MH Message Handling System: User's Manual\fR
+by B. Borden, R. Gaines, and N. Shapiro
+.br
+\fIStandard for the Format of ARPA Network Test Messages\fR
+by D. Crocker, J. Vittal, K. Pogran, and D. Henderson, Jr.
+.br
+send(1)
+.br
+mail(1)
+.br
+rmail(1)
+.br
+uux(1)
+.br
+netmail(5)
+.br
+mh-mail(5)
+.br
+mh-alias(5)
+.SH DEFAULTS
+.br
+`\-noverbose'
+.br
+`\-format'
+.br
+`\-nomsgid'
+.SH BUGS
+If the message is going through a series of hops (say, via UUCP links),
+the "From" field will not be adequate for a reply. Deliver should,
+but currently does not, formulate a "Reply-to:" field for such
+compicated cases.
--- /dev/null
+.TH DIST 1 RAND
+.SH NAME
+dist \- redistribute a message to additional addresses
+.SH SYNOPSIS
+\fBdist\ \fR
+\%[\fB+folder\fR]
+\%[msg]
+\%[\fB\-form\fR\ formfile]
+\%[\fB\-editor\fR\ editor]
+\%[\fB\-annotate\fR]
+\%[\fB\-noannotate\fR]
+\%[\fB\-inplace\fR]
+\%[\fB\-noinplace\fR]
+\%[\fB\-help\fR]
+.SH DESCRIPTION
+\fIDist\fR is similar to \fIforw\fR.
+It prepares the specified
+message for redistribution to addresses that (presumably) are
+not on the original address list.
+The file ``distcomps'' in the
+user's MH directory, or a standard form, or the file specified by
+`\-form formfile' will be used as the blank components file to
+be prepended to the message being distributed.
+The standard form
+has the components ``Distribute-to:'' and ``Distribute-cc:''.
+When
+the message is sent, ``Distribution-Date:\ date'',
+``Distribution-From:\ name'', and
+``Distribution-Id:\ id'' (if `\-msgid' is
+specified to \fIsend(1)\fR;) will be prepended to the outgoing message.
+Only those addresses in ``Distribute-To'', ``Distribute-cc'', and
+``Distribute-Bcc'' will be sent.
+Also, a ``Distribute-Fcc:\ folder''
+will be honored (see \fIsend(1)\fR).
+
+\fISend\fR recognizes a message as a redistribution message by the
+existence of the field ``Distribute-To:'', so don't try to
+redistribute a message with only a ``Distribute-cc:''.
+
+If the `\-annotate' switch is given, each message being
+distributed will be annotated with the lines:
+
+ Distributed:\ <<date>>
+ Distributed:\ Distribute-to: names
+
+where each ``to'' list contains as many lines as required.
+This annotation
+will be done only if the message is sent directly from \fIdist\fR.
+If the
+message is not sent immediately from \fIdist\fR (i.e., if it is sent later
+via \fIsend\fR),
+``comp \-use'' may be used to re-edit and send the constructed message, but
+the annotations won't take place.
+The '\-inplace' switch causes annotation to
+be done in place in order to preserve links to the annotated message.
+
+See \fIcomp(1)\fR for a description of the `\-editor' switch and for options
+upon exiting from the editor.
+See \fImh-profile(5)\fR for further information
+about the how editors are used by MH.
+.SH FILES
+.ta 2.4i
+/etc/mh/components The message skeleton
+.br
+or <mh-dir>/components Rather than the standard skeleton
+.br
+$HOME/.mh\(ruprofile The user profile
+.br
+<mh-dir>/draft The default message file
+.br
+/usr/ucb/send To send the composed message
+.SH PROFILE COMPONENTS
+Path: To determine the user's MH directory
+.br
+Editor: To override the use of /bin/ned as the default editor
+.br
+<lasteditor>\-next: To name an editor to be used
+ after exit from <lasteditor>
+.br
+sendproc: Program to use for Send
+.SH SEE ALSO
+comp(1), deliver(8)
+.SH DEFAULTS
+`+folder' defaults to the current folder
+.br
+`msg' defaults to cur
+.br
+`\-editor' defaults to /bin/ned
+.br
+`\-noannotate'
+.br
+`\-noinplace'
+.SH CONTEXT
+If a +folder is specified, it will become the current
+folder, and the current message will be set to the message
+being redistr
\ No newline at end of file
--- /dev/null
+.TH FILE 1 RAND
+.SH NAME
+file \- file message(s) in (an)other folder(s)
+.SH SYNOPSIS
+\fBfile \%[\fB\-\fRsrc\ +folder] \%[msgs] \%[\fB\-link\fR] \%[\fB\-preserve\fR] \%+folder\ ...
+\%[\fB\-nolink\fR] \%[\fB\-nopreserve\fR]
+\%[\fB\-file\fR\ file] \%[\fB\-nofile\fR] \%[\fB\-help\fR]
+.SH DESCRIPTION
+\fIFile\fR moves (\fImv\fR(1)) or links (\fIln\fR(1)) messages from a
+source folder into one or more destination folders.
+If you think
+of a message as a sheet of paper, this operation is not
+unlike filing the sheet of paper (or copies) in file cabinet
+folders.
+When a message is filed, it is linked into the
+destination folder(s) if possible, and is copied otherwise.
+As long
+as the destination folders are all on the same file system, multiple filing
+causes little storage overhead.
+This facility provides a good way to cross-file or multiply-index
+messages.
+For example, if a message is received from Jones about
+the ARPA Map Project, the command
+
+ file\0cur\0+jones\0+Map
+
+would allow the message to be found in either of the two
+folders `jones' or `Map'.
+
+The option `\-file file' directs \fIfile\fR to use the specified
+file as the source message to be filed, rather than a message from
+a folder.
+
+If a destination folder doesn't exist, \fIfile\fR will ask if you
+want to create one.
+A negative response will abort the file
+operation.
+
+`\-link' preserves the source folder copy of the message
+(i.e., it does a \fIln\fR(1) rather than a \fImv\fR(1)), whereas,
+`\-nolink' deletes the ``filed'' messages from the source
+folder.
+Normally, when a message is filed, it is assigned the
+next highest number available in each of the destination folders.
+Use of the `\-preserve' switch will override this message
+``renaming'', but name conflicts may occur, so
+use this switch cautiously.
+(See \fIpick\fR for more details on
+message numbering.)
+
+If `\-link' is not specified (or `\-nolink' is specified),
+the filed messages will be removed (unlink(2)) from the
+source folder.
+.SH IMPORTANT NOTE
+"File" already exists in many Unix systems as a program to check
+the type of a file. If the Rand MH system has been installed,
+that program will have been renamed to
+.I filetype(1).
+.SH FILES
+.ta 2.4i
+$HOME/\*.mh\(ruprofile The user profile
+.SH PROFILE COMPONENTS
+.br
+Path: To determine the user's MH directory
+.br
+Current-Folder: To find the default current folder
+.br
+Folder\-Protect: To set mode when creating a new folder
+.SH SEE ALSO
+show(1), folder(1)
+.SH DEFAULTS
+`\-src +folder' defaults to the current folder
+.br
+`msgs' defaults to cur
+.br
+`\-nolink'
+.br
+`\-nopreserve'
+.br
+`\-nofile'
+.SH CONTEXT
+If `\-src +folder' is given, it will become the
+current folder for future MH commands.
+If neither `\-link' nor
+`all' are specified, the current message in the source
+folder will be set to the last message specified; otherwise, the
+current message won't be changed.
--- /dev/null
+.TH FOLDER 1 RAND
+.SH NAME
+folder, folders \- set/list current folder/message
+.SH SYNOPSIS
+\fBfolder\fR \%[+folder] \%[msg] \%[\fB\-all\fR]
+\%[\fB\-fast\fR] \%[\fB\-nofast\fR] \%[\fB\-up\fR] \%[\fB\-down\fR]
+\%[\fB\-header\fR] \%[\fB\-noheader\fR] \%[\fB\-total\fR]
+\%[\fB\-nototal\fR] \%[\fB\-pack\fR] \%[\fB\-nopack\fR]
+\%[\fB\-help\fR]
+.br
+\fBfolders\fR
+.SH DESCRIPTION
+Since the MH environment is the shell, it is easy to lose
+track of the current folder from day to day.
+\fIFolder\fR will
+list the current folder, the number of messages in it, the
+range of the messages (low-high), and the current message within
+the folder, and will flag a selection list or extra files if they
+exist.
+An example of the output is:
+
+ inbox+ has 16 messages ( 3\- 22); cur= 5.
+
+If a `+folder' and/or `msg' are specified, they will
+become the current folder and/or message.
+An `\-all' switch
+will produce a line for each folder in the user's MH directory,
+sorted alphabetically.
+These folders are preceded by the read-only
+folders, which occur as \*.mh\(ruprofile ``cur\-'' entries.
+For example,
+
+.nf
+.ta .5i 2.5i 3.6i
+ Folder\ \ #\ of\ messages (\ range\ );\ cur msg (other files)
+ /fsd/rs/m/tacc\ \ has 35\ messages (1\-\035);\ cur=\ 23.
+/rnd/phyl/Mail/EP\ \ has 82\ messages ( 1\-108);\ cur=\ 82.
+ ff\ \ has 4\ messages (1\-\0\04);\ cur=\ \01.
+ inbox+\ has 16\ messages (3\-\022);\ cur=\ \05.
+ mh\ \ has 76\ messages (1\-\076);\ cur=\ 70.
+ notes\ \ has 2\ messages (1\-\0\02);\ cur=\ \01.
+ ucom\ \ has 124\ messages (1\-124);\ cur=\ \06; (select).
+
+ TOTAL=\0339\ messages\0in\0\07\0Folders.
+.re
+.fi
+
+The ``+'' after inbox indicates that it is the current folder.
+The ``(select)'' indicates that the folder ucom has a selection
+list produced by \fIpick\fR.
+If ``others'' had appeared in parentheses at
+the right of a line, it would indicate that there are files in
+the folder directory that don't belong under the MH file naming
+scheme.
+
+The header is output if either an `\-all' or a `\-header' switch
+is specified; it is suppressed by `\-noheader'.
+Also, if \fIfolder\fR
+is invoked by a name ending with ``s'' (e.g., \fIfolders\fR),
+`\-all' is assumed.
+A `\-total' switch will produce only the
+summary line.
+
+If `\-fast' is given, only the folder name (or names in the
+case of `\-all') will be listed.
+(This is faster because the
+folders need not be read.)
+
+The switches `\-up' and `\-down' change the folder to be the
+one above or below the current folder.
+That is, ``folder \-down''
+will set the folder to ``<current\-folder>/select'', and if the
+current folder is a selection-list folder, ``folder \-up'' will
+set the current folder to the parent of the selection-list.
+(See \fIpick(1)\fR for details on selection-lists.)
+
+The `\-pack' switch will compress the message names in a folder, removing
+holes in message numbering.
+.SH FILES
+.ta 2.4i
+$HOME/\*.mh\(ruprofile The user profile
+.br
+/bin/ls To fast-list the folders
+.SH PROFILE COMPONENTS
+Path: To determine the user's MH directory
+.br
+Current-Folder: To find the default current folder
+.SH SEE ALSO
+pick(1)
+.SH DEFAULTS
+`+folder' defaults to the current folder
+.br
+`msg' defaults to none
+.br
+`\-nofast'
+.br
+`\-noheader'
+.br
+`\-nototal'
+.br
+`\-nopack'
+.SH CONTEXT
+If `+folder' and/or `msg' are given, they will become the
+current folder and/or message.
--- /dev/null
+.so /usr/man/man1/folder.1
--- /dev/null
+.TH FORW 1 RAND
+.SH NAME
+forw \- forward messages
+.SH SYNOPSIS
+forw \%[+folder] \%[msgs] \%[\-editor\ editor] \%[\-form\ formfile]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+.SH DESCRIPTION
+\fIForw\fR may be used to prepare a message containing other
+messages.
+It constructs the new message from the components file
+or `\-form formfile' (see \fIcomp\fR), with a body composed of the
+message(s) to be forwarded.
+An editor is invoked as in \fIcomp\fR,
+and after editing is complete, the user is prompted before the message
+is sent.
+
+If the `\-annotate' switch is given, each message being
+forwarded will be annotated with the lines
+
+ Forwarded: \*(<<date\*(>>
+ Forwarded: To: names
+ Forwarded: cc: names
+
+where each \*(lqTo:\*(rq and \*(lqcc:\*(rq list contains as many lines as required.
+This annotation will be done only if the message is sent directly
+from \fIforw\fR.
+If the message is not sent immediately from \fIforw\fR,
+\*(lqcomp \-use\*(rq may be used in a later session to re-edit and send
+the constructed message, but the annotations won't take place.
+The `\-inplace' switch permits annotating a message in place in
+order to preserve its links.
+
+See \fIcomp(1)\fR for a description of the `\-editor' switch and for options
+upon exiting from the editor.
+See \fImh-profile(5)\fR for further information
+about the how editors are used by MH.
+.SH FILES
+.ta 2.4i
+/etc/mh/components The message skeleton
+.br
+or <mh-dir>/components Rather than the standard skeleton
+.br
+$HOME/\*.mh\(ruprofile The user profile
+.br
+<mh-dir>/draft The default message file
+.br
+/usr/bin/send To send the composed message
+.SH PROFILE COMPONENTS
+Path: To determine the user's MH directory
+.Ps
+.br
+Editor: To override the default editor
+.Ps
+.br
+Current-Folder: To find the default current folder
+.Ps
+.br
+<lasteditor>\-next: To name an editor to be used
+ after exit from <lasteditor>
+.SH SEE ALSO
+dist(1), send(1)
+.SH DEFAULTS
+`+folder' defaults to the current folder
+.br
+`msgs' defaults to cur
+.br
+`\-editor' defaults to /bin/ned
+.br
+`\-noannotate'
+.br
+`\-noinplace'
+.SH CONTEXT
+If a +folder is specified, it will become
+the current folder, and the current message will be set to
+the first message being forward
\ No newline at end of file
--- /dev/null
+.TH INC 1 RAND
+.SH NAME
+inc \- incorporate new mail
+.SH SYNOPSIS
+\fBinc\fR \%[+folder] \%[\fB\-audit\ \fRaudit-file] \%[\fB\-help\fR]
+\%[\fB\-changecur\fR] \%[\fB\-nochangecur\fR]
+ \%[\-time] \%[\-notime] \%[\-numdate] \%[\-nonumdate]
+.SH DESCRIPTION
+\fIInc\fR incorporates mail from the user's incoming mail drop
+into an MH folder.
+If `+folder' isn't specified,
+the folder named ``inbox'' in the user's MH directory will be used.
+The
+new messages being incorporated are assigned numbers starting
+with the next highest number in the folder.
+If the specified (or
+default) folder doesn't exist, the user will be queried prior to
+its creation.
+As the messages are processed, a \fIscan\fR listing
+of the new mail is produced.
+
+If the user's profile contains a ``Msg\-Protect: nnn'' entry, it
+will be used as the protection on the newly created messages,
+otherwise the MH default of 664 will be used.
+During all
+operations on messages, this initially assigned protection will
+be preserved for each message, so \fIchmod\fR(I) may be used to set a
+protection on an individual message, and its protection will be
+preserved thereafter.
+
+If the switch `\-audit audit-file' is specified (usually as a
+default switch in the profile), then \fIinc\fR will append a header
+line and a line per message to the end of the specified
+audit-file with the format:
+
+.nf
+.ti 1i
+\*(<<inc\*(>> date
+.ti 1.5i
+<scan line for first message>
+.ti 1.5i
+<scan line for second message>
+.ti 2.5i
+<etc.>
+.fi
+
+This is useful for keeping track of volume and source of incoming
+mail.
+Eventually, \fIrepl\fR, \fIforw\fR, \fIcomp\fR, and \fIdist\fR may also
+produce audits to this (or another) file, perhaps with
+``Message-Id:'' information to keep an exact correspondence history.
+``Audit-file'' will be in the user's MH directory unless a full
+path is specified.
+
+\fIInc\fR will incorporate even illegally formatted messages into the
+user's MH folder, inserting a blank line prior to the offending
+component and printing a comment identifying the bad message.
+
+In all cases, the \*.mail file will be zeroed.
+
+If the `\-time' switch is selected, the time of the message is shown
+after the date in the scan lines.
+If the `\-numdate' switch is selected,
+the date (and time if `\-time' is selected) of the message
+is shown in the scan lines as one long number
+made up of year, month, day, hour, minute.
+.SH FILES
+.ta 2.4i
+$HOME/\*.mh\(ruprofile The user profile
+.br
+/usr/spool/mail/* The user's mail drop
+.br
+<mh-dir>/audit-file Audit trace file (optional)
+.SH PROFILE COMPONENTS
+Path: To determine the user's MH directory
+.br
+Folder\-Protect: For protection on new folders
+.br
+Msg\-Protect: For protection on new messages
+.SH SEE ALSO
+deliver(8), mh-mail(5), scan(1), mail(1)
+.SH DEFAULTS
+`+folder' defaults to ``inbox''
+.br
+`-changecur'
+.br
+`\-notime'
+.br
+`\-nonumdate'
+.SH CONTEXT
+The folder into which the message is
+being incorporated will become the
+current folder, and the first message incorporated will be the
+current message unless the
+.B \-nochangecur
+option is specified.
+This leaves the context ready for a \fIshow\fR
+of the first new message.
+.SH BUGS
+The `\-numdate' option ignores tim
\ No newline at end of file
--- /dev/null
+
+.TH MAIL 1 RAND
+.SH NAME
+mail \- send or read mail
+.SH SYNOPSIS
+.B mail
+[[\fB\-subject\fR\ subject] [\fB\-cc\ \fRname ...] [\fB\-help\fR] user ...]
+.SH DESCRIPTION
+.I Mail
+is intended as a replacement for the standard Bell mail program
+(\fIbellmail(1)\fR), compatible with the Rand message-handling
+system, mh. When invoked without arguments, it simply
+execs
+.I inc(1)
+to incorporate new messages from the user's maildrop.
+When one or more users is specified, a message is read from
+the standard input and spooled to a temporary file.
+.I Mail
+then invokes
+.I deliver(8)
+with the name of the temporary file as
+its argument to deliver the message to the specified user.
+.PP
+The
+.B subject
+and
+.B cc
+switches can be used to insert the corresponding header components into
+the message to be delivered.
+.PP
+This program is intended for the use of programs
+such as
+.I at(1),
+which expect
+to automatically send mail to various users.
+Normally, real people will prefer to use
+.I comp(1)
+and
+.I send(1)
+to send messages.
+.SH FILES
+/etc/mh/deliver
+.br
+/tmp/mail*.tmp
+.br
+/usr/tmp/mh/lst*.tmp
+.SH SEE ALSO
+bellmail(1), rmail(1), send(1), inc(1), deliver(8)
--- /dev/null
+.TH MAILER 8 RAND
+.SH NAME
+mailer \- Send Arpanet mail
+.SH SYNOPSIS
+.B /etc/mailer
+[
+.B \-l
+] [
+.B \-v
+] [file ...]
+.SH DESCRIPTION
+.I Mailer
+is a program to send messages to remote Arpanet sites. If one or more
+.I file\fRs
+are specified,
+.I mailer
+will process
+those files as its only task. If no
+.I file
+is specified,
+.I mailer
+will attempt to process all files in the queue directory,
+/usr/spool/netmail.
+.PP
+The
+.B \-l
+flag causes output to be placed on standard output suitable
+for a log.
+.PP
+The
+.B \-v
+flag causes output to be placed on the standard output suitable
+for a user (as in the \-v option of
+.I deliver(8).
+The two flags should not be used together.
+.PP
+The format of message files is described in
+.I netmail(5).
+It should be noted that control lines for all of the recipients
+of a single message are maintained at the beginning of the file.
+Due to transient Arpanet failures, it is possible for some or
+all of the recipient lines to be marked as
+being in an as-yet-undelivered state.
+When all of the recipients have either accepted or rejected
+the message, it is removed.
+If a message has still not been disposed of after five days,
+it is considered undeliverable.
+.PP
+Messages may also become undeliverable for a number of other reasons,
+such as a "no such user" message from the foreign site. In any case,
+if a message is undeliverable, it is returned to the sender
+via
+.I mail(1)
+with a note prepended to explain the problem. Clearly, more than
+one such returned message may result from a single message file
+with multiple recipients.
+.PP
+.I Mailer
+should be invoked periodically by
+.I cron(8).
+Ten-minute intervals are not unreasonable.
+.SH FILES
+/usr/spool/netmail
+.br
+/dev/imp*
+.br
+/etc/hosttable
+.SH SEE ALSO
+deliver(8),netmail(5),mail(1),imp(4)
--- /dev/null
+.TH MH-ALIAS 5 RAND
+.SH NAME
+mh-alias \- alias file for mh message system
+.SH DESCRIPTION
+The Alias file for mail delivery is the file
+
+ /etc/MailAliases
+
+Each line of the alias file has the format:
+
+match : alias
+
+Where:
+
+ alias := simple-list
+.br
+ | "<" alias-file
+.br
+ | "=" UNIX-group
+.br
+ | "*"
+
+.br
+ simple-list := simple-name
+.br
+ | simple-list, simple-name
+
+.PP
+Alias-file is a fully qualified UNIX file name. UNIX-group is a
+group name from /etc/group. A simple-name is a local user login
+name, including only alphanumerics, `.' and `\-'. Throughout this
+file, case is ignored, except for alias-file names.
+.PP
+In match, a trailing * on a name will match anything. (See example
+below.)
+.PP
+The procedure for mail aliasing is:
+.br
+.HP 3
+1) Build a list of all addresses from the message to be
+delivered, eliminating duplicates.
+.br
+.HP 3
+2) For each line in the alias file, compare "match" against all
+of the existing addresses. If a match, remove the matched
+name from the address list, and add each new alias name to the
+address list if it is not already on the list.
+.PP
+Since the alias file is read line by line, forward references
+work, but backward references are not recognized, thus, there is
+no recursion.
+.PP
+\fBExample:\fR
+.br
+ Borden: bruce
+.br
+ Bruce: bsb
+.br
+ Wahrman: mike
+.br
+ ASRL: bsb, mike, obrien, giarla
+.br
+ UNIX-committee: < /usr/people/unix-committee
+.br
+ System: = sys
+.br
+ Everyone: *
+.br
+ news.*: news
+ ...
+.PP
+In the "unix-committee" example, the file "/usr/people/unix-
+committee" contains one simple-name, or a list of comma separated
+simple-names. A new-line will be treated as a blank in this
+file, s.a.
+.br
+ foo, fie,
+.br
+ fum, fiddle
+.PP
+In the "system" case, the names from the group "sys" will be used
+as the expanded name list.
+.PP
+In the "news.*" case, all names of the form "news.<anything>" will
+be mapped to "news". This is used for the MH news facility.
+.SH FILES
+/etc/MailAliases
+.SH SEE ALSO
+deliver(8),group(5),ali(1),
\ No newline at end of file
--- /dev/null
+.TH MH-MAIL 5 RAND
+.SH NAME
+mh-mail \- Message format for MH
+.SH DESCRIPTION
+.I MH,
+the Rand message-handling system, processes messages in
+a particular format. It should be noted that neither
+the Berkeley mailer nor the Bell mail program produces
+message files in precisely the correct format for
+.I mh.
+.PP
+Each user possesses a mail drop box which initially receives
+all messages processed by
+.I deliver(8).
+.I Inc(1)
+will read from that drop box and incorporate the new messages
+found there into the user's own mail folders. The mail drop
+box consists of one or more messages. To facilitate the
+separation of messages, each message begins and ends with
+a line consisting of nothing but four Control-A (octal 001)
+characters.
+.PP
+Each message consists of two parts: a header, consisting of
+one or more header lines, and a body, containing the actual
+text of the message. These parts are separated by an empty
+line, i.e. two consecutive Newline characters.
+Within MH, the header and body may be separated by a line
+consisting of dashes.
+.PP
+Each header item can be viewed as a single logical line of ASCII
+characters.
+If the text of a header item extends across several
+real lines, the continuation lines are indicated by leading
+spaces or tabs.
+.PP
+Each header item is called a component and is composed of a
+keyword or name, along with associated text.
+The keyword begins at the
+left margin, may contain spaces or tabs, may not exceed 63
+characters, and is terminated by a colon (:).
+Certain
+components (as identified by their keywords) must follow rigidly
+defined formats in their text portions.
+.PP
+The text for most formatted components (e.g., ``Date:'' and ``Message-Id:'')
+is produced automatically.
+The only ones entered by the
+user are address fields such as ``To:'', ``cc:'', etc.
+ARPA addresses
+are assigned mailbox names and host computer specifications.
+The
+rough format is ``mailbox at host'', such as ``Borden at Rand-Unix''.
+Multiple addresses are separated by commas.
+A missing host is
+assumed to be the local host.
+.PP
+Following is a list of header components that are considered
+meaningful to various MH programs.
+.TP 15
+.I Component
+.I Usage
+.br
+.TP
+Date:
+Added by
+.I deliver(8),
+contains date and time of delivery.
+.br
+.ns
+.TP
+From:
+Added by
+.I deliver(8),
+contains the userid of the sender. But see "Sender:"
+.br
+.ns
+.TP
+Sender:
+Added by
+.I deliver(8)
+in the event that the user has supplied a "From:" line,
+contains the userid of the sender.
+.br
+.ns
+.TP
+To:
+Contains address of recipient of message.
+.br
+.ns
+.TP
+cc:
+Contains addresses of additional recipients.
+.br
+.ns
+.TP
+Bcc:
+Still more recipients. However, the Bcc line is not
+copied onto the message as delivered, so these recipients
+are not listed.
+.br
+.ns
+.TP
+fcc:
+Causes
+.I deliver(8)
+to copy the message into the specified folder.
+.br
+.ns
+.TP
+Subject:
+Sender's commentary. It is displayed by
+.I scan(1).
+.br
+.ns
+.TP
+Message-ID:
+A unique message identifier glued on by
+.I deliver
+if the
+.B \-msgid
+flag is set.
+.br
+.ns
+.TP
+In-Reply-To:
+A commentary line added by
+.I repl(1)
+when replying to a message.
+.br
+.ns
+.TP
+Replied:
+Reply date added by
+.I repl(1)
+under the "annotate" option.
+.br
+.ns
+.TP
+Forwarded:
+Forwarding date added by
+.I forw(1)
+under the "annotate" option.
+.br
+.ns
+.TP
+Distribute-to:
+New recipients for a redistributed message processed
+by
+.I dist(1).
+.br
+.ns
+.TP
+Distribute-cc:
+Still more recipients. See "cc:".
+.br
+.ns
+.TP
+Distribute-bcc:
+Even more recipients. See "bcc:.
+.br
+.ns
+.TP
+Distribute-fcc:
+Copy distributed message into a folder. See "fcc:".
+.br
+.ns
+.TP
+Distribute-from:
+Added when redistributing a message.
+.br
+.ns
+.TP
+Distribution-date:
+Is to distribute-from as Date: is to From:.
+.br
+.ns
+.TP
+Distribution-id:
+Added if msgid option is in effect.
+.br
+.ns
+.TP
+Distributed:
+Annotation for
+.I dist(1)
+.SH FILES
+/usr/spool/mail/*
+.SH SEE ALSO
+\fIThe MH Message Handling System: User's Manual\fR
+by B. Borden, R. Gaines, and N. Shapiro
+.br
+\fIStandard for the Format of ARPA Network Test Messages\fR
+by D. Crocker, J. Vittal, K. Pogran, and D. Henderson, Jr.
--- /dev/null
+.TH MH\(ruPROFILE 5 RAND
+.SH NAME
+mh\(ruprofile \- User parameters for MH message handler
+.SH DESCRIPTION
+Each user of
+.I mh
+is expected to have a file named
+.B .mh\(ruprofile
+in his or her home directory. This file contains a set of
+user parameters used by some or all of the
+.I mh
+family of programs. Each line of the file is of the format
+.TP 15
+\fIprofile-component\fR: \fIvalue\fR
+The currently defined profile components are exemplified below:
+.TP
+Path: Mail
+Locates mh transactions in directory "Mail".
+.TP
+Current-Folder: inbox
+Keeps track of currently open folder.
+.TP
+Editor: /bin/e
+Defines editor to be used by
+.I comp(1),
+.I repl(1),
+.I forw(1),
+and
+.I dist(1).
+.br
+.B NOTE:
+.I repl(1)
+invokes the editor with two file arguments.
+The second is intended
+to be used as an `alternate' file.
+If the editor used doesn't have this feature, it must
+ignore the extra file argument and edit the first
+file argument.
+.TP
+Msg\-Protect: 644
+Defines octal protection bits for message files. See
+.I chmod(1)
+for an explanation of the octal number.
+.TP
+Folder\-Protect: 711
+Defines protection bits for folder directories.
+.TP
+\fIprogram\fR: default switches
+Sets default switches to be used whenever the mh program
+.I program
+is invoked. For example, one could override the
+ .I Editor:
+profile component when replying to messages by adding a
+component such as:
+.br
+ repl: -editor /bin/ed
+.TP
+cur\-\fIread-onlyfolder\fR: 172
+Keeps track of the last message seen in the specified read-only
+folder. In folders to which write access is permitted, the
+current-message value is kept in a file called "cur" within
+that folder.
+.TP
+news\-\fInews-topic\fR: 12
+Keeps track of the last message seen in the specified news topic.
+.TP
+News\-Topics: news topics
+Sets the news topics to be selected by default for the news program.
+.TP
+prompter\-next: ed
+Names the editor to be used on exit from
+.I prompter(1)
+.PP
+The following profile elements are used whenever an mh program
+invokes some other program such as
+.I file(1)
+or
+.I ls(1).
+The mh profile can be used to select alternate versions of these
+programs if the user wishes. The default values are given in
+the examples.
+.br
+ fileproc: /usr/ucb/file
+.br
+ installproc: /etc/mh/install-mh
+.br
+ lproc: /usr/ucb/c
+.br
+ lsproc: /usr/ucb/ls
+.br
+ mailproc: /usr/ucb/mail
+.br
+ prproc: /bin/pr
+.br
+ scanproc: /usr/ucb/scan
+.br
+ sendproc: /usr/ucb/send
+.br
+ showproc: /usr/ucb/c
+.TP
+ delete-prog: /bin/rm
+Normally,
+.I rmm(1),
+rather than removing a message in file X will rename the
+file to ,X. At Rand, a program known as the Midnight Skulker
+comes around once a day and eliminates files whose names begin
+with a comma. If a user provides a
+.I delete-prog
+profile entry, however, the specified program will be used
+instead to remove the file.
+.SH FILES
+$HOME/.mh\(ruprofile
+.SH SEE ALS
\ No newline at end of file
--- /dev/null
+.TH MH 1 RAND
+.SH NAME
+mh \- Rand Message Handler
+.SH DESCRIPTION
+.I MH
+is the name of the Rand Message Handling system.
+Rather then being a single comprehensive program,
+.I MH
+consists of a collection of fairly simple
+single-purpose programs to send, receive, save,
+and retrieve messages. The user should refer
+to the MH User's Manual and the pages for the
+.I MH
+programs in the Unix Programmers Manual.
+.SH SEE ALSO
+\fIThe MH Message Handling System: User's Manual\fR
+by B. Borden, R. Gaines, and N. Shapiro.
+Note: the online man pages supercede those in the
+current version of the MH User's Manual just cited.
+.br
+.nf
+.ta 1.5i
+ali (1) - list mail aliases
+comp (1) - compose a message
+dist (1) - redistribute a message to additional addresses
+file (1) - file message(s) in (an)other folder(s)
+folder (1) - set/list current folder/message
+folders (1) - list all folders
+forw (1) - forward messages
+inc (1) - incorporate new mail
+mail (1) - send and receive mail
+mhl (1) - produce formatted listings of MH messages
+mhpath (1) - print full pathnames of MH messages and folders
+news (1) - show news
+next (1) - show the next message
+pick (1) - select messages by content
+prev (1) - show the previous message
+prompter (1) - prompting editor front end
+repl (1) - reply to a message
+rmail (1) - send mail from a remote site
+rmf (1) - remove folder
+rmm (1) - remove messages
+scan (1) - produce a one-line-per-message scan listing
+send (1) - send a message
+show (1) - show (list) messages
+.br
+mh-alias (5) - alias file for mh message system
+mh-mail (5) - Message format for MH
+mh-profile (5) - User parameters for MH message handler
+netmail (5) - Arpanet mail queue
+.br
+conflict (8) - Search for alias/password conflicts
+deliver (8) - deliver a message
+mailer (8) - Send Arpanet mail
--- /dev/null
+.TH MHL 1 RAND(DRAFT)
+.SH NAME
+mhl \- Produce formatted listings of MH messages
+.SH SYNOPSIS
+\fBmhl
+[
+\fB\-clear\fR]
+[\fB\-noclear\fR]
+[\fB\-folder\fR\ folder]
+[\fB\-form\fR\ formfile]
+[\fB\-length\fR\ length]
+[\fB\-width\fR\ width]
+[\fB\-help\fR]
+[file ...]
+.SH DESCRIPTION
+.I Mhl
+is a formatted message listing program. It can be used as a
+replacement for "c" (the default message lister). As with c, each of
+the messages specified as arguments (or stdin) will be output. If more
+than one message file is specified, the user will be prompted prior to
+each one, and a <return> or <eot> will begin the output, with <return>
+clearing the screen (if appropriate), and <eot> suppressing the screen
+clear. An <interrupt> will abort the current message ouput, prompting
+for the next message (if there is one), and a <quit> will terminate the
+program (without core dump).
+.PP
+As in all MH programs, mhl looks for a line "mhl: args" in the user's
+profile, and thus allows tailored defaults. The switches are:
+.PP
+.ta 1.5i
+.br
+\-clear Clear screen each page
+.br
+\-noclear Don't clear screen each page
+.br
+\-folder folder Use this "folder" name
+.br
+\-form formfile Name of the format file
+.br
+\-length length Screen length
+.br
+\-width width Screen width
+.br
+\-help Standard help message
+.PP
+All of the functions these switches perform are affected or controlled
+by information elsewhere. That is, the format file can specify "clear",
+in which case, the command line switches will override. Also, the
+length and width can be specified in the format file, or default to
+40x80. The folder is used in constructing a message name (see special
+component "MessageName" below). If it is not specified in a switch, it
+is taken from the environment variable "mhfolder", which show, next,
+prev, and pick initialize appropriately.
+.PP
+If the form file is not specified, it is taken from the file
+"mhl.format" in the user's MH directory, and if that file doesn't exist,
+it is taken from "/etc/mh/mhl.format". (Same evaluation hierarchy as the
+compose form file.)
+.PP
+Mhl operates in two phases: 1) read and parse the format file, and 2)
+process each message (file). During phase 1, an internal description of
+the format is produced as a structured list. In phase 2, this list is
+walked for each message, outputing message information under the format
+constraints from the format file.
+.PP
+The "mhl.format" file contains information controlling screen clearing,
+screen size, wraparound control, transparent text, component ordering,
+and component formatting. Also, a list of components to ignore may be
+specified, and a couple of "special" components are defined to provide
+added functionality. Message output will be in the order specified by
+the order in the format file.
+.PP
+Each line of mhl.format has one of the formats:
+.PP
+ ;comment
+.br
+ :cleartext
+.br
+ variable[,variable...]
+.br
+ component:[variable,...]
+.PP
+A line beginning with a ";" is a comment, and is ignored. A line
+beginning with a ":" is clear text, and is output exactly as is. (A line
+containing only a ":" produces a blank line in the output.) A line
+beginning with "component:" defines the format for the specified
+component, and finally, remaining lines define the global environment.
+.PP
+For example, the line:
+.PP
+width=80,length=40,clearscreen,overflowtext=***,overflowoffset=5
+.PP
+defines the screen size to be 80 columns by 40 rows, specifies that the
+screen should be cleared prior to each page, that the overflow
+indentation is 5, and that overflow text should be flagged with "***".
+.PP
+Following are all of the current variables and their argmuments. If
+they follow a component, they apply only to that component, otherwise,
+their affect is global. Since the whole format is parsed before any
+output processing, the last global switch setting for a variable applies
+to the whole message.
+.TP 15
+width=#
+Screen width, component width
+.TP
+overflowtext=t
+Text to use at the beginning of an overflow line
+.TP
+overflowoffset=#
+Positions to indent overflow lines
+.TP
+compwidth=#
+Positions to indent component text after first line
+.TP
+nocomponent
+Don't output "component: " for this component
+.TP
+uppercase
+Output text of this component in all upper case
+.TP
+center
+Center component on line (works for one-line components only)
+.TP
+clearscreen
+Clear the screen (form feed) prior to each page
+.TP
+leftadjust
+Strip off leading spaces & tabs on each line of text
+.TP
+compress
+Change newlines in text to spaces
+.PP
+Where "=#" indicates a number must be specified, and "=t" indicates that
+arbitrary text up to end of line or "," is required. The variables
+without arguments are ON indicators, with the default in all cases OFF.
+The variables "nocomponent", center, leftadjust and compress have no
+affect globally, and clearscreen only affects the global environment.
+.PP
+A line of the form:
+.PP
+ignores=component,...
+.PP
+specifies a list of components which are never output.
+.PP
+The component "MessageName" (case is unimportant) will output the actual
+message name (file name) preceded by "folder:" if one is specified or
+found in the environment.
+.PP
+The component "Extras" will output all of the components of the message
+which were not matched by explicit components, or included in the ignore
+list. If this component is not specified, an ignore list is not needed
+since all non-specified components will be ignored.
+.PP
+If "nocomponent" is NOT specified, then the component name will be output
+as it appears in the format file.
+.PP
+The current default format is:
+.PP
+width=80,length=40,overflowtext=***,overflowoffset=5
+.br
+ignores=msgid,message-id
+.br
+Date:leftadjust,offset=40
+.br
+To:leftadjust
+.br
+Cc:leftadjust
+.br
+:
+.br
+From:leftadjust
+.br
+Subject:leftadjust
+.br
+:
+.br
+extras:leftadjust,nocomponent
+.br
+:
+.br
+body:nocomponent
+.SH FILES
+.SH SEE ALSO
+c(1),
\ No newline at end of file
--- /dev/null
+.TH MHPATH 1 RAND
+.SH NAME
+mhpath \- print full pathnames of MH messages and folders
+.SH SYNOPSIS
+mhpath \%[+folder] \%[msgs] \%[\-help]
+.SH DESCRIPTION
+\fIMhpath\fR expands and sorts the message list \%[msgs] and writes
+the full pathnames of the messages to the standard output
+separated by newlines.
+
+If no ``msgs'' are specified, \fImhpath\fR outputs the folder (directory)
+pathname (current folder default).
+
+Contrasted with other MH commands, a message argument to \fImhpath\fR
+may often be intended for \fIwriting\fR.
+Because of this: 1) the name
+"new" has been added to \fImhpath\fR's list of reserved message names
+(the others are first, last, prev, next, cur, all).
+New is last + 1 (where last is 0 in a messageless folder).
+New may not be used as part of a message range.
+2) Within a message list,
+the following designations may refer to messages that do not exist:
+a single numeric message name,
+the single message name cur, and (obviously) the single message name new.
+All other message designations must refer to at least one existing message.
+3) An empty folder is not in itself an error.
+
+Message numbers greater than 999 as part of a range designation
+are replaced with 999. Explicit single message numbers greater
+than 999, or message number 0 in any context, are errors.
+
+Examples: The current folder foo contains messages 3 5 6.
+Cur is 4.
+.nf
+\ % mhpath
+\ /r/phyl/Mail/foo
+
+\ % mhpath all
+\ /r/phyl/Mail/foo/3
+\ /r/phyl/Mail/foo/5
+\ /r/phyl/Mail/foo/6
+
+\ % mhpath 1000
+\ Message 1000 out of range 1-999
+
+\ % mhpath 1-1001
+\ /r/phyl/Mail/foo/3
+\ /r/phyl/Mail/foo/5
+\ /r/phyl/Mail/foo/6
+
+\ % mhpath new
+\ /r/phyl/Mail/foo/7
+
+\ % mhpath last new
+\ /r/phyl/Mail/foo/6
+\ /r/phyl/Mail/foo/7
+
+\ % mhpath last-new
+\ Bad message list "last-new".
+
+\ % mhpath cur
+\ /r/phyl/Mail/foo/4
+
+\ % mhpath 1-2
+\ No messages in range "1-2".
+
+\ % mhpath first:2
+\ /r/phyl/Mail/foo/3
+\ /r/phyl/Mail/foo/5
+
+\ % mhpath 1 2
+\ /r/phyl/Mail/foo/1
+\ /r/phyl/Mail/foo/2
+
+\ % mhpath 0
+\ Bad message list "0".
+
+\ % mhpath 0-last
+\ Bad message list "0-last".
+
+\ --Backquoted Operations--
+
+\ % cd `mhpath +inbox`
+
+ From "e":
+\ <CMD> run cat `mhpath cur`
+
+.fi
+.SH FILES
+.ta 2.4i
+$HOME/\*.mh\(ruprofile The user profile
+.SH PROFILE COMPONENTS
+Path: To determine the user's MH directory
+.br
+Current-Folder: To find the default current folder
+.SH DEFAULTS
+`+folder' defaults to current
+.br
+`msgs' defaults to NULL
+.SH CONTEXT
+The folder and the current message are unaffected.
+.SH BUGS
+Like all MH commands, \fImhpath\fR expands and sorts \%[msgs].
+So don't expect
+.br
+\ mv `mhpath 501 500`
+.br
+to move 501 to 500.
+Quite the reverse. But
+.br
+\ mv `mhpath 501` `mhpath 500`
+.br
+will do the trick.
+
+Out of range message 0 is treated far more severely than large out of
+range message numbers.
--- /dev/null
+.TH NETMAIL 5 RAND
+.SH NAME
+netmail \- Arpanet mail queue
+.SH DESCRIPTION
+Each file in /usr/spool/netmail contains a message to be sent to
+one or more sites on the Arpanet. They are processed by the
+.I mailer(8)
+daemon.
+The format of a message file is as follows:
+The first line has the sender's name, a space, and the date the
+message was sent (in the form returned by
+.I cdate(3)
+). Following lines
+represent addresses and have a code character, a host name, a space,
+and a mailbox name. The code is '/' if this address has not already
+been handled, '|' if it has. The addresses end with a blank line.
+The remainder of the file is the text of the message.
+.PP
+.B Example:
+.br
+ jones 10-Jul-80@13:13:13
+.br
+ /usc-isif op-nobody
+.br
+ |rand-ai smith
+.br
+
+.br
+ From: Jones at Rand-Unix
+.br
+ To: op-nobody at Usc-Isif, smith at Rand-Ai
+.br
+
+.br
+ This is a test message.
+.SH FILES
+/usr/spool/netmail/*
+.SH SEE ALSO
+mailer(8),deliver(8)
--- /dev/null
+.TH NEWS 1 RAND
+.SH NAME
+news \- show news
+.SH SYNOPSIS
+\fBnews\fR \%[topic\ ...]
+\%[\fB\-check\fR]
+\%[\fB\-display\fR]
+\%[\fB\-update\fR]
+\%[\fB\-review\fR\ [topic]]
+\%[\fB\-send\ \fRtopic]
+\%[\fB\-topics\fR]
+\%[\fB\-help\fR]
+.SH DESCRIPTION
+.I News
+is an MH program which checks, displays, reviews, or sends news.
+A pseudo-user called `news' acts as an automated
+custodian for news items on various topics.
+These topics are managed as MH folders in the home directory of news.
+Mail sent to `news.everyone', for instance, will get
+filed in the `everyone' news folder.
+.PP
+You can explicitly select the group of news topics you want
+to check or display by specifying them as arguments to the
+.I news
+command.
+If you don't explicitly select topics in this way,
+the topic `everyone' is selected by default.
+Additional default topics can be selected by listing them on a
+\&``News\-Topics:'' line in your MH profile.
+The MH profile line
+must contain a blank-separated list of topics.
+As a special case, the profile line:
+.br
+ \&``News\-Topics:\ *''
+.br
+means you want to keep track of all news.
+.PP
+\&``\fINews \fB\-topics\fR''
+will show you what topics exist and
+the number of messages in each.
+Topics selected are marked with asterisks.
+\&``\fINews \fB\-help\fR''
+is like
+\&``\fInews \fB\-topics\fR''
+except that it also displays the syntax of the
+.I news
+command.
+.PP
+\&``\fINews \fB\-check\fR''
+will report the existence of unread news in the selected topics.
+.I News
+without any option arguments
+will display all unread news items from
+all selected topics.
+\&``\fINews \fB\-display\fR''
+is identical to
+.I news
+without an argument, but it suppresses the
+no news message (useful in login scripts).
+\&``\fINews \fB\-review\fR [#] [topic]''
+will redisplay the last # (default all) items
+in the selected topics.
+.PP
+News stores in your MH profile the message number of the most recent news
+item it has shown you in each topic.
+\&``\fINews \fB\-update\fR''
+will update your MH profile to indicate no
+outstanding news items to be read.
+.PP
+\&``\fINews \fB\-send\fR topic''
+is identical to
+\&``mail news.topic''.
+The mail sent to news.topic is
+automatically filed in a folder with
+name topic.
+.PP
+Any unrecognized switches to
+.I news
+are sent along to
+.IR l (1)
+for displaying items, or to
+.IR mail (1)
+for sending a news item.
+.SH FILES
+.ta 2.4i
+$HOME/.mh\(ruprofile The user profile
+.br
+~news/<topics> The news folders
+.br
+~news/.<topics> The number of items in <topics>
+.SH PROFILE COMPONENTS
+News-topics: Topics the user is interested in.
+.br
+News-<topic>: Current message in news topics
+.SH SEE ALSO
+mh-mail(5), mh(1)
+.SH DEFAULTS
+The topic `everyone' is the default topic.
+.SH CONTEXT
+The current message in each news folder is maintained in the
+user's mh\(ruprofile.
--- /dev/null
+.TH NEXT 1 RAND
+.SH NAME
+next \- show the next message
+.SH SYNOPSIS
+.B next
+\%[+folder] \%[\-switches\ for\ \fIshowproc\fR] \%[\-help]
+.SH DESCRIPTION
+\fINext\fR performs a \fIshow\fR on the next message in the
+specified (or current) folder.
+Like \fIshow\fR, it passes any
+switches on to the program \fIshowproc\fR, which is called to list the
+message.
+This command is exactly equivalent to ``show next''.
+.SH FILES
+.ta 2.4i
+$HOME/\*.mh\(ruprofile The user profile
+.SH PROFILE COMPONENTS
+Path: To determine the user's MH directory
+showproc: Program called to list the message
+.br
+Current-Folder: To find the default current folder
+.SH DEFAULTS
+showproc: /usr/ucb/c
+.SH SEE ALSO
+show(1),prev(1)
+.SH CONTEXT
+If a folder is specified, it will become the current folder, and the
+message that is shown (i.e., the next message in sequence)
+will become the current message.
--- /dev/null
+.TH PICK 1 RAND
+.SH NAME
+pick \- select messages by content
+.SH SYNOPSIS
+.B pick
+\-hdr-component pattern
+\%[\fB\-src\fR\ +folder] \%[msgs] \%[\fB\-help\fR]
+\%[\fB\-scan\fR] \%[\fB\-noscan\fR]
+\%[\fB\-show\fR] \%[\fB\-noshow\fR] \%[\fB\-nofile\fR] \%[\fB\-nokeep\fR]
+\%[\fB\-fil\fRe \%[\fB\-preserve\fR] \%[\fB\-link\fR]
+\%+folder\ ... \%[\fB\-nopreserve\fR] \%[\fB\-nolink\fR] ]
+\%[\fB\-keep\fR \%[\fB\-stay\fR] \%[\fB\-nostay\fR] \%[+folder\ ...]\ ]
+.br
+
+Where
+.I hdr-component
+is a member of
+.br
+ [\fBcc date from to subject search\fR],
+.br
+or
+is of the form \-text
+.PP
+Typically:
+.in 1i
+pick\0\-from\0jones\0\-scan
+.br
+pick\0\-search\0documentation
+.br
+pick\0\-subject\0ned\0\-scan\0\-keep
+.br
+pick\0\--expires\01-jan-85\0-scan
+.SH DESCRIPTION
+\fIPick\fR searches messages within a folder for the specified
+contents, then performs several operations on the selected
+messages.
+
+A modified \fIgrep\fR(1) is used to perform the searching, so the
+full regular expression (see \fIed\fR(1)) facility is available
+within `pattern'.
+With `\-search',
+.I pattern
+is used directly,
+and with the others, the grep pattern constructed is:
+
+.ti +.5i
+``hdr-component:\*.\*(**pattern''
+
+This means that the pattern specified for a `\-search' will be
+found everywhere in the message, including the header and the body,
+while the other search requests are limited to the single
+specified component.
+The expression `\-\-component pattern'
+is a shorthand for
+specifying `\-search ``component:\*.\*(**pattern''\ '; it is used to pick
+a component not in the set [cc date from subject to].
+An
+example is ``pick \-\-reply\-to pooh \-show''.
+
+Searching is performed on a per-line basis.
+Within the header of
+the message, each component is treated as one long line, but in
+the body, each line is separate.
+Lower-case letters in the
+search pattern will match either lower or upper case in the
+message, while upper case will match only upper case.
+
+Once the search has been performed, the selected messages
+are scanned (see \fIscan(1)\fR) if the `\-scan' switch is given, and
+then they are shown (see \fIshow(1)\fR) if the `\-show' switch is
+given.
+After these two operations, the file operations (if
+requested) are performed.
+
+The `\-file' switch operates exactly like the \fIfile\fR command, with the
+same meaning for the `\-preserve' and `\-link' switches.
+
+The `\-keep' switch is similar to `\-file', but it produces a folder that
+is a subfolder of the folder being searched and defines it as
+the current folder (unless the `\-stay' flag is used).
+This
+subfolder contains the messages which matched the search
+criteria.
+All of the MH commands may be used with the sub-folder
+as the current folder.
+This gives the user considerable power
+in dealing with subsets of messages in a folder.
+
+The messages in a folder produced by `\-keep' will always have the
+same numbers as they have in the source folder (i.e., the
+`\-preserve' switch is automatic).
+This way, the message
+numbers are consistent with the folder from which the messages
+were selected.
+Messages are not removed from the source folder
+(i.e., the `\-link' switch is assumed).
+If a `+folder' is not
+specified, the standard name ``select'' will be used.
+(This is the
+meaning of ``(select)'' when it appears in the output of the
+\fIfolder\fR command.) If `+folder' arguments are given to
+`\-keep', they will be used rather than ``select'' for the names
+of the subfolders.
+This allows for several subfolders to be
+maintained concurrently.
+
+When a `\-keep' is performed, the subfolder becomes the current folder.
+This can be overridden by use
+of the `\-stay' switch.
+
+Here's an example:
+
+.nf
+\01 % folder +inbox
+\02 inbox+ has 16 messages ( 3\- 22); cur= 3.
+\03 % pick \-from dcrocker
+\04 6 hits.
+\05 [+inbox/select now current]
+\06 % folder
+\07 inbox/select+ has \06 messages ( 3\- 16); cur= 3.
+\08 % scan
+.ds p \\h'\\w'+'u'
+\09 \03+ 6/20 Dcrocker Re: ned file update issue...
+10 \06\*p 6/23 Dcrocker removal of files from /tm...
+11 \08\*p 6/27 Dcrocker Problems with the new ned...
+12 13\*p 6/28 d\h'\w'D'u-\w'd'u'crocker newest nned \*(<<I would ap...
+13 15\*p 7/\05 Dcrocker nned \*(<<Last week I asked...
+14 16\*p 7/\05 d\h'\w'D'u-\w'd'u'crocker message id format \*(<<I re...
+15 % show all | print
+16 [produce a full listing of this set of messages on the line printer.]
+17 % folder \-up
+18 inbox+ has 16 messages ( 3\- 22); cur= 3; (select).
+19 % folder \-down
+20 inbox/select+ has 6 messages ( 3\- 16); cur= 3.
+21 % rmf
+22 [+inbox now current]
+23 % folder
+24 inbox+ has 16 messages ( 3\- 22); cur= 3.
+.fi
+
+This is a rather lengthy example, but it shows the power of the
+MH package.
+In item 1, the current folder is set to inbox.
+In 3,
+all of the messages from dcrocker are found in inbox and linked
+into the folder ``inbox/select''.
+(Since no action switch is
+specified, `\-keep' is assumed.) Items 6 and 7 show that this
+subfolder is now the current folder.
+Items 8 through 14 are a
+\fIscan\fR of the selected messages (note that they are all from dcrocker
+and are all in upper and lower case).
+Item 15 lists all of the messages to
+the high-speed printer.
+Item 17 directs \fIfolder\fR to set the
+current folder to the parent of the selection-list folder, which
+is now current.
+Item 18 shows that this has been done.
+Item 19 resets
+the current folder to the selection list, and 21 removes the
+selection-list folder and resets the current folder to the
+parent folder, as shown in 22 and 23.
+.SH FILES
+.ta 2.4i
+$HOME/\*.mh\(ruprofile The user profile
+.SH PROFILE COMPONENTS
+Path: To determine the user's MH directory
+.br
+Folder\-Protect: For protection on new folders
+.br
+Current-Folder: To find the default current folder
+.SH SEE ALSO
+scan(1), show(1), folder(1)
+.SH DEFAULTS
+`\-src +folder' defaults to current
+.br
+`msgs' defaults to all
+.br
+`\-keep +select' is the default if no `\-scan', `\-show', or `\-file' is specified
+.SH CONTEXT
+If a `\-src +folder' is specified, it will
+become the current folder, unless a `\-keep' with 0 or 1
+folder arguments makes the selection-list subfolder the
+current folder.
+Each selection-list folder will have its
+current message set to the first of the messages linked into
+it unless the selection list already existed, in which case the
+current message won't be c
\ No newline at end of file
--- /dev/null
+.TH PREV 1 RAND
+.SH NAME
+prev \- show the previous message
+.SH SYNOPSIS
+.B prev
+\%[+folder] \%[\-switches\ for\ \fIshowproc\fR] \%[\fB\-help\fR]
+.SH DESCRIPTION
+\fIPrev\fR performs a \fIshow\fR on the previous message in the specified
+(or current) folder.
+Like \fIshow\fR, it passes any switches on to the
+program named by \fIshowproc\fR, which is called to list the message.
+This command
+is exactly equivalent to ``show prev''.
+.SH FILES
+.ta 2.4i
+$HOME/\*.mh\(ruprofile The user profile
+.SH PROFILE COMPONENTS
+Showproc: Program to list the message.
+.br
+Path: To determine the user's MH directory
+.Ps
+Current-Folder: To find the default current folder
+.SH SEE ALSO
+next(1), show(1)
+.SH DEFAULTS
+showproc: /usr/ucb/c
+.SH CONTEXT
+If a folder is specified, it will become current, and the
+message that is shown (i.e., the previous message in sequence)
+will become the current message.
--- /dev/null
+.TH PROMPTER 1 RAND
+.SH NAME
+prompter \- prompting editor front end
+.SH SYNOPSIS
+This program is not called directly but takes the place
+of an editor and acts as an editor front end.
+.br
+\fBprompter\fR \%[\fB\-erase\fR\ chr] \%[\fB\-kill\fR\ chr] \%[\fB\-help\fR]
+.SH DESCRIPTION
+\fIPrompter\fR is an editor which allows rapid composition of
+messages.
+It is particularly useful to network and low-speed
+(less than 2400 baud) users of MH.
+It is an MH program in that
+it can have its own profile entry with switches, but it can't
+be invoked directly as all other MH commands can; it is an editor
+in that it is invoked by an ``\-editor prompter'' switch or by the
+profile entry ``Editor: prompter'', but functionally it is merely
+a text-collector and not a true editor.
+
+\fIPrompter\fR expects to be called from \fIcomp\fR, \fIrepl\fR, \fIdist\fR, or
+\fIforw\fR, with a draft file as an argument.
+For example, ``comp
+\-editor prompter'' will call \fIprompter\fR with the file ``draft'' already set
+up with blank components.
+For each blank component it finds in
+the draft, it prompts the user and accepts a response.
+A
+<RETURN> will cause the whole component to be left out.
+A ``\\''
+preceding a <RETURN> will continue the response on the next line,
+allowing for multiline components.
+
+Any component that is non-blank will be copied and echoed to the
+terminal.
+
+The start of the message body is prompted by a line of
+dashes.
+If the body is non-blank, the prompt is
+.br
+``--------Enter additional text''.
+Message-body typing is terminated with
+a <CTRL-D> (or <OPEN>).
+Control is returned to the calling
+program, where the user is asked ``What now?''.
+See \fIcomp\fR for
+the valid options.
+
+The line editing characters for kill and erase may be
+specified by the user via the arguments ``\-kill chr'' and ``\-erase
+chr'', where chr may be a character; or ``\\nnn'', where nnn is the
+octal value for the character.
+(Again, these may come from the
+default switches specified in the user's profile.)
+
+A <DEL> during message-body typing is equivalent to
+<CTRL-D> for compatibility with NED.
+A <DEL> during
+component typing will abort the command that invoked
+\fIprompter\fR.
+.PP
+The first non-flag argument to
+.I comp
+is taken as the name of the draft file, and
+subsequent non-flag arguments are ignored.
+(`Repl' invokes editors with two file arguments:
+the draft file name and the replied-to message file name.)
+.SH FILES
+None
+.SH PROFILE COMPONENTS
+.ta 2.4i
+prompter-next: To name the editor to be
+ used on exit from \fIprom
\ No newline at end of file
--- /dev/null
+.TH REPL 1 RAND
+.SH NAME
+repl \- reply to a message
+.SH SYNOPSIS
+\fBrepl\fR \%[+folder] \%[msg] \%[\fB\-editor\fR\ editor]
+\%[\fB\-inplace\fR] \%[\fB\-annotate\fR]
+\%[\fB\-help\fR] \%[\fB\-noinplace\fR]
+\%[\fB\-noannotate\fR]
+.SH DESCRIPTION
+\fIRepl\fR aids a user in producing a reply to an existing
+message.
+In its simplest form (with no arguments), it will set up
+a message-form skeleton in reply to the current message in the
+current folder, invoke the editor, and send the composed
+message if so directed.
+The composed message is constructed as
+follows:
+
+.nf
+.in 1i
+To: <Reply-To> or <From>
+cc: <cc>, <To>
+Subject: Re: <Subject>
+In-reply-to: Your message of <Date>
+.ti +\w'In-reply-to: 'u
+<Message-Id>
+.in .5i
+.fi
+
+where field names enclosed in angle brackets (< >) indicate the
+contents of the named field from the message to which the reply
+is being made.
+Once the skeleton is constructed, an editor is
+invoked (as in \fIcomp\fR, \fIdist\fR, and \fIforw\fR).
+While in the editor,
+the message being replied to is available through a link named
+``@''.
+
+.B NOTE:
+.I repl
+invokes the editor with two file arguments.
+The second is the filename of the message being
+replied to, and is intended
+to be used as an `alternate' file within the editor.
+If the editor used doesn't have this feature, it must
+ignore the extra file argument and edit the first
+file argument.
+
+As in \fIcomp\fR, \fIdist\fR, and \fIforw\fR, the user will be queried
+before the message is sent.
+If `\-annotate' is
+specified, the replied-to message will be annotated with the
+single line
+
+.ti +.5i
+Replied: \*(<<Date\*(>>.
+
+The command
+``comp \-use'' may be used to pick up interrupted editing, as in
+\fIdist\fR and \fIforw\fR; the `\-inplace' switch annotates the message in place,
+so that all folders with links to it will see the annotation.
+
+See \fIcomp(1)\fR for a description of the `\-editor' switch and for options
+upon exiting from the editor.
+.SH FILES
+.ta 2.4i
+$HOME/\*.mh\(ruprofile The user profile
+.br
+<mh-dir>/draft The constructed message file
+.br
+/usr/bin/send To send the composed message
+.SH PROFILE COMPONENTS
+Path: To determine the user's MH directory
+.br
+Editor: To override the default editor
+.br
+Current-Folder: To find the default current folder
+.SH DEFAULTS
+`+folder' defaults to current
+.br
+`msgs' defaults to cur
+.br
+`\-editor' defaults to /bin/ned
+.br
+`\-noannotate'
+.br
+`\-noinplace'
+.SH SEE ALSO
+comp(1),dist(1), forw(1)
+.SH CONTEXT
+If a `+folder' is specified, it will become the current
+folder, and the current message will be set to the replied-to
+message.
+.sp 2
--- /dev/null
+
+.TH RMAIL 1 RAND
+.SH NAME
+rmail \- send mail from a remote site
+.SH SYNOPSIS
+.B mail
+user
+.SH DESCRIPTION
+.I Rmail
+is intended as an interface between mail sent from foreign
+sites via
+.I uucp(1)
+and the Rand message handling system,
+.I mh(1).
+It reads a message from the standard input and, after creating
+mh-format lines for the sender and recipient user, writes
+it into a temporary file. It then invokes
+.I deliver(8)
+to complete the mail delivery.
+.PP
+.I Rmail
+is able to understand a series of lines of the form:
+.br
+ From \fIuser\fB ... remote from \fIsite\fR
+.br
+and turn them into the correct "From: \fIsite\fR!\fIuser\fR" form,
+thus allowing effective use of the
+.I reply(1)
+command.
+.PP
+If the destination
+.I user
+is in fact a foreign uucp site, no formatting or reprocessing is
+done;
+.I deliver
+will simply forward the message to the foreign site with the
+appropriate uucp-style header on it.
+.SH FILES
+/etc/mh/deliver
+.br
+/tmp/mail*.tmp
+.br
+.SH SEE ALSO
+bellmail(1), deliver(8), mail(1), uucp(1)
--- /dev/null
+.TH RMF 1 RAND
+.SH NAME
+rmf \- remove folder
+.SH SYNOPSIS
+.B rmf
+\%[+folder] \%[
+.B \-help
+]
+.SH DESCRIPTION
+\fIRmf\fR removes all of the files (messages) within the specified
+(or default) folder, and then removes the directory (folder).
+If
+there are any files within the folder which are not a part of MH,
+they will \fInot\fR be removed, and an error will be produced.
+If the
+folder is given explicitly or the current folder is a
+subfolder (i.e., a selection list from \fIpick\fR), it will be
+removed without confirmation.
+If no argument is specified and
+the current folder is not a selection-list folder, the
+user will be asked for confirmation.
+
+\fIRmf\fR irreversibly deletes messages that don't have other links,
+so use it with caution.
+
+If the folder being removed is a subfolder, the parent
+folder will become the new current folder, and \fIrmf\fR will
+produce a message telling the user this has happened.
+This
+provides an easy mechanism for selecting a set of messages,
+operating on the list, then removing the list and returning to
+the current folder from which the list was extracted.
+(See the
+example under \fIpick\fR.)
+
+The files that \fIrmf\fR will delete are cur, any file beginning
+with a comma, and files with purely numeric names.
+All others
+will produce error messages.
+
+\fIRmf\fR of a read-only folder will delete the ``cur\-'' entry from the
+profile without affecting the folder itself.
+.SH FILES
+.ta 2.4i
+$HOME/\*.mh\(ruprofile The user profile
+.SH PROFILE COMPONENTS
+Path: To determine the user's MH directory
+.br
+Current-Folder: To find the default current folder
+.SH SEE ALSO
+rmm(1)
+.SH DEFAULTS
+`+folder' defaults to current, usually with confirmation
+.SH CONTEXT
+\fIRmf\fR will set the current folder to the parent folder if a
+subfolder is removed; or if the current folder is removed,
+it will make ``inbox'' current.
+Otherwise, it doesn't change the
+current folder or message.
--- /dev/null
+.TH RMM 1 RAND
+.SH NAME
+rmm \- remove messages
+.SH SYNOPSIS
+.B rmm
+\%[+folder] \%[msgs] \%[
+.B \-help
+]
+.SH DESCRIPTION
+\fIRmm\fR removes the specified messages by renaming the message
+files with preceding commas.
+(This is the Rand-UNIX backup file
+convention.)
+.PP
+If the user has a profile component such as
+.br
+ delete-prog: /bin/rm
+.br
+then instead of simply renaming the message file,
+.I rmm
+will call the named program to delete the file.
+.PP
+Some users of csh prefer the following:
+.br
+ alias rmm file +d
+.br
+where folder +d is a folder for deleted messages, and
+.br
+ alias mexp 'rm `mhpath +d all`'
+.br
+is used to `exponge' deleted messages.
+.PP
+The current message is not changed by \fIrmm\fR, so a \fInext\fR will
+advance to the next message in the folder as expected.
+.SH FILES
+.ta 2.4i
+$HOME/\*.mh\(ruprofile The user profile
+.SH PROFILE COMPONENTS
+Path: To determine the user's MH directory
+.br
+Current-Folder: To find the default current folder
+.br
+Delete-prog: Optional program to delete the message
+.SH SEE ALSO
+rmf(1)
+.SH DEFAULTS
+.br
+`+folder' defaults to current
+.br
+`msgs' defaults to cur
+.SH CONTEXT
+If a folder is given, it will become current.
--- /dev/null
+.TH SCAN 1 RAND
+.SH NAME
+scan \- produce a one-line-per-message scan listing
+.SH SYNOPSIS
+scan \%[+folder] \%[msgs] \%[\-f\&f] \%[\-header] \%[\-help]
+\%[\-nof\&f] \%[\-noheader] \%[\-time] \%[\-notime] \%[\-numdate] \%[\-nonumdate]
+.SH DESCRIPTION
+\fIScan\fR produces a one-line-per-message listing of the specified
+messages.
+Each \fIscan\fR line contains the message number (name),
+the date, the ``From'' field, the \*(lqSubject'' field, and, if room
+allows, some of the body of the message.
+For example:
+
+.nf
+.ta .5i 1.2i 2.6i
+ # Date From Subject\ \ \ \ \[\*(<<Body]
+15+ 7/\05 dcrocker nned <<Last week I asked some of
+16\ \- 7/\05 dcrocker message id format <<I recommend
+18 7/\06 Obrien Re: Exit status from mkdir
+19 7/\07 Obrien "scan" listing format in MH
+20 7/\07 phyl \ \ \ Short <<message >>
+.re
+.fi
+
+The `+' on message 15 indicates that it is the current message.
+The `\-' on message 16 indicates that it has been
+replied to, as indicated by a ``Replied:'' component produced by
+an `\-annotate' switch to the \fIrepl\fR command.
+
+If there is sufficient room left on the \fIscan\fR line after the
+subject, the line will be filled with text from the body,
+preceded by <<, and terminated by >> if the body is sufficiently short.
+\fIScan\fR actually reads each of the specified
+messages and parses them to extract the desired fields.
+During parsing, appropriate error messages will be produced if
+there are format errors in any of the messages.
+
+The `\-header' switch produces a header line prior to the \fIscan\fR
+listing, and the `\-f\&f' switch will cause a form feed to be
+output at the end of the \fIscan\fR listing.
+.PP
+Example:
+
+The command: (scan -ff -header; show all -pr -f) | print
+
+produces a scan listing of the current folder, followed by a form feed,
+followed by a formatted listing of all messages in the folder, one per
+page. Omitting "-pr -f" will cause the messages to be concatenated,
+separated by a one-line header and two blank lines.
+
+If the `\-time' switch is selected, the time of the message is shown
+after the date.
+If the `\-numdate' switch is selected,
+the date (and time if `\-time' is selected) of the message
+is shown as one long number made up of year, month, day, hour, minute.
+This is useful for sorting messages in a folder.
+.PP
+Example:
+
+162+ 8202192032 Dave-Yost mh distrib <<is almost done.
+
+.SH FILES
+.ta 2.4i
+$HOME/\*.mh\(ruprofile The user profile
+.SH PROFILE COMPONENTS
+Path: To determine the user's MH directory
+.br
+Current-Folder: To find the default current folder
+.SH SEE ALSO
+inc(1), show(1)
+.SH DEFAULTS
+.br
+`+folder' defaults to current
+.br
+`msgs' defaults to all
+.br
+`\-nof\&f'
+.br
+`\-noheader'
+.br
+`\-notime'
+.br
+`\-nonumdate'
+.SH CONTEXT
+If a folder is given, it will become current.
+The current
+message is unaffected.
+.SH BUGS
+The `\-numdate' option ignores timezones.
--- /dev/null
+.TH SEND 1 RAND
+.SH NAME
+send \- send a message
+.SH SYNOPSIS
+send \%[file] \%[\-draft] \%[\-verbose] \%[\-format] \%[\-msgid]
+\%[\-help] \%[\-noverbose] \%[\-noformat] \%[\-nomsgid]
+.SH DESCRIPTION
+\fISend\fR will cause the specified file (default <mh-dir>/draft) to
+be delivered
+(via
+.I deliver(8)
+) to each of the addresses in the ``To:'', ``cc:'', and ``Bcc:''
+fields of the message.
+If `\-verbose' is specified, \fIsend;\fR
+will monitor the delivery of local and net mail.
+\fISend\fR with no
+argument will query whether the draft is the intended file, whereas
+`\-draft' will suppress this question.
+Once the message has
+been mailed (or queued) successfully, the file will be renamed
+with a leading comma, which allows it to be retreived until the
+next draft message is sent.
+If there are errors in the
+formatting of the message, \fIsend;\fR will abort with a (hopefully)
+helpful error message.
+
+If a ``Bcc:'' field is encountered, its addresses will be used for
+delivery, but the ``Bcc:'' field itself will be deleted from all
+copies of the outgoing message.
+
+Prior to sending the message, the fields ``From: user'', and
+``Date: now'' will be prepended to the message.
+If `\-msgid' is
+specified, then a ``Message-Id:'' field will also be added to the
+message.
+If the message already contains a ``From:'' field, then a
+``Sender: user'' field will be added instead.
+(An already existing
+``Sender:'' field will be deleted from the message.)
+
+If the user doesn't specify `\-noformat', each of the entries in
+the ``To:'' and ``cc:'' fields will be replaced with ``standard'' format
+entries.
+This standard format is designed to be usable by all
+of the message handlers on the various systems around the
+ARPANET.
+
+If an ``Fcc: folder'' is encountered, the message will be copied
+to the specified folder in the format in which it will appear to any
+receivers of the message.
+That is, it will have the prepended
+fields and field reformatting.
+
+If a ``Distribute-To:'' field is encountered, the message
+is handled as a redistribution message (see \fIdist(1)\fR for
+details), with ``Distribution-Date: now'' and ``Distribution-From: user''
+added.
+.SH FILES
+.ta 2.4i
+$HOME/\*.mh\(ruprofile The user profile
+.SH PROFILE COMPONENTS
+Path: To determine the user's MH directory
+.SH SEE ALSO
+deliver(8),dist(1),forw(1)
+.SH DEFAULTS
+`file' defaults to draft
+.br
+`\-noverbose'
+.br
+`\-format'
+.br
+`\-nomsgid'
+.SH CONTEXT
+\fISend\fR has no effect on the current message or
\ No newline at end of file
--- /dev/null
+.TH SHOW 1 RAND
+.SH NAME
+show \- show (list) messages
+.SH SYNOPSIS
+show \%[+folder] \%[msgs] \%[\-format] \%[\-noformat] \%[\-pr] \%[\-nopr] \%[\-draft] \%[\-help]
+\%[\fIc\fR\ or\ \fIpr\fR\ switches]
+.SH DESCRIPTION
+\fIShow\fR lists each of the specified messages to the standard
+output (typically, the terminal).
+The messages are listed exactly
+as they are, with no reformatting.
+A program named by the \fBshowproc\fR profile component is
+invoked to do the listing, and any switches not recognized by
+\fIshow\fR are passed along to that program. The default
+program is known as \fIc\fR (also known as \fIl\fR).
+The mh command \fBmhl\fR can be used as a \fBshowproc\fR
+to show messages in a more uniform format. See mhl(1).
+If the `-noformat' option is specified, `/bin/cat' is used
+instead of \fBshowproc\fR.
+The opposite of this is `-format', which is the default.
+
+If no ``msgs'' are specified, the current message is used.
+If
+more than one message is specified, \fIc\fR will prompt for a
+<return> prior to listing each message.
+
+\fIc\fR will list each message, a page at a time.
+When the end of
+page is reached, \fIc\fR will ring the bell and wait for a <RETURN>
+or <CTRL-D>.
+If a <return> is entered, \fIc\fR will clear the
+screen before listing the next page, whereas <CTRL-D> will not.
+The switches to \fIc\fR are
+`\-p#' to indicate the page length in lines, and `\-w#' to
+indicate the width of the page in characters.
+
+If the standard output is not a terminal, no queries are made,
+and each file is listed with a one-line header and two lines of
+separation.
+
+If `\-pr' is specified, then \fIpr\fR(I) will be invoked rather than
+\fIc\fR, and the switches (other than `\-draft') will be passed
+along.
+``Show \-draft'' will list the file <mh-dir>/draft if it
+exists.
+.SH FILES
+.ta 2.4i
+$HOME/\*.mh\(ruprofile The user profile
+.br
+/usr/ucb/c Screen-at-a-time list program
+.br
+/bin/pr \fIpr\fR(I)
+.SH PROFILE COMPONENTS
+Path: To determine the user's MH directory
+.br
+Current-Folder: To find the default current folder
+.br
+showproc: Program to show message
+.br
+prproc: Program to use for ``pr''
+.SH SEE ALSO
+next(1), prev(1), c(1), mhl(1)
+.SH DEFAULTS
+`+folder' defaults to current
+.br
+`msgs' defaults to cur
+.br
+`\-format'
+.br
+`\-nopr'
+.SH CONTEXT
+If a folder is given, it will become the current message.
+The last message
+listed will become the current message.
--- /dev/null
+Only in /usr/src/cmd/mh: Adrparse
+
+
+diff -rb /usr/src/cmd/mh/Bugs mh/Bugs
+215,231d214
+< 5/25/82 phyl
+< news bugs:
+< 1) .mh_receive should have a locking mechanism to guard
+< against simultaneous incoming messages.
+< 2) news/.mh_receive requires its mail directory to be
+< its top level directory. Instead, .mh_receive should
+< be a C program that looks at .mh_profile for the proper
+< mail path.
+< 3) The alias string that is passed off to news/.mh_receive
+< should be the string that matched news.* rather than the
+< 1st alias match. Example:
+< /etc/MailAliases
+< fum: news.pktest
+< news.*: news
+< To: fum
+< execs news/.mh_receive(,,,fum) instead of
+< news/.mh_receive(,,,news.pktest)
+Common subdirectories: /usr/src/cmd/mh/DOC and mh/DOC
+Common subdirectories: /usr/src/cmd/mh/Extras and mh/Extras
+
+
+diff -rb /usr/src/cmd/mh/MHgenerate mh/MHgenerate
+49c49
+< If not, don't define it. If ARPANET is not defined, and if you want to
+---
+> If not, don't define it. If ARPANET is not defined and if you want to
+51,52c51,52
+< adrparse.h. If you are on VMUNIX, define that in mh.h and set up
+< the JOBSLIB define in progs/Makefile.
+---
+> adrparse.h. If you are on VMUNIX, define that in mh.h and set up the
+> JOBSLIB define in progs/Makefile.
+55,58c55,58
+< /usr/include and modify them for your installation.
+< If you are going to use mh over uucp and/or ARPANET links, you must
+< edit your /usr/include/whoami.h to be sure the defines for sysname (uucp)
+< and HOSTNAME & HOSTNUM (ARPANET) are correct. If you are not on the
+---
+> /usr/include or support/ and modify them for your installation.
+> If you are going to use mh over uucp and/or ARPANET links, you must edit
+> your /usr/include/whoami.h to be sure the defines for sysname (uucp) and
+> HOSTNAME & HOSTNUM (ARPANET) are correct. If you are not on the
+92a93,94
+> (Ignore the possible error message "nm: sysname.o--no name list")
+>
+Only in /usr/src/cmd/mh: Makeback
+
+
+diff -rb /usr/src/cmd/mh/Makefile mh/Makefile
+11c11
+< BINDIR = /usr/randbin
+---
+> BINDIR = /usr/local
+
+
+diff -rb /usr/src/cmd/mh/Wishlist mh/Wishlist
+484a485
+>
+512,518d512
+< 5/12/82
+< Send to an alias list, less the following exceptions.
+<
+< To: group<except, except...>
+<
+< Cc: csd-mgrs<terry>
+< Terry West
+Only in /usr/src/cmd/mh: adrparse.h.sav
+Only in /usr/src/cmd/mh: di.man1
+Only in /usr/src/cmd/mh: diff.05112
+Only in /usr/src/cmd/mh: diff.05132
+Common subdirectories: /usr/src/cmd/mh/dytest and mh/dytest
+Only in /usr/src/cmd/mh: err
+Only in /usr/src/cmd/mh: greep
+Common subdirectories: /usr/src/cmd/mh/man and mh/man
+Only in /usr/src/cmd/mh: mh.h.sav
+Common subdirectories: /usr/src/cmd/mh/misc and mh/misc
+Only in /usr/src/cmd/mh: pktest
+Only in /usr/src/cmd/mh: printmh
+Common subdirectories: /usr/src/cmd/mh/progs and mh/progs
+Only in /usr/src/cmd/mh: randnet
+Common subdirectories: /usr/src/cmd/mh/strings and mh/strings
+Common subdirectories: /usr/src/cmd/mh/subs and mh/subs
+Common subdirectories: /usr/src/cmd/mh/support and mh/support
+Common subdirectories: /usr/src/cmd/mh/Extras/libg and mh/Extras/libg
+Common subdirectories: /usr/src/cmd/mh/Extras/libh and mh/Extras/libh
+Only in /usr/src/cmd/mh/Extras: mhl.bsb
+
+
+diff -rb /usr/src/cmd/mh/dytest/Makefile mh/dytest/Makefile
+11c11
+< JOBSLIB= -ljobs
+---
+> LIBJOBS=#-ljobs
+15c15
+< BINDIR = /usr/randbin
+---
+> BINDIR = /usr/local
+60d59
+< ack.c \
+89,91d87
+< ack: ack.o $(SUBS)
+< $(CC) -o ack ack.o $(SUBS)
+<
+419d414
+< show.o: mhl.c
+Only in /usr/src/cmd/mh/dytest: Olson
+Only in /usr/src/cmd/mh/dytest: ack
+Only in /usr/src/cmd/mh/dytest: ack.c
+Only in /usr/src/cmd/mh/dytest: ack.o
+Only in /usr/src/cmd/mh/dytest: err
+Only in /usr/src/cmd/mh/dytest: gimme.c
+Only in /usr/src/cmd/mh/dytest: key.c
+Only in /usr/src/cmd/mh/dytest: key.o
+Only in mh/dytest: mhl.c
+Only in mh/dytest: show.c
+Only in /usr/src/cmd/mh/dytest: test
+Only in /usr/src/cmd/mh/man: test
+Only in /usr/src/cmd/mh/progs: Makeback
+
+
+diff -rb /usr/src/cmd/mh/progs/Makefile mh/progs/Makefile
+11c11
+< JOBSLIB= -ljobs
+---
+> JOBSLIB=#-ljobs
+13c13,16
+< CFLAGS = -O $(A) # -m -DRAND
+---
+> CFLAGS = -O $(A) -I/usr/include -I../support # -m -DRAND
+> # On a PDP/11, if the sticky bit is to be set, text must be shareable
+> CCSHARE = -n
+>
+15c18
+< BINDIR = /usr/randbin
+---
+> BINDIR = /usr/local
+92c95
+< $(CC) -o comp comp.o $(SUBS) $(STRINGS)
+---
+> $(CC) $(CCSHARE) -o comp comp.o $(SUBS) $(STRINGS)
+98,99c101,102
+< $(CC) -o deliver deliver.o adrparse.o adrformat.o $(SUBS) $(STRINGS)\
+< $(JOBSLIB)
+---
+> $(CC) $(CCSHARE) -o deliver deliver.o adrparse.o adrformat.o $(SUBS) \
+> $(STRINGS) $(JOBSLIB)
+114c117
+< $(CC) -o inc inc.o scansub.o $(SUBS) $(STRINGS)
+---
+> $(CC) $(CCSHARE) -o inc inc.o scansub.o $(SUBS) $(STRINGS)
+132c135
+< $(CC) -o next nexthdr.o next.o $(SUBS) $(STRINGS)
+---
+> $(CC) $(CCSHARE) -o next nexthdr.o next.o $(SUBS) $(STRINGS)
+141c144
+< $(CC) -o prompter prompter.o $(SUBS) $(STRINGS)
+---
+> $(CC) $(CCSHARE) -o prompter prompter.o $(SUBS) $(STRINGS)
+162c165
+< $(CC) -o show show.o $(SUBS) $(STRINGS)
+---
+> $(CC) $(CCSHARE) -o show show.o $(SUBS) $(STRINGS)
+207,208c210,211
+< -/etc/chown root $(NETDIR)
+< -chmod 755 $(NETDIR)
+---
+> /etc/chown root $(NETDIR)
+> chmod 755 $(NETDIR)
+210,211c213,214
+< -/etc/chown root $(LOCKDIR)
+< -chmod 777 $(LOCKDIR)
+---
+> /etc/chown root $(LOCKDIR)
+> chmod 777 $(LOCKDIR)
+233c236
+< -chmod a+x $(PROGS)
+---
+> chmod a+x $(PROGS)
+272c275
+< adrparse.o: /usr/include/whoami.h
+---
+> #adrparse.o: /usr/include/whoami.h
+275c278
+< adrparse.o: /usr/include/imp.h
+---
+> #adrparse.o: /usr/include/imp.h
+284c287
+< comp.o: /usr/include/strings.h
+---
+> #comp.o: /usr/include/strings.h
+293,294c296,297
+< conflict.o: /usr/include/mailsys.h
+< deliver.o: /usr/include/whoami.h
+---
+> #conflict.o: /usr/include/mailsys.h
+> #deliver.o: /usr/include/whoami.h
+304,305c307,308
+< deliver.o: /usr/include/strings.h
+< deliver.o: /usr/include/mailsys.h
+---
+> #deliver.o: /usr/include/strings.h
+> #deliver.o: /usr/include/mailsys.h
+310c313
+< dist.o: /usr/include/strings.h
+---
+> #dist.o: /usr/include/strings.h
+320c323
+< folder.o: /usr/include/strings.h
+---
+> #folder.o: /usr/include/strings.h
+324c327
+< forw.o: /usr/include/strings.h
+---
+> #forw.o: /usr/include/strings.h
+332c335
+< inc.o: /usr/include/strings.h
+---
+> #inc.o: /usr/include/strings.h
+350c353
+< mhpath.o: /usr/include/strings.h
+---
+> #mhpath.o: /usr/include/strings.h
+357c360
+< news.o: /usr/include/strings.h
+---
+> #news.o: /usr/include/strings.h
+361c364
+< next.o: /usr/include/strings.h
+---
+> #next.o: /usr/include/strings.h
+373,374c376,377
+< prompter.o: /usr/include/strings.h
+< repl.o: /usr/include/whoami.h
+---
+> #prompter.o: /usr/include/strings.h
+> #repl.o: /usr/include/whoami.h
+378c381
+< repl.o: /usr/include/strings.h
+---
+> #repl.o: /usr/include/strings.h
+383c386
+< rmail.o: /usr/include/whoami.h
+---
+> #rmail.o: /usr/include/whoami.h
+390c393
+< rmf.o: /usr/include/strings.h
+---
+> #rmf.o: /usr/include/strings.h
+393c396
+< rmm.o: /usr/include/strings.h
+---
+> #rmm.o: /usr/include/strings.h
+396c399
+< scan.o: /usr/include/strings.h
+---
+> #scan.o: /usr/include/strings.h
+399c402
+< scansub.o: /usr/include/whoami.h
+---
+> #scansub.o: /usr/include/whoami.h
+409c412
+< send.o: /usr/include/strings.h
+---
+> #send.o: /usr/include/strings.h
+413c416
+< show.o: /usr/include/strings.h
+---
+> #show.o: /usr/include/strings.h
+Only in mh/progs: Makefile.bak
+Only in /usr/src/cmd/mh/progs: adrformat.o
+Only in /usr/src/cmd/mh/progs: adrpars.c.3102
+Only in /usr/src/cmd/mh/progs: adrparse.c.sav
+Only in /usr/src/cmd/mh/progs: adrparse.o
+Only in /usr/src/cmd/mh/progs: ali
+Only in /usr/src/cmd/mh/progs: ali.lint
+Only in /usr/src/cmd/mh/progs: ali.o
+Only in /usr/src/cmd/mh/progs: annotate.o
+Only in /usr/src/cmd/mh/progs: comp
+Only in /usr/src/cmd/mh/progs: comp.lint
+Only in /usr/src/cmd/mh/progs: comp.o
+Only in /usr/src/cmd/mh/progs: conflict
+Only in /usr/src/cmd/mh/progs: conflict.lint
+Only in /usr/src/cmd/mh/progs: conflict.o
+Only in /usr/src/cmd/mh/progs: deliver
+Only in /usr/src/cmd/mh/progs: deliver.c.3-1
+Only in /usr/src/cmd/mh/progs: deliver.c.3102
+Only in /usr/src/cmd/mh/progs: deliver.c.sav
+Only in /usr/src/cmd/mh/progs: deliver.lint
+Only in /usr/src/cmd/mh/progs: deliver.o
+
+
+diff -rb /usr/src/cmd/mh/progs/dist.c mh/progs/dist.c
+26c26
+< extern struct swit aleqs[] = {
+---
+> struct swit aleqs[] = {
+Only in /usr/src/cmd/mh/progs: dist.lint
+Only in /usr/src/cmd/mh/progs: err
+Only in /usr/src/cmd/mh/progs: file
+Only in /usr/src/cmd/mh/progs: file.lint
+Only in /usr/src/cmd/mh/progs: file.o
+Only in /usr/src/cmd/mh/progs: folder
+Only in /usr/src/cmd/mh/progs: folder.lint
+Only in /usr/src/cmd/mh/progs: folder.o
+Only in /usr/src/cmd/mh/progs: forw
+Only in /usr/src/cmd/mh/progs: forw.lint
+Only in /usr/src/cmd/mh/progs: forw.o
+Only in /usr/src/cmd/mh/progs: grep.o
+Only in /usr/src/cmd/mh/progs: inc
+Only in /usr/src/cmd/mh/progs: inc.o
+Only in /usr/src/cmd/mh/progs: install-mh
+Only in /usr/src/cmd/mh/progs: install-mh.o
+Only in /usr/src/cmd/mh/progs: install.lint
+Only in /usr/src/cmd/mh/progs: m_send.c
+Only in /usr/src/cmd/mh/progs: mail
+Only in /usr/src/cmd/mh/progs: mail.lint
+Only in /usr/src/cmd/mh/progs: mail.o
+Only in /usr/src/cmd/mh/progs: mhl
+Only in /usr/src/cmd/mh/progs: mhl.lint
+Only in /usr/src/cmd/mh/progs: mhl.o
+Only in /usr/src/cmd/mh/progs: mhpath
+Only in /usr/src/cmd/mh/progs: mhpath.o
+Only in /usr/src/cmd/mh/progs: news
+Only in /usr/src/cmd/mh/progs: news.lint
+Only in /usr/src/cmd/mh/progs: news.o
+Only in /usr/src/cmd/mh/progs: next
+Only in /usr/src/cmd/mh/progs: next.o
+Only in /usr/src/cmd/mh/progs: nexthdr.o
+Only in /usr/src/cmd/mh/progs: pick
+Only in /usr/src/cmd/mh/progs: pick.lint
+Only in /usr/src/cmd/mh/progs: pick.o
+Only in /usr/src/cmd/mh/progs: prev
+Only in /usr/src/cmd/mh/progs: prev.lint
+Only in /usr/src/cmd/mh/progs: prevhdr.o
+Only in /usr/src/cmd/mh/progs: prompter
+Only in /usr/src/cmd/mh/progs: prompter.lint
+Only in /usr/src/cmd/mh/progs: prompter.nutty
+Only in /usr/src/cmd/mh/progs: prompter.o
+Only in /usr/src/cmd/mh/progs: repl
+Only in /usr/src/cmd/mh/progs: repl.c.03122
+Only in /usr/src/cmd/mh/progs: repl.c.ok
+Only in /usr/src/cmd/mh/progs: repl.lint
+Only in /usr/src/cmd/mh/progs: repl.o
+
+
+diff -rb /usr/src/cmd/mh/progs/replsubs.c mh/progs/replsubs.c
+1,5d0
+< /* This mess pre-dates adrparse. It's function is to
+< * attach the Reply-to or From host to hostless addresses
+< * on a reply.
+< */
+<
+Only in /usr/src/cmd/mh/progs: rmail
+
+
+diff -rb /usr/src/cmd/mh/progs/rmail.c mh/progs/rmail.c
+31,32d30
+< *
+< * 5/8/82: Tack on uu-Date: if msg has no date. PK.
+35d32
+< /*#define DEBUG 1*/
+42,43d38
+< #define PARSE 1
+< #define NOPARSE 0
+45d39
+<
+55,56d48
+< char d1[10], d2[10], d3[10], d4[10], d5[10]; /*** ctime() fields ***/
+<
+68d59
+< int badhdr; /***/
+91,93c82,83
+< /***/ sscanf(lbuf, "%s %s %s %s %s %s %s remote from %s",
+< junk, ufrom, d1, d2, d3, d4, d5, sys);
+< /* sscanf(lbuf, "%s %s", junk, ufrom); */
+---
+> /* sscanf(lbuf, "%s %s %s %s %s %s %s remote from %s", junk, ufrom, junk, junk, junk, junk, junk, sys); */
+> sscanf(lbuf, "%s %s", junk, ufrom);
+136c126
+< putmsg(NOPARSE);
+---
+> putmsg();
+145c135
+< if( !((cp = index(lbuf, ':')) && (cp - lbuf < NAMESZ ))) {
+---
+> if( !((cp = index(lbuf, ':')) && (cp - lbuf < NAMESZ )))
+147,149c137,138
+< badhdr++;
+< }
+< putmsg(badhdr?NOPARSE:PARSE);
+---
+>
+> putmsg();
+223a213
+>
+242c232
+< putmsg(NOPARSE);
+---
+> putmsg();
+296,297c286
+< putmsg(parse)
+< int parse;
+---
+> putmsg()
+299,305d287
+< int dateseen = 0;
+<
+< if(!parse)
+< putall();
+< else {
+< if (uleqn(lbuf, "date:", 5) == 0)
+< dateseen++;
+307,324d288
+< while (fgets(lbuf, sizeof lbuf, stdin)) {
+< if(lbuf[0] == '\n' ) { /* end of hdrs */
+< if(!dateseen)
+< uudate();
+< putall();
+< } else {
+< if (uleqn(lbuf, "date:", 5) == 0)
+< dateseen++;
+< fputs(lbuf, out);
+< }
+< }
+< }
+< }
+<
+<
+< putall()
+< {
+< fputs(lbuf, out);
+342,391d305
+< /*
+< * Compare strings (at most n bytes) without regard to case.
+< * Returns: s1>s2: >0, s1==s2: 0, s1<s2: <0.
+< */
+<
+< uleqn(s1, s2, n)
+< register char *s1, *s2;
+< register n;
+< {
+<
+< while (--n >= 0 && (*s1|040) == (*s2|040)) {
+< s2++;
+< if (*s1++ == '\0')
+< return(0);
+< }
+< return(n<0 ? 0 : (*s1|040) - (*s2|040));
+< }
+<
+<
+< uudate()
+< {
+< char *prefix();
+<
+< /* day 13 Apr 1981 20 :38 -PST */
+< fprintf(out, "Date: %sday, %.2s %.3s %.4s %.2s:%.2s-%.3s\n",
+< prefix(d1), d3, d2, d5, d4, d4+3, "???");
+< }
+<
+< char *
+< prefix(str)
+< char *str;
+< {
+< static char *wday[] = {
+< "Sun",
+< "Mon",
+< "Tues",
+< "Wednes",
+< "Thurs",
+< "Fri",
+< "Satur",
+< 0
+< };
+<
+< register char **wp;
+<
+< for(wp=wday; wp; wp++)
+< if(uleqn(str, *wp, 3) == 0)
+< return(*wp);
+< return("???");
+< }
+Only in /usr/src/cmd/mh/progs: rmail.c.sav
+Only in /usr/src/cmd/mh/progs: rmail.lint
+Only in /usr/src/cmd/mh/progs: rmail.o
+Only in /usr/src/cmd/mh/progs: rmail.sav
+Only in /usr/src/cmd/mh/progs: rmf
+Only in /usr/src/cmd/mh/progs: rmf.lint
+Only in /usr/src/cmd/mh/progs: rmf.o
+Only in /usr/src/cmd/mh/progs: rmm
+Only in /usr/src/cmd/mh/progs: rmm.lint
+Only in /usr/src/cmd/mh/progs: rmm.o
+Only in /usr/src/cmd/mh/progs: scan
+Only in /usr/src/cmd/mh/progs: scan.o
+Only in /usr/src/cmd/mh/progs: scansub.c.sav
+Only in /usr/src/cmd/mh/progs: scansub.o
+Only in /usr/src/cmd/mh/progs: send
+Only in /usr/src/cmd/mh/progs: send.o
+Only in /usr/src/cmd/mh/progs: show
+Only in /usr/src/cmd/mh/progs: show.o
+Only in /usr/src/cmd/mh/strings: Makeback
+
+
+diff -rb /usr/src/cmd/mh/strings/Makefile mh/strings/Makefile
+39c39,40
+< sysed.o
+---
+> sysed.o \
+> sysname.o
+70c71,72
+< sysed.c
+---
+> sysed.c \
+> sysname.c
+89,90c91,92
+< lockdir.o: /usr/include/mailsys.h
+< mailboxes.o: /usr/include/mailsys.h
+---
+> #lockdir.o: /usr/include/mailsys.h
+> #mailboxes.o: /usr/include/mailsys.h
+91a94
+> #sysname.o: /usr/include/whoami.h
+Only in /usr/src/cmd/mh/strings: anoyes.o
+Only in /usr/src/cmd/mh/strings: components.o
+Only in /usr/src/cmd/mh/strings: current.o
+Only in /usr/src/cmd/mh/strings: defalt.o
+Only in /usr/src/cmd/mh/strings: distcomps.o
+Only in /usr/src/cmd/mh/strings: draft.o
+Only in /usr/src/cmd/mh/strings: err
+
+
+diff -rb /usr/src/cmd/mh/strings/fileproc.c mh/strings/fileproc.c
+13c13
+< char *fileproc = "/usr/randbin/file";
+---
+> char *fileproc = "/usr/local/file";
+Only in /usr/src/cmd/mh/strings: fileproc.o
+Only in /usr/src/cmd/mh/strings: foldprot.o
+Only in /usr/src/cmd/mh/strings: installproc.o
+Only in /usr/src/cmd/mh/strings: list
+Only in /usr/src/cmd/mh/strings: listname.o
+Only in /usr/src/cmd/mh/strings: lockdir.o
+
+
+diff -rb /usr/src/cmd/mh/strings/lproc.c mh/strings/lproc.c
+14c14
+< char *lproc = "/usr/randbin/c";
+---
+> char *lproc = "/usr/ucb/more";
+Only in /usr/src/cmd/mh/strings: lproc.o
+Only in /usr/src/cmd/mh/strings: lsproc.o
+Only in /usr/src/cmd/mh/strings: mailboxes.o
+Only in /usr/src/cmd/mh/strings: mailproc.o
+Only in /usr/src/cmd/mh/strings: mh_deliver.o
+Only in /usr/src/cmd/mh/strings: mh_prof.o
+Only in /usr/src/cmd/mh/strings: mhlformat.o
+Only in /usr/src/cmd/mh/strings: mhlstdfmt.o
+Only in /usr/src/cmd/mh/strings: mhnews.o
+Only in /usr/src/cmd/mh/strings: msgprot.o
+Only in /usr/src/cmd/mh/strings: pfolder.o
+Only in /usr/src/cmd/mh/strings: prproc.o
+
+
+diff -rb /usr/src/cmd/mh/strings/rhosts.c mh/strings/rhosts.c
+19,23d18
+< "randvax",
+< "vax",
+< "graphics",
+< "gr",
+< "cs-rand",
+Only in /usr/src/cmd/mh/strings: rhosts.o
+
+
+diff -rb /usr/src/cmd/mh/strings/scanproc.c mh/strings/scanproc.c
+13c13
+< char *scanproc = "/usr/randbin/scan";
+---
+> char *scanproc = "/usr/local/scan";
+Only in /usr/src/cmd/mh/strings: scanproc.o
+
+
+diff -rb /usr/src/cmd/mh/strings/sendproc.c mh/strings/sendproc.c
+14c14
+< char *sendproc = "/usr/randbin/send";
+---
+> char *sendproc = "/usr/local/send";
+Only in /usr/src/cmd/mh/strings: sendproc.o
+
+
+diff -rb /usr/src/cmd/mh/strings/showproc.c mh/strings/showproc.c
+16c16
+< char *showproc = "/usr/randbin/c"; /* 5/6/79 */
+---
+> char *showproc = "/usr/ucb/more"; /* 5/6/79 */
+Only in /usr/src/cmd/mh/strings: showproc.o
+Only in /usr/src/cmd/mh/strings: stdcomps.o
+Only in /usr/src/cmd/mh/strings: stddcomps.o
+Only in /usr/src/cmd/mh/strings: strings.a
+Only in /usr/src/cmd/mh/strings: sysed.o
+Only in mh/strings: sysname.c
+
+
+diff -rb /usr/src/cmd/mh/subs/Makefile mh/subs/Makefile
+8c8
+< CFLAGS = # -m
+---
+> CFLAGS = -O -I/usr/include -I../support # -m
+161c161
+< m_edit.o: /usr/include/strings.h
+---
+> #m_edit.o: /usr/include/strings.h
+204c204
+< pwd.o: /usr/include/strings.h
+---
+> #pwd.o: /usr/include/strings.h
+Only in mh/subs: Makefile.bak
+Only in /usr/src/cmd/mh/subs: add.o
+Only in /usr/src/cmd/mh/subs: ambigsw.o
+Only in /usr/src/cmd/mh/subs: atooi.o
+Only in /usr/src/cmd/mh/subs: brkstring.o
+Only in /usr/src/cmd/mh/subs: cdate.o
+Only in /usr/src/cmd/mh/subs: cndfree.o
+Only in /usr/src/cmd/mh/subs: concat.o
+Only in /usr/src/cmd/mh/subs: copy.o
+Only in /usr/src/cmd/mh/subs: copyip.o
+Only in /usr/src/cmd/mh/subs: cputc.o
+Only in /usr/src/cmd/mh/subs: done.o
+Only in /usr/src/cmd/mh/subs: err
+Only in /usr/src/cmd/mh/subs: fdcompare.o
+Only in /usr/src/cmd/mh/subs: gans.o
+Only in /usr/src/cmd/mh/subs: getans.o
+Only in /usr/src/cmd/mh/subs: getcpy.o
+Only in /usr/src/cmd/mh/subs: help.o
+Only in /usr/src/cmd/mh/subs: locv.o
+Only in /usr/src/cmd/mh/subs: m_convert.o
+Only in /usr/src/cmd/mh/subs: m_delete.o
+Only in /usr/src/cmd/mh/subs: m_edit.o
+Only in /usr/src/cmd/mh/subs: m_file.o
+Only in /usr/src/cmd/mh/subs: m_find.o
+Only in /usr/src/cmd/mh/subs: m_getcur.o
+Only in /usr/src/cmd/mh/subs: m_getdefs.c1
+Only in /usr/src/cmd/mh/subs: m_getdefs.o
+Only in /usr/src/cmd/mh/subs: m_getfld.o
+Only in /usr/src/cmd/mh/subs: m_getfolder.o
+Only in /usr/src/cmd/mh/subs: m_gmprot.o
+Only in /usr/src/cmd/mh/subs: m_gmsg.o
+Only in /usr/src/cmd/mh/subs: m_maildir.o
+Only in /usr/src/cmd/mh/subs: m_name.o
+Only in /usr/src/cmd/mh/subs: m_replace.o
+Only in /usr/src/cmd/mh/subs: m_send.o
+Only in /usr/src/cmd/mh/subs: m_setcur.o
+Only in /usr/src/cmd/mh/subs: m_update.o
+Only in /usr/src/cmd/mh/subs: makedir.o
+Only in /usr/src/cmd/mh/subs: makename.o
+Only in /usr/src/cmd/mh/subs: mu_atoi.o
+Only in /usr/src/cmd/mh/subs: path.o
+Only in /usr/src/cmd/mh/subs: peekc.o
+Only in /usr/src/cmd/mh/subs: pr_array.o
+Only in /usr/src/cmd/mh/subs: printsw.o
+Only in /usr/src/cmd/mh/subs: putenv.o
+Only in /usr/src/cmd/mh/subs: pwd.o
+Only in /usr/src/cmd/mh/subs: r1bindex.o
+Only in /usr/src/cmd/mh/subs: showfile.o
+Only in /usr/src/cmd/mh/subs: smatch.o
+Only in /usr/src/cmd/mh/subs: ssequal.o
+Only in /usr/src/cmd/mh/subs: subs.a
+Only in /usr/src/cmd/mh/subs: trimcpy.o
+Only in /usr/src/cmd/mh/subs: type.o
+Only in /usr/src/cmd/mh/subs: uleq.o
+Only in /usr/src/cmd/mh/support: err
+Only in mh/support: mailsys.h
+Common subdirectories: /usr/src/cmd/mh/support/news and mh/support/news
+Only in mh/support: strings.h
+
+
+diff -rb /usr/src/cmd/mh/support/news/mh_receive mh/support/news/mh_receive
+6c6
+< /usr/randbin/file -link -file $1 +/usr/news/$F
+---
+> /usr/local/file -link -file $1 +/usr/news/$F
+8c8
+< /usr/randbin/file -link -file $1 +/usr/news/Lost+Found
+---
+> /usr/local/file -link -file $1 +/usr/news/Lost+Found
+11c11
+< /usr/randbin/file -link -file $1 +/usr/news/Lost+Found
+---
+> /usr/local/file -link -file $1 +/usr/
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* mh.h - main header file for all of mh */
+
+/* VOID is used to indicate explicitly that the value of a function
+/* is to be ignored.
+/* If you have a newer C compiler, it is better to simply say:
+ #define VOID (void)
+/* instead of what follows
+/**/
+# define void int
+# ifdef lint
+# define VOID _VOID_ = (int)
+ int _VOID_;
+# else
+# define VOID
+# endif
+
+/* #define ARPANET /* if you are on the ARPANET */
+
+/* #define VMUNIX /* if you are running a Berkeley system */
+/* if you define VMUNIX, then define JOBSLIB=-ljobs in progs/Makefile */
+
+#ifdef ARPANET
+#define NOGATEWAY
+#ifdef NOGATEWAY
+ extern char *rhosts[];
+#endif NOGATEWAY
+#endif ARPANET
+
+#define ALL ""
+#define NULLCP (char *)0
+
+#define MAXFOLDER 999 /* Max number of messages in a folder */
+#define DMAXFOLDER 3 /* Number of digits in MAXFOLDER */
+
+#define MAXARGS 1000 /* Max messages to exec */
+
+ /* Flag bits in msgstats */
+#define EXISTS 01 /* Message exists */
+#define DELETED 02 /* Deleted undefined currently */
+#define SELECTED 04 /* Message selected by an arg */
+#define SELECT_EMPTY 010/* Single empty msg selected by an mhpath arg */
+
+#define READONLY 01 /* No write access to folder */
+#define DEFMOD 01 /* In-core profile has been modified */
+
+/*#define NEWS 1 /* Define for news inclusion */
+
+struct swit {
+ char *sw;
+ int minchars;
+};
+
+/*
+ * m_gmsg() returns this structure. It contains the per folder
+ * information which is obtained from reading the folder directory.
+ */
+
+struct msgs {
+ int hghmsg; /* Highest msg in directory */
+ int nummsg; /* Actual Number of msgs */
+ int lowmsg; /* Lowest msg number */
+ int curmsg; /* Number of current msg if any */
+ int lowsel; /* Lowest selected msg number */
+ int hghsel; /* Highest selected msg number */
+ int numsel; /* Number of msgs selected */
+ char *foldpath; /* Pathname of folder */
+ char selist, /* Folder has a "select" file */
+ msgflags, /* Folder status bits */
+ filler,
+ others; /* Folder has other file(s) */
+ char msgstats[1]; /* Stat bytes for each msg */
+};
+
+ /* m_getfld definitions and return values */
+
+#define NAMESZ 64 /* Limit on component name size */
+#define LENERR -2 /* Name too long error from getfld */
+#define FMTERR -3 /* Message Format error */
+
+ /* m_getfld return codes */
+#define FLD 0 /* Field returned */
+#define FLDPLUS 1 /* Field " with more to come */
+#define FLDEOF 2 /* Field " ending at eom */
+#define BODY 3 /* Body " with more to come */
+#define BODYEOF 4 /* Body " ending at eom */
+#define FILEEOF 5 /* Reached end of input file */
+
+/*
+ * These standard strings are defined in strings.a. They are the
+ * only system-dependent parameters in MH, and thus by redefining
+ * their values and reloading the various modules, MH will run
+ * on any system.
+ */
+
+extern char
+ *components, /* Name of user's component file (in mh dir) */
+ *current, /* Name of current msg file in a folder */
+ *defalt, /* Name of the std folder (inbox) */
+ *distcomps, /* Name of `dist' components file */
+ *draft, /* Name of the normal draft file */
+ *fileproc, /* Path of file program */
+ *foldprot, /* Default folder protection */
+/* *hostname, /* Local net host name */
+ *installproc, /* Name of auto-install program path */
+/* *layout, /* Name of mhl layout file */
+ *listname, /* Default selection list folder name */
+ *lockdir, /* Dir for lock files (Same fs as mailboxes)*/
+ *lproc, /* Path of "list" prog for "What now?" */
+ *lsproc, /* Path of the block style ls program */
+ *mailboxes, /* Incoming mail directory */
+ *mailproc, /* Path of Bell equivalent mail pgm, used by news -send */
+ *mh_prof, /* Name of users profile file */
+ *mh_deliver, /* Name of deliverer for mh */
+ *mhlformat, /* Name of mhl format file in MH dir */
+ *mhlstdfmt, /* Name of standard mhl format file */
+ *mhnews, /* Name of MH news file */
+ *msgprot, /* Default message protection (s.a. 0664) */
+ *pfolder, /* Name of current folder profile entry */
+ *prproc, /* Path of the pr program */
+ *scanproc, /* Path of the scan program */
+ *showproc, /* Path of the type (l) program */
+ *sendproc, /* Path of the send message program */
+ *stdcomps, /* Std comp file if missing user's own */
+ *stddcomps, /* Std dist file if missing user's own */
+ *sysed; /* Path of the std (e) editor */
+
+/* Just about every program uses this also via m_getdefs */
+char *mypath; /* User's log-on path */
+
+/*
+ * node structure used to hold a linked list of the users profile
+ * information taken from logpath/.mh_prof.
+ */
+
+struct node {
+ struct node *n_next;
+ char *n_name,
+ *n_field;
+} *m_defs;
+
+char def_flags;
+
+
+/*
+ * The first char in the mhnews file indicates whether the program
+ * calling m_news() should continue running or halt.
+ */
+
+#define NEWSHALT '!' /* Halt after showing the news */
+#define NEWSCONT ' ' /* Continue (ditto) */
+#define NEWSPAUSE '\001' /* Pause during news output... */
+
+
+/*
+ * Miscellaneous Defines to speed things up
+ */
+
+#define error(str) { fprintf(stderr, "%s\n", str); exit(-1); }
+
+/*
+ * Routine type declarations -- needed by version 7 compiler
+ */
+
+char *invo_name;
+char **brkstring();
+char *m_maildir();
+char *m_find();
+char *m_name();
+char *concat();
+char *getcpy();
+char *trimcpy();
+char *add();
+char **copyip();
+char *getcpy();
+char *m_getfolder();
+struct msgs *m_gmsg();
+char *copy();
+char **getans();
+char *cdate();
+char *makename();
+char *r1bindex();
+char *pwd();
+char *path();
+
+/*
+ * Routine type declarations -- SHOULD BE GLOBAL
+ */
+char *getenv();
+
+/*
+ * Defines for path evaluation type--routine path second arg:
+ */
+
+#define TFOLDER 0
+#define TF
\ No newline at end of file
--- /dev/null
+sed "/DEPENDENCIES/,\$d" < Makefile > Maketemp
+echo "###DEPENDENCIES Follow. Do not delete this line" >> Maketemp
+grep \^#include $@ | sed '
+ s/\.c/\.o/
+ s/:#include/: /
+ s/"\(.*\)"/\1/
+ s/<\(.*\)>/\/usr\/include\/\1/
+' >> Maketemp
+mv Makefile Makeback
+mv Maketemp Makefile
--- /dev/null
+#
+# Proprietary Rand Corporation, 1981.
+# Further distribution of this software
+# subject to the terms of the Rand
+# license agreement.
+#
+
+# Remove the -DRAND elsewhere!
+# In ../mh.h: define ARPANET if you are on the arpanet.
+# In ../mh.h: define VMUNIX if you are running a berkeley system
+JOBSLIB=#-ljobs
+
+CFLAGS = -O $(A) -I/usr/include -I../support # -m -DRAND
+# On a PDP/11, if the sticky bit is to be set, text must be shareable
+CCSHARE = -n
+
+# The following two must match entry in ../Makefile
+BINDIR = /usr/local
+MHDIR = /etc/mh
+MHTMP = /usr/tmp/mh
+LOCKDIR = /usr/spool/locks
+NETDIR = /usr/spool/netmail
+
+SUBS = ../subs/subs.a
+STRINGS = ../strings/strings.a
+
+LINT = lint
+
+# The 'dist' program is not ready yet, and so is not listed in the CMDS
+# See also ../man/Makefile
+CMDS = \
+ali \
+comp \
+file \
+folder \
+forw \
+inc \
+mail \
+mhpath \
+next \
+news \
+pick \
+prev \
+prompter \
+repl \
+rmf \
+rmm \
+scan \
+send \
+show
+
+MISC = \
+conflict \
+deliver \
+install-mh \
+mhl
+
+PROGS = $(CMDS) $(MISC) rmail
+
+CFILES = \
+adrformat.c \
+adrparse.c \
+ali.c \
+comp.c \
+conflict.c \
+deliver.c \
+dist.c \
+file.c \
+folder.c \
+forw.c \
+inc.c \
+install-mh.c \
+mail.c \
+mhl.c \
+mhpath.c \
+news.c \
+next.c \
+pick.c \
+prompter.c \
+repl.c \
+rmail.c \
+rmf.c \
+rmm.c \
+scan.c \
+scansub.c \
+send.c \
+show.c
+
+progs: $(PROGS)
+
+ali: ali.o $(SUBS)
+ $(CC) -o ali ali.o $(SUBS)
+
+comp: comp.o $(SUBS) $(STRINGS)
+ $(CC) $(CCSHARE) -o comp comp.o $(SUBS) $(STRINGS)
+
+conflict: conflict.o $(SUBS)
+ $(CC) -o conflict conflict.o $(SUBS)
+
+deliver: deliver.o adrparse.o adrformat.o $(SUBS) $(STRINGS)
+ $(CC) $(CCSHARE) -o deliver deliver.o adrparse.o adrformat.o $(SUBS) \
+ $(STRINGS) $(JOBSLIB)
+
+dist: dist.o annotate.o $(SUBS) $(STRINGS)
+ $(CC) -o dist dist.o annotate.o $(SUBS) $(STRINGS)
+
+file: file.o $(SUBS) $(STRINGS)
+ $(CC) -o file file.o $(SUBS) $(STRINGS)
+
+folder: folder.o $(SUBS) $(STRINGS)
+ $(CC) -o folder folder.o $(SUBS) $(STRINGS)
+
+forw: forw.o annotate.o $(SUBS) $(STRINGS)
+ $(CC) -o forw forw.o annotate.o $(SUBS) $(STRINGS)
+
+inc: inc.o scansub.o $(SUBS) $(STRINGS)
+ $(CC) $(CCSHARE) -o inc inc.o scansub.o $(SUBS) $(STRINGS)
+
+install-mh: install-mh.o $(SUBS) $(STRINGS)
+ $(CC) -o install-mh install-mh.o $(SUBS) $(STRINGS)
+
+mail: mail.o $(SUBS) $(STRINGS)
+ $(CC) -o mail mail.o $(SUBS) $(STRINGS)
+
+mhpath: mhpath.o $(SUBS) $(STRINGS)
+ $(CC) -o mhpath mhpath.o $(SUBS) $(STRINGS)
+
+mhl: mhl.o $(SUBS) $(STRINGS)
+ $(CC) -o mhl mhl.o $(SUBS) $(STRINGS)
+
+news: news.o $(SUBS) $(STRINGS)
+ $(CC) -o news news.o $(SUBS) $(STRINGS)
+
+next: nexthdr.o next.o $(SUBS) $(STRINGS)
+ $(CC) $(CCSHARE) -o next nexthdr.o next.o $(SUBS) $(STRINGS)
+
+pick: pick.o grep.o $(SUBS) $(STRINGS)
+ $(CC) -o pick pick.o grep.o $(SUBS) $(STRINGS)
+
+prev: prevhdr.o next.o $(SUBS) $(STRINGS)
+ $(CC) -o prev prevhdr.o next.o $(SUBS) $(STRINGS)
+
+prompter: prompter.o $(SUBS) $(STRINGS)
+ $(CC) $(CCSHARE) -o prompter prompter.o $(SUBS) $(STRINGS)
+
+repl: repl.o annotate.o adrparse.o adrformat.o $(SUBS) $(STRINGS)
+ $(CC) -o repl repl.o annotate.o adrparse.o adrformat.o $(SUBS) $(STRINGS)
+
+rmail: rmail.o $(SUBS) $(STRINGS)
+ $(CC) -o rmail rmail.o $(SUBS) $(STRINGS)
+
+rmf: rmf.o $(SUBS) $(STRINGS)
+ $(CC) -o rmf rmf.o $(SUBS) $(STRINGS)
+
+rmm: rmm.o $(SUBS) $(STRINGS)
+ $(CC) -o rmm rmm.o $(SUBS) $(STRINGS)
+
+scan: scan.o scansub.o $(SUBS) $(STRINGS)
+ $(CC) -o scan scan.o scansub.o $(SUBS) $(STRINGS)
+
+send: send.o $(SUBS) $(STRINGS)
+ $(CC) -o send send.o $(SUBS) $(STRINGS)
+
+show: show.o $(SUBS) $(STRINGS)
+ $(CC) $(CCSHARE) -o show show.o $(SUBS) $(STRINGS)
+
+lint:
+ -$(LINT) ali.c -v ../subs/subs-lc | tee ali.lint
+ -$(LINT) comp.c -v ../subs/subs-lc | tee comp.lint
+ -$(LINT) conflict.c -v ../subs/subs-lc | tee conflict.lint
+ -$(LINT) deliver.c adrparse.c adrformat.c -v ../subs/subs-lc | tee deliver.lint
+ -$(LINT) dist.c -v ../subs/subs-lc | tee dist.lint
+ -$(LINT) file.c -v ../subs/subs-lc | tee file.lint
+ -$(LINT) folder.c -v ../subs/subs-lc | tee folder.lint
+ -$(LINT) forw.c annotate.c -v ../subs/subs-lc | tee forw.lint
+ -$(LINT) inc.c scansub.c -v ../subs/subs-lc | tee inc.lint
+ -$(LINT) install-mh.c -v ../subs/subs-lc | tee install.lint
+ -$(LINT) mail.c -v ../subs/subs-lc | tee mail.lint
+ -$(LINT) mhl.c -v ../subs/subs-lc | tee mhl.lint
+ -$(LINT) mhpath.c -v ../subs/subs-lc | tee mhpath.lint
+ -$(LINT) news.c -v ../subs/subs-lc | tee news.lint
+ -$(LINT) pick.c -v ../subs/subs-lc | tee pick.lint
+ -$(LINT) prevhdr.c next.c -v ../subs/subs-lc | tee prev.lint
+ -$(LINT) prompter.c -v ../subs/subs-lc | tee prompter.lint
+ -$(LINT) repl.c replsubs.c -v ../subs/subs-lc | tee repl.lint
+ -$(LINT) rmf.c -v ../subs/subs-lc | tee rmf.lint
+ -$(LINT) rmm.c -v ../subs/subs-lc | tee rmm.lint
+ -$(LINT) scan.c scansub.c -v ../subs/subs-lc | tee scan.lint
+ -$(LINT) show.c -v ../subs/subs-lc | tee show.lint
+
+install: strip installprogs
+ -mkdir $(MHTMP)
+ -mkdir $(MHDIR)
+ -mkdir $(LOCKDIR)
+ -mkdir $(NETDIR)
+ -chmod a+x $(MISC)
+ -cd $(MHDIR); rm -f $(MISC)
+ -cp $(MISC) $(MHDIR)
+ echo Now become root and \'make installroot\'
+
+installprogs: chmod
+ -cd $(BINDIR); rm -f $(CMDS) folders
+ -cp $(CMDS) $(BINDIR)
+ -cd $(BINDIR); ln folder folders
+
+installroot:
+ -chmod 777 $(MHTMP)
+ -cd $(BINDIR); chmod a+x $(CMDS)
+ -cd $(MHDIR); chmod a+x $(MISC)
+ /etc/chown root $(NETDIR)
+ chmod 755 $(NETDIR)
+ -rm -f /bin/rmail
+ /etc/chown root $(LOCKDIR)
+ chmod 777 $(LOCKDIR)
+ -cp rmail /bin
+# Setuid and Setgid:
+ -chmod 6755 /bin/rmail
+# Sticky Bit & Setuid:
+ -/etc/chown root $(MHDIR)/deliver;chmod 5755 $(MHDIR)/deliver
+# Sticky Bit:
+ -chmod 1755 $(BINDIR)/comp
+ -chmod 1755 $(BINDIR)/inc
+ -chmod 1755 $(BINDIR)/next
+ -chmod 1755 $(BINDIR)/prompter
+ -chmod 1755 $(BINDIR)/show
+
+uninstall:
+ -rmdir $(MHTMP)
+ -cd $(MHDIR); rm -f $(MISC)
+ -cd $(BINDIR); rm -f $(CMDS) folders
+
+strip:
+ -strip $(PROGS)
+
+chmod:
+ chmod a+x $(PROGS)
+
+pinstall:
+ -install -s comp $(BINDIR)/comp
+ -install -s file $(BINDIR)/file
+ -install -s folder $(BINDIR)/folder
+ -install -s forw $(BINDIR)/forw
+ -install -s inc $(BINDIR)/inc
+ -install -s mhl $(MHDIR)/mhl
+ -install -s mhpath $(BINDIR)/mhpath
+ -install -s next $(BINDIR)/next
+ -install -s pick $(BINDIR)/pick
+ -install -s prev $(BINDIR)/prev
+ -install -s prompter $(BINDIR)/prompter
+ -install -s repl $(BINDIR)/repl
+ -install -s rmf $(BINDIR)/rmf
+ -install -s rmm $(BINDIR)/rmm
+ -install -s scan $(BINDIR)/scan
+ -install -s send $(BINDIR)/send
+ -install -s show $(BINDIR)/show
+
+distribution: clean rmprogs
+
+rmprogs:
+ -rm -f $(PROGS)
+
+clean:
+ -rm -f *.o *.lint
+
+depend:
+ ../misc/depend.sh $(CFILES)
+
+
+###DEPENDENCIES Follow. Do not delete this line
+adrformat.o: /usr/include/stdio.h
+adrformat.o: ../mh.h
+adrformat.o: ../adrparse.h
+adrformat.o: /usr/include/ctype.h
+adrparse.o: /usr/include/stdio.h
+#adrparse.o: /usr/include/whoami.h
+adrparse.o: ../mh.h
+adrparse.o: ../adrparse.h
+#adrparse.o: /usr/include/imp.h
+adrparse.o: /usr/include/ctype.h
+ali.o: ../mh.h
+ali.o: /usr/include/stdio.h
+ali.o: /usr/include/ctype.h
+ali.o: /usr/include/pwd.h
+ali.o: /usr/include/sys/types.h
+comp.o: ../mh.h
+comp.o: /usr/include/stdio.h
+#comp.o: /usr/include/strings.h
+comp.o: /usr/include/signal.h
+conflict.o: /usr/include/stdio.h
+conflict.o: /usr/include/ctype.h
+conflict.o: /usr/include/pwd.h
+conflict.o: /usr/include/grp.h
+conflict.o: /usr/include/sys/types.h
+conflict.o: /usr/include/sys/dir.h
+conflict.o: ../mh.h
+#conflict.o: /usr/include/mailsys.h
+#deliver.o: /usr/include/whoami.h
+deliver.o: ../mh.h
+deliver.o: ../adrparse.h
+deliver.o: /usr/include/stdio.h
+deliver.o: /usr/include/ctype.h
+deliver.o: /usr/include/pwd.h
+deliver.o: /usr/include/sys/types.h
+deliver.o: /usr/include/sys/timeb.h
+deliver.o: /usr/include/sys/stat.h
+deliver.o: /usr/include/signal.h
+#deliver.o: /usr/include/strings.h
+#deliver.o: /usr/include/mailsys.h
+deliver.o: /usr/include/time.h
+dist.o: ../mh.h
+dist.o: /usr/include/stdio.h
+dist.o: /usr/include/signal.h
+#dist.o: /usr/include/strings.h
+dist.o: /usr/include/sys/types.h
+dist.o: /usr/include/sys/stat.h
+file.o: ../mh.h
+file.o: ../folder.h
+file.o: /usr/include/stdio.h
+folder.o: ../mh.h
+folder.o: /usr/include/stdio.h
+folder.o: /usr/include/sys/types.h
+folder.o: /usr/include/sys/stat.h
+#folder.o: /usr/include/strings.h
+forw.o: ../mh.h
+forw.o: /usr/include/stdio.h
+forw.o: /usr/include/signal.h
+#forw.o: /usr/include/strings.h
+forw.o: /usr/include/sys/types.h
+forw.o: /usr/include/sys/stat.h
+inc.o: ../mh.h
+inc.o: /usr/include/stdio.h
+inc.o: /usr/include/sys/types.h
+inc.o: /usr/include/sys/stat.h
+inc.o: /usr/include/errno.h
+#inc.o: /usr/include/strings.h
+inc.o: /usr/include/signal.h
+inc.o: scansub.h
+install-mh.o: ../mh.h
+install-mh.o: /usr/include/stdio.h
+install-mh.o: /usr/include/sys/types.h
+install-mh.o: /usr/include/sys/stat.h
+mail.o: ../mh.h
+mail.o: /usr/include/stdio.h
+mail.o: /usr/include/signal.h
+mhl.o: /usr/include/ctype.h
+mhl.o: /usr/include/signal.h
+mhl.o: /usr/include/setjmp.h
+mhl.o: /usr/include/sgtty.h
+mhl.o: /usr/include/stdio.h
+mhl.o: ../mh.h
+mhpath.o: ../mh.h
+mhpath.o: /usr/include/stdio.h
+#mhpath.o: /usr/include/strings.h
+mhpath.o: /usr/include/ctype.h
+news.o: ../mh.h
+news.o: /usr/include/stdio.h
+news.o: /usr/include/sys/types.h
+news.o: /usr/include/sys/stat.h
+news.o: /usr/include/sys/dir.h
+#news.o: /usr/include/strings.h
+news.o: /usr/include/sys/timeb.h
+next.o: ../mh.h
+next.o: /usr/include/stdio.h
+#next.o: /usr/include/strings.h
+pick.o: ../mh.h
+pick.o: ../folder.h
+pick.o: /usr/include/stdio.h
+pick.o: /usr/include/signal.h
+pick.o: /usr/include/sys/types.h
+pick.o: /usr/include/sys/stat.h
+prompter.o: ../mh.h
+prompter.o: /usr/include/stdio.h
+prompter.o: /usr/include/errno.h
+prompter.o: /usr/include/sgtty.h
+prompter.o: /usr/include/signal.h
+#prompter.o: /usr/include/strings.h
+#repl.o: /usr/include/whoami.h
+repl.o: ../mh.h
+repl.o: /usr/include/stdio.h
+repl.o: /usr/include/signal.h
+#repl.o: /usr/include/strings.h
+repl.o: /usr/include/sys/types.h
+repl.o: /usr/include/sys/stat.h
+repl.o: ../adrparse.h
+rmail.o: ../mh.h
+#rmail.o: /usr/include/whoami.h
+rmail.o: /usr/include/stdio.h
+rmail.o: /usr/include/sys/types.h
+rmail.o: /usr/include/sys/timeb.h
+rmail.o: /usr/include/time.h
+rmf.o: ../mh.h
+rmf.o: /usr/include/stdio.h
+#rmf.o: /usr/include/strings.h
+rmm.o: ../mh.h
+rmm.o: /usr/include/stdio.h
+#rmm.o: /usr/include/strings.h
+scan.o: ../mh.h
+scan.o: /usr/include/stdio.h
+#scan.o: /usr/include/strings.h
+scan.o: scansub.h
+scansub.o: ../mh.h
+#scansub.o: /usr/include/whoami.h
+scansub.o: /usr/include/stdio.h
+scansub.o: /usr/include/ctype.h
+scansub.o: /usr/include/time.h
+scansub.o: ../adrparse.h
+scansub.o: scansub.h
+send.o: ../mh.h
+send.o: /usr/include/stdio.h
+send.o: /usr/include/sys/types.h
+send.o: /usr/include/stat.h
+#send.o: /usr/include/strings.h
+send.o: /usr/include/signal.h
+show.o: ../mh.h
+show.o: /usr/include/stdio.h
+#show.o: /usr/include/strings.h
\ No newline at end of file
--- /dev/null
+#
+# Proprietary Rand Corporation, 1981.
+# Further distribution of this software
+# subject to the terms of the Rand
+# license agreement.
+#
+
+# Remove the -DRAND elsewhere!
+# In ../mh.h: define ARPANET if you are on the arpanet.
+# In ../mh.h: define VMUNIX if you are running a berkeley system
+JOBSLIB=#-ljobs
+
+CFLAGS = -O $(A) # -m -DRAND
+# The following two must match entry in ../Makefile
+BINDIR = /usr/local
+MHDIR = /etc/mh
+MHTMP = /usr/tmp/mh
+LOCKDIR = /usr/spool/locks
+NETDIR = /usr/spool/netmail
+
+SUBS = ../subs/subs.a
+STRINGS = ../strings/strings.a
+
+LINT = lint
+
+# The 'dist' program is not ready yet, and so is not listed in the CMDS
+# See also ../man/Makefile
+CMDS = \
+ali \
+comp \
+file \
+folder \
+forw \
+inc \
+mail \
+mhpath \
+next \
+news \
+pick \
+prev \
+prompter \
+repl \
+rmf \
+rmm \
+scan \
+send \
+show
+
+MISC = \
+conflict \
+deliver \
+install-mh \
+mhl
+
+PROGS = $(CMDS) $(MISC) rmail
+
+CFILES = \
+adrformat.c \
+adrparse.c \
+ali.c \
+comp.c \
+conflict.c \
+deliver.c \
+dist.c \
+file.c \
+folder.c \
+forw.c \
+inc.c \
+install-mh.c \
+mail.c \
+mhl.c \
+mhpath.c \
+news.c \
+next.c \
+pick.c \
+prompter.c \
+repl.c \
+rmail.c \
+rmf.c \
+rmm.c \
+scan.c \
+scansub.c \
+send.c \
+show.c
+
+progs: $(PROGS)
+
+ali: ali.o $(SUBS)
+ $(CC) -o ali ali.o $(SUBS)
+
+comp: comp.o $(SUBS) $(STRINGS)
+ $(CC) -o comp comp.o $(SUBS) $(STRINGS)
+
+conflict: conflict.o $(SUBS)
+ $(CC) -o conflict conflict.o $(SUBS)
+
+deliver: deliver.o adrparse.o adrformat.o $(SUBS) $(STRINGS)
+ $(CC) -o deliver deliver.o adrparse.o adrformat.o $(SUBS) $(STRINGS)\
+ $(JOBSLIB)
+
+dist: dist.o annotate.o $(SUBS) $(STRINGS)
+ $(CC) -o dist dist.o annotate.o $(SUBS) $(STRINGS)
+
+file: file.o $(SUBS) $(STRINGS)
+ $(CC) -o file file.o $(SUBS) $(STRINGS)
+
+folder: folder.o $(SUBS) $(STRINGS)
+ $(CC) -o folder folder.o $(SUBS) $(STRINGS)
+
+forw: forw.o annotate.o $(SUBS) $(STRINGS)
+ $(CC) -o forw forw.o annotate.o $(SUBS) $(STRINGS)
+
+inc: inc.o scansub.o $(SUBS) $(STRINGS)
+ $(CC) -o inc inc.o scansub.o $(SUBS) $(STRINGS)
+
+install-mh: install-mh.o $(SUBS) $(STRINGS)
+ $(CC) -o install-mh install-mh.o $(SUBS) $(STRINGS)
+
+mail: mail.o $(SUBS) $(STRINGS)
+ $(CC) -o mail mail.o $(SUBS) $(STRINGS)
+
+mhpath: mhpath.o $(SUBS) $(STRINGS)
+ $(CC) -o mhpath mhpath.o $(SUBS) $(STRINGS)
+
+mhl: mhl.o $(SUBS) $(STRINGS)
+ $(CC) -o mhl mhl.o $(SUBS) $(STRINGS)
+
+news: news.o $(SUBS) $(STRINGS)
+ $(CC) -o news news.o $(SUBS) $(STRINGS)
+
+next: nexthdr.o next.o $(SUBS) $(STRINGS)
+ $(CC) -o next nexthdr.o next.o $(SUBS) $(STRINGS)
+
+pick: pick.o grep.o $(SUBS) $(STRINGS)
+ $(CC) -o pick pick.o grep.o $(SUBS) $(STRINGS)
+
+prev: prevhdr.o next.o $(SUBS) $(STRINGS)
+ $(CC) -o prev prevhdr.o next.o $(SUBS) $(STRINGS)
+
+prompter: prompter.o $(SUBS) $(STRINGS)
+ $(CC) -o prompter prompter.o $(SUBS) $(STRINGS)
+
+repl: repl.o annotate.o adrparse.o adrformat.o $(SUBS) $(STRINGS)
+ $(CC) -o repl repl.o annotate.o adrparse.o adrformat.o $(SUBS) $(STRINGS)
+
+rmail: rmail.o $(SUBS) $(STRINGS)
+ $(CC) -o rmail rmail.o $(SUBS) $(STRINGS)
+
+rmf: rmf.o $(SUBS) $(STRINGS)
+ $(CC) -o rmf rmf.o $(SUBS) $(STRINGS)
+
+rmm: rmm.o $(SUBS) $(STRINGS)
+ $(CC) -o rmm rmm.o $(SUBS) $(STRINGS)
+
+scan: scan.o scansub.o $(SUBS) $(STRINGS)
+ $(CC) -o scan scan.o scansub.o $(SUBS) $(STRINGS)
+
+send: send.o $(SUBS) $(STRINGS)
+ $(CC) -o send send.o $(SUBS) $(STRINGS)
+
+show: show.o $(SUBS) $(STRINGS)
+ $(CC) -o show show.o $(SUBS) $(STRINGS)
+
+lint:
+ -$(LINT) ali.c -v ../subs/subs-lc | tee ali.lint
+ -$(LINT) comp.c -v ../subs/subs-lc | tee comp.lint
+ -$(LINT) conflict.c -v ../subs/subs-lc | tee conflict.lint
+ -$(LINT) deliver.c adrparse.c adrformat.c -v ../subs/subs-lc | tee deliver.lint
+ -$(LINT) dist.c -v ../subs/subs-lc | tee dist.lint
+ -$(LINT) file.c -v ../subs/subs-lc | tee file.lint
+ -$(LINT) folder.c -v ../subs/subs-lc | tee folder.lint
+ -$(LINT) forw.c annotate.c -v ../subs/subs-lc | tee forw.lint
+ -$(LINT) inc.c scansub.c -v ../subs/subs-lc | tee inc.lint
+ -$(LINT) install-mh.c -v ../subs/subs-lc | tee install.lint
+ -$(LINT) mail.c -v ../subs/subs-lc | tee mail.lint
+ -$(LINT) mhl.c -v ../subs/subs-lc | tee mhl.lint
+ -$(LINT) mhpath.c -v ../subs/subs-lc | tee mhpath.lint
+ -$(LINT) news.c -v ../subs/subs-lc | tee news.lint
+ -$(LINT) pick.c -v ../subs/subs-lc | tee pick.lint
+ -$(LINT) prevhdr.c next.c -v ../subs/subs-lc | tee prev.lint
+ -$(LINT) prompter.c -v ../subs/subs-lc | tee prompter.lint
+ -$(LINT) repl.c replsubs.c -v ../subs/subs-lc | tee repl.lint
+ -$(LINT) rmf.c -v ../subs/subs-lc | tee rmf.lint
+ -$(LINT) rmm.c -v ../subs/subs-lc | tee rmm.lint
+ -$(LINT) scan.c scansub.c -v ../subs/subs-lc | tee scan.lint
+ -$(LINT) show.c -v ../subs/subs-lc | tee show.lint
+
+install: strip installprogs
+ -mkdir $(MHTMP)
+ chmod 777 $(MHTMP)
+ -mkdir $(MHDIR)
+ -mkdir $(LOCKDIR)
+ -mkdir $(NETDIR)
+ -chmod a+x $(MISC)
+ -cd $(MHDIR); rm -f $(MISC)
+ -cp $(MISC) $(MHDIR)
+ echo Now become root and \'make installroot\'
+
+installprogs:
+ -chmod a+x $(PROGS)
+ -cd $(BINDIR); rm -f $(CMDS) folders
+ -cp $(CMDS) $(BINDIR)
+ -cd $(BINDIR); ln folder folders
+
+installroot:
+ -cd $(BINDIR); chmod a+x $(CMDS)
+ -cd $(MHDIR); chmod a+x $(MISC)
+ /etc/chown root $(NETDIR)
+ chmod 755 $(NETDIR)
+ -rm -f /bin/rmail
+ /etc/chown root $(LOCKDIR)
+ chmod 777 $(LOCKDIR)
+ -cp rmail /bin
+# Setuid and Setgid:
+ -chmod 6755 /bin/rmail
+# Sticky Bit & Setgid: (?Setuid? PK)
+ -/etc/chown root $(MHDIR)/deliver;chmod 5755 $(MHDIR)/deliver
+# Sticky Bit:
+ -chmod 1755 $(BINDIR)/comp
+ -chmod 1755 $(BINDIR)/inc
+ -chmod 1755 $(BINDIR)/next
+ -chmod 1755 $(BINDIR)/prompter
+ -chmod 1755 $(BINDIR)/show
+
+uninstall:
+ -rmdir $(MHTMP)
+ -cd $(MHDIR); rm -f $(MISC)
+ -cd $(BINDIR); rm -f $(CMDS) folders
+
+strip:
+ -strip $(PROGS)
+
+chmod:
+ chmod a+x $(PROGS)
+
+pinstall:
+ -install -s comp $(BINDIR)/comp
+ -install -s file $(BINDIR)/file
+ -install -s folder $(BINDIR)/folder
+ -install -s forw $(BINDIR)/forw
+ -install -s inc $(BINDIR)/inc
+ -install -s mhl $(MHDIR)/mhl
+ -install -s mhpath $(BINDIR)/mhpath
+ -install -s next $(BINDIR)/next
+ -install -s pick $(BINDIR)/pick
+ -install -s prev $(BINDIR)/prev
+ -install -s prompter $(BINDIR)/prompter
+ -install -s repl $(BINDIR)/repl
+ -install -s rmf $(BINDIR)/rmf
+ -install -s rmm $(BINDIR)/rmm
+ -install -s scan $(BINDIR)/scan
+ -install -s send $(BINDIR)/send
+ -install -s show $(BINDIR)/show
+
+distribution: clean rmprogs
+
+rmprogs:
+ -rm -f $(PROGS)
+
+clean:
+ -rm -f *.o *.lint
+
+depend:
+ ../misc/depend.sh $(CFILES)
+
+
+###DEPENDENCIES Follow. Do not delete this line
+adrformat.o: /usr/include/stdio.h
+adrformat.o: ../mh.h
+adrformat.o: ../adrparse.h
+adrformat.o: /usr/include/ctype.h
+adrparse.o: /usr/include/stdio.h
+adrparse.o: /usr/include/whoami.h
+adrparse.o: ../mh.h
+adrparse.o: ../adrparse.h
+adrparse.o: /usr/include/imp.h
+adrparse.o: /usr/include/ctype.h
+ali.o: ../mh.h
+ali.o: /usr/include/stdio.h
+ali.o: /usr/include/ctype.h
+ali.o: /usr/include/pwd.h
+ali.o: /usr/include/sys/types.h
+comp.o: ../mh.h
+comp.o: /usr/include/stdio.h
+comp.o: /usr/include/strings.h
+comp.o: /usr/include/signal.h
+conflict.o: /usr/include/stdio.h
+conflict.o: /usr/include/ctype.h
+conflict.o: /usr/include/pwd.h
+conflict.o: /usr/include/grp.h
+conflict.o: /usr/include/sys/types.h
+conflict.o: /usr/include/sys/dir.h
+conflict.o: ../mh.h
+conflict.o: /usr/include/mailsys.h
+deliver.o: /usr/include/whoami.h
+deliver.o: ../mh.h
+deliver.o: ../adrparse.h
+deliver.o: /usr/include/stdio.h
+deliver.o: /usr/include/ctype.h
+deliver.o: /usr/include/pwd.h
+deliver.o: /usr/include/sys/types.h
+deliver.o: /usr/include/sys/timeb.h
+deliver.o: /usr/include/sys/stat.h
+deliver.o: /usr/include/signal.h
+deliver.o: /usr/include/strings.h
+deliver.o: /usr/include/mailsys.h
+deliver.o: /usr/include/time.h
+dist.o: ../mh.h
+dist.o: /usr/include/stdio.h
+dist.o: /usr/include/signal.h
+dist.o: /usr/include/strings.h
+dist.o: /usr/include/sys/types.h
+dist.o: /usr/include/sys/stat.h
+file.o: ../mh.h
+file.o: ../folder.h
+file.o: /usr/include/stdio.h
+folder.o: ../mh.h
+folder.o: /usr/include/stdio.h
+folder.o: /usr/include/sys/types.h
+folder.o: /usr/include/sys/stat.h
+folder.o: /usr/include/strings.h
+forw.o: ../mh.h
+forw.o: /usr/include/stdio.h
+forw.o: /usr/include/signal.h
+forw.o: /usr/include/strings.h
+forw.o: /usr/include/sys/types.h
+forw.o: /usr/include/sys/stat.h
+inc.o: ../mh.h
+inc.o: /usr/include/stdio.h
+inc.o: /usr/include/sys/types.h
+inc.o: /usr/include/sys/stat.h
+inc.o: /usr/include/errno.h
+inc.o: /usr/include/strings.h
+inc.o: /usr/include/signal.h
+inc.o: scansub.h
+install-mh.o: ../mh.h
+install-mh.o: /usr/include/stdio.h
+install-mh.o: /usr/include/sys/types.h
+install-mh.o: /usr/include/sys/stat.h
+mail.o: ../mh.h
+mail.o: /usr/include/stdio.h
+mail.o: /usr/include/signal.h
+mhl.o: /usr/include/ctype.h
+mhl.o: /usr/include/signal.h
+mhl.o: /usr/include/setjmp.h
+mhl.o: /usr/include/sgtty.h
+mhl.o: /usr/include/stdio.h
+mhl.o: ../mh.h
+mhpath.o: ../mh.h
+mhpath.o: /usr/include/stdio.h
+mhpath.o: /usr/include/strings.h
+mhpath.o: /usr/include/ctype.h
+news.o: ../mh.h
+news.o: /usr/include/stdio.h
+news.o: /usr/include/sys/types.h
+news.o: /usr/include/sys/stat.h
+news.o: /usr/include/sys/dir.h
+news.o: /usr/include/strings.h
+news.o: /usr/include/sys/timeb.h
+next.o: ../mh.h
+next.o: /usr/include/stdio.h
+next.o: /usr/include/strings.h
+pick.o: ../mh.h
+pick.o: ../folder.h
+pick.o: /usr/include/stdio.h
+pick.o: /usr/include/signal.h
+pick.o: /usr/include/sys/types.h
+pick.o: /usr/include/sys/stat.h
+prompter.o: ../mh.h
+prompter.o: /usr/include/stdio.h
+prompter.o: /usr/include/errno.h
+prompter.o: /usr/include/sgtty.h
+prompter.o: /usr/include/signal.h
+prompter.o: /usr/include/strings.h
+repl.o: /usr/include/whoami.h
+repl.o: ../mh.h
+repl.o: /usr/include/stdio.h
+repl.o: /usr/include/signal.h
+repl.o: /usr/include/strings.h
+repl.o: /usr/include/sys/types.h
+repl.o: /usr/include/sys/stat.h
+repl.o: ../adrparse.h
+rmail.o: ../mh.h
+rmail.o: /usr/include/whoami.h
+rmail.o: /usr/include/stdio.h
+rmail.o: /usr/include/sys/types.h
+rmail.o: /usr/include/sys/timeb.h
+rmail.o: /usr/include/time.h
+rmf.o: ../mh.h
+rmf.o: /usr/include/stdio.h
+rmf.o: /usr/include/strings.h
+rmm.o: ../mh.h
+rmm.o: /usr/include/stdio.h
+rmm.o: /usr/include/strings.h
+scan.o: ../mh.h
+scan.o: /usr/include/stdio.h
+scan.o: /usr/include/strings.h
+scan.o: scansub.h
+scansub.o: ../mh.h
+scansub.o: /usr/include/whoami.h
+scansub.o: /usr/include/stdio.h
+scansub.o: /usr/include/ctype.h
+scansub.o: /usr/include/time.h
+scansub.o: ../adrparse.h
+scansub.o: scansub.h
+send.o: ../mh.h
+send.o: /usr/include/stdio.h
+send.o: /usr/include/sys/types.h
+send.o: /usr/include/stat.h
+send.o: /usr/include/strings.h
+send.o: /usr/include/signal.h
+show.o: ../mh.h
+show.o: /usr/include/stdio.h
+show.o: /usr/include/strings.h
+show.o:
\ No newline at end of file
--- /dev/null
+ Several changes have been made recently, primarily to
+adrparse.c, adrformat.c, deliver.c, rmail.c, and repl.c.
+These changes permit MH messages to flow between the host
+machine, the Arpanet, and the UUCP system. A description
+of how all this works is included here.
+
+A. SENDING MAIL
+
+1) Arpanet mail. When a message is destined for the Arpanet,
+ a single copy of that message is placed in /usr/spool/netmail,
+ headed by a list of remote recipients. A mailer daemon
+ picks these up and delivers them via the FTP "MAIL" command.
+ If the local site is NOT an Arpanet site, the Arpanet address
+ is simply considered as a local address. One could, conceivably,
+ have a local user named "a@ucla-s", after all.
+
+2) UUCP mail. As DELIVER is processing the message, it is producing
+ a SECOND copy of the message in /usr/tmp/mh/uu*. This copy
+ differs from the normally-delivered copy in that no "format"
+ operation is ever done, and in that no "From: " line is
+ added to the header (the user may still have one if he
+ thinks he knows what he's doing). For each message destined
+ for a UUCP site, say "site!person", a header is prepended
+ of the form "From <local-user> <date> remote from <local-site>".
+ This message is then given as standard input to a command
+ like "uux - site!rmail person". Note that "person" may not
+ contain blanks. If it contains additional uucp routing,
+ the form is "uux - site!rmail (more!person)". Evidently,
+ without the parens, Uux considers "more!person" to be
+ the name of a remote file.
+
+B. RECEIVING MAIL
+
+1) Arpanet Mail. Mail from the Arpanet is received by the
+ FTP Server daemon via the MAIL (or MLFL) command. At
+ present, this server invokes the "rmail" program, which
+ purports to be the name of the standard Unix remote mail
+ program. Supposedly, this would even work on a system
+ not running MH or anything special. Right. Anyhow,
+ the Rmail associated with MH copies its input into a
+ file and gives that file to Deliver, with the special
+ option, "-deliverto <recipient>". This option is
+ reserved to the super-user and members of Uucp's
+ group (constant DAEMON_GROUP in deliver.c . It varies
+ between the /45 and the Vax, unfortunately). If
+ it were not so restricted, anybody could send mail
+ with forged signatures ("From: " lines). When
+ Deliver is given that option, it does nothing but
+ deliver the file as it sees it to the specified
+ recipient, be it local or remote. No formatting
+ or additional "From:" or "Date" processing is
+ performed, although Uucp "From" lines ARE added if needed.
+
+2) UUCP mail. As noted, Uucp mail happens when some
+ remote site executes Rmail via Uux. Out there
+ in the real world, the only thing you can expect
+ a message to have is one of those "From <user> <date>"
+ lines at the beginning. Perhaps several, if
+ it's been through this process before. Rmail is
+ able to take these lines and turn them into
+ a sensible line like "From: site1!site2!site3!person".
+ If a reasonable Arpa header follows (and it's pretty
+ crude about "reasonable"), Rmail just prepends that
+ From: line and copies the input into a file and
+ gives it to Deliver as in the Arpanet case. If not,
+ it adds an extra blank line, thus leaving you
+ with a header consisting of just the From: line.
+ Deliver then sends the formatted-as-best-we-could
+ message to the specified recipient.
+ In the special case in which the destination is
+ another Uucp site (rmail sitex!person), NO processing
+ is done before invoking Deliver; Deliver will
+ add the obligatory extra "From" line at the beginning
+ of the Uucp output.
+
+KNOWN problems.
+
+ When mail is going to somewhere like "graphics!person",
+ and there are "cc:" lines, these "cc:" lines are not
+ formatted in such a way as to allow automatic replies.
+ Note that they would have to be different for local
+ users than they would be for the remote user.
+
+ Similarly, when a message gets sent to someone like
+ "graphics!mike@ucla-s", the "To: " line is going to
+ contain that "graphics!" when it gets to the remote
+ Arpanet site. This will be wrong, there. Note again
+ that local users getting a carbon copy will want
+ that information to appear.
+
+ When a message comes from the Arpanet and gets forwarded
+ to Uucp, it arrives at the destination site with
+ a Uucp-style "From xxx remote from yyy" line at the
+ beginning, and an ARPA-style "From: " line which was
+ generated at the original site. Rmail will cause
+ you to end up with two Arpa-style From lines,
+ "From: yyy!xxx" and the original one. Repl will be
+ able to start up OK, and will try to reply to both.
+ Unfortunately, NEITHER will be right. This is rather
+ difficult to fix without modifying the original Arpa
+ header. Impossible, in fact.
+
+ You can send messages to graphics!person@host. However
+ if you try to send it to "graphics!person at host", you
+ will indeed execute "graphics!rmail person at host".
+ This will cause Rmail to choke (too many args). You never
+ get to hear about it when Uux chokes.
+
+ In general, Rmail should make a better effort to see if
+ things went OK, and send a return message if they didn't.
+ Similarly, the FTP server should make sure Rmail died
+ happy, and reply with a failure code (412 or something,
+ isn't it?) when things don't run smoothly. The
+ Arpanet Mailer, by the way, is pretty good about reporting
+ its failures.
+
+ Replying to messages from various sources works pretty well.
+ However, people who try to invoke the "-format" option
+ when no Arpanet is present currently get a screwy result
+ like "at (local)" getting glued to the end of addresses.
+ Frankly, the "format" option should be completely disabled
+ at non-Arpa sites, as near as I can tell. This applies
+ both to "repl" as well as "send" (deliver).
+
+ While "Ali" has been changed to understand that Uucp and
+ Arpanet addresses should not be checked for validity,
+ there are common subroutines in Ali and Deliver which
+ are Very Similar, though their calling sequences and
+ usages vary somewhat. It would be Aesthetically Preferable
+ to break these routines out and put them in "subs".
+
+ Mike Urban
+ 3/81
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <stdio.h>
+#include "../mh.h"
+#include "../adrparse.h"
+#include <ctype.h>
+
+extern char *sprintf();
+
+char *
+adrformat(mp,hostname)
+ register struct mailname *mp;
+ register char *hostname;
+{
+ static char buf[512];
+ register char *tp, *cp, *sp;
+
+ for(tp = buf, cp = mp->m_text;*cp ;cp++ ) {
+ if(cp == mp->m_at) {
+ if(*cp == '@') {
+ if(cp[-1] != ' ')
+ *tp++ = ' ';
+ *tp++ = 'a';
+ *tp++ = 't';
+ if(cp[1] != ' ')
+ *tp++ = ' ';
+ continue;
+ }
+ }
+ if((cp == mp->m_hs) && (*mp->m_at != '!')){
+ if(sp = stdhost(mp->m_hnum)) {
+ while(*sp)
+ *tp++ = islower(*sp) ?
+ toupper(*sp++) : *sp++;
+ cp = mp->m_he;
+ continue;
+ } else {
+ fprintf(stderr, "adrformat: bad host!?\n");
+ return NULL;
+ }
+ }
+ *tp++ = *cp;
+ }
+ if(mp->m_nohost)
+ VOID sprintf(tp, " at %s", !mp->m_at? mp->m_host: hostname);
+ /* This probably only needs "hostname" unconditionally */
+ else
+ *tp = 0;
+ return buf;
+}
+
+
+char *
+stdhost(num)
+ long num;
+{
+ register struct hosts *hp;
+
+ for(hp = hosts.nh_next; hp; hp = hp->nh_next)
+ if(num == hp->nh_num)
+ return hp->nh_name;
+ return 0;
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <stdio.h>
+#include <whoami.h>
+#include "../mh.h"
+#include "../adrparse.h"
+
+extern char *strcpy(), *strncpy();
+
+#ifndef ARPANET
+#define HOSTTBL "/dev/null"
+#else
+#include <imp.h>
+#endif
+#include <ctype.h>
+
+char *malloc(), *calloc(), *getncpy();
+
+
+char *
+getname(addrs)
+ char *addrs;
+{
+ register char *tp;
+ static char name[256];
+ static char *getaddrs;
+
+ if(!getaddrs)
+ getaddrs = addrs;
+ tp = name;
+
+ while(*getaddrs && isspace(*getaddrs))
+ getaddrs++;
+ if(!*getaddrs) {
+ getaddrs = 0;
+ return NULL;
+ }
+ while(*getaddrs && *getaddrs != ',') {
+ if(isspace(*getaddrs))
+ *tp++ = ' ';
+ else
+ *tp++ = *getaddrs;
+ getaddrs++;
+ }
+ if(*getaddrs) getaddrs++;
+ *tp = 0;
+ while(isspace(tp[-1]) && tp > name)
+ *--tp = 0;
+ tp = name;
+ while(*tp == ' ' || *tp == '\t')
+ tp++;
+ if(*tp == 0)
+ return NULL;
+ return tp;
+}
+
+
+struct mailname *
+getm(str, defaulthost) /* WHY isn't it just taken from HOSTNAME?*/
+ /* Answer: REPLY uses foreign site */
+ char *str;
+ char *defaulthost;
+{
+ register char *cp;
+ register char *mbp = 0, *mbe = 0;
+ register char *hp = 0, *he = 0;
+ register struct mailname *mp;
+ int lbrkt = 0;
+
+ if(!hosts.nh_next)
+ gethosts();
+ mp = (struct mailname *) calloc(1, sizeof *mp);
+ mp->m_headali = "";
+ mp->m_text = cp = getcpy(str);
+ while(*cp) {
+ switch(*cp) {
+#ifdef FOO
+ case '"':
+ if(!mbp) mbp = cp;
+ do {
+ cp++;
+ } while(*cp && *cp != '"');
+ break;
+#endif
+ case '<':
+ mbp = mbe = hp = he = mp->m_at = 0;
+ lbrkt++;
+ break;
+ case '>':
+ if(!lbrkt) {
+ fprintf(stderr, "adrparse: extraneous '>'\n");
+ goto line;
+ }
+ if(mbp && !mbe) {
+ fprintf(stderr, "adrparse: Missing host within <> spec.\n");
+ goto line;
+ } else if(hp && !he)
+ he = cp - 1;
+ goto gotaddr;
+ case ' ': if(!HOSTNUM) break;
+ if(strncmp(cp, " at ", 4) == 0 ||
+ strncmp(cp, " At ", 4) == 0 ||
+ strncmp(cp, " AT ", 4) == 0) {
+ cp++;
+ at: if (!HOSTNUM)break; /* Host 0 means no arpanet */
+ if(!mbp) {
+ fprintf(stderr, "adrparse: at without mbox\n");
+ goto line;
+ }
+ if(!mbe)
+ mbe = cp - 1;
+ if(mp->m_at) {
+ if (*mp->m_at == '!')
+ mbp = hp; /* uusite!person@site */
+ else
+ mbe = cp - 1; /* [x!]y@q@z */
+ }
+ mp->m_at = cp;
+ if(*cp != '@')
+ cp += 2;
+ hp = he = 0;
+ }
+ break;
+ case '@':
+ goto at;
+ case '!': /* uusite!otherstuff */
+ if (!mbp && !hp) break; /* Ignore leading '!'s */
+ if(mbp && !hp) { /* No other '!'s so far...*/
+ hp=mbp; /* Host name */
+ he=cp-1;
+
+ mbp = 0;
+ mp->m_at = cp;
+ }
+ break;
+ case '(':
+ if(mbp && !mbe)
+ mbe = cp - 1;
+ else if(hp && !he)
+ he = cp - 1;
+ while(*cp && *cp != ')') cp++;
+ break;
+ default:
+ if(isalnum(*cp) || *cp == '-' || *cp == '.' ||
+ *cp == '_') {
+ if(!mbp)
+ mbp = cp;
+ else if(mp->m_at && !hp)
+ hp = cp;
+ } else {
+ fprintf(stderr, "adrparse: address err: %s\n", cp);
+ goto line;
+ }
+ break;
+ }
+ cp++;
+ }
+gotaddr:
+ if(mbp && !mbe)
+ mbe = cp - 1;
+ else if(hp && !he)
+ he = cp - 1;
+ if(!mp->m_at) {
+ if(hp) {
+ fprintf(stderr, "adrparse: HUH? host wo @\n");
+ return(0);
+ }
+ mp->m_nohost++;
+ if(defaulthost == 0) {
+ fprintf(stderr, "adrparse: Missing host\n");
+ return(0);
+ }
+ mp->m_host = getcpy(defaulthost);
+ } else {
+ while(*he == ' ') --he;
+ mp->m_host = getncpy(hp, he-hp+1);
+ mp->m_hs = hp;
+ mp->m_he = he;
+ if (*mp->m_at == '!') /* It's a uucp addr, not arpa */
+ mp->m_nohost++; /* So formatter will glue on local name*/
+ }
+ if(!mbp) {
+ fprintf(stderr, "adrparse: No mailbox: %s\n", str);
+ return(0);
+ }
+ while(*mbe == ' ') --mbe;
+ mp->m_mbox = getncpy(mbp, mbe-mbp+1);
+ if (*mp->m_at == '!') /* Going out over UUCP */
+ {
+ mp->m_hnum = -1; /* UUCP addresses are basically local*/
+ return mp;
+ }
+#ifndef ARPANET
+ mp->m_hnum = 0;
+ return mp;
+#else
+ if((mp->m_hnum = gethnum(mp->m_host)) == -1) {
+ fprintf(stderr, "adrparse: Unknown host: %s\n", mp->m_host);
+#endif
+ line: fprintf(stderr, "adrparse: In address: %s\n", str);
+ return(0);
+#ifdef ARPANET
+ }
+ if(mp->m_at && (mp->m_hnum == HOSTNUM))
+ /* Local! Try to reparse in case of UUCP address */
+ {
+ char localname[32];
+
+ strcpy(localname, mp->m_mbox); /* not same struct */
+ mnfree(mp);
+ if((mp = getm(localname,HOSTNAME)) == 0) /* Really local */
+ return(0);
+ }
+ return mp;
+#endif
+}
+
+
+char *
+getncpy(str, len)
+ char *str;
+ int len;
+{
+ register char *cp;
+
+ cp = calloc(1, (unsigned)len + 1);
+ strncpy(cp, str, len);
+ return cp;
+}
+
+
+gethosts()
+{
+ register FILE *ht;
+ register struct hosts *hp = &hosts;
+ char buf[32], hostname[16];
+ int hn;
+
+ if((ht = fopen(HOSTTBL, "r")) == NULL) {
+hte: perror(HOSTTBL);
+ exit(1);
+ }
+ while(fgets(buf, sizeof buf, ht)) {
+ if(sscanf(buf, "%o %s", &hn, hostname) != 2)
+ goto hte;
+ hp->nh_next = (struct hosts *) calloc(1, sizeof *hp);
+ hp = hp->nh_next;
+ hp->nh_name = getcpy(hostname);
+ hp->nh_num = hn;
+ }
+ VOID fclose(ht);
+}
+
+long
+gethnum(host)
+ char *host;
+{
+ register struct hosts *hp;
+
+ for (hp = hosts.nh_next; hp; hp = hp->nh_next)
+ if(uleq(host, hp->nh_name))
+ return hp->nh_num;
+ return -1;
+}
+
+
+mnfree(mn)
+ register struct mailname *mn;
+{
+ free(mn->m_mbox);
+ free(mn->m_host);
+ free(mn->m_text);
+ cndfree(mn->m_headali);
+ free((char *)mn);
+}
+
+#ifdef COMMENT
+/* Eventually we should do something more like this (from tn.c) */
+ if ((hnum>>24) == 0) { /* Old format */
+ netparm.no_imp = hnum&077;
+ netparm.no_host = hnum>>6;
+ }
+ else { /* New format */
+ netparm.no_imp = hnum&0177777;
+ netparm.no_host = hnum>>16;
+ }
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <sys/types.h>
+
+extern char *index();
+
+#define EVERYONE 10
+
+struct shome { /* Internal name/uid/home database */
+ struct shome *h_next;
+ char *h_name;
+ int h_uid;
+ int h_gid;
+ char *h_home;
+} *homes, *home();
+
+struct mailname {
+ struct mailname *m_next;
+ char *m_name;
+} addrlist;
+
+char *malloc();
+
+extern char _sobuf[]; /* MLW standard out buffer */
+
+main(argc, argv)
+ char **argv;
+{
+ register int i, list = 0;
+ register struct mailname *lp;
+
+ invo_name = argv[0];
+ if(argc < 2) {
+ printf("Usage: ali [-l] name ...\n");
+ exit(1);
+ }
+ if(argc > 1 && strcmp(argv[1], "-l") == 0) {
+ list++;
+ argc--; argv++;
+ }
+ setbuf(stdout, _sobuf);
+ gethomes();
+ for(i = 1; i < argc; i++)
+ insert(argv[i]);
+ alias(); /* Map names if needed */
+ for(lp = addrlist.m_next; lp; lp = lp->m_next) {
+ if(home(lp->m_name)) {
+ if(list)
+ printf("%s\n", lp->m_name);
+ else {
+ printf("%s%s", lp->m_name, lp->m_next?", ":"");
+ if(stdout->_cnt < BUFSIZ - 65) {
+ printf("\n"); VOID fflush(stdout);
+ }
+ }
+ }
+ }
+ if(!list && stdout->_cnt && stdout->_cnt < BUFSIZ) {
+ printf("\n"); VOID fflush(stdout);
+ }
+ for(lp = addrlist.m_next; lp; lp = lp->m_next)
+ if(home(lp->m_name) == NULL)
+ fprintf(stderr, "Ali: Unknown User: %s.\n", lp->m_name);
+
+}
+
+insert(name)
+ char *name;
+{
+ register struct mailname *mp;
+ char *getcpy();
+
+/*** printf("insert(%s)\n", name); ***/
+
+ for(mp = &addrlist; mp->m_next; mp = mp->m_next)
+ if(uleq(name, mp->m_next->m_name))
+ return; /* Don't insert existing name! */
+ mp->m_next = (struct mailname *) malloc(sizeof *mp->m_next);
+ mp = mp->m_next;
+ mp->m_next = 0;
+ mp->m_name = getcpy(name);
+}
+
+gethomes()
+{
+ register struct passwd *pw;
+ register struct shome *h, *ph;
+ struct passwd *getpwent();
+ char *strcpy();
+
+ ph = (struct shome *) &homes;
+ while((pw = getpwent()) != NULL) {
+ h = (struct shome *) malloc(sizeof *h);
+ h->h_next = NULL;
+ h->h_name = malloc((unsigned)strlen(pw->pw_name)+1);
+ strcpy(h->h_name, pw->pw_name);
+ h->h_uid = pw->pw_uid;
+ h->h_gid = pw->pw_gid;
+ h->h_home = malloc((unsigned)strlen(pw->pw_dir)+1);
+ strcpy(h->h_home, pw->pw_dir);
+ ph->h_next = h;
+ ph = h;
+ }
+}
+
+struct shome *
+home(name)
+ register char *name;
+{
+ register struct shome *h;
+
+ if (index(name, '@') ||
+ index(name, ' ') ||
+ index(name, '!'))
+ return (homes); /* WARNING! Depends on return value */
+ /* being indifferent! */
+
+ for(h = homes; h; h = h->h_next)
+ if(uleq(name, h->h_name))
+ return(h);
+ return(NULL);
+}
+
+aleq(string, aliasent)
+ register char *string, *aliasent;
+{
+ register int c;
+
+ while(c = *string++)
+ if(*aliasent == '*')
+ return 1;
+ else if((c|040) != (*aliasent|040))
+ return(0);
+ else
+ aliasent++;
+ return(*aliasent == 0 | *aliasent == '*');
+}
+
+
+/* alias implementation below...
+ */
+
+
+
+#define GROUP "/etc/group"
+char *AliasFile = "/etc/MailAliases";
+
+char *termptr;
+
+char *
+parse(ptr, buf)
+ register char *ptr;
+ char *buf;
+{
+ register char *cp;
+
+ cp = buf;
+ while(isspace(*ptr) || *ptr == ',' || *ptr == ':')
+ ptr++;
+ while(isalnum(*ptr) || *ptr == '/' || *ptr == '-' ||
+ *ptr == '!' || *ptr == '@' || *ptr == ' ' ||
+ *ptr == '.' || *ptr == '*')
+ *cp++ = *ptr++;
+ if(cp == buf) {
+ switch(*ptr) {
+ case '<':
+ case '=':
+ *cp++ = *ptr++;
+ }
+ }
+ *cp = 0;
+ if(cp == buf)
+ return 0;
+ termptr = ptr;
+ return buf;
+}
+
+char *
+advance()
+{
+ return(termptr);
+}
+
+alias()
+{
+ register char *cp, *pp;
+ register struct mailname *lp;
+ char line[256], pbuf[64];
+ FILE *a;
+
+ if((a = fopen(AliasFile, "r")) == NULL) {
+ fprintf(stderr, "Can't open alias file ");
+ perror(AliasFile);
+ done(1);
+ }
+ while(fgets(line, sizeof line, a)) {
+ if(line[0] == ';' || line[0] == '\n') /* Comment Line */
+ continue;
+ if((pp = parse(line, pbuf)) == NULL) {
+ oops: fprintf(stderr, "Bad alias file %s\n", AliasFile);
+ fprintf(stderr, "Line: %s", line);
+ done(1);
+ }
+ for(lp = &addrlist; lp->m_next; lp = lp->m_next) {
+ if(aleq(lp->m_next->m_name, pp)) {
+ remove(lp);
+ if(!(cp = advance()) ||
+ !(pp = parse(cp, pbuf)))
+ goto oops;
+ switch(*pp) {
+ case '<': /* From file */
+ cp = advance();
+ if((pp = parse(cp, pbuf)) == NULL)
+ goto oops;
+ addfile(pp);
+ break;
+ case '=': /* UNIX group */
+ cp = advance();
+ if((pp = parse(cp, pbuf)) == NULL)
+ goto oops;
+ addgroup(pp);
+ break;
+ case '*': /* ALL Users */
+ addall();
+ break;
+ default: /* Simple list */
+ for(;;) {
+ insert(pp);
+ if(!(cp = advance()) ||
+ !(pp = parse(cp, pbuf)))
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+addfile(file)
+ char *file;
+{
+ register char *cp, *pp;
+ char line[128], pbuf[64];
+ FILE *f;
+
+/*** printf("addfile(%s)\n", file); ***/
+ if((f = fopen(file, "r")) == NULL) {
+ fprintf(stderr, "Can't open ");
+ perror(file);
+ done(1);
+ }
+ while(fgets(line, sizeof line, f)) {
+ cp = line;
+ while(pp = parse(cp, pbuf)) {
+ insert(pp);
+ cp = advance();
+ }
+ }
+ VOID fclose(f);
+}
+
+addgroup(group)
+ char *group;
+{
+ register char *cp, *pp;
+ int found = 0;
+ char line[128], pbuf[64], *rindex();
+ FILE *f;
+
+/*** printf("addgroup(%s)\n", group); ***/
+ if((f = fopen(GROUP, "r")) == NULL) {
+ fprintf(stderr, "Can't open ");
+ perror(GROUP);
+ done(1);
+ }
+ while(fgets(line, sizeof line, f)) {
+ pp = parse(line, pbuf);
+ if(strcmp(pp, group) == 0) {
+ cp = rindex(line, ':');
+ while(pp = parse(cp, pbuf)) {
+ insert(pp);
+ cp = advance();
+ }
+ found++;
+ }
+ }
+ if(!found) {
+ fprintf(stderr, "Group: %s non-existent\n", group);
+ done(1);
+ }
+ VOID fclose(f);
+}
+
+addall()
+{
+ register struct shome *h;
+
+/*** printf("addall()\n"); ***/
+ for(h = homes; h; h = h->h_next)
+ if(h->h_uid >= EVERYONE)
+ insert(h->h_name);
+}
+
+remove(mp) /* Remove NEXT from argument node! */
+ register struct mailname *mp;
+{
+ register struct mailname *rp;
+
+ rp = mp->m_next;
+ mp->m_next = rp->m_next;
+ cndfree((char *)rp->m_name);
+ cndfree((char *
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+time_t time();
+long lseek();
+
+/* annotate file component data
+ *
+ * prepends Component: data
+ * date stamp
+ */
+
+annotate(file, comp, text, inplace)
+ char *file, *comp, *text;
+{
+ register int src;
+ register char *cp;
+ register FILE *tmp;
+ int cnt, fd;
+ char buf[BUFSIZ], *sp, tmpfil[128];
+ long now;
+ struct stat stbuf;
+ char *cdate();
+
+ if((src = open((cp = file), 2)) == -1) { /* this should be an X-open*/
+ fprintf(stderr, "Can't open ");
+ perror(cp);
+ return(1);
+ }
+ VOID copy(cp, buf);
+ sp = r1bindex(buf, '/');
+ if(sp != buf) {
+ *sp = 0;
+ cp = copy(buf, tmpfil);
+ } else
+ cp = tmpfil;
+ VOID copy(makename("ano",".tmp"), cp);
+ VOID fstat(src, &stbuf);
+ if((tmp = fopen(tmpfil, "w")) == NULL) {
+ fprintf(stderr, "Can't create ");
+ perror(tmpfil);
+ return(1);
+ }
+ VOID chmod(tmpfil, (int)stbuf.st_mode&0777);
+ cp = comp;
+ if(*cp >= 'a' && *cp <= 'z') *cp -= 040;
+ now = time((long *)0);
+ cp = cdate(&now);
+ cp[9] = ' '; cp[15] = 0;
+ if(*cp == ' ') cp++;
+ fprintf(tmp, "%s: <<%s>>\n", comp, cp);
+ cp = text;
+ do {
+ if(*cp == ' ' || *cp == '\t') cp++;
+ sp = cp;
+ while(*cp && *cp++ != '\n') ;
+ if(cp - sp)
+ fprintf(tmp, "%s: %*.*s", comp, cp-sp, cp-sp, sp);
+ } while(*cp);
+ if(cp[-1] != '\n' && cp != text) putc('\n', tmp);
+ do
+ if((cnt = read(src, buf, sizeof buf)) > 0)
+ if(fwrite(buf, cnt, 1, tmp) != 1) {
+ fprintf(stderr, "anno: Error writing to ");
+ perror(tmpfil);
+ done(1);
+ }
+ while(cnt == sizeof buf);
+ VOID fclose(tmp);
+ if(inplace) {
+ fd = open(tmpfil, 0); /* reopen for reading */
+ VOID lseek(src, 0l, 0);
+ do
+ if((cnt = read(fd, buf, sizeof buf)) > 0)
+ if(write(src, buf, cnt) != cnt) {
+ fprintf(stderr, "anno: Error rewriting ");
+ perror(file);
+ done(1);
+ }
+ while(cnt == sizeof buf);
+ VOID close(fd);
+ } else {
+ /* cp = copy(file, buf); */
+ /* *--cp =| 0200; */
+ /* VOID copy(".bak", copy(file, buf)); */
+ cp = copy(file, buf);
+ cp[1] = 0;
+ do
+ *cp = cp[-1];
+ while(--cp >= buf && *cp != '/');
+ *++cp = ','; /* New backup convention */
+ VOID unlink(buf);
+ if(link(file, buf) == -1) {
+ fprintf(stderr, "Can't rename %s to bak file.\n", file);
+ return(1);
+ }
+ if(unlink(file) == -1) {
+ fprintf(stderr, "Can't unlink %s\n", file);
+ return(1);
+ }
+ if(link(tmpfil, file) == -1) {
+ fprintf(stderr, "Can't lnk temp file \"%s\" to %s\n",
+ tmpfil, file);
+ return(1);
+ }
+ }
+ VOID close(src);
+ VOID unlink(tmpfil);
+ retur
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <strings.h>
+#include <signal.h>
+
+/* #define NEWS 1 */
+/* #define TEST 1 */
+
+struct swit anyul[] = {
+ "no", 0,
+ "yes", 0,
+ "use", 0,
+ "list", 0,
+ 0
+};
+
+struct swit aleqs[] = {
+ "list", 0, /* 0 */
+ "edit [<editor>]", 0, /* 1 */
+ "quit [delete]", 0, /* 2 */
+ "send [switches]", 0, /* 3 */
+ 0
+};
+
+
+struct swit switches[] = {
+ "editor editor", 0, /* 0 */
+ "form formfile", 0, /* 1 */
+ "use", 0, /* 2 */
+ "nouse", 0, /* 3 */
+ "help", 4, /* 4 */
+ 0, 0
+};
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ register char *cp;
+ register int in, out;
+ int use, cnt, status;
+ char buf[BUFSIZ], *ed, *file, *form;
+ static char path[128];
+ char **ap;
+ char *arguments[50], **argp;
+
+ invo_name = argv[0];
+/*** setbuf(stdout, _sobuf); ***/
+#ifdef NEWS
+ m_news();
+#endif
+ form = 0; use = 0; file = 0; ed = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-') {
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "comp: -%s unknown\n", cp);
+ goto leave;
+ case 0: if(!(ed = *argp++)) { /* -editor */
+ missing: fprintf(stderr, "comp: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 1: if(!(form = *argp++)) /* -form */
+ goto missing;
+ continue;
+ case 2: use = 1; continue; /* -use */
+ case 3: use = 0; continue; /* -nouse */
+ case 4: help("comp [file] [switches]",
+ switches);
+ goto leave;
+ }
+ }
+ file = cp;
+ }
+ if(form) {
+ if((in = open(m_maildir(form), 0)) < 0) {
+ fprintf(stderr, "comp: Can't open form file: %s\n", form);
+ goto leave;
+ }
+ } else if((in = open(m_maildir(components), 0)) < 0 &&
+ (in = open(stdcomps, 0)) < 0) {
+ fprintf(stderr, "comp: Can't open default components file!!\n");
+ goto leave;
+ }
+ if(!file)
+ file = draft;
+ VOID copy(m_maildir(file), path);
+ if((out = open(path, 0)) >= 0) {
+ cp = concat("\n\"", path, "\" exists; delete? ", 0);
+ if(use || fdcompare(in, out))
+ goto editit;
+ while((status = gans(cp, anyul)) == 3)
+ VOID showfile(path);
+ if(status == 2) {
+ use++;
+ goto editit;
+ }
+ if(status == 0)
+ goto leave;
+ VOID close(out);
+ } else if(use) {
+ fprintf(stderr, "comp: \"%s\" doesn't exist!\n", path);
+ goto leave;
+ }
+ if((out = creat(path, m_gmprot())) < 0) {
+ fprintf(stderr, "comp: Can't create \"%s\"\n", path);
+ goto leave;
+ }
+ do
+ if(cnt = read(in, buf, sizeof buf))
+ if(write(out, buf, cnt) != cnt) {
+ fprintf(stderr, "comp: error writing ");
+ perror(path);
+ goto leave;
+ }
+ while(cnt == sizeof buf);
+ VOID close(in);
+editit:
+ VOID close(out);
+ if(m_edit(&ed, path, use, NULLCP) < 0)
+ goto leave;
+#ifdef TEST
+ fprintf(stderr, "!! Test Version of SEND Being Run !!\n");
+ fprintf(stderr, " Send verbose !\n\n");
+#endif
+
+ for(;;) {
+ if(!(argp = getans("\nWhat now? ", aleqs)))
+ goto leave;
+ switch(smatch(*argp, aleqs)) {
+ case 0: VOID showfile(path); /* list */
+ break;
+
+ case 1: if(*++argp) /* edit */
+ ed = *argp;
+ if(m_edit(&ed, path, use, NULLCP) == -1)
+ goto leave;
+ break;
+ /* quit */
+ case 2: if(*++argp && (*argp[0] == 'd' ||
+ (*argp[0]=='-' && *argp[1]=='d')))
+ if(unlink(path) == -1) {
+ fprintf(stderr, "Can't unlink %s ", path);
+ perror("");
+ }
+ goto leave;
+
+ case 3: VOID m_send(++argp, path); /* send */
+ goto leave;
+
+ default:fprintf(stderr, "comp: illegal option\n"); /*##*/
+ break;
+ }
+ }
+
+leave:
+ m_update();
+ done(0);
+}
+
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include "../mh.h"
+#include <mailsys.h>
+
+char *AliasFile = MAILALIASES;
+char *Password = "/etc/passwd";
+char *MailDir = MAILDROP;
+
+char *termptr;
+char *malloc();
+
+struct mailname {
+ struct mailname *m_next;
+ char *m_name;
+ int m_seen;
+} users, bad;
+
+
+char *parse(ptr, buf)
+register char *ptr;
+char *buf;
+{
+ register char *cp;
+
+ cp = buf;
+ while(isspace(*ptr) || *ptr == ',' || *ptr == ':')
+ ptr++;
+ while(isalnum(*ptr) || *ptr == '/' || *ptr == '-' || *ptr == '.')
+ *cp++ = *ptr++;
+ if(cp == buf) {
+ switch(*ptr) {
+ case '<':
+ case '*':
+ case '=':
+ *cp++ = *ptr++;
+ }
+ }
+ *cp = 0;
+ if(cp == buf)
+ return 0;
+ termptr = ptr;
+ return buf;
+}
+
+
+char *mail = 0;
+FILE *out;
+int donecd = 0;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register char *cp, **cpp;
+ register struct mailname *lp;
+ register struct group *gp;
+ struct direct dir;
+ char line[256], pbuf[64];
+ FILE *a;
+ struct group *getgrent();
+
+ invo_name = argv[0];
+ if(argc == 3 && strcmp(argv[1], "-mail") == 0)
+ mail = argv[2];
+ if(!mail)
+ out = stdout;
+ if((a = fopen(Password, "r")) == NULL) {
+ om();
+ fprintf(out, "Can't open password file ");
+ perror(Password);
+ done(1);
+ }
+ while(fgets(line, sizeof line, a)) {
+ if(line[0] == '\n' || line[0] == ';')
+ continue;
+ cp = parse(line, pbuf);
+ addu(cp, &users);
+ }
+ VOID fclose(a);
+ if((a = fopen(AliasFile, "r")) == NULL) {
+ om();
+ fprintf(out, "Can't open alias file: %s\n", AliasFile);
+ donecd = 1;
+ } else {
+ while(fgets(line, sizeof line, a)) {
+ if(line[0] == '\n' || line[0] == ';')
+ continue;
+ cp = parse(line, pbuf);
+ if(check(cp, 0)) {
+ addu(line, &bad);
+ donecd = 1;
+ }
+ }
+ VOID fclose(a);
+ if(donecd < 1) {
+ if(out)
+ fprintf(out, "No Alias Inconsistencies.\n");
+ } else {
+ om();
+ fprintf(out, "%s :: %s Collisions:\n",
+ Password, AliasFile);
+ fprintf(out, "Colliding alias lines:\n");
+ for(lp = bad.m_next; lp; lp = lp->m_next)
+ fprintf(out, "%s", lp->m_name);
+ donecd = 1;
+ }
+ }
+ while(gp = getgrent()) {
+ for(cpp = gp->gr_mem; *cpp; cpp++)
+ if(!check(*cpp, 1)) {
+ om();
+ fprintf(out, "Group: %s--User: %s not in /etc/passwd\n",
+ gp->gr_name, *cpp);
+ donecd = 2;
+ }
+ }
+ if(donecd < 2 && out)
+ fprintf(out, "No extraneous group entries.\n");
+#ifdef RAND
+ for(lp = users.m_next; lp; lp = lp->m_next)
+ if(lp->m_seen == 0) {
+ om();
+ fprintf(out, "User: %s not in a group.\n", lp->m_name);
+ donecd = 3;
+ }
+ if(donecd < 3 && out)
+ fprintf(out, "No Users not in any group.\n");
+#endif
+ if((a = fopen(MailDir, "r")) == NULL) {
+ om();
+ fprintf(out, "Can't open mail directory: %s\n", MailDir);
+ donecd = 4;
+ } else {
+ while(fread((char *)&dir, sizeof dir, 1, a)) {
+ if( dir.d_ino == 0
+ || dir.d_name[0] == '.'
+ )
+ continue;
+ if(!check(dir.d_name, 0)) {
+ om();
+ fprintf(out, "Mail drop: %s--Nonexistent user.\n",
+ dir.d_name);
+ donecd = 4;
+ }
+ }
+ VOID fclose(a);
+ }
+ if(donecd < 4 && out)
+ fprintf(out, "No Extra mail drops.\n");
+
+ done(donecd);
+}
+
+
+addu(name, list)
+ char *name;
+ struct mailname *list;
+{
+ register struct mailname *mp;
+ char *getcpy();
+
+ for(mp = list; mp->m_next; mp = mp->m_next)
+ ;
+ mp->m_next = (struct mailname *) malloc(sizeof *mp->m_next);
+ mp = mp->m_next;
+ mp->m_next = 0;
+ mp->m_name = getcpy(name);
+}
+
+check(name, mark)
+ char *name;
+ int mark;
+{
+ register struct mailname *mp;
+
+ for(mp = users.m_next; mp; mp = mp->m_next)
+ if(uleq(name, mp->m_name)) {
+ if(mark)
+ mp->m_seen = 1;
+ return 1;
+ }
+ return 0;
+}
+
+
+om()
+{
+ int pipes[2], child;
+
+ if(out)
+ return;
+ if(mail) {
+ VOID pipe(pipes);
+ out = fdopen(pipes[1], "w");
+ if((child = fork()) == -1) {
+ fprintf(stderr, "Conflict: no forks!\n");
+ done(1);
+ }
+ if(child == 0) {
+ VOID close(pipes[1]);
+ VOID close(0);
+ VOID dup(pipes[0]);
+ VOID close(pipes[0]);
+ execl("/bin/mail", "mail", mail, 0);
+ execl("/usr/bin/mail", "mail", mail, 0);
+ perror("mail");
+ done(1);
+ }
+ fprintf(out, "Conflict: "
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <whoami.h>
+#include "../mh.h"
+#include "../adrparse.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <strings.h>
+#include <mailsys.h>
+#include <time.h>
+
+
+time_t time();
+char *malloc(), *calloc(), *getncpy(), *sprintf(), *strcpy(), *strncop();
+char *ctime();
+long lseek();
+
+#define OUTPUTLINELEN 72
+#define EVERYONE 10
+#define RECVPROG "/.mh_receive"
+#define DAEMON_GRP 2
+#define FCCS 10 /* Max number of fcc's allowed */
+
+/* Alias */
+#define STAR 2
+int alitype; /*** 0 = nomatch, 2 = *match, 1 = stringmatch ***/
+
+struct shome { /* Internal name/uid/home database */
+ struct shome *h_next;
+ char *h_name;
+ int h_uid;
+ int h_gid;
+ char *h_home;
+} *homes, *home();
+
+struct swit switches[] = {
+ "debug", -5, /* 0 */
+ "deliver", -1, /* 1 */
+ "format", 0, /* 2 */
+ "noformat", 0, /* 3 */
+ "msgid", 0, /* 4 */
+ "nomsgid", 0, /* 5 */
+ "remove", 0, /* 6 */
+ "noremove", 0, /* 7 */
+ "verbose", 0, /* 8 */
+ "noverbose", 0, /* 9 */
+ "width", 0, /*10 */
+ "help", 4, /*11 */
+ 0, 0
+};
+
+int verbose, format=1, msgid, debug, myuid, rmflg;
+short lockwait; /* Secs to wait for mail lock (From strings/lockdir.c) */
+#define LOCKWAIT (lockwait * 5) /* Ignore lock if older than this */
+short donecd;
+short outputlinelen = OUTPUTLINELEN;
+long now;
+char tmpfil[32], uutmpfil[32], fccfold[FCCS][128];
+short fccind;
+char *deliverto;
+char *head_alias = ""; /* 1st match in a local mailbox's alias chain */
+ /* (If a:b, b:c, c:d then head_alias == "a") */
+
+struct mailname localaddrs, netaddrs, uuaddrs;
+struct mailname *mn_from;
+char *hdrptr;
+
+/*ARGSUSED*/
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register char *cp, **argp;
+ register struct mailname *lp;
+ char buf[BUFSIZ], name[NAMESZ];
+ char *msg;
+ int state, compnum, fd;
+ FILE *in, *out, *uuout;
+
+ invo_name = argv[0];
+#ifndef ARPANET
+ format=0; /* default to noformat if no Arpanet */
+#endif
+ msg = 0;
+ argp = argv + 1;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ done(1);
+ /* unknown */
+ case -1:fprintf(stderr, "deliver: -%s unknown switch.\n", cp);
+ done(1);
+ case 0: verbose++; debug++; continue; /* -debug */
+ case 1: if(!(deliverto = *argp++) || *deliverto == '-'){
+ missing: fprintf(stderr, "deliver: missing arg to %s\n",
+ argp[-2]);
+ done(1);
+ }
+ continue;
+ case 2: format = 1; continue; /* -format */
+ case 3: format = 0; continue; /* -noformat */
+ case 4: msgid = 1; continue; /* -msgid */
+ case 5: msgid = 0; continue; /* -nomsgid */
+ case 6: rmflg = 1; continue; /* -remove */
+ case 7: rmflg = -1; continue; /* -noremove */
+ case 8: verbose = 1; continue; /* -verbose */
+ case 9: verbose = 0; continue; /* -noverbose */
+ case 10: if(!(cp = *argp++) || *cp == '-')
+ goto missing;
+ outputlinelen = atoi(cp);
+ continue;
+ case 11: help("deliver [switches] file",
+ switches);
+ done(1);
+ }
+ if(msg) {
+ fprintf(stderr, "Deliver: Only one message at a time!\n");
+ done(1);
+ } else
+ msg = cp;
+ }
+ if(!msg) {
+ fprintf(stderr, "Deliver: No Message specified.\n");
+ fprintf(stderr, "Deliver: Usage: deliver [switches] file\n");
+ done(1);
+ }
+ if(outputlinelen < 10) {
+ fprintf(stderr, "deliver: Impossible width: %d\n",
+ outputlinelen);
+ done(1);
+ }
+ gethomes();
+ myuid = getuid();
+ if(deliverto) {
+ int uid;
+ if((uid = geteuid()) && uid != 1 && getegid() != DAEMON_GRP) {
+/* if(myuid != 0 && getgid() != DAEMON_GRP) { */
+ fprintf(stderr, "Deliver: -deliver switch su only.\n");
+ done(1);
+ }
+#ifdef VMUNIX
+ setpgrp(0, getpid()); /* So we don't blow away our parent */
+#endif
+ strcpy(tmpfil, msg);
+ strcpy(uutmpfil, msg);
+ if(access(tmpfil, 4) == -1) {
+ fprintf(stderr, "Deliver: Can't access ");
+ perror(tmpfil);
+ done(1);
+ }
+ if(!rmflg) rmflg = -1;
+ goto del1;
+ }
+ if(!rmflg) rmflg = 1;
+ if((in = fopen(msg, "r")) == NULL) {
+ fprintf(stderr, "Deliver: Can't open ");
+ perror(msg);
+ done(1);
+ }
+ VOID copy(makename("locs", ".tmp"), copy("/usr/tmp/mh/", tmpfil));
+ if(!debug) {
+ if((out = fopen(tmpfil, "w")) == NULL) {
+ fprintf(stderr, "Can't create %s\n", tmpfil);
+ done(1);
+ }
+ VOID chmod(tmpfil, 0744);
+ } else
+ out = stdout;
+
+ VOID copy(makename("uulc", ".tmp"), copy("/usr/tmp/mh/", uutmpfil));
+ if(!debug) {
+ if((uuout = fopen(uutmpfil, "w")) == NULL) {
+ fprintf(stderr, "Can't create %s\n", uutmpfil);
+ done(1);
+ }
+ VOID chmod(uutmpfil, 0600);
+ } else
+ uuout = fopen("/dev/null","w");;
+
+ putdate(out); /* Tack on the date */
+ putdate(uuout); /* Tack on the date */
+ for(compnum = 1, state = FLD;;) {
+ state = m_getfld(state, name, buf, sizeof buf, in);
+ switch(state) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ hdrptr = 0;
+ compnum++;
+ if(uleq(name, "fcc")) {
+ cp = buf;
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+ if(fccind >= FCCS) {
+ fprintf(stderr, "Deliver: too many fcc's.\n");
+ done(1);
+ }
+ VOID copy(cp, fccfold[fccind]);
+ if(cp = rindex(fccfold[fccind], '\n'))
+ *cp = 0;
+ fccind++;
+ break;
+ }
+ hdrptr = add(buf, hdrptr);
+ while(state == FLDPLUS) {
+ state = m_getfld(state, name, buf, sizeof buf, in);
+ hdrptr = add(buf, hdrptr);
+ }
+ putfmt(name, hdrptr, out);
+ { /* Do not format uucp mail */
+ int tmpformat;
+ tmpformat = format; format = 0;
+ putfmt (name, hdrptr, uuout);
+ format = tmpformat;
+ }
+ if(state == FLDEOF)
+ goto process;
+ break;
+
+ case BODY:
+ case BODYEOF:
+ putfrom(out); /* Tack on the from */
+ /* But NOT on the UUCP mail */
+ putmsgid(out); /* and msg id if desired */
+ putmsgid(uuout); /* (why not?) */
+
+ fprintf(out, "\n%s", buf);
+ fprintf(uuout, "\n%s", buf);
+ while(state == BODY) {
+ state=m_getfld(state,name,buf,sizeof buf,in);
+ fputs(buf, out);
+ fputs(buf, uuout);
+ }
+
+ case FILEEOF:
+ goto process;
+
+ case LENERR:
+ case FMTERR:
+ fprintf(stderr, "??Message Format Error ");
+ fprintf(stderr, "in Component #%d.\n", compnum);
+ done(1);
+
+ default:
+ fprintf(stderr, "Getfld returned %d\n", state);
+ done(1);
+ }
+ }
+process:
+ if(!debug) {
+ VOID fclose(out);
+ VOID fclose(uuout);
+ }
+ else
+ printf("-----\n");
+ VOID fclose(in);
+del1: if(deliverto) {
+ cinsert(deliverto);
+ }
+ if(debug) {
+ printf("Before alias():\n"); pl();
+ }
+
+ if(localaddrs.m_next)
+ alias(); /* Map names if needed */
+
+ for(lp = localaddrs.m_next; lp; lp = lp->m_next)
+ if(home(lp->m_mbox) == NULL) {
+ fprintf(stderr, "Deliver: Unknown local user: %s.\n", lp->m_mbox);
+ fprintf(stderr, "Deliver: Message not delivered.\n");
+ if(!debug)
+ unlinktmp();
+ done(1);
+ }
+ if(debug) {
+ printf("Addrs:\n"); pl();
+ }
+
+ VOID signal(SIGINT, SIG_IGN);
+ VOID signal(SIGQUIT, SIG_IGN);
+ if(!debug) { /* Send the mail */
+ if(localaddrs.m_next) {
+ fd = open(tmpfil, 0);
+ for(lp = localaddrs.m_next; lp; lp = lp->m_next)
+ sendmail(lp->m_mbox, fd, lp->m_headali);
+ VOID close(fd);
+ }
+ if(fccind)
+ for(state = 0; state < fccind; state++)
+ fcc(tmpfil, fccfold[state]);
+ if(uuaddrs.m_next)
+ uumail();
+ if(netaddrs.m_next)
+ netmail();
+ unlinktmp();
+ }
+ done(donecd);
+}
+
+
+unlinktmp()
+{
+ if (!deliverto) /* "Deliverto" makes it same as tmpfil */
+ VOID unlink (uutmpfil); /* Even if rmflg < 0? */
+ if(rmflg > 0)
+ VOID unlink(tmpfil);
+}
+
+
+
+putfmt(name, str, out)
+ char *name, *str;
+ FILE *out;
+{
+ register char *cp;
+ register struct mailname *mp;
+ int nameoutput = 0;
+ int linepos = 0;
+ int len;
+
+ while(*str == ' ' || *str == '\t') str++;
+ if(uleq(name, "to") ||
+ uleq(name, "cc") ||
+ uleq(name, "bcc") ||
+ uleq(name, "reply-to") ||
+ uleq(name, "from")) {
+ while(cp = getname(str)) {
+ if(!(mp = getm(cp, HOSTNAME)))
+ done(1);
+ if(uleq(name, "from") || uleq(name, "reply-to") ||
+ insert(mp,
+ mp->m_hnum == HOSTNUM ?
+ &localaddrs :
+ (*mp->m_at == '!') ? &uuaddrs :
+ &netaddrs)) {
+ if(!uleq(name, "bcc") && format) {
+ if(!nameoutput) {
+ fprintf(out, "%s: ", name);
+ linepos += (nameoutput = strlen(name)+2);
+ }
+ cp = adrformat(mp,HOSTNAME);
+ /* Needs default name in uumail case */
+ len = strlen(cp);
+ if(linepos != nameoutput)
+ if(len + linepos + 2 > outputlinelen) {
+ fprintf(out, ",\n%*s", nameoutput, "");
+ linepos = nameoutput;
+ } else {
+ fputs(", ", out);
+ linepos += 2;
+ }
+ fputs(cp, out);
+ linepos += len;
+ }
+ if(uleq(name, "from"))
+ mn_from = mp;
+ } else
+ mnfree(mp);
+ }
+ if(linepos) putc('\n', out);
+ if(!format && !uleq(name, "bcc"))
+ goto nofmt;
+ } else {
+nofmt:
+ fprintf(out, "%s: %s", name, str);
+ }
+}
+
+gethomes()
+{
+ register struct passwd *pw;
+ register struct shome *h, *ph;
+ struct passwd *getpwent();
+
+ ph = (struct shome *) &homes;
+ while((pw = getpwent()) != NULL) {
+ h = (struct shome *) malloc(sizeof *h);
+ h->h_next = NULL;
+ h->h_name = (char *) malloc((unsigned)strlen(pw->pw_name)+1);
+ strcpy(h->h_name, pw->pw_name);
+ h->h_uid = pw->pw_uid;
+ h->h_gid = pw->pw_gid;
+ h->h_home = (char *) malloc((unsigned)strlen(pw->pw_dir)+1);
+ strcpy(h->h_home, pw->pw_dir);
+ ph->h_next = h;
+ ph = h;
+ }
+}
+
+
+struct shome *
+home(name)
+ register char *name;
+{
+ register struct shome *h;
+
+ for(h = homes; h; h = h->h_next)
+ if(uleq(name, h->h_name))
+ return(h);
+ return(NULL);
+}
+
+char *bracket = "\1\1\1\1\n";
+
+sendmail(name, fd, head_alias) /* Runs with signals ignored! */
+ char *name;
+ register int fd;
+ char *head_alias;
+{
+ char buf[BUFSIZ];
+ register int i, m, c;
+ register char *mail, *receive, *lock = 0;
+ register struct shome *h;
+ struct stat stbuf;
+
+ if(verbose) {
+ printf("%s: ", name); fflush(stdout);
+ }
+ VOID lseek(fd, 0l, 0);
+ h = home(name);
+
+ mail = concat(mailboxes, "/", h->h_name, NULLCP);
+/*** mail = concat(h->h_home, mailbox, NULLCP); ***/
+ receive = concat(h->h_home, RECVPROG, NULLCP);
+ if(access(receive, 1) == 0) { /* User has a receive prog */
+
+ calluserprog(receive, mail, fd, h, head_alias);
+
+ } else {
+
+ if((m = open(mail, 2)) < 0) {
+ if((m = creat(mail, 0600)) < 0) {
+ fprintf(stderr, "Deliver: Can't write ");
+ perror(mail);
+ donecd = 1; goto out;
+ }
+ VOID chown(mail, h->h_uid, h->h_gid);
+ if(verbose) {
+ printf("Creating %s ", mail); fflush(stdout);
+ }
+ }
+ lock = concat(lockdir, "/", h->h_name, NULLCP);
+ for(i = 0; i < lockwait; i += 2) {
+ if(link(mail, lock) >= 0)
+ break;
+ if(i == 0 && stat(mail, &stbuf) >= 0 &&
+ stbuf.st_ctime + LOCKWAIT < time((long *) 0)) {
+ i = lockwait;
+ break;
+ }
+ if(verbose) {
+ printf("Busy "); fflush(stdout);
+ }
+ sleep(2);
+ }
+ if(i >= lockwait) {
+ VOID unlink(lock);
+ if(verbose) {
+ printf("Removing lock. "); fflush(stdout);
+ }
+ if(link(mail, lock) < 0) {
+ fprintf(stderr, "Can't lock %s to %s\n",
+ mail, lock);
+ donecd = 1;
+ goto out1;
+ }
+ }
+ VOID lseek(m, 0l, 2);
+ if(write(m, bracket, 5) != 5)
+ goto wrerr;
+ do
+ if((c = read(fd, buf, sizeof buf)) > 0)
+ if(write(m, buf, c) != c) {
+ wrerr: fprintf(stderr, "Write error on ");
+ perror(mail);
+ donecd = 1;
+ goto out1;
+ }
+ while(c == sizeof buf);
+ if(write(m, bracket, 5) != 5)
+ goto wrerr;
+out1: VOID close(m);
+out: cndfree(mail);
+ if(lock) {
+ VOID unlink(lock);
+ cndfree(lock);
+ }
+ }
+ if(verbose && !donecd)
+ printf("Sent.\n");
+}
+
+netmail()
+{
+ register struct mailname *mp;
+ register struct shome *h;
+ register struct hosts *hp;
+ register FILE *md;
+ int fd, count;
+ char namebuf[15], tmpname[40], queuename[40];
+ char buf[BUFSIZ];
+
+ crname(namebuf);
+ VOID sprintf(tmpname, "%s/%s", TMAILQDIR, namebuf);
+ VOID sprintf(queuename, "%s/%s", MAILQDIR, namebuf);
+ if((md = fopen(tmpname, "w")) == NULL) {
+ fprintf(stderr, "Deliver: Can't create netmail tmp: ");
+ perror(tmpname);
+ done(1);
+ }
+ for(h = homes; ; h = h->h_next) {
+ if(!h) {
+ fprintf(stderr, "Deliver: Who are you?\n");
+ done(1);
+ }
+ if(h->h_uid == myuid)
+ break;
+ }
+ if(!now)
+ now = time((long *)0);
+ fprintf(md, "%s %s\n", h->h_name, cdate(&now));
+ if(debug) {
+ printf("Netmail..."); fflush(stdout);
+ }
+ for(mp = netaddrs.m_next; mp; mp = mp->m_next) {
+ if(debug) printf("%s at %s\n",mp->m_mbox, mp->m_host);
+ for(hp = hosts.nh_next; hp; hp = hp->nh_next)
+ if(mp->m_hnum == hp->nh_num)
+ break;
+ if(!hp) {
+ fprintf(stderr, "Deliver: hnum->name botch.\n");
+ done(1);
+ }
+ fprintf(md, "/%s %s\n", hp->nh_name, mp->m_mbox);
+ if(verbose)
+ printf("%s at %s: queued\n", mp->m_mbox, mp->m_host);
+ }
+ putc('\n', md);
+ if(fflush(md) == EOF) goto wrerr;
+ if((fd = open(tmpfil, 0)) == -1) {
+ fprintf(stderr, "Deliver: HuH? Can't reopen ");
+ perror(tmpfil);
+ done(1);
+ }
+ do {
+ if((count = read(fd, buf, sizeof buf)) > 0) {
+ if(write(fileno(md), buf, count) != count) {
+ wrerr: fprintf(stderr, "Deliver: write error on ");
+ perror(tmpname);
+ VOID unlink(tmpname);
+ done(1);
+ }
+ } else if(count < 0) {
+ fprintf(stderr, "deliver: Read error on ");
+ perror(tmpfil);
+ VOID unlink(tmpname);
+ done(1);
+ }
+ } while(count == sizeof buf);
+ if(close(fd) == -1 || fclose(md) == EOF) goto wrerr;
+ if(link(tmpname, queuename) == -1 ||
+ unlink(tmpname) == -1) {
+ fprintf(stderr, "Deliver: Trouble linking tmpfile into queue ");
+ perror(queuename);
+ }
+ VOID chmod (queuename, 0600);
+}
+
+uumail()
+{
+ register struct mailname *mp;
+ register struct shome *h;
+ register FILE *rmf;
+ FILE *popen();
+ int fd, count;
+ char cmd[64];
+ char buf[BUFSIZ];
+
+ for(h = homes; h; h = h->h_next)
+ if(h->h_uid == myuid)
+ break;
+ if(!h) {
+ fprintf(stderr, "Deliver: Who are you?\n");
+ done(1);
+ }
+ if(!now)
+ now = time((long *)0);
+ for(mp = uuaddrs.m_next; mp; mp = mp->m_next) {
+ VOID sprintf(cmd, index(mp->m_mbox, '!') ?
+ "uux - %s!rmail \\(%s\\)" :
+ "uux - %s!rmail %s",
+ mp->m_host, mp->m_mbox);
+ if ((rmf=popen (cmd, "w")) == NULL) {
+ fprintf(stderr, "Deliver: Could not open uux pipe.\n");
+ done(1);
+ }
+
+ if((fd = open(uutmpfil, 0)) == -1) {
+ fprintf(stderr, "Deliver: HuH? Can't reopen ");
+ perror(uutmpfil);
+ done(1);
+ }
+ /* UUCP mail insists on beginning with a "From" line. */
+ /* No other concessions (">" before From) will be provided now */
+ fprintf(rmf, "From %s %.24s remote from %s\n", h->h_name,
+ ctime(&now),
+ sysname);
+ VOID fflush(rmf); /* Lest the "write"s get in ahead */
+
+ do {
+ if((count = read(fd, buf, sizeof buf)) > 0) {
+ if(write(fileno(rmf), buf, count) != count) {
+ wrerr: fprintf(stderr, "Deliver: write error on pipe\n");
+ done(1);
+ }
+ } else if(count < 0) {
+ fprintf(stderr, "deliver: Read error on ");
+ perror(uutmpfil);
+ done(1);
+ }
+ } while(count == sizeof buf);
+ if(close(fd) == -1 ) goto wrerr;
+ pclose(rmf);
+ if(verbose)
+ printf("%s At %s (via uux): queued.\n",
+ mp->m_mbox, mp->m_host);
+
+ }
+}
+
+char hex[] = "0123456789ABCDEF"; /* Hexadecimal */
+
+crname(ptr) /* Create unique file name in /usr/tmp */
+ char *ptr;
+{
+ int i;
+ short tvec[4];
+ static int filecnt;
+ register char *p, *q;
+
+ q = ptr;
+ p = (char *)&tvec[0];
+ tvec[2] = getpid();
+ tvec[3] = filecnt++;
+ if (filecnt==256) {
+ filecnt = 0;
+ sleep(1);
+ }
+ VOID time((time_t *)tvec);
+ for (i=7; i; --i) {
+ *q++ = hex[(*p>>4)&017];
+ *q++ = hex[ *p++ &017];
+ }
+ *q = '\0';
+}
+
+
+putfrom(out)
+ register FILE *out;
+{
+ register struct shome *h;
+ register struct mailname *mp;
+ register char *cp;
+
+ for(h = homes; h; h = h->h_next)
+ if(h->h_uid == myuid) {
+ if(format) {
+ if(!(mp = getm(h->h_name, HOSTNAME)))
+ done(1);
+ cp = adrformat(mp,HOSTNAME);
+ mnfree(mp);
+ } else
+ cp = h->h_name;
+ if(mn_from) {
+ if(mn_from->m_hnum != HOSTNUM ||
+ !uleq(mn_from->m_mbox, h->h_name))
+ fprintf(out, "Sender: %s\n", cp);
+ } else
+ fprintf(out, "From: %s\n", cp);
+ return;
+ }
+ fprintf(stderr, "Deliver: WHO ARE YOU?\n");
+ done(1);
+}
+
+
+putdate(out)
+ register FILE *out;
+{
+ register char *t, *p;
+ char *timezone();
+ struct timeb tb;
+ struct tm *tmp, *localtime();
+ static char *wday[] = {
+ "Sun",
+ "Mon",
+ "Tues",
+ "Wednes",
+ "Thurs",
+ "Fri",
+ "Satur"
+ };
+
+ if(!now)
+ now = time((long *)0);
+ t = ctime(&now);
+ ftime(&tb);
+ tmp = localtime(&now);
+ p = timezone(tb.timezone, tmp->tm_isdst);
+
+ /* day 13 Apr 1981 20 :38 -PST */
+ fprintf(out, "Date: %sday, %.2s %.3s %.4s %.2s:%.2s-%.3s\n",
+ wday[tmp->tm_wday], t+8, t+4, t+20, t+11, t+14, p);
+}
+
+
+putmsgid(sp)
+ FILE *sp;
+{
+ if(!msgid)
+ return;
+ if(!now)
+ now = time((long *)0);
+ fprintf(sp, "Message-ID: <%u.%ld@%s>\n", myuid, now, HOSTNAME);
+}
+
+
+/***/
+pl()
+{
+ register struct mailname *mp;
+
+ printf("local: ");
+ for(mp = localaddrs.m_next; mp; mp=mp->m_next)
+ printf("%s (%s)%s",
+ mp->m_mbox, mp->m_headali, mp->m_next?", ":"");
+ printf("\n");
+ printf("net: ");
+ for(mp = netaddrs.m_next; mp; mp=mp->m_next)
+ printf("%s@%s (%s)%s",
+ mp->m_mbox, mp->m_host, mp->m_headali, mp->m_next?", ":"");
+ printf("\n");
+ printf("uucp: ");
+ for(mp = uuaddrs.m_next; mp; mp=mp->m_next)
+ printf("%s!%s (%s)%s",
+ mp->m_host, mp->m_mbox, mp->m_headali, mp->m_next?", ":"");
+ printf("\n");
+}
+/***/
+
+insert(np, queue)
+ register struct mailname *np, *queue;
+{
+ register struct mailname *mp;
+
+ /*** printf("insert(%s@%d)=>", np->m_mbox, np->m_hnum); /***/
+ for(mp = queue; mp->m_next; mp = mp->m_next)
+ if(duplicate(np, mp)) { /* Don't insert existing name! */
+ /*** printf("0\n"); /***/
+ return 0;
+ }
+ mp->m_next = np;
+/*** printf("1\n"); /***/
+ return 1;
+}
+
+duplicate(np, mp)
+struct mailname *np, *mp;
+{
+ if (*np->m_at == '!')
+ /* If uucp, compare host names */
+ if(uleq(np->m_host, mp->m_next->m_host) &&
+ uleq(np->m_mbox, mp->m_next->m_mbox))
+ return(1);
+ else
+ return(0);
+
+ /* Otherwise, compare host numbers */
+ if(np->m_hnum == mp->m_next->m_hnum &&
+ uleq(np->m_mbox, mp->m_next->m_mbox))
+ /* Special consideration, eg: news.topic1 != news.topic2 */
+ return( uleq(np->m_headali, mp->m_next->m_headali) ? 1
+ : alitype == STAR ? 0 : 1);
+ else
+ return(0);
+}
+
+
+
+cinsert(str)
+ char *str;
+{
+ register struct mailname *mp;
+
+ if(!(mp = getm(str, HOSTNAME)))
+ done(1);
+ mp->m_headali = getcpy(head_alias);
+ if(!insert(mp, mp->m_hnum == HOSTNUM ?
+ &localaddrs :
+ (*mp->m_at == '!')? &uuaddrs :
+ &netaddrs)) {
+ mnfree(mp);
+ }
+}
+
+
+/* alias implementation below...
+ */
+
+#define SAVE 0
+#define RESET 1
+#define NEXT 2
+#define GROUP "/etc/group"
+char *AliasFile = "/etc/MailAliases";
+
+char *termptr, *listsave;
+
+char *
+parse(ptr, buf)
+ register char *ptr;
+ char *buf;
+{
+ register char *cp;
+
+ cp = buf;
+ while(isspace(*ptr) || *ptr == ',' || *ptr == ':')
+ ptr++;
+ while(isalnum(*ptr) || *ptr == '/' || *ptr == '-' ||
+ *ptr == '!' || *ptr == '@' || *ptr == ' ' ||
+ *ptr == '.' || *ptr == '*')
+ *cp++ = *ptr++;
+ if(cp == buf) {
+ switch(*ptr) {
+ case '<':
+ case '=':
+ *cp++ = *ptr++;
+ }
+ }
+ *cp = 0;
+ if(cp == buf)
+ return 0;
+ termptr = ptr;
+ return buf;
+}
+
+char *
+setptr(type)
+int type;
+{
+ switch(type) {
+
+ case SAVE:
+ listsave = termptr;
+ break;
+ case RESET: /* Reread the current alias replacement-list */
+ termptr = listsave;
+ break;
+ case NEXT:
+ break;
+ }
+ return(termptr);
+}
+
+alias()
+{
+ register char *cp, *pp;
+ char *parsep = 0;
+ struct mailname ptrsave;
+ register struct mailname *lp;
+ char line[256], pbuf[64];
+ FILE *a;
+
+ if((a = fopen(AliasFile, "r")) == NULL) {
+ fprintf(stderr, "Can't open alias file ");
+ perror(AliasFile);
+ done(1);
+ }
+ while(fgets(line, sizeof line, a)) {
+ if(line[0] == ';' || line[0] == '\n') /* Comment Line */
+ continue;
+ cndfree(parsep);
+ if((parsep = getcpy(parse(line, pbuf))) == NULL) {
+ oops: fprintf(stderr, "Bad alias file %s\n", AliasFile);
+ fprintf(stderr, "Line: %s", line);
+ done(1);
+ }
+ VOID setptr(SAVE);
+ for(lp = &localaddrs; lp->m_next; lp = lp->m_next) {
+ if(alitype = aleq(lp->m_next->m_mbox, parsep)) {
+ setali(lp->m_next);
+
+ ptrsave.m_next = lp; /* Maintain ptr */
+ remove(lp); /* continuity after */
+ lp = &ptrsave; /* lp->next is removed. */
+
+ if(!(cp = setptr(NEXT)) ||
+ !(pp = parse(cp, pbuf)))
+ goto oops;
+ switch(*pp) {
+ case '<': /* From file */
+ cp = setptr(NEXT);
+ if((pp = parse(cp, pbuf)) == NULL)
+ goto oops;
+ addfile(pp);
+ break;
+ case '=': /* UNIX group */
+ cp = setptr(NEXT);
+ if((pp = parse(cp, pbuf)) == NULL)
+ goto oops;
+ addgroup(pp);
+ break;
+ case '*': /* ALL Users */
+ addall();
+ break;
+ default: /* Simple list */
+ for(;;) {
+ cinsert(pp);
+ if(!(cp = setptr(NEXT)) ||
+ !(pp = parse(cp, pbuf)))
+ break;
+ }
+ VOID setptr(RESET);
+ }
+ /* May be more news.*<topics> in hdr */
+ if(alitype == STAR) continue;
+ else break;
+ }
+ }
+ }
+ alitype = 0;
+}
+
+setali(mp)
+struct mailname *mp;
+{
+ /* propogate original alias match */
+
+ cndfree(head_alias);
+ head_alias = (*mp->m_headali ? getcpy(mp->m_headali) :
+ getcpy(mp->m_mbox));
+}
+
+
+addfile(file)
+ char *file;
+{
+ register char *cp, *pp;
+ char line[128], pbuf[64];
+ FILE *f;
+
+/*** printf("addfile(%s)\n", file); ***/
+ if((f = fopen(file, "r")) == NULL) {
+ fprintf(stderr, "Can't open ");
+ perror(file);
+ done(1);
+ }
+ while(fgets(line, sizeof line, f)) {
+ cp = line;
+ while(pp = parse(cp, pbuf)) {
+ cinsert(pp);
+ cp = setptr(NEXT);
+ }
+ }
+ VOID fclose(f);
+}
+
+addgroup(group)
+ char *group;
+{
+ register char *cp, *pp;
+ int found = 0;
+ char line[128], pbuf[64], *rindex();
+ FILE *f;
+
+/*** printf("addgroup(%s)\n", group); ***/
+ if((f = fopen(GROUP, "r")) == NULL) {
+ fprintf(stderr, "Can't open ");
+ perror(GROUP);
+ done(1);
+ }
+ while(fgets(line, sizeof line, f)) {
+ pp = parse(line, pbuf);
+ if(strcmp(pp, group) == 0) {
+ cp = rindex(line, ':');
+ while(pp = parse(cp, pbuf)) {
+ cinsert(pp);
+ cp = setptr(NEXT);
+ }
+ found++;
+ }
+ }
+ if(!found) {
+ fprintf(stderr, "Group: %s non-existent\n", group);
+ done(1);
+ }
+ VOID fclose(f);
+}
+
+addall()
+{
+ register struct shome *h;
+
+/*** printf("addall()\n"); ***/
+ for(h = homes; h; h = h->h_next)
+ if(h->h_uid >= EVERYONE)
+ cinsert(h->h_name);
+}
+
+remove(mp) /* Remove NEXT from argument node! */
+ register struct mailname *mp;
+{
+ register struct mailname *rp;
+
+ rp = mp->m_next;
+ mp->m_next = rp->m_next;
+ cndfree(rp->m_mbox);
+ cndfree(rp->m_host);
+ cndfree(rp->m_text);
+ cndfree(rp->m_headali);
+ cndfree( (char *)rp);
+}
+
+int alarmed;
+
+alarmclock()
+{
+ alarmed++;
+}
+
+char **environ;
+char *empty[] = {0};
+
+calluserprog(prog, mail, fd, h, head_alias)
+ char *prog, *mail, *head_alias;
+ int fd;
+ register struct shome *h;
+{
+ register int pid, child, i;
+ int status;
+
+ if(verbose) {
+ printf("Invoking %s ", prog); fflush(stdout);
+ }
+ i = 0;
+ while((child = fork()) == -1)
+ if(++i > 10) {
+ fprintf(stderr, "Can't get a fork to invoke %s!\n",
+ prog);
+ donecd = 1;
+ return;
+ } else
+ sleep(2);
+ if(child == 0) { /* In child... */
+ if(fd != 3)
+ dup2(fd, 3);
+ for(i = 4; i < 15; i++)
+ VOID close(i);
+ environ = empty;
+ putenv("USER", h->h_name);
+ putenv("HOME", h->h_home);
+ VOID setgid(h->h_gid);
+ VOID setuid(h->h_uid);
+ execlp(prog, prog, tmpfil, mail, h->h_home, head_alias, 0);
+ perror(prog);
+ done(-1);
+ }
+ VOID signal(SIGALRM, alarmclock);
+ alarmed = 0;
+ VOID alarm(120); /* Give receive proc 120 secs */
+ status = 0;
+ while((pid = wait(&status)) != -1 && pid != child && !alarmed) ;
+ if(alarmed) {
+ VOID kill(0, SIGINT);
+ VOID signal(SIGALRM, alarmclock);
+ alarmed = 0;
+ VOID alarm(120);
+ while((pid = wait(&status)) != -1 && pid != child && !alarmed) ;
+ if(alarmed) {
+ VOID kill(child, SIGKILL);
+ VOID signal(SIGALRM, alarmclock);
+ alarmed = 0;
+ VOID alarm(120);
+ while((pid = wait(&status)) != -1 && pid != child && !alarmed) ;
+ }
+ fprintf(stderr, "Deliver: Killed %s--Took more than 120 seconds!\n",
+ prog);
+ donecd = 1;
+ status = 0;
+ } else
+ VOID alarm(0);
+ if(status) {
+ printf("Deliver: %s error %d from %s on delivery to %s\n",
+ status&0377? "System" : "User",
+ status&0377? status&0377 : status>>8,
+ prog, h->h_name);
+ donecd = 1;
+ }
+ if(pid == -1) {
+ fprintf(stderr, "Deliver: wait on receive process returned -1\n");
+ perror("");
+ donecd = 1;
+ }
+}
+
+aleq(string, aliasent)
+ register char *string, *aliasent;
+{
+ register int c;
+
+ while(c = *string++)
+ if(*aliasent == '*')
+ return(STAR);
+ else if((c|040) != (*aliasent|040))
+ return(0);
+ else
+ aliasent++;
+/*** return(*aliasent == 0 | *aliasent == '*'); ***/
+ return(*aliasent == '*' ? STAR : *aliasent == 0 ? 1 : 0);
+}
+
+fcc(file, folder)
+ char *file, *folder;
+{
+ int child, pid, status;
+ char fold[128];
+
+ if(verbose) {
+ printf("Fcc: %s...", folder); fflush(stdout);
+ }
+ while((child = fork()) == -1) sleep(5);
+ if(child == 0) {
+ if(*file != '+')
+ strcpy(fold, "+");
+ strcat(fold, folder);
+ VOID setuid(myuid);
+ execl(fileproc, "file", "-link", "-file", file, fold, 0);
+ exit(-1);
+ } else while((pid = wait(&status)) != -1 && pid != child) ;
+ if(status)
+ fprintf(stderr, "Deliver: Error on fcc to %s\n", folder);
+ else if(verbose)
+ p
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define NOUSE 0
+
+/* #define TEST 1 */
+
+struct swit anyl[] = {
+ "no", 0,
+ "yes", 0,
+ "list", 0,
+ 0,
+};
+
+struct swit aleqs[] = {
+ "list", 0, /* 0 */
+ "edit [<editor>]", 0, /* 1 */
+ "quit [delete]", 0, /* 2 */
+ "send [switches]", 0, /* 3 */
+ 0
+};
+
+struct msgs *mp;
+char drft[128];
+int inplace; /* preserve links in anno */
+
+struct swit switches[] = {
+ "annotate", 0, /* 0 */
+ "noannotate", 0, /* 1 */
+ "editor editor", 0, /* 2 */
+ "form formfile", 0, /* 3 */
+ "inplace", 0, /* 4 */
+ "noinplace", 0, /* 5 */
+ "help", 4, /* 6 */
+ 0, 0
+};
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100], *ed, *form;
+ register int msgnum;
+ register char *cp, **ap;
+ int msgp, anot;
+ int in, out;
+ int pid, wpid;
+ char *arguments[50], **argp;
+
+ invo_name = argv[0];
+#ifdef NEWS
+ m_news();
+#endif
+ anot = 0; folder = 0; msgp = 0; ed = 0; form = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "dist: -%s unknown\n", cp);
+ goto leave;
+ case 0: anot = 1; continue; /* -annotate */
+ case 1: anot = 0; continue; /* -noannotate */
+ case 2: if(!(ed = *argp++)) { /* -editor */
+ missing: fprintf(stderr, "dist: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 3: if(!(form = *argp++)) /* -form */
+ goto missing;
+ continue;
+ case 4: inplace = 1; continue; /* -inplace */
+ case 5: inplace = 0; continue; /* -noinplace */
+ /* -help */
+ case 6: help("dist [+folder] [msg] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = path(cp+1, TFOLDER);
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!m_find("path")) free(path("./", TFOLDER));
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert((cp = msgs[msgnum])))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "dist: Tuna Melt\n"); /* never get here */
+ goto leave;
+ }
+ if(mp->numsel > 1) {
+ fprintf(stderr, "Only one message at a time.\n");
+ goto leave;
+ }
+ if(form) {
+ if((in = open(m_maildir(form), 0)) < 0) {
+ fprintf(stderr, "dist: Can't open form file: %s\n", form);
+ goto leave;
+ }
+ } else if(/***(in = open(m_maildir(distcomps), 0)) < 0 && ***/
+ (in = open(stddcomps, 0)) < 0) {
+ fprintf(stderr, "dist: Can't open default components file!!\n");
+ goto leave;
+ }
+ VOID copy(m_maildir(draft), drft);
+ if((out = open(drft, 0)) >= 0) {
+ if(!fdcompare(in, out)) {
+ cp = concat("\"", drft, "\" exists; Delete? ", 0);
+ while((msgnum = gans(cp, anyl)) == 2)
+ VOID showfile(drft);
+ if(!msgnum)
+ return;
+ }
+ VOID close(out);
+ }
+ if((out = creat(drft, m_gmprot())) < 0) {
+ fprintf(stderr, "Can't create \"%s\"\n", drft);
+ goto leave;
+ }
+ cpydata(in, out);
+ VOID close(in);
+ if((in = open(cp = m_name(mp->lowsel), 0)) < 0) {
+ fprintf(stderr, "Can't open message \"%s\"\n", cp);
+ VOID unlink(drft);
+ goto leave;
+ }
+ cpydata(in, out);
+ VOID close(in);
+ VOID close(out);
+ m_replace(pfolder, folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ if(m_edit(&ed, drft, NOUSE, NULLCP) < 0)
+ goto leave;
+#ifdef TEST
+ fprintf(stderr, "!! Test Version of SEND Being Run !!\n");
+ fprintf(stderr, " Send verbose !\n\n");
+#endif
+
+ for(;;) {
+ if(!(argp = getans("\nWhat now? ", aleqs)))
+ goto leave;
+ switch(smatch(*argp, aleqs)) {
+ case 0: VOID showfile(drft); /* list */
+ break;
+
+ case 1: if(*++argp) /* edit */
+ ed = *argp;
+ if(m_edit(&ed, drft, NOUSE, NULLCP) == -1)
+ goto leave;
+ break;
+
+ case 2: if(*++argp && (*argp[0] == 'd' || /* quit */
+ (*argp[0]=='-' && *argp[1]=='d')))
+ if(unlink(drft) == -1) {
+ fprintf(stderr, "Can't unlink %s ", drft);
+ perror("");
+ }
+ goto leave;
+ case 3: /* send */
+ if(!mp->msgflags&READONLY) { /* annotate first */
+ if(anot > 0) {
+ while((pid = fork()) == -1) sleep(5);
+ if(pid) {
+ while((wpid=wait((int *)NULL))!= -1
+ && wpid != pid);
+ doano();
+ goto leave;
+ }
+ }
+ }
+ VOID m_send(++argp, drft);
+ goto leave;
+
+ default:fprintf(stderr, "dist: illegal option\n"); /*##*/
+ break;
+ }
+ }
+
+ leave:
+ m_update();
+ done(0);
+}
+
+
+cpydata(in, out)
+{
+ char buf[BUFSIZ];
+ register int i;
+
+ do
+ if((i = read(in, buf, sizeof buf)) > 0)
+ if(write(out, buf, i) != i) {
+ fprintf(stderr, "dist: error on ");
+ perror("write");
+ done(1);
+ }
+ while(i == sizeof buf);
+}
+
+
+doano()
+{
+ register FILE *in;
+ char name[NAMESZ], field[256];
+ register int state;
+ register char *text;
+
+ if(stat(drft, (struct stat *)field) != -1) {
+ fprintf(stderr, "%s not sent-- no annotations made.\n", drft);
+ return;
+ }
+ text = copy(drft, field);
+ text[1] = 0;
+ do
+ *text = text[-1];
+ while(--text >= field && *text != '/');
+ *++text = ','; /* New backup convention */
+ if((in = fopen(field, "r")) == NULL) {
+ fprintf(stderr, "Can't open %s\n", field);
+ return;
+ }
+ state = FLD;
+ text = 0;
+ for(;;) switch(state = m_getfld(state, name, field, sizeof field, in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(uleq(name, "distribute-to") ||
+ uleq(name, "distribute-cc") ) {
+ if(state == FLD) {
+ text = add(name, text);
+ text = add(":", text);
+ }
+ text = add(field, text);
+ }
+ if(state == FLDEOF)
+ goto out;
+ continue;
+ case BODY:
+ case BODYEOF:
+ goto out;
+ default:
+ fprintf(stderr, "Getfld returned %d\n", state);
+ return;
+ }
+
+out:
+ VOID fclose(in);
+ annotate(m_name(mp->lowsel), "Distributed", text, inplace);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include "../folder.h"
+#include <stdio.h>
+
+#define NFOLD 20 /* Allow 20 folder specs */
+char *calloc();
+
+/* file [-src folder] [msgs] +folder [+folder ...]
+ *
+ * moves messages from src folder (or current) to other one(s).
+ *
+ * all = 1-999 (MAXFOLDER) for a message sequence
+ * -preserve says preserve msg numbers
+ * -link says don't delete old msg
+ */
+
+extern struct swit anoyes[]; /* Std no/yes gans array */
+
+int vecp, foldp, prsrvf;
+char **vec, maildir[128], *folder;
+struct msgs *mp;
+
+struct st_fold folders[NFOLD];
+
+char *files[NFOLD + 1]; /* Vec of files to process--starts at 1! */
+int filec = 1;
+
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "link", 0, /* 1 */
+ "nolink", 0, /* 2 */
+ "preserve", 0, /* 3 */
+ "nopreserve", 0, /* 4 */
+ "src +folder", 0, /* 5 */
+ "file", 0, /* 6 */
+ "help", 4, /* 7 */
+ 0, 0
+};
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ register int i, msgnum;
+ register char *cp;
+ char *msgs[128];
+ int msgp, linkf;
+ char **ap;
+ char *arguments[50], **argp;
+
+ invo_name = argv[0];
+#ifdef NEWS
+ m_news();
+#endif
+ folder = 0; msgp = 0; linkf = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "file: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: linkf = 1; continue; /* -link */
+ case 2: linkf = 0; continue; /* -nolink */
+ case 3: prsrvf = 1; continue; /* -preserve */
+ case 4: prsrvf = 0; continue; /* -nopreserve */
+ case 5: if(folder) { /* -src */
+ fprintf(stderr, "Only one src folder.\n");
+ goto leave;
+ }
+ if(!(folder = *argp++) || *folder == '-') {
+missing: fprintf(stderr, "file: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ if(*folder == '+')
+ folder++;
+ folder = path(folder, TFOLDER);
+ continue;
+ case 6:
+ if(filec >= NFOLD) {
+ fprintf(stderr, "Too many src files.\n");
+ goto leave;
+ }
+ if(!(cp = *argp++) || *cp == '-')
+ goto missing;
+ files[filec++] = path(cp, TFILE);
+ continue;
+
+ /* -help */
+ case 7: help("file [msgs] [switches] +folder ...",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(foldp < NFOLD)
+ folders[foldp++].f_name = path(++cp, TFOLDER);
+ else {
+ fprintf(stderr, "Only %d folders allowed.\n", NFOLD);
+ goto leave;
+ }
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!m_find("path")) free(path("./", TFOLDER));
+ if(!foldp) {
+ fprintf(stderr, "No folder specified.\n");
+fprintf(stderr, "Usage: file [-src folder] [msg ...] [switches] +folder [+folder]\n");
+ goto leave;
+ }
+ if(filec > 1) {
+ if(msgp) {
+ fprintf(stderr, "File: Can't mix files and messages.\n");
+ goto leave;
+ }
+ if(opnfolds())
+ goto leave;
+ for(i = 1; i < filec; i++) {
+ if(m_file(folder, files[i], folders, foldp, prsrvf, 0))
+ goto leave;
+ }
+ if(!linkf) {
+ if((cp = m_find("delete-prog")) != NULL) {
+ files[0] = r1bindex(cp, '/');
+ execvp(cp, files);
+ fprintf(stderr, "Can't exec deletion-prog--");
+ perror(cp);
+ } else for(i = 1; i < filec; i++) {
+ if(unlink(files[i]) == -1) {
+ fprintf(stderr, "Can't unlink ");
+ perror(files[i]);
+ }
+ }
+ }
+ goto leave;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ VOID copy(m_maildir(folder), maildir);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder %s!?\n",folder);
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert((cp = msgs[msgnum])))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "file: ham 'n cheese\n"); /* never get here */
+ goto leave;
+ }
+ m_replace(pfolder, folder);
+ if(mp->hghsel != mp->curmsg && ((mp->numsel != mp->nummsg) || linkf))
+ m_setcur(mp->hghsel);
+ if(opnfolds())
+ goto leave;
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum] & SELECTED)
+ if(m_file(folder, cp = getcpy(m_name(msgnum)),
+ folders, foldp, prsrvf, 0))
+ goto leave;
+ else
+ cndfree(cp);
+ if(!linkf) {
+ if((cp = m_find("delete-prog")) != NULL) {
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "file: more than %d messages for deletion-prog\n",MAXARGS-2);
+ printf("[messages not unlinked]\n");
+ goto leave;
+ }
+ vecp = 1;
+ vec = (char **) calloc(MAXARGS + 2, sizeof *vec);
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ vec[vecp++] = getcpy(m_name(msgnum));
+ vec[vecp] = 0;
+ m_update();
+ VOID fflush(stdout);
+ vec[0] = r1bindex(cp, '/');
+ execv(vec[0], vec);
+ fprintf(stderr, "Can't exec deletion-prog--");
+ perror(cp);
+ } else {
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum] & SELECTED)
+ if(unlink(cp = m_name(msgnum))== -1) {
+ fprintf(stderr, "Can't unlink %s:",folder);
+ perror(cp);
+ }
+ }
+ }
+leave:
+ m_update();
+ done(0);
+}
+
+
+opnfolds()
+{
+ register int i;
+ register char *cp;
+ char nmaildir[128];
+
+ for(i = 0; i < foldp; i++) {
+ VOID copy(m_maildir(folders[i].f_name), nmaildir);
+ if(access(nmaildir, 5) < 0) {
+ cp = concat("Create folder \"", nmaildir, "\"? ", 0);
+ if(!gans(cp, anoyes))
+ goto bad;
+ free(cp);
+ if(!makedir(nmaildir)) {
+ fprintf(stderr, "Can't create folder.\n");
+ goto bad;
+ }
+ }
+ if(chdir(nmaildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(nmaildir);
+ goto bad;
+ }
+ if(!(folders[i].f_mp = m_gmsg(folders[i].f_name))) {
+ fprintf(stderr, "Can't read folder %s\n", folders[i].f_name);
+ goto bad;
+ }
+ }
+ VOID chdir(maildir); /* return to src folder */
+ return(0);
+bad:
+ retur
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <strings.h>
+
+#define NFOLDERS 300
+
+int all, hdrflag, foldp;
+struct msgs *mp;
+char folder[128], *folds[NFOLDERS];
+int msgtot, foldtot, totonly, fshort;
+int fpack;
+struct swit switches[] = {
+ "all", 0, /* 0 */
+ "down", 0, /* 1 */
+ "fast", 0, /* 2 */
+ "nofast", 0, /* 3 */
+ "header", 0, /* 4 */
+ "noheader", 0, /* 5 */
+ "pack", 0, /* 6 */
+ "nopack", 0, /* 7 */
+ "short", -1, /* 8 */
+ "total", 0, /* 9 */
+ "nototal", 0, /*10 */
+ "up", 0, /*11 */
+ "help", 4, /*12 */
+ 0, 0
+};
+
+extern char _sobuf[]; /* MLW standard out buffer */
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ register char *cp, *curm;
+ register int i;
+ char *argfolder;
+ int up, down, def_short = 0;
+ char *arguments[50], **argp, **ap;
+ struct stat stbf;
+ struct node *np;
+ struct { short inum;
+ char name[14];
+ int pad;
+ } ent;
+
+ invo_name = argv[0];
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ up = down = 0;
+ argfolder = NULL;
+ curm = 0;
+ /* set -all if program name ends in 's' -- "folders" */
+ if(argv[0][strlen(argv[0])-1] == 's') /* Plural name?? */
+ all++;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "folder: -%s unknown\n", cp);
+ goto leave;
+ case 0: all++; continue; /* -all */
+ case 1: down++; continue; /* -down */
+ case 2: /* -fast */
+ case 8: fshort = 1; continue; /* -short */
+ case 3: fshort = 0; continue; /* -nofast */
+ case 4: hdrflag = -1; continue; /* -header */
+ case 5: hdrflag = 0; continue; /* -noheader */
+ case 6: fpack = 1; continue; /* -pack */
+ case 7: fpack = 0; continue; /* -nopack */
+ case 9: all++; totonly = 1; /* -total */
+ continue;
+ case 10:if(totonly) all--; /* -nototal */
+ totonly =0; continue;
+ case 11:up++; continue; /* -up */
+ /* -help */
+ case 12:help("folder [+folder] [msg] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(argfolder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ argfolder = path(cp+1, TFOLDER);
+ } else if(curm) {
+ fprintf(stderr, "Only one current may be given.\n");
+ goto leave;
+ } else
+ curm = cp;
+ }
+ /* free() has side affects!!! */
+ if(!m_find("path")) free(path("./", TFOLDER));
+ if(all) {
+ hdrflag = 0;
+ cp = m_maildir("");
+ m_getdefs();
+ for(np = m_defs; np; np = np->n_next) {
+ if(!ssequal("cur-", np->n_name))
+ continue;
+ if(fshort) {
+ def_short++;
+ printf("%s\n", np->n_name+4);
+ } else
+ addfold(np->n_name+4);
+ }
+ if(def_short)
+ putchar('\n');
+ if(fshort) {
+ m_update();
+ VOID fflush(stdout);
+ execl(lsproc, r1bindex(lsproc, '/'), "-x", cp, 0);
+ fprintf(stderr, "Can't exec: ");
+ perror(lsproc);
+ goto leave;
+ }
+ if(chdir(cp) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(cp);
+ goto leave;
+ }
+ if((cp = m_find(pfolder)) == NULL)
+ *folder = 0;
+ else
+ VOID copy(cp, folder);
+ i = open(".", 0);
+ ent.pad = 0;
+ while(read(i, (char *)&ent.inum,
+ sizeof ent.name + sizeof ent.inum))
+ if(ent.inum && ent.name[0] != '.' &&
+ stat(ent.name, &stbf) >= 0 &&
+ (stbf.st_mode&S_IFMT) == S_IFDIR)
+ addfold(ent.name);
+ VOID close(i);
+ for(i = 0; i < foldp; i++) {
+ VOID pfold(folds[i], NULLCP); VOID fflush(stdout);
+ }
+ if(!totonly)
+ printf("\n\t\t ");
+ printf("TOTAL= %3d message%c in %d Folder%s.\n",
+ msgtot, msgtot!=1? 's':' ',
+ foldtot, foldtot!=1? "s":"");
+ } else {
+ hdrflag++;
+ if(argfolder)
+ cp = copy(argfolder, folder);
+ else
+ cp = copy(m_getfolder(), folder);
+ if(up) {
+ while(cp > folder && *cp != '/') --cp;
+ if(cp > folder)
+ *cp = 0;
+ argfolder = folder;
+ } else if(down) {
+ VOID copy(listname, copy("/", cp));
+ argfolder = folder;
+ }
+ if(pfold(folder, curm) && argfolder)
+ m_replace(pfolder, argfolder);
+ }
+
+ leave:
+ m_update();
+ done(0);
+}
+
+
+addfold(fold)
+char *fold;
+{
+ register int i,j;
+ register char *cp;
+
+ if(foldp >= NFOLDERS) {
+ fprintf(stderr, "More than %d folders!!\n", NFOLDERS);
+ done(1);
+ }
+ cp = getcpy(fold);
+ for(i = 0; i < foldp; i++)
+ if(compare(cp, folds[i]) < 0) {
+ for(j = foldp - 1; j >= i; j--)
+ folds[j+1] = folds[j];
+ foldp++;
+ folds[i] = cp;
+ return;
+ }
+ folds[foldp++] = cp;
+ return;
+}
+
+
+pfold(fold, curm)
+ char *fold, *curm;
+{
+ register char *mailfile;
+ register int msgnum, hole;
+ char newmsg[8], oldmsg[8];
+
+ mailfile = m_maildir(fold);
+ if(chdir(mailfile) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(mailfile);
+ return(0);
+ }
+ if(fshort) {
+ printf("%s\n", fold);
+ return(0);
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder %s!?\n",folder);
+ return(0);
+ }
+ foldtot++;
+ msgtot += mp->nummsg;
+ if(fpack) {
+ for(msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++) {
+ if(mp->msgstats[msgnum]&EXISTS) {
+ if(msgnum != hole) {
+ VOID copy(m_name(hole), newmsg);
+ VOID copy(m_name(msgnum), oldmsg);
+ if(link(oldmsg, newmsg) == -1 ||
+ unlink(oldmsg) == -1) {
+ fprintf(stderr, "Error moving %s to ", oldmsg);
+ perror(newmsg);
+ done(1);
+ }
+ if (msgnum == mp->curmsg)
+ m_setcur(mp->curmsg = hole);
+ mp->msgstats[hole] = mp->msgstats[msgnum];
+ if(msgnum == mp->lowsel)
+ mp->lowsel = hole;
+ if(msgnum == mp->hghsel)
+ mp->hghsel = hole;
+ }
+ hole++;
+ }
+ }
+ if(mp->nummsg > 0) {
+ mp->lowmsg = 1;
+ mp->hghmsg = hole - 1;
+ }
+ }
+ if(totonly)
+ goto out;
+ if(curm) {
+ if(!m_convert(curm))
+ return(0);
+ if(mp->numsel > 1) {
+ fprintf(stderr, "Can't set current msg to range: %s\n", curm);
+ return(0);
+ }
+ m_setcur(mp->curmsg = mp->hghsel);
+ }
+ if(!hdrflag++)
+ printf("\t\tFolder # of messages ( range ); cur msg (other files)\n");
+ printf("%22s", fold);
+ if(strcmp(folder, fold) == 0)
+ printf("+ ");
+ else
+ printf(" ");
+ if(mp->hghmsg == 0)
+ printf("has no messages");
+ else {
+ printf("has %3d message%s (%3d-%3d)",
+ mp->nummsg, (mp->nummsg==1)?" ":"s",
+ mp->lowmsg, mp->hghmsg);
+ if(mp->curmsg >= mp->lowmsg && mp->curmsg <= mp->hghmsg)
+ printf("; cur=%3s", m_name(mp->curmsg));
+ }
+ if(mp->selist || mp->others) {
+ printf("; (");
+ if(mp->selist) {
+ printf("%s", listname);
+ if(mp->others)
+ printf(", ");
+ }
+ if(mp->others)
+ printf("others");
+ putchar(')');
+ }
+ putchar('.');
+ putchar('\n');
+out:
+ free( (char *)mp);
+ mp = 0;
+ return(1);
+}
+
+
+compare(s1, s2)
+char *s1, *s2;
+{
+ register char *c1, *c2;
+ register int i;
+
+ c1 = s1; c2 = s2;
+ while(*c1 || *c2)
+ if(i = *c1++ - *c2++)
+ return(i);
+ retur
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+extern char *sprintf();
+
+#define NOUSE 0
+
+/* #define TEST 1 */
+
+struct msgs *mp;
+char drft[128];
+int inplace; /* preserve links in anno */
+
+struct swit anyl[] = {
+ "no", 0,
+ "yes", 0,
+ "list", 0,
+ 0,
+};
+
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "annotate", 0, /* 1 */
+ "noannotate", 0, /* 2 */
+ "editor editor", 0, /* 3 */
+ "form formfile", 0, /* 4 */
+ "inplace", 0, /* 5 */
+ "noinplace", 0, /* 6 */
+ "help", 4, /* 7 */
+ 0, 0
+};
+
+struct swit aleqs[] = {
+ "list", 0, /* 0 */
+ "edit [<editor>]", 0, /* 1 */
+ "quit [delete]", 0, /* 2 */
+ "send [switches]", 0, /* 3 */
+ 0
+};
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100], *ed, *form;
+ register int msgnum;
+ register char *cp, **ap;
+ int msgp, anot;
+ int in, out;
+ int pid, wpid, msgcnt;
+ char *arguments[50], **argp;
+ char numbuf[5];
+
+ invo_name = argv[0];
+#ifdef NEWS
+ m_news();
+#endif
+ form = 0; anot = 0; folder = 0; msgp = 0; ed = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "forw: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: anot = 1; continue; /* -annotate */
+ case 2: anot = 0; continue; /* -noannotate */
+ case 3: if(!(ed = *argp++)) { /* -editor */
+ missing: fprintf(stderr, "forw: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 4: if(!(form = *argp++)) /* -form */
+ goto missing;
+ continue;
+ case 5: inplace = 1; continue; /* -inplace */
+ case 6: inplace = 0; continue; /* -noinplace */
+ /* -help */
+ case 7: help("forw [+folder] [msgs] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = path(cp+1, TFOLDER);
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!m_find("path")) free(path("./", TFOLDER));
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "forw: italian salami.\n"); /* never get here */
+ goto leave;
+ }
+ if(form) {
+ if((in = open(m_maildir(form), 0)) < 0) {
+ fprintf(stderr, "forw: Can't open form file: %s\n", form);
+ goto leave;
+ }
+ } else if((in = open(m_maildir(components), 0)) < 0 &&
+ (in = open(stdcomps, 0)) < 0) {
+ fprintf(stderr, "forw: Can't open default components file!!\n");
+ goto leave;
+ }
+ VOID copy(m_maildir(draft), drft);
+ if((out = open(drft, 0)) >= 0) {
+ if(!fdcompare(in, out)) {
+ cp = concat("\"", drft, "\" exists; Delete? ", 0);
+ while((msgnum = gans(cp, anyl)) == 2)
+ VOID showfile(drft);
+ if(!msgnum)
+ return;
+ }
+ VOID close(out);
+ }
+ if((out = creat(drft, m_gmprot())) < 0) {
+ fprintf(stderr, "Can't create \"%s\"\n", drft);
+ goto leave;
+ }
+ cpydata(in, out);
+ VOID close(in);
+ for(msgcnt = 1, msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED) {
+ if((in = open(cp = m_name(msgnum), 0)) < 0) {
+ fprintf(stderr, "Can't open message \"%s\"\n", cp);
+ VOID unlink(drft);
+ goto leave;
+ }
+ VOID type(out, "\n\n-------");
+ if(msgnum == mp->lowsel) {
+ VOID type(out, " Forwarded Message");
+ if(mp->numsel > 1)
+ VOID type(out, "s");
+ } else {
+ VOID type(out, " Message ");
+ VOID sprintf(numbuf, "%d", msgcnt);
+ VOID type(out, numbuf);
+ }
+ VOID type(out, "\n\n");
+ cpydata(in, out);
+ VOID close(in);
+ msgcnt++;
+ }
+ VOID type(out, "\n\n------- End of Forwarded Message");
+ if(mp->numsel > 1)
+ VOID type(out, "s");
+ VOID type(out, "\n");
+ VOID close(out);
+ m_replace(pfolder, folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ if(m_edit(&ed, drft, NOUSE, NULLCP) < 0)
+ goto leave;
+
+#ifdef TEST
+ fprintf(stderr, "!! Test Version of SEND Being Run !!\n");
+ fprintf(stderr, " Send verbose !\n\n");
+#endif
+ for(;;) {
+ if(!(argp = getans("\nWhat now? ", aleqs)))
+ goto leave;
+ switch(smatch(*argp, aleqs)) {
+ case 0: VOID showfile(drft); /* list */
+ break;
+
+ case 1: if(*++argp) /* edit */
+ ed = *argp;
+ if(m_edit(&ed, drft, NOUSE, NULLCP) == -1)
+ goto leave;
+ break;
+ case 2: if(*++argp && (*argp[0] == 'd' || /* quit */
+ (*argp[0]=='-' && *argp[1]=='d')))
+ if(unlink(drft) == -1) {
+ fprintf(stderr, "Can't unlink %s ", drft);
+ perror("");
+ }
+ goto leave;
+
+ case 3: /* send */
+ if(!mp->msgflags&READONLY) { /* annotate first */
+ if(anot > 0) {
+ while((pid = fork()) == -1) sleep(5);
+ if(pid) {
+ while((wpid=wait((int *)NULL))!= -1
+ && wpid!= pid);
+ doano();
+ goto leave;
+ }
+ }
+ }
+ VOID m_send(++argp, drft);
+ goto leave;
+
+ default:fprintf(stderr, "forw: illegal option\n"); /*##*/
+ break;
+ }
+ }
+
+ leave:
+ m_update();
+ done(0);
+}
+
+
+cpydata(in, out)
+{
+ char buf[BUFSIZ];
+ register int i;
+
+ do
+ if((i = read(in, buf, sizeof buf)) > 0)
+ if(write(out, buf, i) != i) {
+ fprintf(stderr, "forw: write ");
+ perror("error");
+ done(1);
+ }
+ while(i == sizeof buf);
+}
+
+
+doano()
+{
+ FILE *in;
+ char name[NAMESZ], field[256];
+ register int ind, state;
+ register char *text;
+
+ if(stat(drft, (struct stat *)field) != -1) {
+ fprintf(stderr, "%s not sent-- no annotations made.\n", drft);
+ return;
+ }
+ text = copy(drft, field);
+ text[1] = 0;
+ do
+ *text = text[-1];
+ while(--text >= field && *text != '/');
+ *++text = ','; /* New backup convention */
+ if((in = fopen(field, "r")) == NULL) {
+ fprintf(stderr, "Can't open "); perror(field);
+ return;
+ }
+ state = FLD;
+ text = 0;
+ for(;;) switch(state = m_getfld(state, name, field, sizeof field, in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(uleq(name, "to") || uleq(name, "cc") ) {
+ if(state == FLD) {
+ text = add(name, text);
+ text = add(":", text);
+ }
+ text = add(field, text);
+ }
+ if(state == FLDEOF)
+ goto out;
+ continue;
+ case BODY:
+ case BODYEOF:
+ goto out;
+ default:
+ fprintf(stderr, "Getfld returned %d\n", state);
+ return;
+ }
+
+out:
+ VOID fclose(in);
+
+ for(ind = mp->lowsel; ind <= mp->hghsel; ind++)
+ if(mp->msgstats[ind] & SELECTED)
+ VOID annotate(m_name(ind), "Forwarded", text, inpl
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <stdio.h>
+#define CCHR 2
+#define CDOT 4
+#define CCL 6
+#define NCCL 8
+#define CDOL 10
+#define CEOF 11
+
+#define STAR 01
+
+#define LBSIZE 1024
+#define ESIZE 256
+
+char ibuf[BUFSIZ];
+char expbuf[ESIZE];
+char linebuf[LBSIZE+1];
+int circf;
+
+char cc[] = {
+ 0000,0001,0002,0003,0004,0005,0006,0007,
+ 0010,0011,0012,0013,0014,0015,0016,0017,
+ 0020,0021,0022,0023,0024,0025,0026,0027,
+ 0030,0031,0032,0033,0034,0035,0036,0037,
+ 0040,0041,0042,0043,0044,0045,0046,0047,
+ 0050,0051,0052,0053,0054,0055,0056,0057,
+ 0060,0061,0062,0063,0064,0065,0066,0067,
+ 0070,0071,0072,0073,0074,0075,0076,0077,
+ 0100,0141,0142,0143,0144,0145,0146,0147,
+ 0150,0151,0152,0153,0154,0155,0156,0157,
+ 0160,0161,0162,0163,0164,0165,0166,0167,
+ 0170,0171,0172,0133,0134,0135,0136,0137,
+ 0140,0141,0142,0143,0144,0145,0146,0147,
+ 0150,0151,0152,0153,0154,0155,0156,0157,
+ 0160,0161,0162,0163,0164,0165,0166,0167,
+ 0170,0171,0172,0173,0174,0175,0176,0177,
+};
+
+
+compile(astr)
+char *astr;
+{
+ register c;
+ register char *ep, *sp;
+ char *lastep;
+ int cclcnt;
+
+ ep = expbuf;
+ sp = astr;
+ if (*sp == '^') {
+ circf++;
+ sp++;
+ }
+ for (;;) {
+ if (ep >= &expbuf[ESIZE])
+ goto cerror;
+ if ((c = *sp++) != '*')
+ lastep = ep;
+ switch (c) {
+
+ case '\0':
+ *ep++ = CEOF;
+ return(1);
+
+ case '.':
+ *ep++ = CDOT;
+ continue;
+
+ case '*':
+ if (lastep==0)
+ goto defchar;
+ *lastep |= STAR;
+ continue;
+
+ case '$':
+ if (*sp != '\0')
+ goto defchar;
+ *ep++ = CDOL;
+ continue;
+
+ case '[':
+ *ep++ = CCL;
+ *ep++ = 0;
+ cclcnt = 1;
+ if ((c = *sp++) == '^') {
+ c = *sp++;
+ ep[-2] = NCCL;
+ }
+ do {
+ *ep++ = c;
+ cclcnt++;
+ if (c=='\0' || ep >= &expbuf[ESIZE])
+ goto cerror;
+ } while ((c = *sp++) != ']');
+ lastep[1] = cclcnt;
+ continue;
+
+ case '\\':
+ if ((c = *sp++) == '\0')
+ goto cerror;
+ defchar:
+ default:
+ *ep++ = CCHR;
+ *ep++ = c;
+ }
+ }
+ cerror:
+ return(0);
+}
+
+
+execute(file)
+char *file;
+{
+ register char *p1, *p2;
+ register c;
+ int f, body, lf;
+ char *ebp, *cbp;
+
+ if ((f = open(file, 0)) < 0) {
+ fprintf(stderr, "Grep: Can't open %s\n", file);
+ return(0);
+ }
+ body = 0;
+ ebp = ibuf;
+ cbp = ibuf;
+ for (;;) {
+ p1 = linebuf;
+ p2 = cbp;
+ lf = 0;
+ for (;;) {
+ if (p2 >= ebp) {
+ if ((c = read(f, ibuf, sizeof ibuf)) <= 0) {
+ close(f);
+ if(lf) break; /* bodyless comp! */
+ return(0);
+ }
+ p2 = ibuf;
+ ebp = ibuf+c;
+ }
+ c = *p2++;
+ if(lf) if(c != ' ' && c != '\t') {
+ --p2;
+ break;
+ } else
+ lf = 0;
+ if (c == '\n')
+ if(body)
+ break;
+ else {
+ if(lf) {
+ body++;
+ break;
+ }
+ lf++;
+ c = ' ';
+ }
+ if(c && p1 < &linebuf[LBSIZE-1])
+ *p1++ = c;
+ }
+ *p1++ = 0;
+ cbp = p2;
+ p1 = linebuf;
+ p2 = expbuf;
+ if (circf) {
+ if (advance(p1, p2))
+ goto found;
+ continue;
+ }
+ /* fast check for first character */
+ if (*p2==CCHR) {
+ c = p2[1];
+ do {
+ if(*p1==c || cc[*p1]==c)
+ if (advance(p1, p2))
+ goto found;
+ } while (*p1++);
+ continue;
+ }
+ /* regular algorithm */
+ do {
+ if (advance(p1, p2))
+ goto found;
+ } while (*p1++);
+ continue;
+ found:
+ close(f);
+ return(1);
+ }
+}
+
+
+advance(alp, aep)
+char *alp, *aep;
+{
+ register char *lp, *ep, *curlp;
+
+ lp = alp;
+ ep = aep;
+ for (;;) switch (*ep++) {
+
+ case CCHR:
+ if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
+ continue;
+ return(0);
+
+ case CDOT:
+ if (*lp++)
+ continue;
+ return(0);
+
+ case CDOL:
+ if (*lp==0)
+ continue;
+ return(0);
+
+ case CEOF:
+ return(1);
+
+ case CCL:
+ if (cclass(ep, *lp++, 1)) {
+ ep += *ep;
+ continue;
+ }
+ return(0);
+
+ case NCCL:
+ if (cclass(ep, *lp++, 0)) {
+ ep += *ep;
+ continue;
+ }
+ return(0);
+
+ case CDOT|STAR:
+ curlp = lp;
+ while (*lp++);
+ goto star;
+
+ case CCHR|STAR:
+ curlp = lp;
+ while (*lp++ == *ep || cc[lp[-1]] == *ep) ;
+ ep++;
+ goto star;
+
+ case CCL|STAR:
+ case NCCL|STAR:
+ curlp = lp;
+ while (cclass(ep, *lp++, ep[-1]==(CCL|STAR)));
+ ep += *ep;
+ goto star;
+
+ star:
+ do {
+ lp--;
+ if (advance(lp, ep))
+ return(1);
+ } while (lp > curlp);
+ return(0);
+
+ default:
+ printf("RE botch\n");
+ return(0);
+ }
+}
+
+
+cclass(aset, ac, af)
+char *aset;
+{
+ register char *set, c;
+ register n;
+
+ set = aset;
+ if ((c = ac) == 0)
+ return(0);
+ n = *set++;
+ while (--n)
+ if (*set++ == c)
+ return(af);
+ return(!af);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <strings.h>
+#include <signal.h>
+#include "scansub.h"
+
+extern char *sprintf();
+
+extern struct swit anoyes[]; /* Std no/yes gans array */
+
+char scanl[];
+struct msgs *mp;
+FILE *in, *aud;
+struct stat stbuf;
+char *locknode;
+int lockwait; /* Secs to wait for lock-Def in strings/lockdir.c */
+#define LOCKWAIT (lockwait*5) /* If lock is this old, simply ignore it! */
+
+int timeflag;
+int numflag;
+
+extern int errno; /* MLW 4bsd does not have errno defined in errno.h */
+extern char _sobuf[]; /* MLW standard out buffer */
+
+struct swit switches[] = {
+ "audit audit-file", 0, /* 0 */
+ "ms ms-folder", 0, /* 1 */
+ "help", 4, /* 2 */
+ "changecur", 0, /* 3 */
+ "nochangecur", 0, /* 4 */
+ "time", 0, /* 5 */
+ "notime", 0, /* 6 */
+ "numdate", 0, /* 7 */
+ "nonumdate", 0, /* 8 */
+ 0, 0
+};
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+
+ char *newmail, maildir[128], *folder, *from, *audfile;
+ char *myname;
+ int change_cur;
+ register char *cp;
+ register int i, msgnum;
+ long now;
+ char **ap;
+ char *arguments[50], **argp;
+ int done();
+ long time();
+
+ invo_name = argv[0];
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+
+ change_cur = 1; /* Default */
+ from = 0; folder = 0; audfile = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "inc: -%s unknown\n", cp);
+ goto leave;
+ case 0: if(!(audfile = *argp++)) { /* -audit */
+ missing: fprintf(stderr, "inc: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 1: if(!(from = *argp++)) /* -ms */
+ goto missing;
+ continue;
+ case 2: /* -help */
+ help("inc [+folder] [switches]", switches);
+ goto leave;
+ case 3:
+ change_cur = 1;
+ continue;
+ case 4:
+ change_cur = 0;
+ continue;
+ case 5: timeflag = 1; continue; /* -time */
+ case 6: timeflag = 0; continue; /* -notime */
+ case 7: numflag = 1; continue; /* -numdate */
+ case 8: numflag = 0; continue; /* -nonumdate */
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = path(cp+1, TFOLDER);
+ } else {
+ fprintf(stderr, "Bad arg: %s\n", argp[-1]);
+ fprintf(stderr, "Usage: inc [+folder] [-ms ms-folder] [-audit audit-file]\n");
+ goto leave;
+ }
+ }
+ if(!m_find("path")) free(path("./", TFOLDER));
+ if(from)
+ newmail = from;
+ else {
+ if((myname = getenv("USER")) == 0) {
+ fprintf(stderr,
+"Environment Variable \"USER\" Must be set to your login name!\n");
+ done(1);
+ }
+ newmail = concat(mailboxes, "/", myname, NULLCP);
+/*** VOID copy(mailbox, copy(mypath, newmail)); ***/
+ if(stat(newmail, &stbuf) < 0 ||
+ stbuf.st_size == 0) {
+ fprintf(stderr, "No Mail to incorporate.\n");
+ goto leave;
+ }
+ }
+ if(!folder) {
+ folder = defalt;
+ if(from && strcmp(from, "inbox") == 0) {
+ cp = concat("Do you really want to convert from ",
+ from, " into ", folder, "?? ", NULLCP);
+ if(!gans(cp, anoyes))
+ goto leave;
+ cndfree(cp);
+ }
+ }
+ VOID copy(m_maildir(folder), maildir);
+ if(stat(maildir, &stbuf) < 0) {
+ if(errno != ENOENT) {
+ fprintf(stderr, "Error on folder ");
+ perror(maildir);
+ goto leave;
+ }
+ cp = concat("Create folder \"", maildir, "\"? ", NULLCP);
+ if(!gans(cp, anoyes))
+ goto leave;
+ if(!makedir(maildir)) {
+ fprintf(stderr, "Can't create folder \"%s\"\n", maildir);
+ goto leave;
+ }
+ }
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ /* Lock the mail file */
+ if(!from) {
+ VOID signal(SIGINT, done);
+ cp = concat(lockdir, "/", myname, NULLCP);
+ for(i = 0; i < lockwait; i += 2) {
+ if(link(newmail, cp) == -1) {
+ fprintf(stderr, "Mailbox busy...\n");
+ if(i == 0 && stat(newmail, &stbuf) >= 0)
+ if(stbuf.st_ctime + LOCKWAIT < time((long *)0)) {
+ VOID unlink(cp);
+ fprintf(stderr, "Removing lock.\n");
+ continue;
+ }
+ sleep(2);
+ } else {
+ locknode = cp; /* We own the lock now! */
+ break;
+ }
+ }
+ if(i >= lockwait) {
+ fprintf(stderr, "Try again.\n");
+ done(1);
+ }
+ }
+ if((in = fopen(newmail, "r")) == NULL) {
+ fprintf(stderr, "Can't open "); perror(newmail);
+ goto leave;
+ }
+ if(audfile) {
+ cp = m_maildir(audfile);
+ if((i = stat(cp, &stbuf)) < 0)
+ fprintf(stderr, "Creating Receive-Audit: %s\n", cp);
+ if((aud = fopen(cp, "a")) == NULL) {
+ fprintf(stderr, "Can't append to ");
+ perror(cp);
+ goto leave;
+ } else if(i < 0)
+ VOID chmod(cp, 0600);
+ now = time((long *)0);
+ fputs("<<inc>> ", aud);
+ cp = cdate(&now);
+ cp[9] = ' ';
+ fputs(cp, aud);
+ if(from) {
+ fputs(" -ms ", aud);
+ fputs(from, aud);
+ }
+ putc('\n', aud);
+ }
+ printf("Incorporating new mail into %s...\n\n", folder);
+ VOID fflush(stdout);
+ msgnum = mp->hghmsg;
+
+ while((i = scan(in, msgnum+1, msgnum+1, msgnum == mp->hghmsg,
+ (timeflag ? DOTIME : 0)
+ | (numflag ? NUMDATE : 0), 0))) {
+ if(i == -1) {
+ fprintf(stderr, "inc aborted!\n");
+ if(aud)
+ fputs("inc aborted!\n", aud);
+ goto leave;
+ }
+ if(i == -2) {
+ fprintf(stderr,
+ "More than %d messages. Inc aborted!\n",
+ MAXFOLDER);
+ fprintf(stderr,"%s not zero'd\n", newmail);
+ goto leave;
+ }
+ if(aud)
+ fputs(scanl, aud);
+ VOID fflush(stdout);
+ msgnum++;
+ }
+
+ VOID fclose(in);
+ if(aud)
+ VOID fclose(aud);
+
+ if(!from) {
+ if((i = creat(newmail, 0600)) >= 0) /* Zap .mail file */
+ VOID close(i);
+ else
+ fprintf(stderr, "Error zeroing %s\n", newmail);
+ } else
+ printf("%s not zero'd\n", newmail);
+
+ i = msgnum - mp->hghmsg;
+ /* printf("%d new message%s\n", i, i==1? "":"s"); */
+ if(!i)
+ fprintf(stderr, "[No messages incorporated.]\n");
+ else {
+ m_replace(pfolder, folder);
+ if (change_cur)
+ m_setcur(mp->hghmsg + 1);
+ }
+leave:
+ m_update();
+ done(0);
+}
+
+
+done(status)
+{
+ if(locknode);
+ VOID unlink(locknode);
+ exit(sta
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+extern struct swit anoyes[]; /* Std no/yes gans array */
+char *malloc();
+
+char defpath[128];
+
+extern char _sobuf[]; /* MLW standard out buffer */
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp, *path;
+ register struct node *np;
+ int autof, exitstat;
+ struct stat stbuf;
+ char *geta();
+
+ invo_name = argv[0];
+ setbuf(stdout, _sobuf);
+ autof = (argc == 2 && strcmp(argv[1], "-auto") == 0);
+ exitstat = 1; /* Assume errors will occur */
+ mypath = getenv("HOME");
+/*** mypath = getpath(getruid()); /* to prevent recursion via m_getdefs */
+ VOID copy(mh_prof, copy(mypath, defpath));
+ if(stat(defpath, &stbuf) != -1) {
+ if(autof)
+ printf("Install-defs invocation error!\n");
+ else
+ printf("You already have an MH profile... use an editor \
+to modify it.\n");
+ goto leave;
+
+ }
+ if(autof || gans("Do you want help? ", anoyes)) {
+printf("\nPrior to using MH, it is necessary to have a file in your login\n");
+printf("directory (%s) named %s which contains information\n",mypath,mh_prof+1);
+printf("to direct certain MH operations. The only item which is required\n");
+printf("is the path to use for all MH folder operations. The suggested MH\n");
+printf("path for you is %s/Mail...\n\n", mypath);
+ }
+ cp = concat(mypath, "/", "Mail", NULLCP);
+ if(stat(cp, &stbuf) != -1) {
+ if((stbuf.st_mode&S_IFMT) == S_IFDIR) {
+ cp = concat("You already have the standard MH directory \"",
+ cp, "\".\nDo you want to use it for MH? ", NULLCP);
+ if(gans(cp, anoyes))
+ path = "Mail";
+ else
+ goto xyz;
+ }
+ } else {
+ cp = concat("Do you want the standard MH path \"", mypath,
+ "/", "Mail\"? ", NULLCP);
+ if(gans(cp, anoyes))
+ path = "Mail";
+ else {
+ xyz: if(gans("Do you want a path below your login directory? ",
+ anoyes)) {
+ printf("What is the path ?? %s/", mypath);
+ path = geta();
+ } else {
+ printf("What is the whole path?? /");
+ path = concat("/", geta(), NULLCP);
+ }
+ }
+ }
+ VOID chdir(mypath);
+ if(chdir(path) == -1) {
+ cp = concat("\"", path, "\" doesn't exist; Create it? ", NULLCP);
+ if(gans(cp, anoyes))
+ if(makedir(path) == 0) {
+ printf("Can't create it!\n");
+ goto leave;
+ }
+ } else
+ printf("[Using existing directory]\n");
+
+ np = m_defs = (struct node *) malloc(sizeof *np);
+ np->n_name = "Path";
+ np->n_field = path;
+ np->n_next = 0;
+ m_replace(pfolder, defalt);
+ exitstat = 0;
+
+leave:
+ m_update();
+ done(exitstat);
+}
+
+
+char *geta()
+{
+ static char line[128];
+ register char *cp;
+ register int c;
+
+ VOID fflush(stdout);
+ cp = line;
+ while((c = getchar()) != EOF) {
+ if(c == '\n') {
+ *cp = 0;
+ return(line);
+ }
+ if(cp < &line[128])
+ *cp++ = c;
+ }
+ done(1);
+ /*NOTREACHED*/
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <signal.h>
+
+extern char *sprintf();
+
+#define NUMTOS 10 /* Number of to's & cc's accepted */
+
+char tmpfil[32];
+int exitstat = 1;
+char *subject, *body;
+
+struct swit switches[] = {
+ "body", 0, /* 0 */
+ "cc", 0, /* 1 */
+ "subject", 0, /* 2 */
+ "help", 4, /* 3 */
+ 0, 0
+};
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ register FILE *out;
+ register int i, cnt;
+ register char *cp;
+ int pid, status, top, ccp, sig(), somebody = 0;
+ char buf[BUFSIZ], *tos[NUMTOS], *ccs[NUMTOS], **argp;
+
+ invo_name = argv[0];
+ top = 0;
+ ccp = -1; /* -1 -> collecting TOs */
+ if(argc == 1) { /* Just call inc to read mail */
+ execlp("inc", "inc", 0);
+ perror("Mail: inc");
+ done(exitstat);
+ }
+ argp = argv + 1;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ done(exitstat);
+ /* unknown */
+ case -1:fprintf(stderr, "send: -%s unknown\n", cp);
+ done(exitstat);
+ /* -body */
+ case 0: if((body = *argp++) == 0) {
+ missing: fprintf(stderr, "Mail: Missing %s arg\n", cp);
+ done(exitstat);
+ }
+ continue;
+ /* -cc */
+ case 1: ccp = 0; /* Now collecting ccs */
+ continue;
+ /* -subject */
+ case 2: if((subject = *argp++) == 0)
+ goto missing;
+ continue;
+ /* -help */
+ case 3: help("mail [switches] users ...",
+ switches);
+ done(0);
+ }
+ else {
+ if(ccp >= 0) { /* If getting ccs..*/
+ if(ccp < NUMTOS)
+ ccs[ccp++] = cp;
+ else {
+ fprintf(stderr, "Mail: Too many ccs\n");
+ done(exitstat);
+ }
+ } else { /* Else, to */
+ if(top < NUMTOS)
+ tos[top++] = cp;
+ else {
+ fprintf(stderr, "Mail: Too many tos\n");
+ done(exitstat);
+ }
+ }
+ }
+ }
+ /* Create a mail temp file */
+ VOID sprintf(tmpfil, "/tmp/%s", makename("mail", ".tmp"));
+ if((out = fopen(tmpfil, "w")) == NULL) {
+ perror(tmpfil);
+ done(exitstat);
+ }
+ VOID signal(SIGINT, sig); /* Clean up if user <del>s out */
+ fprintf(out, "To: "); /* Create to list */
+ for(i = 0; i < top;) {
+ fprintf(out, "%s", tos[i]);
+ if(++i < top)
+ fprintf(out, ", ");
+ }
+ fprintf(out, "\n");
+ if(ccp > 0) {
+ fprintf(out, "Cc: "); /* Create cc list if needed */
+ for(i = 0; i < ccp;) {
+ fprintf(out, "%s", ccs[i]);
+ if(++i < ccp)
+ fprintf(out, ", ");
+ }
+ fprintf(out, "\n");
+ }
+ if(subject) /* Create subject if needed */
+ fprintf(out, "Subject: %s\n", subject);
+
+ fprintf(out, "\n");
+
+ if(body) { /* Use body if I have it, */
+ somebody++;
+ fprintf(out, "%s\n", body);
+ } else { /* Otherwise, get a body */
+ while((cnt = read(0, buf, sizeof buf)) > 0) {
+ somebody++;
+ if(!fwrite(buf, cnt, 1, out)) {
+ perror(tmpfil);
+ sig();
+ }
+ }
+ }
+
+ if(ferror(out)) { /* Check that all wrote well */
+ fprintf(stderr, "Error writing tmp file\n");
+ sig();
+ }
+ VOID fclose(out);
+ if(!somebody) /* If NO body, then don't send */
+ sig(); /* To be compatible with BELL mail */
+ while((i = fork()) == -1) { /* Now, deliver the mail */
+ fprintf(stderr, "Waiting for a fork...\n");
+ sleep(2);
+ }
+ if(i == 0) { /* Call deliverer in child */
+ execl(mh_deliver, r1bindex(mh_deliver, '/'), tmpfil, 0);
+ perror(mh_deliver);
+ done(exitstat);
+ }
+ VOID signal(SIGINT, SIG_IGN);
+ while((pid = wait(&status)) != -1 && pid != i) ;
+ if(status) { /* And save mail if delivery failed */
+ VOID signal(SIGINT, SIG_DFL);
+ fprintf(stderr, "Letter saved in dead.letter\n");
+ execl("/bin/mv", "mv", tmpfil, "dead.letter", 0);
+ execl("/usr/bin/mv", "mv", tmpfil, "dead.letter", 0);
+ perror("/bin/mv");
+ done(exitstat);
+ }
+ exitstat = 0;
+ sig();
+}
+
+sig()
+{
+ VOID unlink(tmpfil);
+ done(exitstat);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* THIS command is included wholesale by show.c, which calls
+ * its `main' rather than execing it when showproc is "mhl"
+ */
+
+#include <ctype.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sgtty.h>
+#ifndef INCLUDED_BY_SHOW
+#include <stdio.h>
+#include "../mh.h"
+#endif INCLUDED_BY_SHOW
+char *calloc();
+extern char *index();
+extern char *sprintf();
+
+char *ignores[25];
+char **igp = ignores; /* List of ignored components */
+char *parptr, *parse();
+char *fmtfile; /* User specified format file */
+char *folder; /* Name of folder messages are in */
+char *profargs[32]; /* Args extracted from profile */
+int ofilec; /* Count of real output file args */
+int ofilen; /* Number of output file */
+int ontty; /* Output to char device */
+int clearflg; /* Overrides format screen clear */
+int row, column; /* For character output routine */
+int alength, awidth; /* -length and -width args */
+char *oneline();
+int sigcatch();
+int exitstat;
+jmp_buf env;
+
+extern char _sobuf[]; /* MLW standard out buffer */
+char *strcpy();
+
+/* Defines for c_flags (see below) */
+#define NOCOMPONENT 01 /* Don't show component name */
+#define UPPERCASE 02 /* Display in all upper case */
+#define CENTER 04 /* Center line within width */
+#define CLEARTEXT 010 /* Clear text line--simply copy to output */
+#define PROCESSED 020 /* This item processed already */
+#define EXTRA 040 /* This message comp is an "extra" */
+#define HDROUTPUT 0100 /* This comp's hdr has been output */
+#define CLEARSCR 0200 /* Clear screen before each file */
+#define LEFTADJUST 0400 /* Left adjust mult lines of component */
+#define COMPRESS 01000 /* Compress text--ignore <lf's> */
+
+struct comp {
+ struct comp *c_next; /* Chain to next */
+ char *c_name, /* Component name */
+ *c_text, /* Text associated with component */
+ *c_ovtxt; /* Line overflow indicator text */
+ int c_offset, /* Left margin indent */
+ c_ovoff, /* Line overflow indent */
+ c_width, /* Width of field */
+ c_cwidth, /* Component width (default strlen(comp)) */
+ c_length; /* Length in lines */
+ short c_flags; /* Special flags (see above) */
+
+} *msghd, *msgtl, *fmthd, *fmttl,
+ /* Global contains global len/wid info */
+ global = { NULL, NULL, NULL, "", 0, 0, 80, 0, 40, 0 },
+ holder = { NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, NOCOMPONENT };
+
+/* Defines for putcomp subrutine mode arg */
+#define ONECOMP 0 /* Display only control comp name */
+#define BOTHCOMP 1 /* Display both comp names (conditionally) */
+
+/*ARGSUSED*/
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct comp *comp;
+ register char *cp, **ap;
+ FILE *fp;
+ char line[256], name[64];
+ int out();
+
+ invo_name = argv[0];
+ setbuf(stdout, _sobuf);
+ VOID signal(SIGQUIT, out);
+ ontty = gtty(1, (struct sgttyb *)name) != -1;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(getcpy(cp), " ", "\n");
+ VOID copyip(ap, profargs);
+/* procargs(ap);*/
+ procargs(profargs);
+ }
+ procargs(argv + 1);
+ if(!folder)
+ folder = getenv("mhfolder");
+ if(fmtfile) {
+ if((fp = fopen(m_maildir(fmtfile), "r")) == NULL) {
+ fprintf(stderr, "mhl: Can't open format file: %s\n",
+ fmtfile);
+ done(1);
+ }
+ } else if((fp = fopen(m_maildir(mhlformat), "r")) == NULL &&
+ (fp = fopen(mhlstdfmt, "r")) == NULL) {
+ fprintf(stderr, "mhl: Can't open default format file.\n");
+ done(1);
+ }
+ while(fgets(line, sizeof line, fp)) {
+ if(line[0] == ';') /* Comment line */
+ continue;
+
+ line[strlen(line)-1] = 0; /* Zap the <lf> */
+
+ if(line[0] == ':') { /* Clear text line */
+ comp = (struct comp *) calloc(1, sizeof (struct comp));
+ comp->c_text = getcpy(line+1);
+ comp->c_flags = CLEARTEXT;
+ comp->c_ovoff = -1;
+ comp->c_cwidth = -1;
+ goto fmtqueue;
+ }
+
+ parptr = line;
+ strcpy(name, parse());
+/*** printf("%s %c %s\n", name, *parptr, parptr+1); */
+ switch(*parptr) {
+
+ case '\0':
+ case ',':
+ case '=':
+ if(uleq(name, "ignores")) {
+ igp = copyip(brkstring(getcpy(++parptr), ",", NULLCP), igp);
+ continue;
+ }
+ parptr = line;
+ while(*parptr) {
+ if(evalvar(&global)) {
+ fmterr: fprintf(stderr, "mhl: format file syntax error: %s\n",
+ line);
+ done(1);
+ }
+ if(*parptr)
+ parptr++;
+ }
+ continue;
+
+ case ':':
+ comp = (struct comp *) calloc(1, sizeof (struct comp));
+ comp->c_name = getcpy(name);
+ comp->c_cwidth = -1;
+ comp->c_ovoff = -1;
+ while(*parptr == ':' || *parptr == ',') {
+ parptr++;
+ if(evalvar(comp))
+ goto fmterr;
+ }
+ fmtqueue: if(!fmthd)
+ fmthd = fmttl = comp;
+ else {
+ fmttl->c_next = comp;
+ fmttl = comp;
+ }
+ continue;
+
+ default:
+ goto fmterr;
+
+ }
+ }
+ if(clearflg == 1)
+ global.c_flags |= CLEARSCR;
+ else if(clearflg == -1)
+ global.c_flags &= ~CLEARSCR;
+ if(awidth) global.c_width = awidth;
+ if(alength) global.c_length = alength;
+ if(global.c_width < 5) global.c_width = 10000;
+ if(global.c_length < 5) global.c_length = 10000;
+ VOID fclose(fp);
+ if(!ofilec)
+ process(NULLCP);
+ else {
+ for(ap = profargs; *ap; ap++)
+ if(**ap)
+ process(*ap);
+ for(ap = argv+1; *ap; ap++)
+ if(**ap)
+ process(*ap);
+ }
+ done(exitstat);
+}
+
+
+evalvar(sp)
+ register struct comp *sp;
+{
+ register char *cp;
+ int c;
+ char name[32];
+
+ if(!*parptr)
+ return 0;
+ strcpy(name, parse());
+/***printf("evalvar: %s %c %s\n", name, *parptr, parptr+1); */
+ if(uleq(name, "width")) {
+ if(!*parptr++ == '=' || !*(cp = parse())) {
+missing: fprintf(stderr, "mhl: missing arg to variable %s\n",
+ name);
+ return 1;
+ }
+ sp->c_width = atoi(cp);
+ return 0;
+ }
+ if(uleq(name, "compwidth")) {
+ if(!*parptr++ == '=' || !*(cp = parse())) goto missing;
+ sp->c_cwidth = atoi(cp);
+ return 0;
+ }
+ if(uleq(name, "length")) {
+ if(!*parptr++ == '=' || !*(cp = parse())) goto missing;
+ sp->c_length = atoi(cp);
+ return 0;
+ }
+ if(uleq(name, "overflowtext")) {
+ if(!*parptr++ == '=') goto missing;
+ cp = parptr;
+ while(*parptr && *parptr != ':' && *parptr != ',') parptr++;
+ c = *parptr;
+ *parptr = 0;
+ sp->c_ovtxt = getcpy(cp);
+ *parptr = c;
+ return 0;
+ }
+ if(uleq(name, "offset")) {
+ if(!*parptr++ == '=' || !*(cp = parse())) goto missing;
+ sp->c_offset = atoi(cp);
+ return 0;
+ }
+ if(uleq(name, "overflowoffset")) {
+ if(!*parptr++ == '=' || !*(cp = parse())) goto missing;
+ sp->c_ovoff = atoi(cp);
+ return 0;
+ }
+ if(uleq(name, "nocomponent")) {
+ sp->c_flags |= NOCOMPONENT;
+ return 0;
+ }
+ if(uleq(name, "uppercase")) {
+ sp->c_flags |= UPPERCASE;
+ return 0;
+ }
+ if(uleq(name, "center")) {
+ sp->c_flags |= CENTER;
+ return 0;
+ }
+ if(uleq(name, "clearscreen")) {
+ sp->c_flags |= CLEARSCR;
+ return 0;
+ }
+ if(uleq(name, "leftadjust")) {
+ sp->c_flags |= LEFTADJUST;
+ return 0;
+ }
+ if(uleq(name, "compress")) {
+ sp->c_flags |= COMPRESS;
+ return 0;
+ }
+ return 1;
+}
+
+
+char *
+parse()
+{
+ static char result[64];
+ register char *cp;
+ register int c;
+
+ cp = result;
+ while(c = *parptr)
+ if(isalnum(c) || c == '.' || c == '-' || c == '_') {
+ *cp++ = c;
+ parptr++;
+ } else
+ break;
+ *cp = 0;
+ return result;
+}
+
+struct swit switches[] = {
+ "clear", 0, /* 0 */
+ "noclear", 0, /* 1 */
+ "folder folder", 0, /* 2 */
+ "form formfile", 0, /* 3 */
+ "length of page", 0, /* 4 */
+ "width of line", 0, /* 5 */
+ "help", 4, /* 6 */
+ 0, 0
+};
+
+procargs(ap)
+ register char **ap;
+{
+ register char *cp;
+
+ while(cp = *ap++)
+ if(*cp == '-') switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ done(1);
+ /* unknown */
+ case -1:fprintf(stderr, "mhl: -%s unknown\n", cp);
+ done(1);
+ /* -form format */
+ case 0: clearflg = 1; /* -clear */
+ ap[-1] = "";
+ break;
+
+ case 1: clearflg = -1; /* -noclear */
+ ap[-1] = "";
+ break;
+
+ case 2: if(!(folder = *ap++) || *folder == '-') {
+ missing: fprintf(stderr, "mhl: Missing arg for %s\n", ap[-2]);
+ done(1);
+ }
+ ap[-2] = ""; ap[-1] = "";
+ break;
+
+ case 3: if(!(fmtfile = *ap++) || *fmtfile == '-')
+ goto missing;
+ ap[-2] = ""; ap[-1] = "";
+ break;
+ /* length */
+ case 4: if(!(cp = *ap++) || *cp == '-')
+ goto missing;
+ alength = atoi(cp);
+ ap[-2] = ""; ap[-1] = "";
+ break;
+ /* width */
+ case 5: if(!(cp = *ap++) || *cp == '-')
+ goto missing;
+ awidth = atoi(cp);
+ ap[-2] = ""; ap[-1] = "";
+ break;
+ /* -help */
+ case 6: help("mhl [switches] [files]", switches);
+ done(0);
+
+ } else
+ ofilec++;
+}
+
+FILE *fp;
+
+process(fname)
+ char *fname;
+{
+ register int state;
+ register struct comp *comp, *c2, *c3;
+ char *cp, **ip, name[NAMESZ], buf[BUFSIZ];
+
+ if(setjmp(env)) {
+ discard(stdout);
+ putchar('\n');
+ goto out;
+ }
+ VOID signal(SIGINT, sigcatch);
+ if(fname) {
+ if((fp = fopen(fname, "r")) == NULL) {
+ fprintf(stderr, "mhl: Can't open ");
+ perror(fname);
+ exitstat++;
+ VOID signal(SIGINT, SIG_IGN);
+ return;
+ }
+ } else
+ fp = stdin;
+ if(ontty) {
+ strcpy(buf, "\n");
+ if(ofilec > 1) {
+ if(ofilen)
+ printf("\n\n\n");
+ printf("Press <return> to list \"");
+ if(folder) printf("%s:", folder);
+ printf("%s\"...", fname);
+ VOID fflush(stdout);
+ strcpy(buf, "");
+ VOID read(1, buf, sizeof buf);
+ }
+ if(index(buf, '\n')) {
+ if(global.c_flags & CLEARSCR)
+ printf("\014\200");
+ } else
+ printf("\n");
+ } else if(ofilec > 1) {
+ if(ofilen)
+ printf("\n\n\n");
+ printf(">>> ");
+ if(folder) printf("%s: ", folder);
+ printf("%s\n\n", fname);
+ }
+
+ ofilen++;
+ row = column = 0;
+ msghd = 0;
+ for(state = FLD ; ;) {
+ state = m_getfld(state, name, buf, sizeof buf, fp);
+ switch(state) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ for(ip = ignores; *ip; ip++)
+ if(uleq(name, *ip)) {
+ while(state == FLDPLUS)
+ state = m_getfld(state, name, buf, sizeof buf, fp);
+ goto next;
+ }
+ for(c3 = msghd; c3; c3 = c3->c_next)
+ if(uleq(name, c3->c_name))
+ break;
+ if(c3) {
+ comp = c3;
+ comp->c_text = add(buf, comp->c_text);
+ } else {
+ comp = (struct comp *) calloc(1, sizeof (struct comp));
+ comp->c_name = getcpy(name);
+ comp->c_text = getcpy(buf);
+ comp->c_cwidth = -1;
+ comp->c_ovoff = -1;
+ }
+ while(state == FLDPLUS) {
+ state = m_getfld(state, name, buf, sizeof buf, fp);
+ comp->c_text = add(buf, comp->c_text);
+ }
+ for(c2 = fmthd; c2; c2 = c2->c_next)
+ if(uleq(c2->c_name, comp->c_name))
+ goto goodun;
+ comp->c_flags |= EXTRA;
+ goodun: if(!c3) {
+ if(!msghd)
+ msghd = msgtl = comp;
+ else {
+ msgtl->c_next = comp;
+ msgtl = comp;
+ }
+ }
+ if(state == FLDEOF)
+ goto doit;
+ continue;
+
+ default:
+ case LENERR:
+ case FMTERR:
+ fprintf(stderr, "Message format error!\n");
+ exitstat++;
+ return;
+
+ case BODY:
+ case BODYEOF:
+ case FILEEOF:
+ doit:
+ for(comp = fmthd; comp; comp = comp->c_next) {
+ if(comp->c_flags & CLEARTEXT) {
+ putcomp(comp, comp, ONECOMP);
+ continue;
+ }
+ if(uleq(comp->c_name, "messagename")) {
+ cp = concat(fname, "\n", NULLCP);
+ if(folder) {
+ holder.c_text = concat(folder, ":", cp, NULLCP);
+ free(cp);
+ } else
+ holder.c_text = cp;
+ putcomp(comp, &holder, ONECOMP);
+ free(holder.c_text);
+ holder.c_text = 0;
+ }
+ if(uleq(comp->c_name, "extras")) {
+ for(c2 = msghd; c2; c2 = c2->c_next)
+ if(c2->c_flags & EXTRA)
+ putcomp(comp, c2, BOTHCOMP);
+ continue;
+ }
+ if(uleq(comp->c_name, "body")) {
+ holder.c_text = buf;
+ putcomp(comp, &holder, ONECOMP);
+ holder.c_text = 0;
+ while(state == BODY) {
+ state = m_getfld(state, name, buf, sizeof buf, fp);
+ holder.c_text = buf;
+ putcomp(comp, &holder, ONECOMP);
+ holder.c_text = 0;
+ }
+ continue;
+ }
+ for(c2 = msghd; c2; c2 = c2->c_next)
+ if(uleq(c2->c_name, comp->c_name)) {
+ putcomp(comp, c2, ONECOMP);
+ break;
+ }
+ }
+ out:
+ if(fp)
+ VOID fclose(fp);
+ fp = NULL;
+ if(holder.c_text) cndfree(holder.c_text);
+ holder.c_text = 0;
+ for(c2 = msghd; c2; c2 = comp) {
+ comp = c2->c_next;
+ cndfree(c2->c_name);
+ cndfree(c2->c_text);
+ free( (char *)c2);
+ }
+ msghd = msgtl = NULL;
+ for(c2 = fmthd; c2; c2 = c2->c_next)
+ c2->c_flags &= ~HDROUTPUT;
+ VOID signal(SIGINT, SIG_IGN);
+ return;
+ }
+next: ;
+ }
+}
+
+int lm; /* Left Margin for putstr */
+int llim; /* line limit for this component */
+int wid; /* width limit for this comp */
+int ovoff; /* overflow offset for this comp */
+char *ovtxt; /* overflow text for this comp */
+int term; /* term from last oneline() */
+char *onelp; /* oneline() text pointer */
+
+putcomp(cc, c2, flag)
+ register struct comp *cc, *c2;
+ int flag;
+{
+ register char *cp;
+ int count, cchdr = 0;
+
+#ifdef DEBUGCOMP
+ printf("%s(%o):%s:%s", cc->c_name, cc->c_flags, c2->c_name,
+ c2->c_text);
+#endif
+ onelp = NULL;
+ lm = 0;
+ llim = cc->c_length? cc->c_length : -1;
+ wid = cc->c_width? cc->c_width : global.c_width;
+ ovoff = cc->c_ovoff >= 0 ? cc->c_ovoff : global.c_ovoff;
+ ovoff += cc->c_offset;
+ ovtxt = cc->c_ovtxt ? cc->c_ovtxt : global.c_ovtxt;
+ if(!ovtxt) ovtxt = "";
+ if(wid < ovoff + strlen(ovtxt) + 5) {
+ fprintf(stderr, "mhl: component: %s width too small for overflow.\n",
+ cc->c_name);
+ done(1);
+ }
+ if(cc->c_flags & CLEARTEXT) {
+ putstr(cc->c_text);
+ putstr("\n");
+ return;
+ }
+ if(cc->c_flags & CENTER) {
+ count = global.c_width;
+ if(cc->c_width) count = cc->c_width;
+ count -= cc->c_offset;
+ count -= strlen(c2->c_text);
+ if(!(cc->c_flags&HDROUTPUT) && !(cc->c_flags&NOCOMPONENT))
+ count -= strlen(cc->c_name) + 2;
+ lm = cc->c_offset+(count/2);
+ } else if(cc->c_offset)
+ lm = cc->c_offset;
+ if(!(cc->c_flags & HDROUTPUT) && !(cc->c_flags & NOCOMPONENT)) {
+ putstr(cc->c_name); putstr(": ");
+ cc->c_flags |= HDROUTPUT;
+ cchdr++;
+ if((count = cc->c_cwidth - strlen(cc->c_name) - 2) > 0)
+ while(count--) putstr(" ");
+ }
+ if(flag == BOTHCOMP && !(c2->c_flags & HDROUTPUT) &&
+ !(c2->c_flags & NOCOMPONENT)) {
+ putstr(c2->c_name); putstr(": ");
+ c2->c_flags |= HDROUTPUT;
+ }
+ if(cc->c_flags & UPPERCASE)
+ for(cp = c2->c_text; *cp; cp++)
+ if(islower(*cp))
+ *cp -= 'a' - 'A';
+ count = 0;
+ if(cchdr)
+ count = (cc->c_cwidth>=0) ? cc->c_cwidth : strlen(cc->c_name)+2;
+ count += cc->c_offset;
+ putstr(oneline(c2->c_text, cc->c_flags));
+/*** if(cc->c_flags & COMPRESS) printf("-1-"); /***/
+ if(term == '\n')
+ putstr("\n");
+ while(cp = oneline(c2->c_text, cc->c_flags)) {
+/*** if(cc->c_flags & COMPRESS) printf("-2-"); /***/
+ if(*cp) {
+ lm = count;
+ putstr(cp);
+ if(term == '\n')
+ putstr("\n");
+ } else
+ if(term == '\n')
+ putstr("\n");
+ }
+ c2->c_flags |= PROCESSED;
+}
+
+putstr(string)
+ register char *string;
+{
+ if(!column && lm > 0)
+ while(lm > 0)
+ if(lm >= 8) {
+ putch('\t');
+ lm -= 8;
+ } else {
+ putch(' ');
+ lm--;
+ }
+ lm = 0;
+ while(*string)
+ putch(*string++);
+}
+
+putch(ch)
+{
+ char buf[32];
+
+ if(llim == 0)
+ return;
+ switch(ch) {
+ case '\n':
+ if(llim > 0) llim--;
+ column = 0;
+ row++;
+ if(ontty && row == global.c_length) {
+ putchar('\007');
+ VOID fflush(stdout);
+ buf[0] = 0;
+ VOID read(1, buf, sizeof buf);
+ if(index(buf, '\n')) {
+ if(global.c_flags & CLEARSCR) {
+ putchar('\014');
+ putchar('\200');
+ }
+ row = 0;
+ } else {
+ putchar('\n');
+ row = global.c_length / 3;
+ }
+ return;
+ }
+ break;
+ case '\t':
+ column |= 07;
+ column++;
+ break;
+
+ case '\010':
+ column--;
+ break;
+
+ case '\r':
+ column = 0;
+ break;
+
+ default:
+ if(ch >= ' ')
+ column++;
+ }
+ if(column >= wid) {
+ putch('\n');
+ if(ovoff > 0)
+ lm = ovoff;
+ if(ovtxt)
+ putstr(ovtxt);
+ else
+ putstr("");
+ putch(ch);
+ return;
+ }
+ putchar(ch);
+}
+
+
+char *
+oneline(stuff, flgs)
+ char *stuff;
+{
+ register char *ret;
+ register char *cp;
+ int spc;
+
+ if(!onelp)
+ onelp = stuff;
+ if(!*onelp) {
+ onelp = 0;
+ return NULL;
+ }
+ ret = onelp;
+ term = 0;
+ if(flgs & COMPRESS) {
+ cp = ret;
+ spc = 0;
+ while(*onelp) {
+ if(*onelp == '\n' || *onelp == '\t' || *onelp == ' '){
+ if(*onelp == '\n' && !onelp[1]) {
+ term = '\n';
+ break;
+ } else if(!spc) {
+ *cp++ = ' ';
+ spc++;
+ }
+ } else {
+ *cp++ = *onelp;
+ spc = 0;
+ }
+ onelp++;
+ }
+ *onelp = 0;
+ *cp = 0;
+ } else {
+ while(*onelp && *onelp != '\n') onelp++;
+ if(*onelp == '\n') {
+ term = '\n';
+ *onelp++ = 0;
+ }
+ if(flgs&LEFTADJUST)
+ while(*ret == ' ' || *ret == '\t') ret++;
+ }
+ return ret;
+}
+
+
+sigcatch()
+{
+ longjmp(env, 1);
+}
+
+
+out()
+{
+ putchar('\n');
+ VOID fflush(stdout);
+ exit(-1);
+}
+
+discard(io)
+register FILE *io;
+{
+ struct sgttyb sg;
+
+ if (ioctl(fileno (io), TIOCGETP, &sg) >= 0)
+ ioctl(fileno (io), TIOCSETP, &sg);
+ io->_cnt = BUFSIZ;
+ io->_ptr
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <strings.h>
+
+
+struct msgs *mp;
+extern char _sobuf[];
+
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "help", 4, /* 1 */
+ 0, 0
+};
+
+/*ARGSUSED*/
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *cp;
+ char *mhnam();
+
+ if(!(cp = mhnam(&argv[1])))
+ done(1);
+ printf("%s\n", cp); /* Expanded message list */
+ done(0);
+}
+
+char *
+mhnam(args)
+ char **args;
+{
+ int j;
+ static char *string;
+ char buf[100];
+ char *folder, *maildir, *msgs[100];
+ register int msgnum;
+ register char *cp;
+ int msgp;
+ char *arguments[50], **argp;
+
+ setbuf(stdout, _sobuf);
+
+ folder = (char *) 0;
+ msgp = 0;
+ VOID copyip(args, arguments);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ return(0);
+ /* unknown */
+ case -1:fprintf(stderr, "mhnam: -%s unknown\n", cp);
+ return(0);
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ return(0);
+ case 1: help("mhnam [+folder] [msgs] [switches]", switches);
+ return(0);
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ return(0);
+ } else
+ folder = path(cp+1, TFOLDER);
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!m_find("path")) free(path("./", TFOLDER));
+
+ /* Mhpath defaults to the folder name */
+ /*** if(!msgp)
+ *** msgs[msgp++] = "cur";
+ ***/
+
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+
+
+ if(!msgp)
+ return(maildir);
+
+
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ return(0);
+ }
+
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ return(0);
+ }
+ /* Need to accomodate MAXFOLDER messages instead of mp->hghmsg */
+ if( (char *) (mp = (struct msgs *)
+ realloc((char *) mp, (unsigned)(sizeof *mp + MAXFOLDER + 1 + 2)))
+ == (char *) 0)
+ return(0);
+
+ /* Clear the newly allocated space */
+ for(j = mp->hghmsg + 1; j <= MAXFOLDER; j++)
+ mp->msgstats[j] = 0;
+
+ /* Mhpath permits empty folders */
+ /*** if(mp->hghmsg == 0) {
+ *** fprintf(stderr, "No messages in \"%s\".\n", folder);
+ *** return(0);
+ *** }
+ ***/
+
+ if(msgp)
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!convert(msgs[msgnum]))
+ return(0);
+ if(mp->numsel == 0) {
+ fprintf(stderr, "mhnam: Never get here. \n");
+ return(0);
+ }
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "mhnam: more than %d messages \n", MAXARGS-2);
+ return(0);
+ }
+
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ {
+ VOID sprintf(buf,"%s%c%s", maildir,'/', m_name(msgnum));
+
+ if(string)
+ string = add("\n", string);
+ string = add(buf, string);
+ /*** printf("buf %s string %s\n",buf,string); ***/
+ }
+ return(string);
+}
+
+
+#include <ctype.h>
+
+int convdir;
+char *delimp;
+
+#define FIRST 1 /***/
+#define LAST 2 /***/
+
+convert(name) /*** Slightly hacked version of ../subs/m_convert.c */
+char *name;
+{
+ register char *cp;
+ register int first, last;
+ int found, range, err;
+ char *bp;
+
+ found = 0;
+
+
+ if(strcmp((cp = name), "new") == 0) /***/
+ {
+ if((err = first = getnew(cp)) <= 0)
+ goto badbad;
+ goto single;
+ }
+ if(strcmp((cp = name), "all") == 0)
+ cp = "first-last";
+ if((err = first = conv(cp, FIRST)) <= 0) /***/
+ goto badbad;
+ if(*(cp = delimp) && *cp != '-' && *cp != ':') {
+ baddel: fprintf(stderr, "Illegal argument delimiter: \"%c\"\n", *delimp);
+ return(0);
+ }
+ if(*cp == '-') {
+ cp++;
+ if((err = last = conv(cp, LAST)) <= 0) { /***/
+ badbad: if(err == -1)
+ fprintf(stderr, "No %s message\n", cp);
+ else if (err == -2) /***/
+ fprintf(stderr,
+ "Message %s out of range 1-%d\n",
+ cp,MAXFOLDER);
+ else
+ badlist: fprintf(stderr, "Bad message list \"%s\".\n",
+ name);
+ return(0);
+ }
+ if(last < first) goto badlist;
+ if(*delimp) goto baddel;
+ if(first > mp->hghmsg || last < mp->lowmsg) {
+ rangerr: fprintf(stderr,"No messages in range \"%s\".\n",name);
+ return(0);
+ }
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ } else if(*cp == ':') {
+ cp++;
+ if(*cp == '-') {
+ convdir = -1;
+ cp++;
+ } else if(*cp == '+') {
+ convdir = 1;
+ cp++;
+ }
+ if((range = atoi(bp = cp)) == 0)
+ goto badlist;
+ while(isdigit(*bp)) bp++;
+ if(*bp)
+ goto baddel;
+ if((convdir > 0 && first > mp->hghmsg) ||
+ (convdir < 0 && first < mp->lowmsg))
+ goto rangerr;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ if(first > mp->hghmsg)
+ first = mp->hghmsg;
+ for(last = first; last >= mp->lowmsg && last <= mp->hghmsg;
+ last += convdir)
+ if(mp->msgstats[last]&EXISTS)
+ if(--range <= 0)
+ break;
+ if(last < mp->lowmsg)
+ last = mp->lowmsg;
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(last < first) {
+ range = last; last = first; first = range;
+ }
+ } else {
+ /*** Here's the hack: cur message, single numeric message,
+ *** or new message are permitted to be non-existent
+ ***/
+single: last = first;
+ mp->msgstats[first] |= SELECT_EMPTY;
+ }
+ while(first <= last) {
+ if(mp->msgstats[first]&(EXISTS|SELECT_EMPTY)) { /***/
+ if(!(mp->msgstats[first]&SELECTED)) {
+ mp->numsel++;
+ mp->msgstats[first] |= SELECTED;
+ if(first < mp->lowsel)
+ mp->lowsel = first;
+ if(first > mp->hghsel)
+ mp->hghsel = first;
+ }
+ found++;
+ }
+ first++;
+ }
+ if(!found)
+ goto rangerr;
+ return(1);
+}
+
+conv(str, callno) /*** Slightly hacked version of ../subs/m_conv.c */
+char *str;
+int callno; /***/
+{
+ register char *cp, *bp;
+ register int i;
+ char buf[16];
+
+ convdir = 1;
+ cp = bp = str;
+ if(isdigit(*cp)) {
+ while(isdigit(*bp)) bp++;
+ delimp = bp;
+/*** return (i = atoi(cp)) > MAXFOLDER ? MAXFOLDER : i; ***/
+ /* If msg # <= MAXFOLDER, return it;
+ * if > MAXFOLDER but part of a range, return MAXFOLDER;
+ * if single explicit msg #, return error.
+ */
+ return (i = atoi(cp)) <= MAXFOLDER ? i :
+ *delimp || callno == LAST ? MAXFOLDER : -2;
+ }
+ bp = buf;
+ while((*cp >= 'a' && *cp <= 'z') || *cp == '.')
+ *bp++ = *cp++;
+ *bp++ = 0;
+ delimp = cp;
+ if(strcmp(buf, "first") == 0)
+ return(mp->hghmsg? mp->lowmsg : -1); /* Folder empty? */
+/*** return(mp->lowmsg); ***/
+ else if(strcmp(buf, "last") == 0) {
+ convdir = -1;
+ return(mp->hghmsg? mp->hghmsg : -1);
+/*** return(mp->hghmsg); ***/
+ } else if(strcmp(buf, "cur") == 0 || strcmp(buf, ".") == 0)
+ return(mp->curmsg > 0 ? mp->curmsg : -1);
+ else if(strcmp(buf, "prev") == 0) {
+ convdir = -1;
+ for(i = (mp->curmsg<=mp->hghmsg)? mp->curmsg-1: mp->hghmsg;
+ i >= mp->lowmsg; i--) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1); /* non-existent message */
+ } else if(strcmp(buf, "next") == 0) {
+ for(i = (mp->curmsg>=mp->lowmsg)? mp->curmsg+1: mp->lowmsg;
+ i <= mp->hghmsg; i++) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1);
+ } else
+ return(0); /* bad message list */
+}
+
+getnew(str)
+char *str;
+{
+ register char *cp;
+
+ return(mp->hghmsg<MAXFOLDER? mp->hghmsg+ 1 :
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/dir.h>
+#include <strings.h>
+
+extern char *sprintf();
+
+#define max(a,b) (a > b ? a : b)
+#define YES 1
+#define NO 0
+
+#define NEWSP "/usr/news" /* MUST be same as login News's login dir */
+#define MAXTOPICS 50 /* Enough for a while */
+
+int vecp, topicp;
+int topicspec; /* topic argument(s) given */
+char *topics[MAXTOPICS+1];
+char *vec[MAXARGS];
+int fdisplay, fcheck, fupdate, fsend, freview, fbody; /* flags */
+int frevback, fverbose, fhelp, ftopics; /* flags */
+int hit;
+
+struct nts {
+ char t_name[16];
+ int t_num;
+} nts[MAXTOPICS+1], *check();
+struct nts *ntps[MAXTOPICS];
+int nnts; /* number of actual topics */
+
+struct swit switches[] = {
+ "add", -1, /* 0 */
+ "body", -1, /* 1 */
+ "check", 0, /* 2 */
+ "display", 0, /* 3 */
+ "review [#]", 0, /* 4 */
+ "send topic ...",0, /* 5 */
+ "topics", 0, /* 6 */
+ "update", 0, /* 7 */
+ "help", 4, /* 8 */
+ 0, 0,
+};
+
+extern char _sobuf[]; /* MLW standard out buffer */
+
+/*ARGSUSED*/
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int i;
+ register char *cp, **ap;
+ char *arguments[50], **argp;
+
+ invo_name = argv[0];
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ if (chdir (NEWSP) < 0) { /* <-- N.B. */
+ fprintf(stderr, "Can't change directory to ");
+ perror(NEWSP);
+ done(1);
+ }
+ vecp = 2;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ done(0);
+ /* unknown */
+ case -1:vec[vecp++] = --cp; continue;
+ case 0:
+ case 5: fsend = YES; continue;
+ case 1: fbody = YES;
+ vec[vecp++] = --cp; continue;
+ case 2: fcheck = YES; continue;
+ case 3: fdisplay = YES; continue;
+ case 4: freview = YES;
+ if(**argp >= '0' && **argp <= '9')
+ frevback = atoi(*argp++);
+ continue;
+ case 7: fupdate = YES; continue;
+
+ case 8:
+ fhelp = YES;
+ case 6:
+ ftopics = YES;
+ continue;
+ }
+ else
+ if(vecp == 2) {
+ VOID addtopic (cp, YES);
+ topicspec = YES;
+ }
+ else
+ vec[vecp++] = cp;
+ }
+ if (!topicspec)
+ /* user didn't specify topics so give him his defaults */
+ gettopics();
+ getnts();
+ if (fhelp) {
+ help(
+"news [topic ...] [switches] [switches for \"c\" or \"mail\" ]", switches);
+ putchar('\n');
+ }
+ if (ftopics) {
+ showtopics();
+ done(0);
+ }
+ if(fsend) {
+ if(!topicspec) {
+ fprintf(stderr, "Usage: news -send topic [mail switches]\n");
+ done(1);
+ }
+ for(i = 0; i < topicp; i++)
+ if(check(topics[i]))
+ send(topics[i]);
+ else
+ printf("Unknown topic: %s\n", topics[i]);
+ done(0);
+ }
+ for(i = 0; i < topicp; i++)
+ if(check(topics[i]) == NULL)
+ printf("Topic: %s unknown.\n", topics[i]);
+ else
+ disp(topics[i], fverbose || topicspec);
+ if(fcheck) {
+ if(hit)
+ printf(".\n");
+ } else if(!hit && !topicspec && !fupdate && !fdisplay)
+ nonews();
+ m_update();
+ done(0);
+}
+
+
+struct nts *
+check(topic)
+ char *topic;
+{
+ register struct nts *t;
+
+ for(t = nts; t->t_name[0]; t++)
+ if(strncmp(topic, t->t_name, DIRSIZ) == 0)
+ return t;
+ return 0;
+}
+
+
+disp(topic, argflg)
+ register char *topic;
+ int argflg;
+{
+ register struct nts *t;
+ register char *cp, *np;
+ register int msgnum;
+ int high;
+ char buf[128];
+
+ if((t = check(topic)) == 0)
+ fprintf(stderr, "HUH?\n");
+ if((cp = m_find(np = concat("news-", topic, NULLCP))) == NULL)
+ cp = "0";
+ high = atoi(cp);
+ if(fcheck) {
+ if(t->t_num > high) {
+ if(!hit++)
+ printf("Unread news in");
+ if(hit > 1)
+ printf(",");
+ printf(" '%s'", topic);
+ }
+ return;
+ }
+ if(fupdate) {
+ if(t->t_num > high) {
+ m_replace(np, getcpy(m_name(t->t_num)));
+ printf("Skipping %d items in %s.\n",
+ t->t_num - high, topic);
+ }
+ return;
+ }
+ if(freview)
+ if(frevback)
+ msgnum = max(high - frevback, 0);
+ else
+ msgnum = 0;
+ else
+ msgnum = high;
+/*** msgnum = freview? frevback? high - frevback : 0 : high; */
+ if(msgnum >= t->t_num) {
+ if(argflg)
+ printf("%s: no new news.\n", topic);
+ return;
+ }
+ VOID sprintf(buf, "%s/%s", NEWSP, topic);
+ if(chdir(buf) == -1) {
+ perror(buf);
+ return;
+ }
+ vec[1] = showproc;
+ for( ; msgnum < t->t_num;) {
+ cp = m_name(++msgnum);
+ if(hit) {
+ printf("\nPress <return> for %s:%s...", topic, cp);
+ VOID fflush(stdout);
+ VOID read(0, buf, sizeof buf);
+ } else
+ printf("News item %s:%s\n", topic, cp);
+ if(msgnum > high) {
+ m_replace(np, getcpy(cp));
+ m_update();
+ }
+ putenv("mhfolder", topic);
+ vec[vecp] = cp;
+ putchar('\n');
+ call(vec + 1);
+ hit = 1;
+ }
+}
+
+
+call(vector)
+ char **vector;
+{
+ register int pid, child;
+ int status;
+
+ VOID fflush(stdout);
+ while((child = fork()) == -1) {
+ printf("No forks...\n"); VOID fflush(stdout);
+ sleep(2);
+ }
+ if(child == 0) {
+ execv(vector[0], vector);
+ perror(vector[0]);
+ done(1);
+ }
+ while((pid = wait(&status)) != -1 && pid != child) ;
+ if(pid == -1 || status) {
+ fprintf(stderr, "Abnormal termination from %s\n", vector[0]);
+ done(1);
+ }
+}
+
+
+send(topic)
+ register char *topic;
+{
+ vec[0] = mailproc;
+ vec[1] = concat("news.", topic, NULLCP);
+ if(!fbody)
+ printf("Enter text for %s\n", topic);
+ call(vec);
+ free(vec[1]);
+}
+
+
+#ifdef CUTE
+char *nons[] = {
+ "No new news",
+ "No news to peruse",
+ "Only old news",
+ "News shortage",
+ "News reporters on strike",
+ "Report your own news",
+ "News presses broken"
+};
+#define NONS (sizeof nons/ sizeof nons[0])
+#endif
+
+nonews()
+{
+#ifdef CUTE
+#include <sys/timeb.h>
+ struct timeb tb;
+
+ ftime(&tb);
+ printf("%s.\n", nons[tb.millitm % NONS]);
+#else
+ printf("No new news.\n");
+#endif
+}
+
+showtopics()
+{
+ register int i;
+
+ sortnts();
+ printf("Chk Items Topics\n");
+ printf("--- ----- ------\n");
+ for(i = 0; i < nnts; i++)
+ printf(" %s %4d %s\n",
+ addtopic (ntps[i]->t_name, NO) ? "*" : " ",
+ ntps[i]->t_num, ntps[i]->t_name);
+ return;
+}
+
+gettopics ()
+{
+ register char **ap;
+ register char *cp;
+
+ VOID addtopic ("everyone", YES);
+ if((cp = m_find("news-topics")) != NULL) {
+ for (ap = brkstring (cp = getcpy(cp), " ", "\n")
+ ; *ap; ap++)
+ VOID addtopic (*ap, YES);
+ }
+ return;
+}
+
+addtopic (cp, real)
+char *cp;
+int real;
+{
+ register char **cpp;
+
+ for (cpp = topics; *cpp; cpp++)
+ if (!strcmp (*cpp, cp))
+ return YES; /* We have it already */
+ if (real) {
+ if (!strcmp ("*", cp)) {
+ register int i;
+ getnts ();
+ for(i = 0; i < nnts; i++)
+ VOID addtopic (nts[i].t_name, YES);
+ }
+ else if (topicp < MAXTOPICS - 1)
+ topics[topicp++] = cp;
+ }
+ return NO; /* We don't have it already */
+}
+
+getnts()
+{
+ /* shouldn't ALWAYS look up all news folders.
+ * Should only do that for a -topics or -help.
+ */
+ struct direct dir;
+ struct stat st;
+ register struct nts *t;
+ register FILE *d;
+ char tbuf[DIRSIZ + 2];
+
+ if (nnts > 0)
+ /* we've done it already */
+ return;
+ t = nts;
+ if((d = fopen(".", "r")) == NULL) {
+ fprintf(stderr, "Can't open ");
+ perror(NEWSP);
+ done(1);
+ }
+ tbuf[0] = '.';
+ while(fread((char *)&dir, sizeof dir, 1, d)) {
+ if(dir.d_ino && dir.d_name[0] != '.') {
+ strncpy(t->t_name, dir.d_name, DIRSIZ);
+ strcpy(&tbuf[1], t->t_name);
+ if(stat(tbuf, &st) != -1)
+ t->t_num = st.st_size;
+ nnts++;
+ t++;
+ }
+ }
+ VOID fclose(d);
+ return;
+}
+
+sortnts()
+{
+ register int i;
+ extern int ntcmp();
+
+ for (i = 0; i < nnts; i++)
+ ntps[i] = &nts[i];
+ qsort ((char *) ntps, nnts, sizeof ntps[0], ntcmp);
+ return;
+}
+
+ntcmp (n1, n2)
+struct nts **n1;
+struct nts **n2;
+{
+ return strcmp ((*n1)->t_name, (*n2)->t_name);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <strings.h>
+
+int glbtype;
+int header = 1;
+struct msgs *mp;
+
+struct swit switches[] = {
+ "header", 0, /* 0 */
+ "noheader", 0, /* 1 */
+ "help", 4, /* 2 */
+ 0, 0
+};
+
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ char *maildir, *vec[20], *folder;
+ register char *cp;
+ int next;
+ int vecp;
+ char **ap;
+ char *arguments[50], **argp;
+ extern char _sobuf[];
+
+ invo_name = argv[0];
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ next = glbtype;
+ folder = 0; vecp = 2;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:vec[vecp++] = --cp; continue;
+ case 0: header = 1; continue; /* -header */
+ case 1: header = 0; continue; /* -noheader */
+ case 2: if(next > 0) /* -help */
+ help("next [+folder] [switches] [switches for \"type\" ]", switches);
+ else
+ help("prev [+folder] [switches] [switches for \"type\" ]", switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = path(cp+1, TFOLDER);
+ } else {
+ fprintf(stderr, "Bad arg: %s\n", cp);
+ fprintf(stderr, "Usage: %s [+folder] [-l.switches]\n",
+ next>0? "next" : "prev");
+ goto leave;
+ }
+ }
+ vec[vecp] = 0;
+ if(!m_find("path")) free(path("./", TFOLDER));
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!m_convert(next > 0 ? "next" : "prev"))
+ goto leave;
+ m_replace(pfolder, folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ vec[1] = m_name(mp->lowsel);
+ if(header)
+ printf("(Message %s:%s)\n", folder, vec[1]);
+ VOID fflush(stdout);
+ vec[0] = r1bindex(showproc, '/');
+ m_update();
+ putenv("mhfolder", folder);
+ execv(showproc, vec);
+ perror("Can't exec type");
+ leave:
+ m_update();
+ done(0);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+int glbtype = 1;
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include "../folder.h"
+#include <stdio.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+char *malloc();
+
+#define NFOLD 20 /* Allow 20 folder specs */
+
+extern struct swit anoyes[]; /* Std no/yes gans array */
+
+/*
+ * pick [-src folder] [msgs] search [-scan] [-show] [file-op]
+ *
+ * search = -from \
+ * -to \
+ * -cc \
+ * -subject \ pattern
+ * -sub /
+ * -date /
+ * -search /
+ * --component /
+ *
+ * file-op = -file [-preserve] [-link] +folder ...
+ * -keep [-stay] [+folder ...]
+ */
+
+int nvecp, foldp;
+char **nvec;
+struct msgs *mp;
+char grep[256], *grepp, *folder, maildir[128];
+int showf, scanfl, filef, keepf, linkf, noteold, prsrvf, stayf;
+int grep_lowsel = 5000,
+ grep_hghsel = 0;
+char *delprog;
+
+struct st_fold folders[NFOLD];
+
+struct swit switches[] = {
+ "cc pattern", 0, /* 0 */
+ "date pattern", 0, /* 1 */
+ "from pattern", 0, /* 2 */
+ "search pattern", 0, /* 3 */
+ "subject pattern", 0, /* 4 */
+ "to pattern", 0, /* 5 */
+ "-othercomponent pattern", 15, /* 6 */
+ "all", -3, /* 7 */
+ "file +folder ...", 0, /* 8 */
+ "nofile", 0, /* 9 */
+ "keep [+folder ...]", 0, /* 10 */
+ "nokeep", 0, /* 11 */
+ "link", 0, /* 12 */
+ "nolink", 0, /* 13 */
+ "preserve", 0, /* 14 */
+ "nopreserve", 0, /* 15 */
+ "scan", 0, /* 16 */
+ "noscan", 0, /* 17 */
+ "show", 0, /* 18 */
+ "noshow", 0, /* 19 */
+ "src +folder", 0, /* 20 */
+ "stay", 0, /* 21 */
+ "nostay", 0, /* 22 */
+ "help", 4, /* 23 */
+ 0, 0
+};
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ char *msgs[128], buf[128];
+ register int msgnum;
+ register char *cp;
+ int msgp, i;
+ char **ap;
+ char *arguments[50], **argp, **arrp;
+
+ invo_name = argv[0];
+#ifdef NEWS
+ m_news();
+#endif
+ nvecp = 1;
+ msgp = 0;
+ grepp = grep;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-') {
+ if(*++cp == '-') { /* --component */
+ toomany: if(grepp != grep) {
+ fprintf(stderr, "Only one search string.\n");
+ goto leave;
+ }
+ grepp = copy("^", grepp);
+ grepp = copy(++cp, grepp);
+ grepp = copy(":.*", grepp);
+ goto pattern;
+ }
+ switch(i = smatch(cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "pick: -%s unknown\n", cp);
+ goto leave;
+ /* -component */
+ case 0: case 1: case 2: case 4: case 5:
+ if(grepp != grep)
+ goto toomany;
+ grepp = copy("^", grepp);
+ arrp = brkstring(switches[i].sw, " ", NULLCP);
+ grepp = copy(*arrp, grepp);
+ grepp = copy(":.*", grepp);
+ case 3: /* -search */
+ pattern: grepp = copy(*argp++, grepp);
+ continue;
+ case 6: fprintf(stderr, "pick: can't get here\n");
+ goto leave;
+ /* -all */
+ case 7: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 8: filef = 1; continue; /* -file */
+ case 9: filef = 0; continue; /* -nofile */
+ case 10:keepf = 1; continue; /* -keep */
+ case 11:keepf = 0; continue; /* -nokeep */
+ case 12:linkf = 1; continue; /* -link */
+ case 13:linkf = 0; continue; /* -nolink */
+ case 14:prsrvf = 1; continue; /* -preserve */
+ case 15:prsrvf = 0; continue; /* -nopreserve */
+ case 16:scanfl = 1; continue; /* -scan */
+ case 17:scanfl = 0; continue; /* -noscan */
+ case 18:showf = 1; continue; /* -show */
+ case 19:showf = 0; continue; /* -noshow */
+ case 21:stayf = 1; continue; /* -stay */
+ case 22:stayf = 0; continue; /* -nostay */
+ case 20:if(folder) { /* -src */
+ fprintf(stderr, "Only one src folder.\n");
+ goto leave;
+ }
+ if(!(folder = *argp++) || *folder == '-') {
+ fprintf(stderr, "pick: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ if(*folder == '+')
+ folder++;
+ folder = path(folder, TFOLDER);
+ continue;
+ /* -help */
+ case 23:help("pick [msgs] [switches]", switches);
+ goto leave;
+ }
+ } else if(*cp == '+') {
+ if(foldp < NFOLD)
+ folders[foldp++].f_name = path(cp+1, TFOLDER);
+ else {
+ fprintf(stderr, "Only %d folders allowed.\n", NFOLD);
+ goto leave;
+ }
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!m_find("path")) free(path("./", TFOLDER));
+ if(grepp == grep) {
+ fprintf(stderr, "No search pattern specified.\n");
+ goto leave;
+ }
+ if(filef && keepf) {
+ fprintf(stderr, "-file and -keep don't go together.\n");
+ goto leave;
+ }
+ if(!scanfl && !showf && !filef)
+ keepf++; /* The default is -keep */
+ if(keepf) {
+ prsrvf++; /* -keep forces -preserve */
+ linkf++; /* and -link */
+ }
+ if(!folder)
+ folder = m_getfolder(); /* use cur folder if no -src */
+ VOID copy(m_maildir(folder), maildir);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!foldp) { /* if no +folder given... */
+ if(filef) { /* -file requires one */
+ fprintf(stderr, "-file requires at least one folder arg.\n");
+ goto leave;
+ }
+ if(keepf) { /* use default selection-list name */
+ VOID copy(listname, copy("/", copy(folder, buf)));
+ folders[foldp++].f_name = getcpy(buf);
+ noteold++; /* tell user if existing folder */
+ }
+ } else if(keepf) { /* make folders sub-folders */
+ for(msgnum = 0; msgnum < foldp; msgnum++)
+ if(*(cp = folders[msgnum].f_name) != '.' &&
+ *cp != '/') {
+ VOID copy(cp, copy("/", copy(folder, buf)));
+ folders[msgnum].f_name = getcpy(buf);
+ }
+ noteold++;
+ }
+ if(!msgp)
+ msgs[msgp++] = "first-last";
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "pick: Peanut butter 'n jelly\n");/* never get here */
+ goto leave;
+ }
+ if(!compile(grep)) {
+ fprintf(stderr, "Pattern Error.\n");
+ goto leave;
+ }
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ grepfn(msgnum);
+ if(mp->numsel == 0) {
+ fprintf(stderr, "No messages match specification.\n");
+ goto leave;
+ }
+ mp->lowsel = grep_lowsel;
+ mp->hghsel = grep_hghsel;
+ /* all the exec's */
+ if((((delprog = m_find("delete-prog")) != NULL) &&
+ ((filef || keepf) && !linkf)) ||
+ scanfl || showf) {
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "pick: more than %d messages for %s exec\n",
+ MAXARGS-2,
+ scanfl ? "scan" : showf ? "show" : delprog);
+ goto leave;
+ }
+ nvec = (char **) malloc(MAXARGS * sizeof nvec[0]);
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ nvec[nvecp++] = getcpy(m_name(msgnum));
+ nvec[nvecp] = 0;
+ }
+ if(keepf || filef)
+ if(opnfolds())
+ goto leave;
+ if(!noteold || foldp > 1)
+ m_replace(pfolder, folder);
+ if(scanfl)
+ scanfn(showf|filef|keepf);
+ else {
+ printf("%d hit%s.\n", mp->numsel, mp->numsel == 1 ? "" : "s");
+ VOID fflush(stdout);
+ }
+ if(showf)
+ showfn(filef|keepf);
+ if(!(filef|keepf))
+ goto leave;
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ if(m_file(folder, cp = getcpy(m_name(msgnum)),
+ folders, foldp, prsrvf, 1))
+ goto leave;
+ else
+ free (cp);
+ if(!linkf)
+ remove();
+ if(noteold) {
+ struct st_fold *fptr;
+ if(!stayf && foldp == 1) {
+ m_replace(pfolder, cp = folders[0].f_name);
+ printf("[+%s now current]\n", cp); VOID fflush(stdout);
+ }
+ for(fptr = folders; fptr < &folders[foldp]; fptr++)
+ if(!fptr->f_reused) {
+ VOID chdir(m_maildir(fptr->f_name));
+ m_setcur(fptr->f_mp->curmsg);
+ }
+ }
+ leave:
+ m_update();
+}
+
+
+grepfn(msg)
+{
+ if(execute(m_name(msg))) { /* a match */
+ if(msg < grep_lowsel)
+ grep_lowsel = msg;
+ if(msg > grep_hghsel)
+ grep_hghsel = msg;
+ } else {
+ mp->msgstats[msg] &= ~SELECTED; /* clear SELECTED bit */
+ mp->numsel--;
+ }
+}
+
+
+opnfolds()
+{
+ register int i;
+ register char *cp, *ap;
+ char nmaildir[128];
+ struct stat stbuf;
+
+ for(i = 0; i < foldp; i++) {
+ VOID copy(m_maildir(cp = folders[i].f_name), nmaildir);
+ if(stat(nmaildir, &stbuf) < 0) {
+ if(!noteold) {
+ ap = concat("Create folder \"",
+ nmaildir, "\"? ", 0);
+ if(!gans(ap, anoyes))
+ return(1);
+ }
+ if(!makedir(nmaildir)) {
+ fprintf(stderr, "Can't create folder.\n");
+ return(1);
+ }
+ } else if(noteold) {
+ printf("[Folder %s being re-used.]\n", cp);
+ VOID fflush(stdout);
+ folders[i].f_reused++; /* Don't change cur in old fold */
+ }
+ if(chdir(nmaildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(nmaildir);
+ return(1);
+ }
+ if(!(folders[i].f_mp = m_gmsg(folders[i].f_name))) {
+ fprintf(stderr, "Can't read folder %s\n", folders[i].f_name);
+ return(1);
+ }
+ folders[i].f_mp->curmsg = 0;
+ }
+ VOID chdir(maildir); /* return to src folder */
+ return(0);
+}
+
+
+scanfn(forkf)
+{
+ register int pid;
+
+ nvec[0] = r1bindex(scanproc, '/');
+ if(forkf && (pid = fork())) {
+ if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ done(1);
+ }
+ while(wait((int *)NULL) != pid) ;
+ } else {
+ m_update();
+ VOID fflush(stdout);
+ execv(scanproc, nvec);
+ perror(scanproc);
+ done(1);
+ }
+}
+
+
+showfn(forkf)
+{
+ register int pid;
+ int (*sint)(), (*sqit)();
+
+ nvec[0] = r1bindex(showproc, '/');
+ if(forkf) {
+ sint = signal(SIGINT, SIG_IGN);
+ sqit = signal(SIGQUIT, SIG_IGN);
+ }
+ if(forkf && (pid = fork())) {
+ if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ done(1);
+ }
+ while(wait((int *)NULL) != pid) ;
+ VOID signal(SIGINT, sint);
+ VOID signal(SIGQUIT, sqit);
+ } else {
+ m_update();
+ VOID fflush(stdout);
+ putenv("mhfolder", folder);
+ execv(showproc, nvec);
+ perror(showproc);
+ done(1);
+ }
+}
+
+
+remove()
+{
+ register int i;
+ register char *cp;
+
+ if(delprog != NULL) {
+ nvec[0] = r1bindex(delprog, '/');
+ m_update();
+ VOID fflush(stdout);
+ execv(delprog, nvec);
+ fprintf(stderr, "Can't exec deletion-prog--");
+ perror(delprog);
+ } else {
+ for(i= mp->lowsel; i<= mp->hghsel; i++)
+ if(mp->msgstats[i]&SELECTED)
+ if(unlink(cp = m_name(i)) == -1) {
+ fprintf(stderr, "Can't unlink %s:",folder);
+ perror(cp);
+
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+int glbtype = -1;
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <errno.h>
+#include <sgtty.h>
+#include <signal.h>
+#include <strings.h>
+
+#define CKILL 006 /* @ => <CLOSE> */
+#define CERASE 001 /* # => <CTRL A> */
+
+int wtuser; /* waiting for user input */
+int sigint; /* sensed an interrupt */
+FILE *in, *out;
+struct sgttyb sg;
+struct swit switches[] = {
+ "erase chr", 2, /* 0 */ /* "2" can become "0",since no ed */
+ "kill chr", 0, /* 1 */
+ "help", 4, /* 2 */
+ 0, 0
+};
+
+extern int errno; /* MLW 4bsd does not have errno defined in errno.h */
+extern char _sobuf[]; /* MLW standard out buffer */
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ char tmpfil[32], *drft, name[NAMESZ], field[BUFSIZ];
+ int exitstat;
+ char skill, serase;
+ char *killp, *erasep;
+ register int i, state;
+ register char *cp;
+ char **ap;
+ char *arguments[50], **argp;
+ int sig();
+
+ invo_name = argv[0];
+ setbuf(stdout, _sobuf);
+ tmpfil[0] = 0;
+ skill = 0; exitstat = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ drft = NULLCP;
+ while(cp = *argp++)
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto badleave;
+ /* unknown */
+ case -1:fprintf(stderr, "prompter: -%s unknown\n", cp);
+ goto badleave;
+ case 0: if(!(erasep = *argp++)) { /* -erase */
+ missing: fprintf(stderr, "prompter: Missing argument for %s switch\n", argp[-2]);
+ goto badleave;
+ }
+ continue;
+ case 1: if(!(killp= *argp++)) /* -kill */
+ goto missing;
+ continue;
+ /* -help */
+ case 2: help("prompter [switches]",
+ switches);
+ goto badleave;
+ }
+ else if (!drft)
+ drft = cp;
+ if(!drft) {
+ fprintf(stderr, "prompter: missing skeleton\n");
+ goto badleave;
+ }
+ if((in = fopen(drft, "r")) == NULL) {
+ fprintf(stderr, "Can't open %s\n", drft);
+ goto badleave;
+ }
+ VOID copy(makename("prmt", ".tmp"), copy("/tmp/", tmpfil));
+ if((out = fopen(tmpfil, "w")) == NULL) {
+ fprintf(stderr, "Can't create %s\n", tmpfil);
+ goto badleave;
+ }
+ VOID chmod(tmpfil, 0700);
+ VOID signal(SIGINT, sig);
+ VOID gtty(0, &sg);
+ skill = sg.sg_kill;
+ serase = sg.sg_erase;
+ sg.sg_kill = killp ? chrcnv(killp) : skill;
+ sg.sg_erase = erasep ? chrcnv(erasep) : serase;
+/*** stty(0, &sg); ***/
+ ioctl(0, TIOCSETN, &sg);
+ if(killp || erasep) {
+ printf("Erase Char="); chrdisp(sg.sg_erase);
+ printf("; Kill Line="); chrdisp(sg.sg_kill);
+ printf(".\n"); VOID fflush(stdout);
+ }
+ state = FLD;
+ for(;;) switch(state = m_getfld(state,name,field,sizeof field,in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(field[0] != '\n' || field[1] != 0) {
+ printf("%s:%s", name, field);
+ fprintf(out, "%s:%s", name, field);
+ while(state == FLDPLUS) {
+ state=m_getfld(state,name,field,sizeof field,in);
+ printf("%s", field);
+ fprintf(out, "%s", field);
+ }
+ } else {
+ printf("%s: ", name);
+ VOID fflush(stdout);
+ i = getln(field);
+ if(i == -1)
+ goto badleave;
+ if(i == 0 && (field[0] == '\n' || !field[0]))
+ continue;
+ fprintf(out, "%s:", name);
+ do {
+ if(field[0] != ' ' && field[0] != '\t')
+ putc(' ', out);
+ fputs(field, out);
+ } while(i == 1 && (i = getln(field)) >= 0);
+ if(i == -1)
+ goto badleave;
+ }
+ field[0] = 0;
+ if(state == FLDEOF)
+ goto body;
+ continue;
+
+ case BODY:
+ case BODYEOF:
+ case FILEEOF:
+ body: fputs("--------\n", out);
+ printf("--------\n");
+ if(field[0]) {
+ do {
+ fputs(field, out);
+ if(!sigint)
+ printf("%s", field);
+ } while(state == BODY &&
+ (state=m_getfld(state,name,field,sizeof field,in)));
+ printf("\n--------Enter additional text\n\n");
+ }
+ VOID fflush(stdout);
+ for(;;) {
+ VOID getln(field);
+ if(field[0] == 0)
+ break;
+ fputs(field, out);
+ }
+ goto finish;
+
+ default:
+ fprintf(stderr, "Bad format file!\n");
+ goto badleave;
+ }
+
+
+finish:
+ printf("--------\n"); VOID fflush(stdout);
+ VOID fclose(out);
+ out = fopen(tmpfil, "r");
+ VOID fclose(in);
+ in = fopen(drft, "w"); /* Truncate prior to copy back */
+ do
+ if((i = read(fileno(out), field, sizeof field)) > 0)
+ if(write(fileno(in), field, i) != i) {
+ fprintf(stderr, "Write error to ");
+ perror(drft);
+ done(1);
+ }
+ while(i == sizeof field);
+ goto leave;
+
+badleave:
+ exitstat = 1;
+
+leave:
+ if(in)
+ VOID fclose(in);
+ if(out)
+ VOID fclose(out);
+ if(tmpfil[0])
+ VOID unlink(tmpfil);
+ m_update();
+ if(killp || erasep) {
+ sg.sg_kill = skill;
+ sg.sg_erase = serase;
+/*** stty(0, &sg); ***/
+ ioctl(0, TIOCSETN, &sg);
+ }
+ done(exitstat);
+}
+
+
+getln(buf)
+ char *buf;
+{
+ register char *cp;
+ register int c;
+ int stat;
+
+ cp = buf;
+ *cp = 0;
+ wtuser = 1;
+ for(;;) {
+ c = getchar();
+/*** fprintf(stderr,"getchar()=\\%o,errno=%d,EINTR=%d\n",c,errno,EINTR);/***/
+ if(c == EOF)
+ if(errno == EINTR) {
+ stat = -1;
+ goto leave;
+ } else {
+ stat = 0;
+ goto leave;
+ }
+ if(c == '\n') {
+ if(cp[-1] == '\\') {
+ cp[-1] = c;
+ stat = 1;
+ goto leave;
+ }
+ *cp++ = c;
+ *cp = 0;
+ stat = 0;
+ goto leave;
+ }
+ if(cp < buf + 500)
+ *cp++ = c;
+ *cp = 0;
+ }
+ leave: wtuser = 0;
+ return(stat);
+ }
+
+
+sig()
+{
+ VOID signal(SIGINT, sig);
+ if(!wtuser)
+ sigint = 1;
+ return;
+}
+
+
+chrcnv(str)
+char *str;
+{
+ register char *cp;
+ register int c;
+
+ cp = str;
+ if((c = *cp++) != '\\')
+ return(c);
+ c = 0;
+ while(*cp && *cp != '\n') {
+ c *= 8;
+ c += *cp++ - '0';
+ }
+ return c;
+}
+
+
+chrdisp(chr)
+{
+ register int c;
+
+ c = chr;
+ if(c < ' ')
+ printf("<CTRL-%c>", c + '@');
+ else
+ printf("%c"
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../adrparse.h"
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct mailname *mp;
+ register char *cp;
+
+ if(!(mp = getm(argv[1],"RAND-UNIX"))) {
+ printf("adrparse returned 0\n");
+ exit(0);
+ }
+ printf("%s\n", mp->m_text);
+ printf("mbox: %s\n", mp->m_mbox);
+ if(!mp->m_nohost) {
+ printf("at: ");
+ cp = mp->m_at;
+ if(*cp == '@') putchar('@');
+ else while(*cp != ' ') putchar(*cp++);
+ printf("\n");
+ }
+ printf("host: %s ", mp->m_host);
+ if(mp->m_nohost)
+ printf("[default] ");
+ else {
+ putchar('"');
+ for(cp = mp->m_hs; cp <= mp->m_he; )
+ putchar(*cp++);
+ putchar('"');
+ }
+ printf("\n");
+ printf("hnum: %d\n", mp->m_hnum);
+ printf("Proper: %s\n", adrformat(mp,"RAND-UNIX"));
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <whoami.h>
+#include "../mh.h"
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "../adrparse.h"
+
+#define ERRHOST "?????"
+/*#define NEWS 1*/
+
+#define NOUSE 0
+
+/* #define TEST 1 */
+
+struct swit anyl[] = {
+ "no", 0,
+ "yes", 0,
+ "list", 0,
+ 0
+};
+
+struct swit aleqs[] = {
+ "list", 0, /* 0 */
+ "edit [<editor>]", 0, /* 1 */
+ "quit [delete]", 0, /* 2 */
+ "send [switches]", 0, /* 3 */
+ 0
+};
+
+short anot;
+#define OUTPUTLINELEN 72
+short outputlinelen = OUTPUTLINELEN;
+short ccme = 1;
+struct msgs *mp;
+char *ed;
+short format = -1; /* Default to re-format optionally*/
+short inplace; /* preserve links in anno */
+short debug;
+char *badaddrs;
+
+struct swit switches[] = {
+ "annotate", 0, /* 0 */
+ "noannotate", 0, /* 1 */
+ "ccme", -1, /* 2 */
+ "noccme", -1, /* 3 */
+ "editor editor", 0, /* 4 */
+ "format", 0, /* 5 */
+ "noformat", 0, /* 6 */
+ "inplace", 0, /* 7 */
+ "noinplace", 0, /* 8 */
+ "width", 0, /* 9 */
+ "help", 4, /*10 */
+ "debug", -5, /*11 */
+ 0, 0
+};
+
+char *ltrim();
+char *rtrim();
+char *niceadd();
+char *fix();
+char *addr();
+
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *msg, *maildir;
+ register char *cp, **ap, **argp;
+ char *arguments[50];
+
+ invo_name = argv[0];
+#ifdef NEWS
+ m_news();
+#endif
+ msg = 0; anot = 0; folder = 0;
+
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "repl: -%s unknown\n", cp);
+ goto leave;
+ case 0: anot = 1; continue; /* -annotate */
+ case 1: anot = 0; continue; /* -noannotate */
+ case 2: ccme = 1; continue; /* -ccme */
+ case 3: ccme = 0; continue; /* -noccme */
+ case 4: if(!(ed = *argp++)) { /* -editor */
+missing: fprintf(stderr, "repl: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 5: format = 1; continue; /* -format */
+ case 6: format = 0; continue; /* -noformat */
+ case 7: inplace = 1; continue; /* -inplace */
+ case 8: inplace = 0; continue; /* -noinplace */
+ case 9: if(!(cp = *argp++) || *cp == '-')
+ goto missing;
+ outputlinelen = atoi(cp); continue;
+ /* -help */
+ case 10:help("repl [+folder] [msg] [switches]",
+ switches);
+ goto leave;
+ case 11:debug++; continue; /* -debug */
+
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = path(cp+1, TFOLDER);
+ } else if(msg) {
+ fprintf(stderr, "Only one message per reply.\n");
+ goto leave;
+ } else
+ msg = cp;
+ }
+ if(!m_find("path")) free(path("./", TFOLDER));
+ if(!msg)
+ msg = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!m_convert(msg))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "repl: pepperoni pizza\n");/* never get here */
+ goto leave;
+ }
+ if(mp->numsel > 1) {
+ fprintf(stderr, "Only one message at a time.\n");
+ goto leave;
+ }
+ m_replace(pfolder, folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ repl(getcpy(m_name(mp->lowsel)));
+ leave:
+ m_update();
+ done(0);
+}
+
+char *mn_rep;
+
+repl(msg)
+ char *msg;
+{
+ register char *cp;
+ register int i;
+ FILE *in, *out;
+ char name[NAMESZ], field[BUFSIZ];
+ char *drft, *msgid, *replto, *from, *sub, *date, *sender, *to, *cc;
+ int state;
+ int pid, wpid;
+ char **argp;
+ struct mailname *mnp = 0;
+ struct stat stbuf;
+
+/***/if(debug) printf("repl(%s)\n", msg);
+ if((in = fopen(msg, "r")) == NULL) {
+ fprintf(stderr, "Can't open "); perror(msg);
+ return;
+ }
+ drft = m_maildir(draft);
+/***/if(debug) printf("drft=%s\n", drft);
+ if(stat(drft, &stbuf) != -1) {
+ cp = concat("\"", drft, "\" exists; delete? ", 0);
+ while((i = gans(cp, anyl)) == 2)
+ VOID showfile(drft);
+ if(!i)
+ return;
+ free(cp);
+ }
+ if((out = fopen(drft, "w")) == NULL) {
+ fprintf(stderr, "Can't create \"%s\".\n", drft);
+ return;
+ }
+ VOID chmod(drft, m_gmprot());
+
+ state = FLD;
+ to = cc = sender = replto = msgid = from = sub = date = 0;
+
+ for(;;) {
+
+ switch(state = m_getfld(state, name, field, sizeof field, in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(uleq(name, "from")) {
+ if(state == FLD && from) from = add(",",from);
+ from = add(field, from);
+ }
+ if(uleq(name, "cc")) {
+ if(state == FLD && cc) cc = add(",",cc);
+ cc = add(field, cc);
+ }
+ if(uleq(name, "subject"))
+ sub = add(field, sub);
+ if(uleq(name, "date"))
+ date = add(field, date);
+ if(uleq(name, "to")) {
+ if(state == FLD && to) to = add(",",to);
+ to = add(field, to);
+ }
+ if(uleq(name, "message-id"))
+ msgid = add(field, msgid);
+ if(uleq(name, "reply-to")) {
+ if(state == FLD && replto) replto = add(",",replto);
+ replto = add(field, replto);
+ }
+ if(uleq(name, "sender")) {
+ if(state == FLD && sender) sender = add(",",sender);
+ sender = add(field, sender);
+ }
+ if(state == FLDEOF)
+ goto done;
+ break;
+
+ case BODY:
+ case BODYEOF:
+ case FILEEOF:
+ goto done;
+
+ default:
+ fprintf(stderr, "getfld returned %d\n", state);
+ return;
+ }
+
+ }
+
+done:
+ VOID fclose(in);
+
+ if(!(sender || from)) {
+ fprintf(stderr, "repl: No Sender or From!?\n");
+ return;
+ }
+
+ /* Pick up replacement host from "sender", else "from" */
+#ifdef ARPANET
+ if((cp = getname(sender ? sender : from)) == 0)
+ return;
+ if((mnp = getm(cp, HOSTNAME)) == 0)
+ mn_rep = ERRHOST;
+ else {
+ if((mnp -> m_at) && ((*mnp -> m_at) == '!')) { /* UUCP address */
+ cp = stdhost((long)HOSTNUM);
+ }
+ else
+ cp = stdhost(mnp->m_hnum);
+ if(!cp) {
+ fprintf(stderr, "repl: Unknown host: %s\n", mnp->m_host);
+ return;
+ }
+ mn_rep = getcpy(cp);
+ mnfree(mnp);
+ }
+#else
+ mn_rep = getcpy (HOSTNAME);
+#endif
+ while(getname("")) ; /* In case multi-name from/sender */
+
+ /***/if(debug) printf("before testformats\n");
+ /* Set format flag to 0 or 1 based on actual addresses, */
+ /* provided it hasn't been explicitly set */
+
+ if(format == -1 && *mn_rep == '?') /* Oops, error in sender/from.*/
+ format = 1; /* Format! Use replacement host ERRHOST */
+ if(format == -1) testformat(sender);
+ if(format == -1) testformat(from);
+ if(format == -1) testformat(replto);
+ if(format == -1) testformat(to);
+ if(format == -1) testformat(cc);
+ if(format == -1) format = 0; /* All LOCAL--don't format! */
+
+/***/if(debug) printf("after testformats\n");
+ if(!(from || replto)) {
+ fprintf(stderr, "No one to reply to!!!\n");
+ return;
+ }
+ outfmt(out, replto ? replto : from, "To", 0);
+
+ if(to && cc) /* Combine to & cc data */
+ to = add(" ,", to);
+ if(cc)
+ to = add(cc, to);
+ outfmt(out, to, "Cc", 1);
+
+ if(sub) { /* Subject: Re: */
+ fprintf(out, "Subject: ");
+ if(*sub == ' ') sub++;
+ if((sub[0] != 'R' && sub[0] != 'r') ||
+ (sub[1] != 'E' && sub[1] != 'e') ||
+ sub[2] != ':')
+ fprintf(out, "Re: ");
+ fprintf(out, sub);
+ }
+ if(date) { /* In-reply-to: */
+ date[strlen(date)-1] = '.';
+ if(*date == ' ') date++;
+ fprintf(out, "In-reply-to: Your message of %s\n", date);
+ if(msgid) {
+ if(*msgid == ' ') msgid++;
+ fprintf(out, " %s", msgid);
+ }
+ }
+ fprintf(out, "----------\n");
+ if(badaddrs)
+ fprintf(out, "\nREPL: CANT CONSTRUCT:\n%s\n", badaddrs);
+ if(fclose(out) == EOF) {
+ fprintf(stderr, "reply: Write error on ");
+ perror(drft);
+ return;
+ }
+ if(!debug)
+ if(m_edit(&ed, drft, NOUSE, msg) < 0)
+ return;
+#ifdef TEST
+ fprintf(stderr, "!! Test Version of SEND Being Run !!\n");
+ fprintf(stderr, " Send verbose !\n\n");
+#endif
+
+ for(;;) {
+ if(!(argp = getans("\nWhat now? ", aleqs))) {
+ VOID unlink("@");
+ return;
+ }
+ switch(smatch(*argp, aleqs)) {
+ case 0: VOID showfile(drft); /* list */
+ break;
+
+ case 1: if(*++argp) /* edit */
+ ed = *argp;
+ if(m_edit(&ed, drft, NOUSE, msg) == -1)
+ return;
+ break;
+
+ case 2: if(*++argp && (*argp[0] == 'd' || /* quit */
+ (*argp[0]=='-' && *argp[1]=='d')))
+ if(unlink(drft) == -1) {
+ fprintf(stderr, "Can't unlink %s ", drft);
+ perror("");
+ }
+ return;
+
+ case 3: /* send */
+ if(!mp->msgflags&READONLY) { /* annotate first */
+ if(anot > 0) {
+ while((pid = fork()) == -1) sleep(5);
+ if(pid) {
+ while((wpid=wait((int *)NULL))!= -1
+ && wpid!= pid);
+ if(stat(drft, &stbuf) == -1)
+ annotate(msg, "Replied", "", inplace);
+ return;
+ }
+ }
+ }
+ VOID m_send(++argp, drft);
+ return;
+
+ default:fprintf(stderr, "repl: illegal option\n"); /*##*/
+ break;
+ }
+ }
+}
+
+
+outfmt(out, str, fn, chk)
+ FILE *out;
+ char *str, *fn;
+ int chk;
+{
+ register char *cp;
+ register struct mailname *mnp = 0;
+ short ccoutput = 0, linepos = 0, len;
+
+/***/if(debug)printf("outfmt mn_rep=%s\n", mn_rep);
+ while(cp = getname(str)) {
+ if(mnp) mnfree(mnp);
+/***/if(debug)printf("Parse '%s'\n",cp);
+
+ /* If couldn't find foreign default host due to sender/from */
+ /* parse error, hand adrparse HOSTNAME for the time. */
+
+ if((mnp = getm(cp, *mn_rep == '?' ? HOSTNAME : mn_rep)) == 0){
+ char buf[512];
+ /* Can't parse. Add to badlist. */
+ VOID sprintf(buf, " %s: %s\n", fn, cp);
+ badaddrs = add(buf, badaddrs);
+ continue;
+ } else if(*mn_rep == '?') {
+ /*
+ * Now must distinguish between explicit-local and
+ * hostless-foreign, which parse identically
+ * because of the borrowed HOSTNAME.
+ * Kludge: If same string gives parse error when
+ * default host is ERRHOST, then original string was
+ * hostless (foreign). Otherwise original string had
+ * HOSTNAME explicitly and is local.
+ */
+ struct mailname *tmpmnp;
+
+ if(tmpmnp = getm(cp, ERRHOST))
+ mnfree(tmpmnp);
+ else
+ mnp->m_host = getcpy(ERRHOST);
+
+ }
+/***/if(debug) printf ("Host %D\n",mnp->m_hnum);
+ if(chk && !ccme && uleq(mnp->m_mbox, getenv("USER")) &&
+ mnp->m_hnum == HOSTNUM)
+ continue;
+ if(!ccoutput) {
+ fprintf(out, "%s: ", fn);
+ linepos += (ccoutput = strlen(fn) + 2);
+ }
+ if((format && *mn_rep != '?')|| ((mnp->m_at && *mnp->m_at != '!') &&
+ (mnp->m_hnum != HOSTNUM)) ) {
+
+/***/if(debug) printf ("That's not %d, so format it (name %s)\n",
+ HOSTNUM, HOSTNAME);
+ cp = adrformat(mnp,HOSTNAME);
+/***/if(debug) printf ("Formatting produces '%s'\n",cp);
+ }
+ else if (format && *mn_rep == '?') {
+ cp = adrformat(mnp, mn_rep);
+ }
+ else
+ cp = mnp->m_text;
+ len = strlen(cp);
+ if(linepos != ccoutput)
+ if(len + linepos + 2 > outputlinelen) {
+ fprintf(out, ",\n%*s", ccoutput, "");
+ linepos = ccoutput;
+ } else {
+ fputs(", ", out);
+ linepos += 2;
+ }
+ fputs(cp, out);
+ linepos += len;
+ }
+ if(mnp) mnfree(mnp);
+ if(linepos) putc('\n', out);
+}
+
+
+testformat(str)
+ char *str;
+{
+ register struct mailname *mnp;
+ register char *cp;
+
+ if(str)
+ while(cp = getname(str)) {
+ if(mnp = getm(cp, mn_rep)) {
+ if((mnp->m_hnum != HOSTNUM) &&
+ (mnp->m_at) && (*mnp->m_at != '!'))
+ format = 1;
+ mnfree(m
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+
+char *ltrim(cp)
+char *cp;
+{
+ /* Return pointer to 1st non-blank char in string;
+ * If ptr ==> 0 or ptr ==> '\n'0, return NUL;
+ */
+
+ register char *cp1;
+
+ cp1 = cp;
+ while((*cp1 == ' ') || (*cp1 == '\t')) cp1++;
+ if((*cp1 == 0) || (*cp1 == '\n' && cp1[1] == 0))
+ cp1 = 0;
+ return(cp1);
+}
+
+char *rtrim(cp)
+ char *cp;
+{
+ /* trim newline and blanks from the right */
+
+ register char *cp1;
+
+ cp1 = cp+strlen(cp)-1;
+ if(*cp1 == '\n') *cp1 = 0;
+ while(*--cp1 == ' ') ;
+ *++cp1 = 0;
+ return(cp);
+}
+
+char *niceadd(this, that)
+char *this, *that;
+{
+ register char *from, *to;
+
+ if(!(from = ltrim(this))) /* nothing to add */
+ return(that);
+
+ if(to = that)
+ to = add(",\n ", rtrim(to)); /* enuf blanks for "cc: " */
+ return(add(from, to));
+}
+
+#define ADDRLEN (needadr ? addrlen : 0)
+
+char *fix(field, address)
+char *field, *address;
+{
+ /* Appends address to each needy addressee in "field".
+ * Returns pointer to copy of new string. (HUH?)
+ * "field" should never be 0
+ */
+
+ register int len;
+ register char *newp;
+ int addrlen;
+ int needadr;
+ int fieldlen;
+ char *cp;
+
+ addrlen = strlen(address);
+ len = 0;
+ newp = "";
+
+ for(cp = field; ;cp += fieldlen + 1) {
+ needadr = needsaddr(&cp, &fieldlen); /* cp may be changed */
+ if(fieldlen == 0) {
+ cndfree(field);
+ newp = add("\n", newp);
+ return(newp);
+ }
+ if((len + fieldlen + ADDRLEN) > 70) {
+ newp = add(",\n ", newp);
+ len = 4;
+ } else if (*newp) {
+ newp = add(", ", newp);
+ len += 2;
+ }
+ *(cp + fieldlen) = 0;
+ newp = add(cp, newp);
+ if(needadr)
+ newp = add(address, newp);
+ len += fieldlen + ADDRLEN;
+ }
+}
+
+anychar(fchars, field)
+char *fchars, *field;
+{
+ /* Returns 1 if any fancy char appears in "field"
+ * Returns 0 if either "field" is nul or contains no fancy chars
+ */
+
+ register char *fp;
+
+ if(!field)
+ return(0);
+ for(fp = fchars; *fp; fp++)
+ if(r_any(*fp, field))
+ return(1);
+ return(0);
+}
+
+
+r_any(chr,stg)
+char chr, *stg;
+{
+ register char c, *s;
+
+ c = chr;
+ for (s = stg; (*s) && (*s != ',') && (*s != '\n');)
+ if (*s++ == c) return (1);
+ return (0);
+}
+
+char *
+addr(text)
+char *text;
+{
+ static char buf[128];
+ register char *cp, *bufp;
+ int textseen, blankseen;
+ char *copyaddr();
+
+ textseen = blankseen = 0;
+ bufp = buf;
+ if(!text)
+ return(0);
+ for(cp = text; (*cp == ' ' || *cp == '\t'); cp++);
+ for(;;cp++) {
+ switch(*cp) {
+ default:
+ textseen++;
+ break;
+ case ' ': case '\t':
+ blankseen++;
+ break;
+ case 'a':
+ if(!blankseen || !textseen || !ssequal("at ",cp)){
+ textseen++;
+ break;
+ }
+ bufp = copy(" at ", buf);
+ VOID copyaddr(cp+3, bufp);
+ return(buf);
+ case '@':
+ if(!textseen)
+ return(0);
+ bufp = copy(" @ ", buf);
+ VOID copyaddr(cp+1, bufp);
+ return(buf);
+ case ',': case '\n': case 0:
+ return(0);
+ }
+ }
+}
+
+#define ND1 (*fp) && (*fp != ' ') && (*fp != '\t')
+#define ND2 (*fp != '<') && (*fp != '(') && (*fp != '>') && (*fp != ')')
+#define ND3 (*fp != '\n') && (*fp!= ',') && (*fp != ':')
+#define NOTDELIM ND1 && ND2 && ND3
+
+char *copyaddr(fp, tp)
+ register char *fp, *tp;
+{
+ /* Copies left-trimmed "from" to "to".
+ * Copy terminates on any delimiter.
+ * Returns pointer to NUL terminator in destination string
+ */
+
+ for( ; *fp == ' ' || *fp == '\t'; fp++) ;
+ for( ; NOTDELIM; *tp++ = *fp++);
+ *tp = 0;
+ return(tp);
+}
+#define NOTRELEVANT (*cp == ' ' || *cp == '\t' || *cp == '\n'|| *cp == ',')
+
+needsaddr(field, fieldlen)
+char **field;
+int *fieldlen;
+{
+ /* Returns 1 if this field needs an address
+ * Returns 0 if field contains any funny chars or has
+ * an address of the form "xxxx at " or "xxxx[<b>]@"
+ * "field": on input -- addr of pointer to start of field
+ * on output -- val of ptr moved to 1st meaty char
+ * "fieldlen" returns the length of the new field
+ * (it terminates on ',' or '\n' or 0)
+ */
+
+ register char *cp;
+ int textseen = 0, blankseen = 0;
+ int retval;
+ /* find 1st relevant char in field */
+ for(cp = *field; NOTRELEVANT ; cp++);
+
+ *field = cp; /* return it to caller */
+ if(anychar("(<:", cp)) {
+ retval = 0;
+ goto leave;
+ }
+ for(;;cp++) {
+ switch(*cp) {
+ default:
+ textseen++;
+ break;
+ case ' ': case '\t':
+ blankseen++;
+ break;
+ case 'a':
+ if(!blankseen || !textseen || !ssequal("at ",cp)){
+ textseen++;
+ break;
+ }
+ case '@':
+ retval = 0;
+ goto leave;
+ case ',': case '\n': case 0:
+ retval = 1;
+ goto leave;
+
+ }
+ }
+ leave:
+ for(; (*cp) && (*cp != ',') && (*cp != '\n'); cp++) ;
+ *fieldlen = cp- *field;
+ return(retv
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+static char *sccsid = "@(#)from rmail.c 4.1 (Berkeley) 10/1/80";
+/*
+ * rmail: front end for mail to stack up those stupid >From ... remote from ...
+ * lines and make a correct return address. This works with the -f option
+ * to /etc/delivermail so it won't work on systems without delivermail.
+ * However, it ought to be easy to modify a standard /bin/mail to do the
+ * same thing.
+ *
+ * NOTE: Rmail is SPECIFICALLY INTENDED for ERNIE COVAX because of its
+ * physical position as a gateway between the uucp net and the arpanet.
+ * By default, other sites will probably want /bin/rmail to be a link
+ * to /bin/mail, as it was intended by BTL. However, other than the
+ * (somewhat annoying) loss of information about when the mail was
+ * originally sent, rmail should work OK on other systems running uucp.
+ * If you don't run uucp you don't even need any rmail.
+ *
+ * This version revised around New Year's Day 1981 to interface with
+ * Rand's MH system. The nature of the revision is to (1) do nothing
+ * if the destination is uucp-remote (note the assumption of single
+ * destination) and (2) to call "/etc/mh/deliver" to do the deed.
+ *
+ * Revised Aug 1981 to add NOGATEWAY screen. Also fixed a few bugs.
+ * PK.
+ *
+ * 5/8/82: Tack on uu-Date: if msg has no date. PK.
+ */
+
+/*#define DEBUG 1*/
+
+#include "../mh.h"
+#include <whoami.h>
+#include <stdio.h>
+
+#define MATCH 0
+#define PARSE 1
+#define NOPARSE 0
+
+
+char *index();
+
+FILE *out; /* output to delivermail */
+char *tmpfil; /* file name of same */
+char tmpfila[24]; /* array for tmpfil */
+char *to; /* argv[1] */
+char from[512]; /* accumulated path of sender */
+char lbuf[512]; /* one line of the message */
+
+char d1[10], d2[10], d3[10], d4[10], d5[10]; /*** ctime() fields ***/
+
+#ifdef ARPANET
+int netaddr; /* set if "to" contains an arpanet address */
+#endif
+
+main(argc, argv)
+char **argv;
+{
+ char ufrom[64]; /* user on remote system */
+ char sys[64]; /* a system in path */
+ char junk[512]; /* scratchpad */
+ char *cp;
+ int badhdr; /***/
+
+ to = argv[1];
+ if (argc != 2) {
+ fprintf(stderr, "Usage: rmail user\n");
+ exit(1);
+ }
+#ifdef DEBUG
+ out=stdout;
+ tmpfil = "/dev/tty";
+#else
+ tmpfil = tmpfila;
+ sprintf (tmpfil, "/tmp/%s", makename ("mail",".tmp"));
+ if ((out=fopen(tmpfil, "w")) == NULL) {
+ fprintf(stderr, "Can't create %s\n", tmpfil);
+ exit(1);
+ }
+#endif
+ for (;;) {
+ fgets(lbuf, sizeof lbuf, stdin);
+ if (strncmp(lbuf, "From ", 5) && strncmp(lbuf, ">From ", 6))
+ break;
+ fputs(lbuf, out); /* Save--in case we are just forwarding */
+/***/ sscanf(lbuf, "%s %s %s %s %s %s %s remote from %s",
+ junk, ufrom, d1, d2, d3, d4, d5, sys);
+/* sscanf(lbuf, "%s %s", junk, ufrom); */
+ cp = lbuf;
+ for (;;) {
+ cp = index(cp+1, 'r');
+ if (cp == NULL)
+ cp = "remote from somewhere";
+#ifdef DEBUG
+ printf("cp='%s'\n", cp);
+#endif
+ if (strncmp(cp, "remote from ", 12) == MATCH)
+ break;
+ }
+ sscanf(cp, "remote from %s", sys);
+ strcat(from, sys);
+ strcat(from, "!");
+#ifdef DEBUG
+ printf("ufrom='%s', sys='%s', from now '%s'\n", ufrom, sys, from);
+#endif
+ }
+ strcat(from, ufrom);
+
+#ifdef DEBUG
+ printf("from now '%s'\n", from);
+#endif
+
+
+#ifdef ARPANET
+ netaddr = isarpa(to); /* Arpanet destination? */
+
+#ifdef NOGATEWAY
+ if(netaddr && !okhost(sys))
+ {
+ truncate();
+ returnmail("Sorry, not an Arpanet gateway!");
+ exit(0);
+ }
+#endif
+
+ if (index (to, '!') && !netaddr) {
+#else
+ if (index (to, '!')) {
+#endif
+ /* Just forwarding! */
+ putmsg(NOPARSE);
+ deliver(to);
+ exit(0);
+ }
+
+ truncate();
+ /* fprintf(out, "To: %s\n",to); */
+ putfrom();
+
+ if( !((cp = index(lbuf, ':')) && (cp - lbuf < NAMESZ ))) {
+ fputs("\n",out);/* Doesn't look good; terminate hdr */
+ badhdr++;
+ }
+ putmsg(badhdr?NOPARSE:PARSE);
+ deliver(to);
+
+}
+
+
+deliver(to)
+ char *to;
+{
+ int sts,pid,waitid;
+
+#ifdef DEBUG
+ printf("%s would get called here; Delivery to: %s \n", mh_deliver,to);
+ exit(0);
+#endif
+ fclose(out);
+
+ if ((pid=fork()) == -1) {
+ fprintf(stderr, "Cannot fork Deliver!\n");
+
+#ifndef DEBUG /* Extra precaution */
+ unlink(tmpfil);
+#endif
+ exit(1);
+ }
+ if(pid) {
+ while(((waitid = wait(&sts)) != pid) && (waitid != -1));
+
+#ifndef DEBUG /* Extra precaution */
+ unlink(tmpfil);
+#endif
+ exit(0);
+ }
+ execl(mh_deliver, "deliver", "-deliver", to, tmpfil, 0);
+
+ perror( "Cannot exec Deliver ");
+
+ exit(1);
+
+}
+
+#ifdef ARPANET
+
+isarpa(str) /* Gateway to Arpanet? */
+ char *str;
+{
+ char *cp;
+
+ if (index (str, '@'))
+ return(1);
+
+ for (cp = str; ;) {
+ if((cp = index(cp, ' ')) == NULL)
+ return(0);
+ while(*cp == ' ')
+ cp++;
+ if ((strncmp(cp, "at ", 3) == MATCH) ||
+ (strncmp(cp, "AT ", 3) == MATCH) ||
+ (strncmp(cp, "At ", 3) == MATCH))
+
+ return(1);
+ }
+}
+
+
+okhost(str) /* Host permitted to use us as an arpanet gateway? */
+ char *str;
+{
+ register short i;
+
+ for (i=0; rhosts[i]; i++)
+ if (strcmp (str, rhosts[i]) == MATCH)
+ return(1);
+ return(0);
+}
+#endif
+
+returnmail(message)
+ char *message;
+{
+
+#ifdef DEBUG
+ printf("returnmail()\n");
+#endif
+ if(!from) return;
+
+ putdate();
+ fprintf(out, "To: %s\n", from);
+ fputs("\n",out);
+ fputs (message, out);
+ fputs("\n\n\n*--------------RETURNED MESSAGE---------------*\n\n",
+ out);
+
+ putmsg(NOPARSE);
+ deliver(from);
+
+}
+
+
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <time.h>
+
+putdate()
+{
+ long now;
+ register char *t, *p;
+ char *timezone();
+ struct timeb tb;
+ struct tm *tmp;
+ static char *wday[] = {
+ "Sun",
+ "Mon",
+ "Tues",
+ "Wednes",
+ "Thurs",
+ "Fri",
+ "Satur"
+ };
+
+ now = time((long *)0);
+ t = ctime(&now);
+ ftime(&tb);
+ tmp = localtime(&now);
+ p = timezone(tb.timezone, tmp->tm_isdst);
+
+ /* day 13 Apr 1981 20 :38 -PST */
+ fprintf(out, "Date: %sday, %.2s %.3s %.4s %.2s:%.2s-%.3s\n",
+ wday[tmp->tm_wday], t+8, t+4, t+20, t+11, t+14, p);
+}
+
+
+putfrom()
+{
+ if (strlen(from))
+#ifdef ARPANET
+ if (netaddr)
+ fprintf(out, "From: %s at %s\n",from, HOSTNAME);
+ else
+ fprintf(out, "From: %s\n", from);
+#else
+ fprintf(out, "From: %s\n",from);
+#endif
+
+}
+
+
+putmsg(parse)
+int parse;
+{
+ int dateseen = 0;
+
+ if(!parse)
+ putall();
+ else {
+ if (uleqn(lbuf, "date:", 5) == 0)
+ dateseen++;
+ fputs(lbuf, out);
+ while (fgets(lbuf, sizeof lbuf, stdin)) {
+ if(lbuf[0] == '\n' ) { /* end of hdrs */
+ if(!dateseen)
+ uudate();
+ putall();
+ } else {
+ if (uleqn(lbuf, "date:", 5) == 0)
+ dateseen++;
+ fputs(lbuf, out);
+ }
+ }
+ }
+}
+
+
+putall()
+{
+ fputs(lbuf, out);
+ while (fgets(lbuf, sizeof lbuf, stdin))
+ fputs(lbuf, out);
+}
+
+
+truncate()
+{
+ /* Truncate those "...remote from..." header lines. */
+ /* They're kept only if the message is to be uucp-forwarded */
+
+#ifndef DEBUG
+ fclose (out); out=fopen(tmpfil, "w");
+#endif
+
+}
+
+
+/*
+ * Compare strings (at most n bytes) without regard to case.
+ * Returns: s1>s2: >0, s1==s2: 0, s1<s2: <0.
+ */
+
+uleqn(s1, s2, n)
+register char *s1, *s2;
+register n;
+{
+
+ while (--n >= 0 && (*s1|040) == (*s2|040)) {
+ s2++;
+ if (*s1++ == '\0')
+ return(0);
+ }
+ return(n<0 ? 0 : (*s1|040) - (*s2|040));
+}
+
+
+uudate()
+{
+ char *prefix();
+
+ /* day 13 Apr 1981 20 :38 -PST */
+ fprintf(out, "Date: %sday, %.2s %.3s %.4s %.2s:%.2s-%.3s\n",
+ prefix(d1), d3, d2, d5, d4, d4+3, "???");
+}
+
+char *
+prefix(str)
+char *str;
+{
+ static char *wday[] = {
+ "Sun",
+ "Mon",
+ "Tues",
+ "Wednes",
+ "Thurs",
+ "Fri",
+ "Satur",
+ 0
+ };
+
+ register char **wp;
+
+ for(wp=wday; wp; wp++)
+ if(uleqn(str, *wp, 3) == 0)
+ return(*wp);
+ return("???");
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+static char *sccsid = "@(#)from rmail.c 4.1 (Berkeley) 10/1/80";
+/*
+ * rmail: front end for mail to stack up those stupid >From ... remote from ...
+ * lines and make a correct return address. This works with the -f option
+ * to /etc/delivermail so it won't work on systems without delivermail.
+ * However, it ought to be easy to modify a standard /bin/mail to do the
+ * same thing.
+ *
+ * NOTE: Rmail is SPECIFICALLY INTENDED for ERNIE COVAX because of its
+ * physical position as a gateway between the uucp net and the arpanet.
+ * By default, other sites will probably want /bin/rmail to be a link
+ * to /bin/mail, as it was intended by BTL. However, other than the
+ * (somewhat annoying) loss of information about when the mail was
+ * originally sent, rmail should work OK on other systems running uucp.
+ * If you don't run uucp you don't even need any rmail.
+ *
+ * This version revised around New Year's Day 1981 to interface with
+ * Rand's MH system. The nature of the revision is to (1) do nothing
+ * if the destination is uucp-remote (note the assumption of single
+ * destination) and (2) to call "/etc/mh/deliver" to do the deed.
+ *
+ * Revised Aug 1981 to add NOGATEWAY screen. Also fixed a few bugs.
+ * PK.
+ */
+
+
+#include "../mh.h"
+#include <whoami.h>
+#include <stdio.h>
+
+#define MATCH 0
+
+char *index();
+
+FILE *out; /* output to delivermail */
+char *tmpfil; /* file name of same */
+char tmpfila[24]; /* array for tmpfil */
+char *to; /* argv[1] */
+char from[512]; /* accumulated path of sender */
+char lbuf[512]; /* one line of the message */
+
+#ifdef ARPANET
+int netaddr; /* set if "to" contains an arpanet address */
+#endif
+
+main(argc, argv)
+char **argv;
+{
+ char ufrom[64]; /* user on remote system */
+ char sys[64]; /* a system in path */
+ char junk[512]; /* scratchpad */
+ char *cp;
+
+ to = argv[1];
+ if (argc != 2) {
+ fprintf(stderr, "Usage: rmail user\n");
+ exit(1);
+ }
+#ifdef DEBUG
+ out=stdout;
+ tmpfil = "/dev/tty";
+#else
+ tmpfil = tmpfila;
+ sprintf (tmpfil, "/tmp/%s", makename ("mail",".tmp"));
+ if ((out=fopen(tmpfil, "w")) == NULL) {
+ fprintf(stderr, "Can't create %s\n", tmpfil);
+ exit(1);
+ }
+#endif
+ for (;;) {
+ fgets(lbuf, sizeof lbuf, stdin);
+ if (strncmp(lbuf, "From ", 5) && strncmp(lbuf, ">From ", 6))
+ break;
+ fputs(lbuf, out); /* Save--in case we are just forwarding */
+ /* sscanf(lbuf, "%s %s %s %s %s %s %s remote from %s", junk, ufrom, junk, junk, junk, junk, junk, sys); */
+ sscanf(lbuf, "%s %s", junk, ufrom);
+ cp = lbuf;
+ for (;;) {
+ cp = index(cp+1, 'r');
+ if (cp == NULL)
+ cp = "remote from somewhere";
+#ifdef DEBUG
+ printf("cp='%s'\n", cp);
+#endif
+ if (strncmp(cp, "remote from ", 12) == MATCH)
+ break;
+ }
+ sscanf(cp, "remote from %s", sys);
+ strcat(from, sys);
+ strcat(from, "!");
+#ifdef DEBUG
+ printf("ufrom='%s', sys='%s', from now '%s'\n", ufrom, sys, from);
+#endif
+ }
+ strcat(from, ufrom);
+
+#ifdef DEBUG
+ printf("from now '%s'\n", from);
+#endif
+
+
+#ifdef ARPANET
+ netaddr = isarpa(to); /* Arpanet destination? */
+
+#ifdef NOGATEWAY
+ if(netaddr && !okhost(sys))
+ {
+ truncate();
+ returnmail("Sorry, not an Arpanet gateway!");
+ exit(0);
+ }
+#endif
+
+ if (index (to, '!') && !netaddr) {
+#else
+ if (index (to, '!')) {
+#endif
+ /* Just forwarding! */
+ putmsg();
+ deliver(to);
+ exit(0);
+ }
+
+ truncate();
+ /* fprintf(out, "To: %s\n",to); */
+ putfrom();
+
+ if( !((cp = index(lbuf, ':')) && (cp - lbuf < NAMESZ )))
+ fputs("\n",out);/* Doesn't look good; terminate hdr */
+
+ putmsg();
+ deliver(to);
+
+}
+
+
+deliver(to)
+ char *to;
+{
+ int sts,pid,waitid;
+
+#ifdef DEBUG
+ printf("%s would get called here; Delivery to: %s \n", mh_deliver,to);
+ exit(0);
+#endif
+ fclose(out);
+
+ if ((pid=fork()) == -1) {
+ fprintf(stderr, "Cannot fork Deliver!\n");
+
+#ifndef DEBUG /* Extra precaution */
+ unlink(tmpfil);
+#endif
+ exit(1);
+ }
+ if(pid) {
+ while(((waitid = wait(&sts)) != pid) && (waitid != -1));
+
+#ifndef DEBUG /* Extra precaution */
+ unlink(tmpfil);
+#endif
+ exit(0);
+ }
+ execl(mh_deliver, "deliver", "-deliver", to, tmpfil, 0);
+
+ perror( "Cannot exec Deliver ");
+
+ exit(1);
+
+}
+
+#ifdef ARPANET
+
+isarpa(str) /* Gateway to Arpanet? */
+ char *str;
+{
+ char *cp;
+
+ if (index (str, '@'))
+ return(1);
+
+ for (cp = str; ;) {
+ if((cp = index(cp, ' ')) == NULL)
+ return(0);
+ while(*cp == ' ')
+ cp++;
+ if ((strncmp(cp, "at ", 3) == MATCH) ||
+ (strncmp(cp, "AT ", 3) == MATCH) ||
+ (strncmp(cp, "At ", 3) == MATCH))
+
+ return(1);
+ }
+}
+
+
+okhost(str) /* Host permitted to use us as an arpanet gateway? */
+ char *str;
+{
+ register short i;
+
+ for (i=0; rhosts[i]; i++)
+ if (strcmp (str, rhosts[i]) == MATCH)
+ return(1);
+ return(0);
+}
+
+#endif
+
+returnmail(message)
+ char *message;
+{
+
+#ifdef DEBUG
+ printf("returnmail()\n");
+#endif
+ if(!from) return;
+
+ putdate();
+ fprintf(out, "To: %s\n", from);
+ fputs("\n",out);
+ fputs (message, out);
+ fputs("\n\n\n*--------------RETURNED MESSAGE---------------*\n\n",
+ out);
+
+ putmsg();
+ deliver(from);
+
+}
+
+
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <time.h>
+
+putdate()
+{
+ long now;
+ register char *t, *p;
+ char *timezone();
+ struct timeb tb;
+ struct tm *tmp;
+ static char *wday[] = {
+ "Sun",
+ "Mon",
+ "Tues",
+ "Wednes",
+ "Thurs",
+ "Fri",
+ "Satur"
+ };
+
+ now = time((long *)0);
+ t = ctime(&now);
+ ftime(&tb);
+ tmp = localtime(&now);
+ p = timezone(tb.timezone, tmp->tm_isdst);
+
+ /* day 13 Apr 1981 20 :38 -PST */
+ fprintf(out, "Date: %sday, %.2s %.3s %.4s %.2s:%.2s-%.3s\n",
+ wday[tmp->tm_wday], t+8, t+4, t+20, t+11, t+14, p);
+}
+
+
+putfrom()
+{
+ if (strlen(from))
+#ifdef ARPANET
+ if (netaddr)
+ fprintf(out, "From: %s at %s\n",from, HOSTNAME);
+ else
+ fprintf(out, "From: %s\n", from);
+#else
+ fprintf(out, "From: %s\n",from);
+#endif
+
+}
+
+
+putmsg()
+{
+ fputs(lbuf, out);
+ while (fgets(lbuf, sizeof lbuf, stdin))
+ fputs(lbuf, out);
+}
+
+
+truncate()
+{
+ /* Truncate those "...remote from..." header lines. */
+ /* They're kept only if the message is to be uucp-forwarded */
+
+#ifndef DEBUG
+ fclose (out); out=fopen(tmpfil, "w");
+#end
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <strings.h>
+
+extern struct swit anoyes[]; /* Std no/yes gans array */
+
+int subf;
+
+struct dirent {
+ short inum;
+ char name[14];
+ int pad;
+};
+
+struct swit switches[] = {
+ "help", 4, /* 0 */
+ 0, 0
+};
+
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ register char *cp, **ap;
+ char *folder, buf[128];
+ int def_fold = 0;
+ char *arguments[50], **argp;
+
+ invo_name = argv[0];
+#ifdef NEWS
+ m_news();
+#endif
+ folder = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "rmf: -%s unknown\n", cp);
+ goto leave;
+ /* -help */
+ case 0: help("rmf [+folder] [switches]", switches);
+ goto leave;
+ }
+ if(*cp == '+')
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = path(cp+1, TFOLDER);
+ else {
+ fprintf(stderr, "Usage: rmf [+folder]\n");
+ goto leave;
+ }
+ }
+ if(!m_find("path")) free(path("./", TFOLDER));
+ if(!folder) {
+ folder = m_getfolder();
+ def_fold++;
+ }
+ subf = !((!index(folder, '/')) | (*folder == '/') | (*folder == '.'));
+ if(def_fold && !subf) {
+ cp = concat("Remove folder \"", folder, "\" ?? ", NULLCP);
+ if(!gans(cp, anoyes))
+ goto leave;
+ free(cp);
+ }
+ if(rmfold(folder))
+ goto leave;
+ if(subf) { /* make parent "current" */
+ cp = copy(folder, buf);
+ while(cp > buf && *cp != '/') --cp;
+ if(cp > buf) {
+ *cp = 0;
+ if(strcmp(m_find(pfolder), buf) != 0) {
+ printf("[+%s now current]\n", buf);
+ m_replace(pfolder, buf);
+ }
+ }
+ }
+ leave:
+ m_update();
+ done(0);
+}
+
+struct dirent ent;
+
+rmfold(fold)
+char *fold;
+{
+ register char *maildir;
+ int i, leftover, cd;
+
+ leftover = 0;
+ if(!subf && strcmp(m_find(pfolder), fold) == 0) /* make default "current"*/
+ if(strcmp(m_find(pfolder), defalt) != 0) {
+ printf("[+%s now current]\n", defalt);
+ VOID fflush(stdout); /*??*/
+ m_replace(pfolder, defalt);
+ }
+ maildir = m_maildir(fold);
+ if((cd = chdir(maildir)) < 0)
+ goto funnyfold;
+ if(access(".", 2) == -1) {
+ funnyfold: if(!m_delete(concat("cur-", fold, NULLCP)))
+ printf("[Folder %s de-referenced]\n", fold);
+ else
+ fprintf(stderr, "You have no profile entry for the %s folder %s\n",
+ cd < 0 ? "unreadable" : "read-only", fold);
+ return(1);
+ }
+ i = open(".", 0);
+ ent.pad = 0;
+ while(read(i, (char *)&ent.inum, sizeof ent.name + sizeof ent.inum))
+ if(ent.inum)
+ if((ent.name[0] >= '0' && ent.name[0] <= '9') ||
+ ent.name[0] == ',' ||
+ (ent.name[0] == '.' && ent.name[1] && ent.name[1] != '.') ||
+ strcmp(ent.name, "cur") == 0 ||
+ strcmp(ent.name, "@") == 0) {
+ if(unlink(ent.name) == -1) {
+ fprintf(stderr, "Can't unlink %s:%s\n", fold,ent.name);
+ leftover++;
+ }
+ } else if(strcmp(ent.name,".") != 0 &&
+ strcmp(ent.name,"..") != 0) {
+ fprintf(stderr, "File \"%s/%s\" not deleted!\n",
+ fold, ent.name);
+ leftover++;
+ }
+ VOID close(i);
+ VOID chdir(".."); /* Move out of dir to be deleted */
+ if(!leftover && removedir(maildir))
+ return(0);
+ else
+ fprintf(stderr, "Folder %s not removed!\n", fold);
+ return(1);
+}
+
+
+removedir(dir)
+ char *dir;
+{
+ register int pid, wpid;
+ int status;
+
+ if((pid = fork()) == 0) {
+ m_update();
+ VOID fflush(stdout);
+ execl("/bin/rmdir", "rmdir", dir, 0);
+ execl("/usr/bin/rmdir", "rmdir", dir, 0);
+ fprintf(stderr, "Can't exec rmdir!!?\n");
+ return(0);
+ }
+ if(pid == -1) {
+ fprintf(stderr, "Can't fork\n");
+ return(0);
+ }
+ while((wpid = wait(&status)) != pid && wpid != -1) ;
+ if(status) {
+ fprintf(stderr, "Bad exit status (%o) from rmdir.\n", status);
+ /* return(0); */
+ }
+ retur
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <strings.h>
+char *calloc();
+
+int vecp;
+char **vec;
+struct msgs *mp;
+
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "help", 4, /* 1 */
+ 0, 0
+};
+
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100], buf[32];
+ register int msgnum;
+ register char *cp, *sp;
+ int msgp;
+ char **ap;
+ char *arguments[50], **argp;
+
+ invo_name = argv[0];
+#ifdef NEWS
+ m_news();
+#endif
+ folder = 0; msgp = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "rmm: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ /* -help */
+ case 1: help("rmm [+folder] [msgs] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = path(cp+1, TFOLDER);
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!m_find("path")) free(path("./", TFOLDER));
+#ifdef COMMENT
+ if(!msgp)
+ msgs[msgp++] = "cur";
+#endif
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!msgp) {
+ if((msgnum = m_getcur(folder)) == 0) {
+ fprintf(stderr, "%s: No current message.\n", folder);
+ goto leave;
+ }
+ goto doit;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "rmm: lasagne 'n sausage\n"); /* never get here */
+ goto leave;
+ }
+doit:
+ m_replace(pfolder, folder);
+ if((cp = m_find("delete-prog")) == NULL) {
+ if(!msgp)
+ goto lp1;
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum] & SELECTED) {
+ lp1: sp = getcpy(m_name(msgnum));
+ cp = copy(sp, buf);
+ cp[1] = 0;
+ do
+ *cp = cp[-1];
+ while(--cp >= buf && *cp != '/');
+ *++cp = ','; /* New backup convention */
+ VOID unlink(buf);
+ if(link(sp, buf) == -1 || unlink(sp) == -1)
+ fprintf(stderr, "Can't rename %s to %s.\n", sp, buf);
+ if(!msgp)
+ goto leave;
+ }
+ } else {
+ if(!msgp) {
+ vec = (char **) calloc(3, sizeof *vec);
+ vecp = 1;
+ vec[vecp++] = getcpy(m_name(msgnum));
+ goto lp2;
+ }
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "rmm: more than %d messages for deletion-prog\n",MAXARGS-2);
+ goto leave;
+ }
+ vec = (char **) calloc(MAXARGS +2, sizeof *vec);
+ vecp = 1;
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ vec[vecp++] = getcpy(m_name(msgnum));
+ lp2: vec[vecp] = 0;
+ vec[0] = r1bindex(cp, '/');
+ m_update();
+ VOID fflush(stdout);
+ execv(cp, vec);
+ fprintf(stderr, "Can't exec deletion prog--");
+ perror(cp);
+ }
+leave:
+ m_update();
+ done(0);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <strings.h>
+#include "scansub.h"
+
+long time();
+
+int hdrflag;
+int timeflag;
+int numflag;
+struct msgs *mp;
+
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "ff", 0, /* 1 */
+ "noff", 0, /* 2 */
+ "header", 0, /* 3 */
+ "noheader", 0, /* 4 */
+ "help", 4, /* 5 */
+ "time", 0, /* 6 */
+ "notime", 0, /* 7 */
+ "numdate", 0, /* 8 */
+ "nonumdate", 0, /* 9 */
+ 0, 0
+};
+
+extern char _sobuf[]; /* MLW standard out buffer */
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100];
+ register int msgnum;
+ register char *cp, **ap;
+ int msgp, ff;
+ FILE *in;
+ long now;
+ char *arguments[50], **argp;
+
+ invo_name = argv[0];
+#ifndef _IOLBF
+ setbuf(stdout, _sobuf);
+#endif _IOLBF
+#ifdef NEWS
+ m_news();
+#endif
+ ff = 0; msgp = 0; folder = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "scan: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: ff = 1; continue; /* -ff */
+ case 2: ff = 0; continue; /* -noff */
+ case 3: hdrflag = 1; continue; /* -header */
+ case 4: hdrflag = 0; continue; /* -noheader */
+ case 6: timeflag = 1; continue; /* -time */
+ case 7: timeflag = 0; continue; /* -notime */
+ case 8: numflag = 1; continue; /* -numdate */
+ case 9: numflag = 0; continue; /* -nonumdate */
+ case 5: help("scan [+folder] [msgs] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = path(cp+1, TFOLDER);
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!m_find("path")) free(path("./", TFOLDER));
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!msgp)
+ msgs[msgp++] = "first-last";
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "scan: matzo balls.\n"); /* never get here */
+ goto leave;
+ }
+ m_replace(pfolder,folder);
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
+ if(mp->msgstats[msgnum]&SELECTED) {
+ if((in = fopen(cp = m_name(msgnum), "r")) == NULL)
+ fprintf(stderr, "--Can't open %s\n", cp);
+ else {
+ if(hdrflag) {
+ now = time((long *)0);
+ cp = cdate(&now);
+ cp[9] = ' '; cp[15] = 0;
+printf("\
+ Folder %-32s%s\n\n", folder, cp);
+ }
+ VOID scan(in, msgnum, 0,
+ msgnum == mp->curmsg,
+ (timeflag ? DOTIME : 0)
+ | (numflag ? NUMDATE : 0), hdrflag);
+ hdrflag = 0;
+ VOID fclose(in);
+ if(stdout->_cnt < 80)
+ VOID fflush(stdout);
+ }
+ }
+ }
+ if(ff)
+ putchar('\014');
+leave:
+ m_update();
+ done
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* the only thing wrong with this version is that
+ the numeric date format needs to be adjusted for
+ the timezone. See adjtime() at the end of the file.
+ -- dave yost, june, 1981
+ */
+#include "../mh.h"
+#include <whoami.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+#include "../adrparse.h"
+#include "scansub.h"
+
+#define Block
+
+#define _FROM 1
+#define _NOTFROM 0
+
+#define MSGN 0 /* Start of msg name field */
+#define SMSGN DMAXFOLDER /* Length */
+#define SFLGS 2 /* Width of flag field */
+#define SDATE 7 /* Length of Date field */
+#define STIME 8 /* Length of time field */
+#define SNDATE 6 /* Length of numeric date */
+#define SNTIME 4 /* Length of numeric time */
+#define SFROM 16 /* Length of " " */
+#define SLINE 79 /* size of line */
+#define BSUBJ 20 /* Room needed in Sub field to */
+ /* add stuff from the body */
+
+FILE *scnout;
+char scanl[512];
+int local;
+int hostseen;
+char *frmtok();
+
+scan(inb, innum, outnum, curflg, howdate, header)
+ FILE *inb;
+ int outnum;
+{
+
+ char buf[BUFSIZ], name[NAMESZ], tobuf[32], frombuf[32];
+ register char *cp, **tok1;
+ int state, subsz, first, compnum;
+ static char *myname;
+ int f_msgn; /* Start of msg name field */
+ int f_smsgn; /* Length */
+ int f_flgs; /* Start of flags field */
+ int f_sflgs; /* Width of flag field */
+ int f_date; /* Start of Date field */
+ int f_sdate; /* Length */
+ int f_from; /* Start of From field */
+ int f_sfrom; /* Length of " " */
+ int f_subj; /* Start of Subject field */
+ int f_ssubj; /* Size of Subject field */
+ int f_bsubj; /* Room needed in Sub field to */
+ /* add stuff from the body */
+
+ f_msgn = MSGN;
+ f_smsgn = SMSGN;
+ f_flgs = f_msgn + f_smsgn;
+ f_sflgs = SFLGS;
+ f_date = f_flgs + f_sflgs;
+
+ switch (howdate) {
+ default:
+ f_sdate = SDATE;
+ break;
+
+ case DOTIME:
+ f_sdate = SDATE + 1 + STIME;
+ break;
+
+ case NUMDATE:
+ f_sdate = SNDATE;
+ break;
+
+ case DOTIME | NUMDATE:
+ f_sdate = SNDATE + SNTIME;
+ break;
+ }
+ f_from = f_date + f_sdate + 1;
+ f_sfrom = SFROM;
+ f_subj = f_from + f_sfrom + 2;
+ f_ssubj = SLINE - f_subj;
+ f_bsubj = BSUBJ;
+
+ local = 0; hostseen = 0;
+ if(!myname)
+ myname = getenv("USER");
+ tobuf[0] = 0; frombuf[0] = 0;
+ first = 0;
+ state = FLD;
+ compnum = 1;
+
+ if (header)
+ printf (" # %-*sFrom Subject [<<Body]\n\n",
+ f_from - f_date - 1,
+ howdate == DOTIME ? "Date Time" : "Date");
+ for(;;) {
+
+ state = m_getfld(state, name, buf, sizeof buf, inb);
+ if(!first++ && state != FILEEOF) { /*##*/
+ if(outnum) {
+ cp = m_name(outnum);
+ if(*cp == '?') /* msg num out of range */
+ return(-2);
+ if((scnout = fopen(cp, "w")) == NULL) {
+ fprintf(stderr, "Error creating msg ");
+ perror(cp); done(-1);
+ }
+ VOID chmod(cp, m_gmprot());
+ }
+ sfill(scanl, sizeof scanl);
+ scanl[sizeof scanl - 1] = 0;
+ subsz = 0;
+ tobuf[0] = 0;
+ }
+
+ switch(state) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ compnum++;
+ if(uleq(name, "from"))
+ frombuf[cpyfrm(buf,frombuf,sizeof frombuf,_FROM)]
+ = 0;
+ else if(uleq(name, "date"))
+ cpydat(buf, &scanl[f_date], f_sdate, howdate);
+ else if(uleq(name, "subject") && scanl[f_subj] == ' ')
+ subsz = cpy(buf, &scanl[f_subj], f_ssubj);
+ else if(uleq(name, "to") && !tobuf[0])
+ tobuf[
+ cpyfrm(buf,tobuf,sizeof tobuf-1,_NOTFROM)]=0;
+ else if(uleq(name, "replied"))
+ VOID cpy("-", &scanl[f_flgs+1], 1);
+ put(name, buf, scnout);
+ while(state == FLDPLUS) {
+ state=m_getfld(state,name,buf,sizeof buf,inb);
+ if(scnout)
+ fputs(buf, scnout);
+ }
+ if(state == FLDEOF)
+ goto putscan;
+ continue;
+
+ case BODY:
+ case BODYEOF:
+ compnum = -1;
+ if(buf[0] && subsz < f_ssubj - f_bsubj) {
+ int bodsz;
+ scanl[f_subj+subsz+1] = '<';
+ scanl[f_subj+subsz+2] = '<';
+ bodsz= cpy(buf, scanl+f_subj+subsz+3,
+ f_ssubj-subsz-3);
+ if(bodsz < f_ssubj - subsz - 3)
+ scanl[f_subj+subsz+3 + bodsz] = '>';
+ if(bodsz < f_ssubj - subsz - 4)
+ scanl[f_subj+subsz+4 + bodsz] = '>';
+ subsz = f_ssubj;
+ }
+ if(buf[0] && scnout) {
+ putc('\n', scnout);
+ fputs(buf, scnout);
+ if(ferror(scnout)) {
+ fprintf(stderr, "Write error on ");
+ perror(m_name(outnum));done(-1);
+ }
+ }
+ body:
+ if (!scnout)
+ state = FILEEOF; /* stop now if scan cmd */
+ else while(state == BODY) { /*else inc, so copy body*/
+ state=m_getfld(state,name,buf,sizeof buf,inb);
+ if(state != FILEEOF)
+ fputs(buf, scnout);
+ }
+ if(state == BODYEOF || state == FILEEOF) {
+ putscan: cpymsgn(m_name(innum), &scanl[f_msgn], f_smsgn);
+ tok1= brkstring(getcpy(frombuf), " ", "\n");
+ if(!frombuf[0] || uleq(frombuf, myname) ||
+ (local && uleq(*tok1, myname))) {
+ VOID cpy("To:", &scanl[f_from], 3);
+ VOID cpy(tobuf, &scanl[f_from+3], f_sfrom-3);
+ } else
+ VOID cpy(frombuf, &scanl[f_from], f_sfrom);
+ if(curflg)
+ VOID cpy("+", &scanl[f_flgs], f_sflgs);
+ trim(scanl);
+ fputs(scanl, stdout);
+
+ if(scnout) {
+ VOID fflush(scnout);
+ if(ferror(scnout)) {
+ perror("Write error on ");
+ perror(m_name(outnum));
+ done(-1);
+ }
+ VOID fclose(scnout);
+ scnout = NULL;
+ }
+ return(1);
+ }
+ break;
+
+ case LENERR:
+ case FMTERR:
+ fprintf(stderr, "??Message Format Error ");
+ fprintf(stderr, "(Message %d) ", outnum ? outnum :innum);/*##*/
+ if(compnum < 0) fprintf(stderr, "in the Body.\n");
+ else fprintf(stderr, "in Component #%d.\n", compnum);
+ fprintf(stderr, "-----------------------------------------");
+ fprintf(stderr, "-------------------------------------\n");
+ goto badret;
+ default:
+ fprintf(stderr, "Getfld returned %d\n", state);
+
+
+ badret: if(outnum) {
+ fputs("\n\nBAD MSG:\n", scnout);
+ if(compnum < 0)
+ fputs(buf, scnout);
+ else {
+ fputs(name, scnout);
+ putc('\n', scnout);
+ }
+ /*** ungetc(inb); ***/
+ state = BODY;
+ goto body;
+
+ }
+ if(scnout)
+ VOID fflush(scnout);
+ return(-1);
+ case FILEEOF:
+ return(0);
+
+ }
+
+ }
+}
+
+
+trim(str)
+char *str;
+{
+ register char *cp;
+
+ cp = str;
+ while(*cp) cp++;
+ while(*--cp == ' ') ;
+ cp++;
+ *cp++ = '\n';
+ *cp++ = 0;
+}
+
+sfill(str, cnt)
+char *str;
+{
+ register char *cp;
+ register int i;
+
+ cp = str; i = cnt;
+ do
+ *cp++ = ' ';
+ while(--i);
+}
+
+
+put(name, buf, ip)
+ char *name, *buf;
+ register FILE *ip;
+{
+ if(ip) {
+ fputs(name, ip);
+ putc(':', ip);
+ fputs(buf, ip);
+ if(ferror(ip)) { perror("Write error");done(-1);}
+ }
+}
+
+
+cpy(from, to, cnt)
+ register char *from, *to;
+ register int cnt;
+{
+ register int c;
+ char *savto;
+
+ savto = to;
+ while(*from == ' ' || *from == '\t' || *from == '\n' || *from == '\f')
+ from++;
+ while(cnt--)
+ if(c = *from) {
+ if(c == '\t' || c == ' ' || c == '\n' || c == '\f') {
+ *to++ = ' ';
+ do
+ from++;
+ while((c= *from)==' '||c=='\t'||c=='\n'||c=='\f');
+ continue;
+ } else {
+ *to++ = c;
+ from++;
+ }
+ } else
+ break;
+ return(to - savto); /*Includes 1 char trailing white space, if any*/
+}
+
+struct tm *localtime();
+long time();
+char *findmonth();
+
+struct date {
+ char *day;
+ char *month;
+ char *year;
+ char *timestr;
+ char *zone;
+ char zoneadd;
+ };
+
+cpydat(sfrom, sto, cnt, how)
+ char *sfrom, *sto;
+{
+ register char *cp;
+ register char *to;
+ static struct tm *locvec;
+ char frombuf[100];
+ char buf[30]; /* should be char buf[cnt + 1] */
+ long now;
+ struct date dt;
+
+ strncpy(frombuf, sfrom, sizeof frombuf);
+ frombuf[sizeof frombuf -1] = '\0';
+ if(!locvec) {
+ now = time((long *)0);
+ locvec = localtime(&now);
+ }
+
+ /* Collect the various fields of the date */
+ for(cp = frombuf; *cp < '0' || *cp > '9'; cp++)
+ if(!*cp)
+ return;
+
+ /* get the day */
+ dt.day = cp;
+ while (isdigit(*cp))
+ cp++;
+ if (*cp)
+ *cp++ = '\0';
+
+ /* get the month */
+ while (*cp && !isalpha(*cp))
+ cp++;
+ dt.month = cp;
+ while (isalpha (*cp))
+ cp++;
+ if (*cp)
+ *cp++ = '\0';
+
+ /* get the year */
+ while (*cp && !isdigit(*cp))
+ cp++;
+ dt.year = cp;
+ while (isdigit(*cp))
+ cp++;
+ if (*cp)
+ *cp++ = '\0';
+
+ /* Point timestr at the time, and remove colons, if present */
+ while (*cp && !isdigit(*cp))
+ cp++;
+ dt.timestr = to = cp;
+ for (; isdigit(*cp) || *cp == ':'; cp++)
+ if (*cp != ':')
+ *to++ = *cp;
+ if (*cp)
+ cp++;
+ *to = '\0';
+
+ /* get the time zone. */
+ /* Can be alphas as in PST */
+ /* If plus/minus digits, then set zoneadd to the + or - */
+ /* point zone at the string of digits or alphas */
+ dt.zoneadd = '\0';
+ while (*cp && !isalpha(*cp) && !isdigit(*cp)) {
+ if (*cp == '+' || *cp == '-')
+ dt.zoneadd = *cp;
+ cp++;
+ }
+ dt.zone = cp;
+ if (isdigit(*cp))
+ while (isdigit (*cp))
+ cp++;
+ else {
+ dt.zoneadd = '\0';
+ while (isalpha (*cp))
+ cp++;
+ }
+ if (*cp)
+ *cp++ = '\0';
+
+ /* printf ("Yr='%s' Mo='%s' Day='%s' Time='%s' Zone='%s'\n",
+ dt.year, dt.month, dt.day, dt.timestr, dt.zone);
+ if(cp = findmonth(dt.month))
+ printf ("month='%s'\n", cp);
+ return;
+ /**/
+ to = buf;
+ if(cp = findmonth(dt.month)) {
+ if (how & NUMDATE) {
+ adjtime(&dt);
+ if(strlen(dt.year) >= 2) {
+ cp = &dt.year[strlen(dt.year) - 2];
+ *to++ = *cp++;
+ *to++ = *cp++;
+ }
+ else {
+ *to++ = ' ';
+ *to++ = ' ';
+ }
+ if ((cp = findmonth(dt.month))[1])
+ *to++ = *cp++;
+ else
+ *to++ = '0';
+ *to++ = *cp++;
+ if (*(cp = dt.day)) {
+ if (cp[1])
+ *to++ = *cp++;
+ else
+ *to++ = '0';
+ *to++ = *cp++;
+ }
+ else {
+ *to++ = ' ';
+ *to++ = ' ';
+ }
+ *to = '\0';
+ if (how & DOTIME) {
+ /* kludge for now */
+ dt.timestr[4] = '\0';
+ strcpy (to, dt.timestr);
+ }
+ }
+ else {
+ if(!cp[1])
+ *to++ = ' ';
+ while(*cp)
+ *to++ = *cp++;
+ *to++ = '/';
+
+ cp = dt.day;
+ if(!cp[1])
+ *to++ = ' ';
+ while(*cp >= '0' && *cp <= '9')
+ *to++ = *cp++;
+ Block {
+ register int yr;
+ if( ( (yr = atoi(dt.year)) > 1970
+ && yr - 1900 < locvec->tm_year
+ )
+ || yr < locvec->tm_year
+ ) {
+ *to++ = '/';
+ *to++ = (yr - (yr < 100 ? 70 : 1970))
+ % 10 + '0';
+ }
+ else {
+ *to++ = ' ';
+ *to++ = ' ';
+ }
+ }
+ *to = '\0';
+ if (how & DOTIME) {
+ *to++ = ' ';
+ sprintf (to, "%4.4s", dt.timestr);
+ to += 4;
+ if (*dt.zone) {
+ *to++ = '-';
+ strncpy(to, dt.zone, 3);
+ }
+ }
+ }
+ }
+ else {
+ cp = dt.day;
+ if(!cp[1])
+ *to++ = ' ';
+ while(*cp)
+ *to++ = *cp++;
+ }
+ Block {
+ register int tmp;
+ if (cnt < (tmp = strlen(buf)))
+ tmp = cnt;
+ strncpy(sto, buf, tmp);
+ }
+ return;
+}
+
+
+char *fromp, fromdlm, pfromdlm;
+
+cpyfrm(sfrom, sto, cnt, fromcall)
+char *sfrom, *sto;
+{
+ register char *to, *cp;
+ register int c;
+
+ fromdlm = ' ';
+ fromp = sfrom; to = sto;
+ cp = frmtok();
+ do
+ if(c = *cp++)
+ *to++ = c;
+ else
+ break;
+ while(--cnt);
+ for(;;) {
+ if(cnt < 3) break;
+ if(*(cp = frmtok()) == 0) break;
+ if(*cp == '@' || uleq(cp, "at")) {
+ cp = frmtok();
+ if(uleq(cp, HOSTNAME)) {
+ /* if the first "From:" host is local */
+ if(fromcall != _NOTFROM && !hostseen++)
+ local++;
+ } else {
+ *to++ = '@';
+ cnt--;
+ do
+ if(c = *cp++)
+ *to++ = c;
+ else
+ break;
+ while(--cnt);
+ }
+ } else if(cnt > 4) {
+ cnt--; *to++ = pfromdlm;
+ do
+ if(c = *cp++)
+ *to++ = c;
+ else
+ break;
+ while(--cnt);
+ }
+ }
+ if(fromcall != _NOTFROM)
+ hostseen++;
+ return(to - sto);
+}
+
+
+char *frmtok()
+{
+ static char tokbuf[64];
+ register char *cp;
+ register int c;
+
+ pfromdlm = fromdlm;
+ cp = tokbuf; *cp = 0;
+ while(c = *fromp++) {
+ if(c == '\t')
+ c = ' ';
+ if(c == ' ' && cp == tokbuf)
+ continue;
+ if(c == ' ' || c == '\n' || c == ',')
+ break;
+ *cp++ = c;
+ *cp = 0;
+ if(c == '@' || *fromp == '@' || cp == &tokbuf[63])
+ break;
+ }
+ fromdlm = c;
+ return(tokbuf);
+}
+
+
+/* num specific! */
+
+/* copy msgnam to addr, right justified */
+cpymsgn(msgnam, addr, len)
+char *msgnam, *addr;
+{
+ register char *cp, *sp;
+
+ sp = msgnam;
+ cp = &addr[len - strlen(sp)];
+ if (cp < addr)
+ cp = addr;
+ while(*sp)
+ *cp++ = *sp++;
+}
+
+char *monthtab[] = {
+ "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec",
+};
+
+char *findmonth(str)
+char *str;
+{
+ register char *cp, *sp;
+ register int i;
+ static char buf[4];
+
+ for(cp=str, sp=buf; (*sp++ = *cp++) && sp < &buf[3] && *cp != ' '; )
+ continue;
+ *sp = 0;
+ for(i = 0; i < 12; i++)
+ if(uleq(buf, monthtab[i])) {
+ VOID sprintf(buf, "%d", i+1);
+ return buf;
+ }
+ return(0);
+}
+
+struct tzone {
+ char *z_nam;
+ int z_hour;
+ int z_min;
+};
+struct tzone zonetab[] = {
+ { "GMT", 0, 0, },
+ { "NST", -3, -30, },
+ { "AST", -4, 0, },
+ { "ADT", -3, 0, },
+ { "EST", -5, 0, },
+ { "EDT", -4, 0, },
+ { "CST", -6, 0, },
+ { "CDT", -5, 0, },
+ { "MST", -7, 0, },
+ { "MDT", -6, 0, },
+ { "PST", -8, 0, },
+ { "PDT", -7, 0, },
+ { "YST", -9, 0, },
+ { "YDT", -8, 0, },
+ { "HST", -10, 0, },
+ { "HDT", -9, 0, },
+ { "BST", -11, 0, },
+ { "BDT", -10, 0, },
+ { "Z", 0, 0, },
+ { "A", -1, 0, },
+ { "M", -12, 0, },
+ { "N", 1, 0, },
+ { "Y", 12, 0, },
+ { 0 }
+ };
+
+/* adjust for timezone */
+adjtime(dt)
+ register struct date *dt;
+{
+ /* what we should do here is adjust all other timezones to our own */
+ return;
+
+ /* if (isdigit (dt->zone[0])) {
+ atoi ...
+ if (dt->zoneadd == '+')
+ ;
+ }
+ else {
+ }
+ return;
--- /dev/null
+
+#define DOTIME 1 /* show the time with the date */
+#define NUMDATE 2 /* do entire date like yymmdd */
+ /* or yymmddhhmm if DOTIME set */
+ /* not implemented yet */
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <stat.h>
+#include <strings.h>
+#include <signal.h>
+
+extern struct swit anoyes[]; /* Std no/yes gans array */
+
+char *vec[20];
+int vecp = 1;
+
+struct swit switches[] = {
+ "debug", -5, /* 0 */
+ "draft", 0, /* 1 */
+ "format", 0, /* 2 */
+ "noformat", 0, /* 3 */
+ "msgid", 0, /* 4 */
+ "nomsgid", 0, /* 5 */
+ "verbose", 0, /* 6 */
+ "noverbose", 0, /* 7 */
+ "help", 4, /* 8 */
+ 0, 0
+};
+
+int debug;
+
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ register char *drft, *cp;
+ register int i;
+ int status, pid;
+ struct stat stbuf;
+ char **ap;
+ char *arguments[50], **argp;
+
+ invo_name = argv[0];
+#ifdef NEWS
+ m_news();
+#endif
+ drft = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "send: -%s unknown\n", cp);
+ goto leave;
+ /* -draft */
+ case 1: vec[vecp++] = drft = m_maildir(draft);
+ continue;
+ case 0: debug++;
+ case 2: case 3: case 4:
+ case 5: case 6: case 7:
+ vec[vecp++] = --cp;
+ continue;
+ case 8: help("send [file] [switches]",
+ switches);
+ goto leave;
+ }
+ if(drft) {
+ fprintf(stderr, "Send: Only one message at a time.\n");
+ done(1);
+ }
+ vec[vecp++] = drft = cp;
+ }
+ if(!drft) {
+ drft = m_maildir(draft);
+ if(stat(drft, &stbuf) == -1) {
+ fprintf(stderr, "Draft file: %s doesn't exist.\n", drft);
+ done(1);
+ }
+ cp = concat("Use \"", drft, "\"? ", 0);
+ if(!gans(cp, anoyes))
+ done(0);
+ vec[vecp++] = drft;
+ } else {
+ if(stat(drft, &stbuf) == -1) {
+ fprintf(stderr, "Draft file: %s doesn't exist.\n", drft);
+ done(1);
+ }
+ }
+ m_update();
+ vec[vecp] = 0;
+ vec[0] = r1bindex(mh_deliver, '/');
+
+ while((pid = fork()) == -1) {
+ fprintf(stderr, "Waiting for a fork\n");
+ sleep(2);
+ }
+ if(pid == 0) {
+ execv(mh_deliver, vec);
+ perror(mh_deliver);
+ done(1);
+ }
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ while((i = wait(&status)) != -1 && i != pid) ;
+ if(status == 0 && !debug)
+ backup(drft);
+
+leave: ;
+/*** m_update(); ***/
+}
+
+
+backup(file)
+char *file;
+{
+ char buf[128];
+ register char *cp;
+
+ buf[0] = 0;
+ if(cp = rindex(file, '/'))
+ sprintf(buf, "%.*s", (++cp)-file, file);
+ else
+ cp = file;
+ strcat(buf, ",");
+ strcat(buf, cp);
+ unlink(buf);
+ if(link(file, buf) < 0 || unlink(file) < 0) {
+ fprintf(stderr, "Send: Backup rename failure ");
+ perror(buf);
+ done(1);
+ }
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <strings.h>
+
+int vecp;
+int header = 1;
+char *vec[MAXARGS];
+struct msgs *mp;
+/* The minimum match numbers below are all at least 2 as
+/* a kludge to avoid conflict between switches intended for
+/* "show" and those that it passes on to pr, mhl, c, ...
+/**/
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "draft", 2, /* 1 */
+ "header", 2, /* 2 */
+ "noheader", 2, /* 3 */
+ "format", 2, /* 4 */
+ "noformat", 2, /* 5 */
+ "pr", 2, /* 6 */
+ "nopr", 2, /* 7 */
+ "help", 4, /* 8 */
+ 0, 0
+};
+
+extern char _sobuf[]; /* MLW standard out buffer */
+
+/*ARGSUSED*/
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100];
+ register int msgnum;
+ register char *cp, **ap;
+ int msgp, drft, pr, format;
+ char *arguments[50], **argp;
+
+ invo_name = argv[0];
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ folder = (char *) 0;
+ pr = msgp = 0;
+ format = 1;
+ vecp = 1;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ VOID copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:vec[vecp++] = --cp; continue;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: drft = 1; continue; /* -draft */
+ case 2: header = 1; continue; /* -header */
+ case 3: header = 0; continue; /* -noheader */
+ case 4: format = 1; continue; /* -format */
+ case 5: format = 0; continue; /* -noformat */
+ case 6: pr = 1; continue; /* -pr */
+ case 7: pr = 0; vecp = 1; continue;/* -nopr */
+ case 8: /* -help */
+ help("show [+folder] [msgs] [switches] [switches for \"type\" or \"pr\" ]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = path(cp+1, TFOLDER);
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!m_find("path")) free(path("./", TFOLDER));
+ if(drft)
+ maildir = m_maildir("");
+ else {
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ }
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(drft) {
+ vec[vecp++] = draft;
+ goto doit;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(msgp)
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "show: potato pancakes.\n"); /* never get here */
+ goto leave;
+ }
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "show: more than %d messages for show-exec\n", MAXARGS-2);
+ goto leave;
+ }
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ vec[vecp++] = getcpy(m_name(msgnum));
+ m_replace(pfolder, folder);
+ if(mp->hghsel != mp->curmsg)
+ m_setcur(mp->hghsel);
+ if(vecp == 2 && header) {
+ printf("(Message %s:%s)\n", folder, vec[1]);
+ }
+doit:
+ VOID fflush(stdout);
+ vec[vecp] = 0;
+ {
+ register char *proc;
+ if(pr)
+ proc = prproc;
+ else if(format) {
+ extern char *r1bindex();
+ putenv("mhfolder", folder);
+ if (!strcmp (r1bindex(showproc, '/'), "mhl")) {
+ mhl(vecp, vec);
+ m_update();
+ done(0);
+ }
+ proc = showproc;
+ } else {
+ proc = "/bin/cat";
+ /* THIS IS INEFFICIENT */
+ /* what we really should do in this case is
+ /* copy it out ourself to save the extra exec */
+ }
+ m_update();
+ vec[0] = r1bindex(proc, '/');
+ execv(proc, vec);
+ perror(proc);
+ }
+ done(0);
+ leave:
+ m_update();
+ done(0);
+}
+
+#define switches mhlswitches
+#define INCLUDED_BY_SHOW
+#define main(a,b) mhl(a,b)
+
+#include
\ No newline at end of file
--- /dev/null
+#
+# Proprietary Rand Corporation, 1981.
+# Further distribution of this software
+# subject to the terms of the Rand
+# license agreement.
+#
+
+LIB = strings.a
+OFILES =\
+ anoyes.o \
+ components.o \
+ current.o \
+ defalt.o \
+ distcomps.o \
+ draft.o \
+ fileproc.o \
+ foldprot.o \
+ installproc.o \
+ listname.o \
+ lockdir.o \
+ lproc.o \
+ lsproc.o \
+ mailboxes.o \
+ mailproc.o \
+ mh_deliver.o \
+ mh_prof.o \
+ mhlformat.o \
+ mhlstdfmt.o \
+ mhnews.o \
+ msgprot.o \
+ pfolder.o \
+ prproc.o \
+ rhosts.o \
+ scanproc.o \
+ sendproc.o \
+ showproc.o \
+ stdcomps.o \
+ stddcomps.o \
+ sysed.o \
+ sysname.o
+
+CFILES = anoyes.c \
+ components.c \
+ current.c \
+ defalt.c \
+ distcomps.c \
+ draft.c \
+ fileproc.c \
+ foldprot.c \
+ installproc.c \
+ listname.c \
+ lockdir.c \
+ lproc.c \
+ lsproc.c \
+ mailboxes.c \
+ mailproc.c \
+ mh_deliver.c \
+ mh_prof.c \
+ mhlformat.c \
+ mhlstdfmt.c \
+ mhnews.c \
+ msgprot.c \
+ pfolder.c \
+ prproc.c \
+ rhosts.c \
+ scanproc.c \
+ sendproc.c \
+ showproc.c \
+ stdcomps.c \
+ stddcomps.c \
+ sysed.c \
+ sysname.c
+
+$(LIB): $(OFILES)
+ -rm -f $(LIB)
+ ar cr $(LIB) $(OFILES)
+ ranlib $(LIB)
+
+distribution: clean
+ -rm -f $(LIB)
+
+clean:
+ -rm -f $(OFILES)
+
+depend:
+ ../misc/depend.sh $(CFILES)
+
+
+###DEPENDENCIES Follow. Do not delete this line
+anoyes.o: ../mh.h
+#lockdir.o: /usr/include/mailsys.h
+#mailboxes.o: /usr/include/mailsys.h
+rhosts.o: ../mh.h
+#sysname.o: /usr/include/whoami.h
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+
+struct swit anoyes[] = {
+ "no", 0,
+ "yes", 0,
+ 0,
+};
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char *components = "components";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char *current = "cur";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char *defalt = "inbox";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char *distcomps = "distcomps";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char *draft = "draft";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This program is usually called directly by users, but it is
+ * also invoked by the deliver program to process an "fcc".
+ */
+
+char *fileproc = "/usr/local/file";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * Folders (directories) are created with this protection (mode)
+ */
+
+char *foldprot = "0751";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * When a user runs an MH program for the first time, this program
+ * is called to create his MH profile, and mail directory.
+ */
+
+char *installproc = "/etc/mh/install-mh";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char *listname = "select";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This is where the lock files are kept. It MUST be on the same
+ * file system as the "mailboxes" directory. It also must be read/
+ * write by the world. When a mailbox needs locking (while being
+ * read and cleared by inc, or written by deliver), a link to the
+ * mailbox is made in this directory, under the same name (i.e., the
+ * users name). Links are one of the few things even a privileged
+ * process (deliver) cannot over-ride. The deliver process waits
+ * for lockwait seconds for the lock to clear, then it over-rides
+ * the lock. This number should be set around 15-30 seconds in the
+ * case of a VERY loaded system.
+ */
+
+#include <mailsys.h>
+
+char *lockdir = MAILLOCKDIR;
+short lockwait = 15; /* Sec
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This is the program invoked by a "list" response to "What now?"
+ * whereas, showproc is the program invoked by show, next, prev,
+ * "pick -show".
+ */
+
+char *lproc = "/usr/ucb/more";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This is standard ls, but "folder -all -short" calls it with
+ * a -x switch meaning "list only directories".
+ *
+ * Also, its nice to have columnated output rather than a simple
+ * list... (personal prejudice).
+ */
+
+char *lsproc = "/usr/ucb/ls";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This is where the user mailboxes are kept. On our 11/70 they were
+ * kept in each users $HOME directory. This is where the VAX login
+ * program is looking for them, as well as the old BELL mail.
+ */
+
+#include <mailsys.h>
+
+char *mailboxes = MAILDROP;
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This is the path for the Bell equivalent mail program... Used
+ * by "news -send" to send news items to the news user.
+ */
+
+char *mailproc = "/usr/ucb/mail";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This is the delivery program called ONLY through send to
+ * actually deliver mail to users. It is fairly small, and
+ * must run SUID ROOT, to create new mailboxes.
+ */
+
+char *mh_deliver = "/etc/mh/deliver";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char *mh_prof = "/.mh_profile";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char *mhlformat = "mhl.format";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char *mhlstdfmt = "/etc/mh/mhl.format";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This program is called to print out MH news IF NEWS is defined
+ * when the MH programs are compiled. This whole mechanism has not
+ * been tested under version 7!
+ */
+
+char *mhnews = "/etc/mh/news";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * Every NEW message will be created with this protection. When a
+ * message is filed it retains its protection, so this only applies
+ * to messages coming in through inc.
+ */
+
+char *msgprot = "0664";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char *pfolder = "current-folder";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This is the std BELL pr, which is invoked through show with the
+ * -pr switch.
+ */
+
+char *prproc = "/bin/pr";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+
+#ifdef ARPANET
+
+#ifdef NOGATEWAY
+
+/* rhosts is a list of legal uucp hosts who are allowed to
+/* send stuff out over the arpanet.
+/**/
+
+char *rhosts[] = {
+ 0
+ };
+
+#endif
+
+#endif
+
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This program is usually called directly by users, but it is
+ * also invoked by "pick -scan".
+ */
+
+char *scanproc = "/usr/local/scan";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This program is usually called by one of the message composition
+ * programs: comp, repl, dist, and forw, but it may also be called
+ * directly to send a message previously composed.
+ */
+
+char *sendproc = "/usr/local/send";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This program is called to list messages. At Rand, the program
+ * `c' stops at the end of each page and waits for a <return> or
+ * <open> to continue. Eventually, this path should invoke a
+ * special program which displays messages much more intelligently--
+ * such as layed out nicely on the screen.
+ */
+
+char *showproc = "/usr/ucb/more"; /* 5/6/79 */
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This is the standard skeleton for message composition with both
+ * comp and forw.
+ */
+
+char *stdcomps = "/etc/mh/components";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This is the standard skeleton for message composition with dist.
+ */
+
+char *stddcomps = "/etc/mh/distcomps";
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This is the editor invoked by the various message composition
+ * programs. It SHOULD be a 2-D scope editor, such as Rand's Ned
+ * or Berkeley's ex, but any editor will work. If you don't have
+ * a scope editor, you might want to default to prompter, but it
+ * works very marginally with forw and dist.
+ */
+
+char *sysed = "/bin/e";
--- /dev/null
+#include <whoami.h>
+
+#ifndef sysname
+char sysname[] = SYSNAME;
+#endif
--- /dev/null
+#
+# Proprietary Rand Corporation, 1981.
+# Further distribution of this software
+# subject to the terms of the Rand
+# license agreement.
+#
+
+CFLAGS = -O -I/usr/include -I../support # -m
+LIB = subs.a
+OFILES =\
+ add.o \
+ ambigsw.o \
+ atooi.o \
+ brkstring.o \
+ cdate.o \
+ cndfree.o \
+ concat.o \
+ copy.o \
+ copyip.o \
+ cputc.o \
+ done.o \
+ fdcompare.o \
+ gans.o \
+ getans.o \
+ getcpy.o \
+ help.o \
+ locv.o \
+ m_convert.o \
+ m_delete.o \
+ m_edit.o \
+ m_file.o \
+ m_find.o \
+ m_getcur.o \
+ m_getdefs.o \
+ m_getfld.o \
+ m_getfolder.o \
+ m_gmprot.o \
+ m_gmsg.o \
+ m_maildir.o \
+ m_name.o \
+ m_replace.o \
+ m_send.o \
+ m_setcur.o \
+ m_update.o \
+ makedir.o \
+ makename.o \
+ mu_atoi.o \
+ path.o \
+ peekc.o \
+ pr_array.o \
+ printsw.o \
+ putenv.o \
+ pwd.o \
+ r1bindex.o \
+ showfile.o \
+ smatch.o \
+ ssequal.o \
+ trimcpy.o \
+ type.o \
+ uleq.o
+
+CFILES =\
+ add.c \
+ ambigsw.c \
+ atooi.c \
+ brkstring.c \
+ cdate.c \
+ cndfree.c \
+ concat.c \
+ copy.c \
+ copyip.c \
+ cputc.c \
+ done.c \
+ fdcompare.c \
+ gans.c \
+ getans.c \
+ getcpy.c \
+ help.c \
+ locv.c \
+ m_convert.c \
+ m_delete.c \
+ m_edit.c \
+ m_file.c \
+ m_find.c \
+ m_getcur.c \
+ m_getdefs.c \
+ m_getfld.c \
+ m_getfolder.c \
+ m_gmprot.c \
+ m_gmsg.c \
+ m_maildir.c \
+ m_name.c \
+ m_replace.c \
+ m_send.c \
+ m_setcur.c \
+ m_update.c \
+ makedir.c \
+ makename.c \
+ mu_atoi.c \
+ path.c \
+ peekc.c \
+ pr_array.c \
+ printsw.c \
+ putenv.c \
+ pwd.c \
+ r1bindex.c \
+ showfile.c \
+ smatch.c \
+ ssequal.c \
+ trimcpy.c \
+ type.c \
+ uleq.c
+
+$(LIB): $(OFILES)
+ -rm -f $(LIB)
+ ar cr $(LIB) `lorder $(OFILES) | tsort`
+ ranlib $(LIB)
+
+.c.o:
+ $(CC) $(CFLAGS) -c -O $*.c
+ -@ld -x -r $@
+ @mv a.out $@
+
+lint:
+ -lint $(CFILES) subs-lc
+
+distribution: clean
+ -rm -f $(LIB)
+
+clean:
+ -rm -f $(OFILES)
+
+depend:
+ ../misc/depend.sh $(CFILES)
+
+###DEPENDENCIES Follow. Do not delete this line
+add.o: /usr/include/stdio.h
+add.o: ../mh.h
+ambigsw.o: /usr/include/stdio.h
+ambigsw.o: ../mh.h
+concat.o: ../mh.h
+cputc.o: /usr/include/stdio.h
+fdcompare.o: ../mh.h
+gans.o: ../mh.h
+gans.o: /usr/include/stdio.h
+getans.o: ../mh.h
+getans.o: /usr/include/signal.h
+getans.o: /usr/include/stdio.h
+getcpy.o: ../mh.h
+help.o: ../mh.h
+locv.o: /usr/include/stdio.h
+m_convert.o: ../mh.h
+m_convert.o: /usr/include/stdio.h
+m_convert.o: /usr/include/ctype.h
+m_delete.o: ../mh.h
+m_edit.o: ../mh.h
+m_edit.o: /usr/include/sys/types.h
+m_edit.o: /usr/include/sys/stat.h
+m_edit.o: /usr/include/signal.h
+m_edit.o: /usr/include/stdio.h
+#m_edit.o: /usr/include/strings.h
+m_file.o: ../mh.h
+m_file.o: ../folder.h
+m_file.o: /usr/include/stdio.h
+m_file.o: /usr/include/sys/types.h
+m_file.o: /usr/include/sys/stat.h
+m_file.o: /usr/include/errno.h
+m_find.o: ../mh.h
+m_find.o: /usr/include/stdio.h
+m_getcur.o: /usr/include/stdio.h
+m_getcur.o: ../mh.h
+m_getdefs.o: ../mh.h
+m_getdefs.o: /usr/include/stdio.h
+m_getfld.o: ../mh.h
+m_getfld.o: /usr/include/stdio.h
+m_getfolder.o: ../mh.h
+m_getfolder.o: /usr/include/stdio.h
+m_gmprot.o: ../mh.h
+m_gmprot.o: /usr/include/stdio.h
+m_gmsg.o: ../mh.h
+m_gmsg.o: /usr/include/stdio.h
+m_maildir.o: ../mh.h
+m_maildir.o: /usr/include/stdio.h
+m_name.o: ../mh.h
+m_replace.o: ../mh.h
+m_send.o: ../mh.h
+m_send.o: /usr/include/stdio.h
+m_setcur.o: ../mh.h
+m_setcur.o: /usr/include/stdio.h
+m_update.o: ../mh.h
+m_update.o: /usr/include/stdio.h
+m_update.o: /usr/include/signal.h
+makedir.o: ../mh.h
+makedir.o: /usr/include/stdio.h
+makename.o: ../mh.h
+makename.o: /usr/include/stdio.h
+mu_atoi.o: ../mh.h
+path.o: ../mh.h
+peekc.o: /usr/include/stdio.h
+peekc.o: ../mh.h
+printsw.o: ../mh.h
+putenv.o: /usr/include/stdio.h
+pwd.o: /usr/include/stdio.h
+#pwd.o: /usr/include/strings.h
+showfile.o: ../mh.h
+showfile.o: /usr/include/signal.h
+showfile.o: /usr/include/stdio.h
+smatch.o: ../mh.h
+type.o: /usr/include/stdio.h
--- /dev/null
+#
+# Proprietary Rand Corporation, 1981.
+# Further distribution of this software
+# subject to the terms of the Rand
+# license agreement.
+#
+
+CFLAGS = # -m
+LIB = subs.a
+OFILES =\
+ add.o \
+ ambigsw.o \
+ atooi.o \
+ brkstring.o \
+ cdate.o \
+ cndfree.o \
+ concat.o \
+ copy.o \
+ copyip.o \
+ cputc.o \
+ done.o \
+ fdcompare.o \
+ gans.o \
+ getans.o \
+ getcpy.o \
+ help.o \
+ locv.o \
+ m_convert.o \
+ m_delete.o \
+ m_edit.o \
+ m_file.o \
+ m_find.o \
+ m_getcur.o \
+ m_getdefs.o \
+ m_getfld.o \
+ m_getfolder.o \
+ m_gmprot.o \
+ m_gmsg.o \
+ m_maildir.o \
+ m_name.o \
+ m_replace.o \
+ m_send.o \
+ m_setcur.o \
+ m_update.o \
+ makedir.o \
+ makename.o \
+ mu_atoi.o \
+ path.o \
+ peekc.o \
+ pr_array.o \
+ printsw.o \
+ putenv.o \
+ pwd.o \
+ r1bindex.o \
+ showfile.o \
+ smatch.o \
+ ssequal.o \
+ trimcpy.o \
+ type.o \
+ uleq.o
+
+CFILES =\
+ add.c \
+ ambigsw.c \
+ atooi.c \
+ brkstring.c \
+ cdate.c \
+ cndfree.c \
+ concat.c \
+ copy.c \
+ copyip.c \
+ cputc.c \
+ done.c \
+ fdcompare.c \
+ gans.c \
+ getans.c \
+ getcpy.c \
+ help.c \
+ locv.c \
+ m_convert.c \
+ m_delete.c \
+ m_edit.c \
+ m_file.c \
+ m_find.c \
+ m_getcur.c \
+ m_getdefs.c \
+ m_getfld.c \
+ m_getfolder.c \
+ m_gmprot.c \
+ m_gmsg.c \
+ m_maildir.c \
+ m_name.c \
+ m_replace.c \
+ m_send.c \
+ m_setcur.c \
+ m_update.c \
+ makedir.c \
+ makename.c \
+ mu_atoi.c \
+ path.c \
+ peekc.c \
+ pr_array.c \
+ printsw.c \
+ putenv.c \
+ pwd.c \
+ r1bindex.c \
+ showfile.c \
+ smatch.c \
+ ssequal.c \
+ trimcpy.c \
+ type.c \
+ uleq.c
+
+$(LIB): $(OFILES)
+ -rm -f $(LIB)
+ ar cr $(LIB) `lorder $(OFILES) | tsort`
+ ranlib $(LIB)
+
+.c.o:
+ $(CC) $(CFLAGS) -c -O $*.c
+ -@ld -x -r $@
+ @mv a.out $@
+
+lint:
+ -lint $(CFILES) subs-lc
+
+distribution: clean
+ -rm -f $(LIB)
+
+clean:
+ -rm -f $(OFILES)
+
+depend:
+ ../misc/depend.sh $(CFILES)
+
+###DEPENDENCIES Follow. Do not delete this line
+add.o: /usr/include/stdio.h
+add.o: ../mh.h
+ambigsw.o: /usr/include/stdio.h
+ambigsw.o: ../mh.h
+concat.o: ../mh.h
+cputc.o: /usr/include/stdio.h
+fdcompare.o: ../mh.h
+gans.o: ../mh.h
+gans.o: /usr/include/stdio.h
+getans.o: ../mh.h
+getans.o: /usr/include/signal.h
+getans.o: /usr/include/stdio.h
+getcpy.o: ../mh.h
+help.o: ../mh.h
+locv.o: /usr/include/stdio.h
+m_convert.o: ../mh.h
+m_convert.o: /usr/include/stdio.h
+m_convert.o: /usr/include/ctype.h
+m_delete.o: ../mh.h
+m_edit.o: ../mh.h
+m_edit.o: /usr/include/sys/types.h
+m_edit.o: /usr/include/sys/stat.h
+m_edit.o: /usr/include/signal.h
+m_edit.o: /usr/include/stdio.h
+m_edit.o: /usr/include/strings.h
+m_file.o: ../mh.h
+m_file.o: ../folder.h
+m_file.o: /usr/include/stdio.h
+m_file.o: /usr/include/sys/types.h
+m_file.o: /usr/include/sys/stat.h
+m_file.o: /usr/include/errno.h
+m_find.o: ../mh.h
+m_find.o: /usr/include/stdio.h
+m_getcur.o: /usr/include/stdio.h
+m_getcur.o: ../mh.h
+m_getdefs.o: ../mh.h
+m_getdefs.o: /usr/include/stdio.h
+m_getfld.o: ../mh.h
+m_getfld.o: /usr/include/stdio.h
+m_getfolder.o: ../mh.h
+m_getfolder.o: /usr/include/stdio.h
+m_gmprot.o: ../mh.h
+m_gmprot.o: /usr/include/stdio.h
+m_gmsg.o: ../mh.h
+m_gmsg.o: /usr/include/stdio.h
+m_maildir.o: ../mh.h
+m_maildir.o: /usr/include/stdio.h
+m_name.o: ../mh.h
+m_replace.o: ../mh.h
+m_send.o: ../mh.h
+m_send.o: /usr/include/stdio.h
+m_setcur.o: ../mh.h
+m_setcur.o: /usr/include/stdio.h
+m_update.o: ../mh.h
+m_update.o: /usr/include/stdio.h
+m_update.o: /usr/include/signal.h
+makedir.o: ../mh.h
+makedir.o: /usr/include/stdio.h
+makename.o: ../mh.h
+makename.o: /usr/include/stdio.h
+mu_atoi.o: ../mh.h
+path.o: ../mh.h
+peekc.o: /usr/include/stdio.h
+peekc.o: ../mh.h
+printsw.o: ../mh.h
+putenv.o: /usr/include/stdio.h
+pwd.o: /usr/include/stdio.h
+pwd.o: /usr/include/strings.h
+showfile.o: ../mh.h
+showfile.o: /usr/include/signal.h
+showfile.o: /usr/include/stdio.h
+smatch.o: ../mh.h
+type.o: /usr/include/
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <stdio.h>
+#include "../mh.h"
+
+char *sprintf();
+char *malloc();
+
+char *add(this, that)
+ register char *this, *that;
+{
+ register char *r;
+
+ if(!this)
+ this = "";
+ if(!that)
+ that = "";
+ r = malloc((unsigned) (strlen(this)+strlen(that)+1));
+ VOID sprintf(r, "%s%s", that, this);
+ if(*that)
+ cndfree(that);
+ return(r);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <stdio.h>
+#include "../mh.h"
+
+ambigsw(arg, swp)
+ char *arg;
+ struct swit *swp;
+{
+ fprintf(stderr, "%s: ", invo_name);
+ fprintf(stderr, "-%s ambiguous. It matches \n", arg);
+ printsw(arg, swp, "-");
+}
+
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+
+/* octal version of atoi */
+atooi(cp)
+register char *cp;
+{
+ register int i, base;
+
+ i = 0;
+ base = 8;
+ while(*cp >= '0' && *cp <= '7') {
+ i *= base;
+ i += *cp++ - '0';
+ }
+ return(i);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* returns pointer to static table of substring ptrs */
+
+#define NSTR 25
+
+char **
+brkstring(strg,brksep,brkterm)
+ char *strg;
+ char *brksep, *brkterm;
+{
+
+ register char c, *sp;
+ static char *broken[NSTR+1]; /* static array of substring start addresses */
+ int bi;
+
+ sp = strg; /* scan string, replacing separators with zeroes */
+
+ for (bi=0; bi<NSTR; bi++) { /* and entering start addrs in "broken" */
+ while (brkany(c = *sp, brksep)) *sp++ = 0;
+ if (!c || brkany(c, brkterm)) {
+ *sp=0;
+ broken[bi] = 0;
+ return(broken); /* terminator found, finish up */
+ }
+
+ broken[bi] = sp; /* set next start addr */
+
+ while ((c = *++sp) && !brkany(c,brksep) && !brkany(c,brkterm));
+
+ }
+ broken[NSTR] = 0; /* reached limit of NSTR substrings */
+ return (broken);
+}
+
+brkany (chr,strg) /* returns 1 if chr in strg, 0 otherwise */
+char chr,*strg;
+{
+ register char *sp;
+
+ for (sp=strg; *sp; sp++)
+ if (chr == *sp) return (1);
+ return (0);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* returns date in format dd-mon-yy@hh:mm:ss\0 */
+char *cdate(dataddr)
+long *dataddr;
+{
+ register char *cp;
+ char *ctime();
+
+ cp = ctime(dataddr);
+ cp[1] = cp[8];
+ cp[2] = cp[9];
+ cp[3] = '-';
+ cp[7] = '-';
+ cp[8] = cp[22];
+ cp[9] = cp[23];
+ cp[10] = '@';
+ cp[19] = 0;
+ return(cp+1);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* Conditional free -- perform a free call if the address passed
+ * is in free storage; else NOP
+ */
+
+
+cndfree(addr)
+char *addr;
+{
+ extern char end;
+
+ if(addr >= &end) free(addr);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+char *malloc();
+
+/*VARARGS*/
+char *concat(args)
+ char *args;
+{
+ register char **a;
+ register char *cp;
+ register unsigned len;
+ register char *ret;
+
+ len = 1;
+ for(a = &args; *a; )
+ len += strlen(*a++);
+ ret = cp = malloc(len);
+ for(a = &args; *a; )
+ cp = copy(*a++, cp);
+ return(ret);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char *copy(from,to)
+register char *from, *to;
+{
+ while(*to++ = *from++);
+ return to-1;
+};
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char **
+copyip(cpf, cpt)
+char **cpf, **cpt;
+{
+ register int *ipf, *ipt;
+
+ ipf = (int *) cpf;
+ ipt = (int *) cpt;
+
+ while((*ipt = *ipf) && *ipf++ != -1)
+ ipt++;
+ *ipt = 0;
+ return (char **) ipt;
+}
+
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <stdio.h>
+
+cputc(chr, ip)
+register FILE *ip;
+{
+ if(ip != NULL) {
+ putc(chr, ip);
+ if(ferror(ip)) {
+ perror("Write error");
+ done(-1);
+ }
+ }
+}
--- /dev/null
+sed "/DEPENDENCIES/,\$d" < Makefile > Maketemp
+echo "###DEPENDENCIES Follow. Do not delete this line" >> Maketemp
+grep \^#include $@ | sed '
+ s/\.c/\.o/
+ s/:#include/: /
+ s/"\(.*\)"/\1/
+ s/<\(.*\)>/\/usr\/include\/\1/
+' >> Maketemp
+mv Makefile Makeback
+mv Maketemp Makefile
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* This routine is replaced by some modules if they need to do
+ * cleanup. All exits in the code call done rather than exit.
+ */
+
+done(status)
+{
+ exit(status);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+long lseek();
+
+fdcompare(fd1, fd2)
+{
+ int n1, n2, resp;
+ register int i;
+ register char *c1, *c2;
+ char b1[512], b2[512];
+
+ resp = 1;
+ while((n1 = read(fd1, b1, 512)) >= 0 &&
+ (n2 = read(fd2, b2, 512)) >= 0 &&
+ n1 == n2) {
+
+ c1 = b1; c2 = b2;
+ for(i = n1 < 512? n1 : 512; i--; )
+ if(*c1++ != *c2++) {
+ resp = 0;
+ goto leave;
+ }
+ if(n1 < 512)
+ goto leave;
+ }
+ resp = 0;
+leave:
+ VOID lseek(fd1, 0l, 0);
+ VOID lseek(fd2, 0l, 0);
+ return(resp);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+
+gans(prompt, ansp)
+char *prompt;
+struct swit *ansp;
+{
+ char ansbuf[32];
+ register char *cp;
+ register int i;
+ struct swit *ap;
+
+ for(;;) {
+ printf("%s", prompt);
+ VOID fflush(stdout);
+ cp = ansbuf;
+ while((i = getchar()) != '\n') {
+ if(i == EOF)
+ return(0);
+ if(cp < &ansbuf[31]) {
+ if(i >= 'A' && i <= 'Z')
+ i += 'a'-'A';
+ *cp++ = i;
+ }
+ }
+ *cp = 0;
+ if(ansbuf[0] == '?' || cp == ansbuf) {
+ printf("Options are:\n");
+ for(ap = ansp; ap->sw; ap++)
+ printf(" %s\n", ap->sw);
+ continue;
+ }
+ if((i = smatch(ansbuf, ansp)) < 0) {
+ printf("%s: %s.\n", ansbuf, i == -1? "unknown":"ambiguous");
+ continue;
+ }
+ return(i);
+ }
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <signal.h>
+#include <stdio.h>
+
+int g_sigint; /* sensed an interrupt */
+int g_sig();
+
+char **
+getans(prompt, ansp)
+ char *prompt;
+ struct swit *ansp;
+{
+ static char ansbuf[128];
+ register char *cp, **cpp;
+ register int i;
+
+ VOID signal(SIGINT, g_sig);
+ for(;;) {
+ printf("%s", prompt);
+ VOID fflush(stdout);
+ cp = ansbuf;
+ while((i = getchar()) != '\n') {
+ if(i == EOF || g_sigint) {
+ g_sigint = 0;
+ return(0);
+ }
+ if(cp < &ansbuf[127])
+ *cp++ = i;
+ }
+ *cp = 0;
+ if(ansbuf[0] == '?' || cp == ansbuf) {
+ printf("Options are:\n");
+ printsw(ALL, ansp, "");
+ continue;
+ }
+ cpp = brkstring(ansbuf, " ", NULLCP);
+ switch(smatch(*cpp, ansp)) {
+ case -2:ambigsw(*cpp, ansp); /* ambiguous */
+ continue;
+ case -1: /* unknown */
+ printf(" -%s unknown. Hit <CR> for help.\n", *cpp);
+ continue;
+ default:
+ return(cpp); /* list, edit, quit, send */
+ }
+ }
+}
+
+
+g_sig()
+{
+ VOID signal(SIGINT, g_sig);
+ g_sigint = 1;
+ return;
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+
+char *malloc();
+char *strcpy();
+
+char *
+getcpy(str)
+ char *str;
+{
+ register char *cp;
+
+ cp = malloc((unsigned)strlen(str) + 1);
+ VOID strcpy(cp, str);
+ return(cp);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+
+help(str, swp)
+ char *str;
+ struct swit *swp;
+{
+ printf("syntax: %s\n", str);
+ printf(" switches are:\n");
+ printsw(ALL, swp, "-");
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * This routine returns the address on the stack of the text of the
+ * first argument to the process. It only works on the VAX, and only
+ * if the process was not called with 4 empty args in a row.
+ *
+ * This is a crock, and it doesn't work on 4bsd.
+ * invo_name is now an external char * pointer
+ * 2/1/81 - dave yost.
+ */
+
+char *invo_name()
+{
+ register int *ip;
+
+ ip = (int *) 0x7ffffff8; /* Highest stack address -4 */
+
+ while(*--ip != 0) /* Look backwards for bumber */
+ continue;
+ return (char *) &ip[1]; /* Next string is i
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <stdio.h>
+
+extern char *sprintf ();
+
+char *
+locv(longint)
+ long longint;
+{
+ static char locvbuf[12];
+
+ return sprintf(locvbuf, "%ld", longint);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <ctype.h>
+
+int convdir;
+struct msgs *mp;
+char *delimp;
+
+m_convert(name)
+char *name;
+{
+ register char *cp;
+ register int first, last;
+ int found, range, err;
+ char *bp;
+
+ found = 0;
+ if(strcmp((cp = name), "all") == 0)
+ cp = "first-last";
+ if((err = first = m_conv(cp)) <= 0)
+ goto badbad;
+ if(*(cp = delimp) && *cp != '-' && *cp != ':') {
+ baddel: fprintf(stderr, "Illegal argument delimiter: \"%c\"\n", *delimp);
+ return(0);
+ }
+ if(*cp == '-') {
+ cp++;
+ if((err = last = m_conv(cp)) <= 0) {
+ badbad: if(err == -1)
+ fprintf(stderr, "No %s message\n", cp);
+ else
+ badlist: fprintf(stderr, "Bad message list \"%s\".\n",
+ name);
+ return(0);
+ }
+ if(last < first) goto badlist;
+ if(*delimp) goto baddel;
+ if(first > mp->hghmsg || last < mp->lowmsg) {
+ rangerr: fprintf(stderr, "No messages in range \"%s\".\n", name);
+ return(0);
+ }
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ } else if(*cp == ':') {
+ cp++;
+ if(*cp == '-') {
+ convdir = -1;
+ cp++;
+ } else if(*cp == '+') {
+ convdir = 1;
+ cp++;
+ }
+ if((range = atoi(bp = cp)) == 0)
+ goto badlist;
+ while(isdigit(*bp)) bp++;
+ if(*bp)
+ goto baddel;
+ if((convdir > 0 && first > mp->hghmsg) ||
+ (convdir < 0 && first < mp->lowmsg))
+ goto rangerr;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ if(first > mp->hghmsg)
+ first = mp->hghmsg;
+ for(last = first; last >= mp->lowmsg && last <= mp->hghmsg;
+ last += convdir)
+ if(mp->msgstats[last]&EXISTS)
+ if(--range <= 0)
+ break;
+ if(last < mp->lowmsg)
+ last = mp->lowmsg;
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(last < first) {
+ range = last; last = first; first = range;
+ }
+ } else {
+ if(first > mp->hghmsg || first < mp->lowmsg ||
+ !(mp->msgstats[first]&EXISTS)) {
+ fprintf(stderr, "Message %d doesn't exist.\n", first);
+ return(0);
+ }
+ last = first;
+ }
+ while(first <= last) {
+ if(mp->msgstats[first]&EXISTS) {
+ if(!(mp->msgstats[first]&SELECTED)) {
+ mp->numsel++;
+ mp->msgstats[first] |= SELECTED;
+ if(first < mp->lowsel)
+ mp->lowsel = first;
+ if(first > mp->hghsel)
+ mp->hghsel = first;
+ }
+ found++;
+ }
+ first++;
+ }
+ if(!found)
+ goto rangerr;
+ return(1);
+}
+
+m_conv(str)
+char *str;
+{
+ register char *cp, *bp;
+ register int i;
+ char buf[16];
+
+ convdir = 1;
+ cp = bp = str;
+ if(isdigit(*cp)) {
+ while(isdigit(*bp)) bp++;
+ delimp = bp;
+ return (i = atoi(cp)) > MAXFOLDER ? MAXFOLDER : i;
+ }
+ bp = buf;
+ while((*cp >= 'a' && *cp <= 'z') || *cp == '.')
+ *bp++ = *cp++;
+ *bp++ = 0;
+ delimp = cp;
+ if(strcmp(buf, "first") == 0)
+ return(mp->lowmsg);
+ else if(strcmp(buf, "last") == 0) {
+ convdir = -1;
+ return(mp->hghmsg);
+ } else if(strcmp(buf, "cur") == 0 || strcmp(buf, ".") == 0)
+ return(mp->curmsg > 0 ? mp->curmsg : -1);
+ else if(strcmp(buf, "prev") == 0) {
+ convdir = -1;
+ for(i = (mp->curmsg<=mp->hghmsg)? mp->curmsg-1: mp->hghmsg;
+ i >= mp->lowmsg; i--) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1); /* non-existent message */
+ } else if(strcmp(buf, "next") == 0) {
+ for(i = (mp->curmsg>=mp->lowmsg)? mp->curmsg+1: mp->lowmsg;
+ i <= mp->hghmsg; i++) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1);
+ } else
+ return(0); /* bad message list */
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+
+m_delete(key)
+char *key;
+{
+ register struct node *np, *npprev;
+
+ m_getdefs();
+ for(np = (struct node *) &m_defs; npprev = np; ) {
+ if((np = np->n_next) == 0)
+ break;
+ if(uleq(np->n_name, key)) {
+ npprev->n_next = np->n_next;
+ cndfree(np->n_name);
+ cndfree(np->n_field);
+ free((char *)np);
+ def_flags |= DEFMOD;
+ return(0);
+ }
+ }
+ return(1);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <stdio.h>
+#include <strings.h>
+
+struct msgs *mp;
+
+m_edit(ed, file, use, altmsg)
+char **ed, *file, *altmsg;
+int use;
+{
+ /* Exec editor. Normal exit returns 0.
+ * To abort, returns -1. To try again, returns -2
+ */
+
+ static char *edsave;
+ static int reedit;
+ struct stat stbuf;
+ int retstat;
+ register char *cp;
+ int pid, wpid;
+ int (*intr)();
+ int status;
+
+ if(!reedit) { /* set initial editor */
+ if(!*ed && (*ed = m_find("editor")) == NULL)
+ *ed = sysed;
+ } else
+ if(!*ed) { /* no explicit editor */
+ *ed = edsave;
+ cp = rindex(*ed, '/');
+ if(cp == 0)
+ cp = *ed;
+ cp = concat(cp, "-next", 0);
+ if((cp = m_find(cp)) != NULL)
+ *ed = cp;
+ }
+ intr = signal(SIGINT, SIG_IGN);
+ if((pid = fork()) == 0) {
+ if(altmsg) {
+ VOID unlink("@");
+ VOID link(altmsg, "@"); /* An easy handle on cur msg */
+ putenv("editalt", altmsg);
+ }
+ m_update();
+ VOID fflush(stdout);
+ VOID signal(SIGINT, intr);
+ execlp(*ed, r1bindex(*ed, '/'), file, 0);
+ fprintf(stderr, "Can't exec the editor: ");
+ perror(*ed); done(-1);
+ } else if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ retstat = -1;
+ goto leave;
+ } else
+ while((wpid = wait(&status)) != -1 && wpid != pid) ;
+ VOID signal(SIGINT, intr);
+ if(status) {
+ if((status&0177400 == 0177400) || /* Can't exec editor */
+ (reedit && (status&0377) == 0)) { /*2nd edit.Aborted by user*/
+ retstat = -2;
+ goto leave;
+ }
+ fprintf(stderr, "[%s aborted--%s ", invo_name, file);
+ if(!use && (status&017740)) { /* edit aborted by user */
+ VOID unlink(file);
+ fprintf(stderr, "deleted]\n");
+ } else /* 'use' or system abort */
+ fprintf(stderr, "preserved]\n");
+ retstat = -2;
+ goto leave;
+ }
+ reedit++;
+ retstat = 0;
+ if(altmsg && !mp->msgflags&READONLY) {
+ VOID stat("@", &stbuf);
+ if(stbuf.st_nlink == 1) /*@'s been edited by Ned*/
+ if(unlink(altmsg) == -1 || link("@", altmsg) == -1){
+ fprintf(stderr, "Can't update %s from @ file!\n",altmsg);
+ retstat = 0;
+ goto leave;
+ }
+ }
+ leave:
+ edsave = getcpy(*ed);
+ *ed = 0;
+ VOID unlink("@"); /* Remove this extra link */
+ return(retstat);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include "../folder.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+extern int errno;
+
+m_file(folder, msg, folders, nfolders, prsrvf, setcur)
+char *folder;
+char *msg;
+struct st_fold folders[];
+int nfolders;
+int prsrvf;
+int setcur;
+{
+ char newmsg[256], buf[BUFSIZ];
+ register int i;
+ register char *nmsg;
+ register struct st_fold *fp;
+ struct stat stbuf, stbf1;
+ int n, o, linkerr;
+
+ for(fp = folders; fp < &folders[nfolders]; fp++) {
+ if(prsrvf)
+ nmsg = msg;
+ else {
+ if (fp->f_mp->hghmsg >= MAXFOLDER) {
+ fprintf(stderr,
+ "Can't file msg %s -- folder %s is full.\n",
+ msg, fp->f_name);
+ return(1);
+ }
+ nmsg = m_name(fp->f_mp->hghmsg++ + 1);
+ }
+ VOID copy(nmsg, copy("/", copy(m_maildir(fp->f_name), newmsg)));
+ if(link(msg, newmsg) < 0) {
+ linkerr = errno;
+ if(linkerr == EEXIST ||
+ (linkerr == EXDEV && stat(newmsg, &stbuf) != -1)) {
+ if(linkerr != EEXIST || stat(msg, &stbf1) < 0 ||
+ stat(newmsg, &stbuf) < 0 ||
+ stbf1.st_ino != stbuf.st_ino) {
+ fprintf(stderr, "Message %s:%s already exists.\n",
+ fp->f_name, msg);
+ return(1);
+ }
+ continue;
+ }
+ if(linkerr == EXDEV) {
+ if((o = open(msg, 0)) == -1) {
+ fprintf(stderr, "Can't open %s:%s.\n",
+ folder, msg);
+ return(1);
+ }
+ VOID fstat(o, &stbuf);
+ if((n = creat(newmsg, (int)stbuf.st_mode&0777)) == -1) {
+ fprintf(stderr, "Can't create %s:%s.\n",
+ fp->f_name, nmsg);
+ VOID close(o);
+ return(1);
+ }
+ do
+ if((i=read(o, buf, sizeof buf)) < 0 ||
+ write(n, buf, i) == -1) {
+ fprintf(stderr, "Copy error on %s:%s to %s:%s!\n",
+ folder, msg, fp->f_name, nmsg);
+ VOID close(o); VOID close(n);
+ return(1);
+ }
+ while(i == sizeof buf);
+ VOID close(n); VOID close(o);
+ } else {
+ fprintf(stderr, "Error on link %s:%s to %s:",
+ folder, msg, fp->f_name);
+ perror(nmsg);
+ return(1);
+ }
+ }
+ if( setcur
+ && ( (i = atoi(nmsg)) < fp->f_mp->curmsg
+ || !fp->f_mp->curmsg
+ )
+ )
+ fp->f_mp->curmsg = i;
+ }
+ retur
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+
+char *m_find(str)
+ char *str;
+{
+ register struct node *n;
+
+ m_getdefs();
+ for(n = m_defs; n; n = n->n_next)
+ if(uleq(n->n_name, str))
+ return(n->n_field);
+ return(NULL);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <stdio.h>
+#include "../mh.h"
+
+extern char *sprintf();
+
+m_getcur(name)
+ char *name;
+{
+ register char *cp;
+ register int i, j;
+ short readonly, curfil = 0;
+ char buf[132];
+
+ readonly = (access(".",2) == -1);
+ if(readonly) {
+ VOID sprintf(buf, "cur-%s", name);
+ if(cp = m_find(buf))
+ curfil = mu_atoi(cp);
+ } else if(i = open(current, 0)) {
+ if((j = read(i, buf, sizeof buf)) >= 2){
+ buf[j-1] = 0; /* Zap <lf> */
+ curfil = mu_atoi(buf);
+ }
+ VOID close(i);
+ }
+ return curfil;
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+
+char *malloc();
+extern char *sprintf();
+
+char defpath[128];
+
+struct procs {
+ char *procname;
+ char **procnaddr;
+} procs [] = {
+ { "lproc", &lproc },
+ { "lsproc", &lsproc },
+ { "mh_deliver", &mh_deliver },
+ { "prproc", &prproc },
+ { "scanproc", &scanproc },
+ { "showproc", &showproc },
+ { "sendproc", &sendproc },
+ { "fileproc", &fileproc },
+ { 0, 0 },
+};
+
+m_getdefs()
+{
+ register struct node *np;
+ register int state, wpid, pid;
+ register struct procs *ps;
+ int status;
+ FILE *ib;
+ char name[NAMESZ], field[1024];
+
+ if(defpath[0])
+ return; /* We've already been called! */
+ if(!mypath)
+ if((mypath = getenv("HOME")) == NULL) {
+ fprintf(stderr, "HOME environment variable not set!\n");
+ done(1);
+ }
+ VOID sprintf(defpath, "%s%s", mypath, mh_prof);
+/*** copy(mh_prof, copy(mypath, defpath)); ***/
+
+ if((ib = fopen(defpath, "r")) == NULL) {
+ if((pid = fork()) == 0) {
+ execl(installproc, "install-mh", "-auto", 0);
+ fprintf(stderr, "Can't exec ");perror(installproc);
+ done(1);
+ } else if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ done(1);
+ } else
+ while((wpid = wait(&status)) != -1 && wpid != pid)
+ ;
+ if(status || (ib = fopen(defpath, "r")) == NULL) {
+ fprintf(stderr, "[install-mh aborted]\n");
+ done(1);
+ }
+ }
+
+#ifdef NEWS /* NOT CONVERTED TO V7!!! */
+ VOID fstat(fildes(ib), field);
+ deftime = (&field)->i_atime;
+#endif
+
+ np = (struct node *) &m_defs;
+ state = FLD;
+ for(;;)
+ switch(state = m_getfld(state,name,field,sizeof field,ib)) {
+ case FLD:
+ case FLDEOF:
+ np->n_next = (struct node *) malloc(sizeof *np);
+ np = np->n_next;
+ np->n_name = getcpy(name);
+ np->n_field = trimcpy(field);
+ np->n_next = 0;
+ for(ps = procs; ps->procname; ps++)
+ if(strcmp(np->n_name, ps->procname) == 0) {
+ *ps->procnaddr = np->n_field;
+ break;
+ }
+ if(state == FLDEOF) {
+ VOID fclose(ib);
+ return;
+ }
+ continue;
+ case BODY:
+ case BODYEOF:
+ fprintf(stderr, ".mh_profile must not contain a body--it can't \
+end with a blank line!\n");
+ default:
+ fprintf(stderr, "Bad format: .mh_profile!\n");
+ done(1
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+
+int m_fldsz;
+
+m_getfld(state, name, buf, bufsz, iob)
+int state, bufsz;
+char *name, *buf;
+FILE *iob;
+{
+ register char *cp;
+ register c;
+
+ while((c = getc(iob)) == '\001' && peekc(iob) == '\001')
+ while(getc(iob) != '\n');
+
+ if(c < 0)
+ return(FILEEOF);
+ m_fldsz = 0;
+
+ switch(state) {
+
+ case FLDEOF:
+ case BODYEOF:
+ case FLD:
+ if(c == '\n' || c == '-')
+ goto body;
+ cp = name;
+ for(;;) {
+ if(c == ':')
+ break;
+ if(cp >= &name[NAMESZ-1]) {
+ *cp = 0;
+fprintf(stderr, "??Component Name Exceeds %d Chars:\n \"%s\"\n", NAMESZ-1, name);
+ return(LENERR);
+ }
+ if(c == '\n' || c < 0) {
+ *cp = 0;
+fprintf(stderr, "??%s Encountered While Scanning for a colon:\n \"%s\"\n",
+ (c < 0)? "<eof>":"<end of line>", name);
+ return(FMTERR);
+ }
+ *cp++ = c;
+ *cp = 0;
+ c = getc(iob);
+ }
+
+ case FLDPLUS:
+ cp = buf;
+ for(;;) {
+ if((c = getc(iob)) < 0)
+ return(FLDEOF);
+ *cp++ = c;
+ *cp = 0;
+ m_fldsz++;
+ if(c == '\n')
+ if((c = peekc(iob)) != ' ' && c != '\t')
+ if(c == '\001' || c < 0)
+ return(FLDEOF);
+ else
+ return(FLD);
+ if(cp >= &buf[bufsz-1])
+ return(peekc(iob) < 0? FLDEOF:FLDPLUS);
+ }
+
+ body: if(c == '-')
+ while(getc(iob) != '\n') ;
+ buf[0] = 0;
+ if((c = getc(iob)) == '\001' && peekc(iob) == '\001')
+ return(BODYEOF);
+
+ case BODY:
+ cp = buf; *cp = 0;
+ for(;;) {
+ if(c < 0 || (c == '\001' && peekc(iob) == '\001'))
+ return(BODYEOF);
+ *cp++ = c;
+ *cp = 0;
+ m_fldsz++;
+ if(cp >= &buf[bufsz-1])
+ return(((c=peekc(iob))<0||c=='\001')?
+ BODYEOF: BODY);
+ c = getc(iob);
+ }
+
+ }
+/*NOTREACHED*/
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+
+char *m_getfolder()
+{
+ register char *folder;
+
+ m_getdefs();
+ if((folder = m_find(pfolder)) == NULL || *folder == 0)
+ folder = defalt;
+ return(folder);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+
+m_gmprot()
+{
+ register char *cp;
+ register int prot;
+
+ if((cp = m_find("msg-protect")) != NULL)
+ prot = atooi(cp);
+ else
+ prot = atooi(msgprot);
+ return(prot);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+
+extern char *malloc();
+extern char *sprintf();
+
+#define Block
+
+struct msgs *mp;
+
+/* Look through a folder.
+/* Alloc a 'struct msgs' structure and fill it in
+/* with such things as what the low, high, and current messages are.
+/* Return a pointer to this structure or a null pointer if trouble.
+/**/
+struct msgs *
+m_gmsg(name)
+char *name;
+{
+ FILE *ifp; /***/
+ register int i, j;
+ register char *cp;
+ int curfil;
+
+ struct {
+ struct {
+ short d_inum;
+ char d_name[14];
+ } ent;
+ int terminator;
+ } dir;
+
+ struct {
+ int xhghmsg,
+ xnummsg,
+ xlowmsg,
+ xcurmsg;
+ char xselist,
+ xflags,
+ xfiller,
+ xothers;
+ char xmsgs[MAXFOLDER + 1];
+ } msgbuf;
+
+ if((ifp = fopen(".", "r")) == 0)
+ return(0);
+ for(j = 0; j <= MAXFOLDER; j++)
+ msgbuf.xmsgs[j] = 0;
+ msgbuf.xcurmsg = 0;
+ msgbuf.xnummsg = 0;
+ msgbuf.xselist = 0;
+ msgbuf.xothers = 0;
+ msgbuf.xlowmsg = 5000;
+ msgbuf.xhghmsg = 0;
+ msgbuf.xflags = (access(".",2) == -1)? READONLY:0; /*RAND sys call*/
+ curfil = 0;
+ dir.terminator = 0;
+ cp = dir.ent.d_name;
+ for(;;) {
+ if(fread(&dir, sizeof dir.ent, 1, ifp) != 1)
+ break;
+ if(dir.ent.d_inum)
+ if(j = mu_atoi(cp)) {
+ if(j > msgbuf.xhghmsg)
+ msgbuf.xhghmsg = j;
+ msgbuf.xnummsg++;
+ if(j < msgbuf.xlowmsg)
+ msgbuf.xlowmsg = j;
+ msgbuf.xmsgs[j] = EXISTS;
+ } else if(*cp != ',' && *cp != '.')
+ if(strcmp(cp, current) == 0)
+ curfil++;
+ else if(strcmp(cp, listname) == 0)
+ msgbuf.xselist++;
+ else
+ msgbuf.xothers++;
+ }
+ if(!msgbuf.xhghmsg)
+ msgbuf.xlowmsg = 0;
+ VOID fclose(ifp);
+ if(msgbuf.xflags&READONLY) Block {
+ char buf[132];
+ VOID sprintf(buf, "cur-%s", name);
+/*** copy(name, copy("cur-", buf)); ***/
+ if((cp = m_find(buf)) != NULL)
+ if(j = mu_atoi(cp))
+ msgbuf.xcurmsg = j;
+ } else if(curfil && (i = open(current, 0)) >= 0) {
+ if((j = read(i, dir.ent.d_name, sizeof dir.ent.d_name)) >= 2){
+ dir.ent.d_name[j-1] = 0; /* Zap <lf> */
+ if(j = mu_atoi(dir.ent.d_name))
+ msgbuf.xcurmsg = j;
+ }
+ VOID close(i);
+ }
+ Block {
+ register struct msgs *msgp;
+ if( (char *) (msgp = (struct msgs *)
+ malloc((unsigned) (sizeof *mp + msgbuf.xhghmsg + 2)))
+ == (char *) 0)
+ return(0);
+ msgp->hghmsg = msgbuf.xhghmsg;
+ msgp->nummsg = msgbuf.xnummsg;
+ msgp->lowmsg = msgbuf.xlowmsg;
+ msgp->curmsg = msgbuf.xcurmsg;
+ msgp->selist = msgbuf.xselist;
+ msgp->msgflags = msgbuf.xflags;
+ msgp->others = msgbuf.xothers;
+ msgp->foldpath = name;
+ msgp->lowsel = 5000;
+ msgp->hghsel = 0;
+ msgp->numsel = 0;
+ for(j = 0; j <= msgbuf.xhghmsg; j++)
+ msgp->msgstats[j] = msgbuf.xmsgs[j];
+ return(msgp);
+ }
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+
+extern char *sprintf();
+extern char *strcpy();
+
+char *mypath;
+
+char *m_maildir(folder)
+char *folder;
+{
+ register char *fold, *pth, *cp;
+ static char mailfold[128];
+
+ m_getdefs();
+ if(!(fold = folder))
+ fold = m_getfolder();
+ if(*fold == '/' || *fold == '.')
+ return(fold);
+ cp = mailfold;
+ if((pth = m_find("path")) != NULL && *pth) {
+ if(*pth != '/') {
+ VOID sprintf(cp, "%s/", mypath);
+ cp += strlen(cp);
+ }
+ cp = copy(pth, cp);
+ if(cp[-1] != '/')
+ *cp++ = '/';
+ } else
+ cp = copy(path("./", TFOLDER), cp);
+ strcpy(cp, fold);
+ return(mailf
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+
+char *m_name(num)
+{
+ static char name[4];
+ register char *cp;
+ register int i;
+
+ name[0] = 0;
+ name[1] = 0;
+ name[2] = 0;
+ name[3] = 0;
+ i = num;
+ cp = &name[3];
+ if(i > 0 && i <= MAXFOLDER)
+ do {
+ *--cp = (i % 10) + '0';
+ i /= 10;
+ } while(i);
+ else
+ *--cp = '?';
+ return(cp);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "mh.h"
+#include "/rnd/borden/h/stat.h"
+#include "/rnd/borden/h/iobuf.h"
+
+char mhnews[];
+char anoyes[];
+
+m_news()
+{
+ struct inode stbf;
+ struct iobuf in;
+ register flag, c;
+ long readdate, gdate();
+ char *cp, *ap;
+
+ if(stat(mhnews, &stbf) == -1)
+ return;
+ m_getdefs();
+ if((ap = m_find("newsdate")) != -1 ) { /* seen news? */
+ readdate = gdate(ap);
+ if(stbf.i_mtime < readdate) /* recently? */
+ return;
+ }
+ time(&readdate); /* current time */
+ m_replace("newsdate", cdate(&readdate)); /* update profile */
+ m_update();
+
+ fopen(mhnews, &in); /* show news */
+ flag = getc(&in);
+
+ /**************************************************
+ while((c = getc(&in)) != -1)
+ * if(c == NEWSPAUSE) {
+ * if(!gans("More? ", anoyes))
+ * break;
+ * } else
+ * putchar(c);
+ ***************************************************
+ */
+ flush();
+ showfile(mhnews);
+ if(flag == NEWSHALT)
+ exit(0);
+ close(in.b_fildes);
+}
+
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+char *malloc();
+
+m_replace(key,value)
+char *key, *value;
+
+{
+ register struct node *np;
+
+ m_getdefs();
+ for(np = m_defs; ; np = np->n_next) {
+ if(uleq(np->n_name, key)) {
+ if(strcmp(value, np->n_field) != 0) {
+ cndfree(np->n_field);
+ np->n_field = value;
+ def_flags |= DEFMOD;
+ }
+ return;
+ }
+ if(!np->n_next)
+ break;
+ }
+ np->n_next = (struct node *) malloc(sizeof *np);
+ np = np->n_next;
+ np->n_name = getcpy(key);
+ np->n_next = 0;
+ np->n_field = value;
+ def_flags |= DEFMOD;
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+
+m_send(arg, file)
+char **arg, *file;
+{
+ char *vec[15];
+ int ivec;
+
+ ivec = 0;
+ vec[ivec++] = "send";
+ vec[ivec++] = file;
+ if(**arg == 'v')
+ vec[ivec++] = "-verbose";
+ else if(*arg) {
+ do
+ vec[ivec++] = *arg++;
+ while(*arg);
+ }
+ vec[ivec++] = 0;
+ m_update();
+ VOID fflush(stdout);
+ execv(sendproc, vec);
+ fprintf(stderr, "Can't exec %s.\n", sendproc);
+ return(0);
+
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+
+extern char *strcpy();
+
+struct msgs *mp;
+
+m_setcur(num)
+{
+ char buf[6];
+ register int i;
+ register char *cp1;
+
+ if(mp->msgflags&READONLY) {
+ m_replace(cp1 = concat("cur-",mp->foldpath,0), m_name(num));
+ free(cp1);
+ } else {
+ strcpy(buf, m_name(num));
+ cp1 = buf + strlen(buf);
+ *cp1++ = '\n';
+ if(strcmp(current, "cur"))
+ error("\"current\" got Clobbered!! Bug!");
+ if((i = creat(current, 0660)) >= 0) {
+ if(write(i, buf, cp1-buf) != cp1-buf) {
+ fprintf(stderr, "m_setcur: write error on ");
+ perror(current);
+ done(1);
+ }
+ VOID close(i);
+ }
+ }
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+#include <signal.h>
+
+char defpath[];
+
+m_update()
+{
+ FILE *out;
+ register struct node *np;
+ int (*save)();
+
+ if(def_flags & DEFMOD) {
+ save = signal(SIGINT, SIG_IGN);
+ if((out = fopen(defpath, "w")) == NULL) {
+ fprintf(stderr, "Can't create %s!!\n", defpath);
+ done(1);
+ }
+ for(np = m_defs; np; np = np->n_next)
+ fprintf(out, "%s: %s\n", np->n_name, np->n_field);
+ VOID fclose(out);
+ VOID signal(SIGINT, save);
+ def_flags &= ~DEFMOD;
+ }
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+
+makedir(dir)
+ char *dir;
+{
+ register int pid, wpid;
+ register char *c;
+ int status;
+
+ if((pid = fork()) == 0) {
+ execl("/bin/mkdir", "mkdir", dir, 0);
+ execl("/usr/bin/mkdir", "mkdir", dir, 0);
+ fprintf(stderr, "Can't exec mkdir!!?\n");
+ return(0);
+ }
+ if(pid == -1) {
+ fprintf(stderr, "Can't fork\n");
+ return(0);
+ }
+ while((wpid = wait(&status)) != pid && wpid != -1) ;
+ if(status) {
+ fprintf(stderr, "Bad exit status (%o) from mkdir.\n", status);
+ return(0);
+ }
+ if((c = m_find("folder-protect")) == NULL)
+ c = foldprot;
+ VOID chmod(dir, atooi(c));
+ return(1);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <stdio.h>
+
+char *makename(prefix,suffix)
+char *prefix, *suffix;
+{
+ static char tmpname[15];
+ register char *cp1, *cp2;
+ register int pid;
+
+ pid = getpid();
+ cp1 = tmpname;
+ for (cp2 = prefix; *cp1++ = *cp2++; );
+ cp1--;
+ do *cp1++ = pid%10 + '0'; while (pid /= 10);
+ for (cp2 = suffix; *cp1++ = *cp2++; );
+ if (cp1 >= &tmpname[15]) error("strs too long to makename");
+ return (tmpn
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+
+mu_atoi(str)
+ char *str;
+{
+ register char *cp;
+ register int i;
+
+ i = 0;
+ cp = str;
+ while(*cp) {
+ if(*cp < '0' || *cp > '9')
+ return 0;
+ i *= 10;
+ i += *cp++ - '0';
+ }
+ if (i > MAXFOLDER)
+ return 0;
+ return i;
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+
+char *path(name, type)
+ register char *name;
+{
+ static char *pwds;
+
+ if(*name == '/' ||
+ (type == TFOLDER && *name != '.'))
+ return name;
+ if(!pwds)
+ pwds = pwd();
+ if(*name == '.' && name[1] == '/')
+ name += 2;
+ return concat(pwds, "/", name, 0);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <stdio.h>
+#include "../mh.h"
+
+peekc(ib)
+FILE *ib;
+{
+ register c;
+
+ c = getc(ib);
+ VOID ungetc(c,ib);
+ return(c);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+pr_array(cp,ap)
+char *cp, **ap;
+{
+ register int i;
+
+ for(i=0; *ap; ap++,i++)
+ printf("%s[%d]=> %s\n", cp,i,*ap);
+}
+
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+
+printsw(substr, swp, prefix)
+ char *substr, *prefix;
+ struct swit *swp;
+{
+ char buf[128];
+ register char *cp, *cp1;
+ register int i;
+ int len;
+
+ len = strlen(substr);
+ for(; swp->sw; swp++)
+ if(!*substr || /* null matches all strings */
+ (ssequal(substr, swp->sw) && len >= swp->minchars))
+ if(swp->minchars > 0) {
+ cp = buf;
+ *cp++ = '(';
+ for(cp1 = swp->sw, i = 0; i < swp->minchars; i++)
+ *cp++ = *cp1++;
+ *cp++ = ')';
+ while(*cp++ = *cp1++);
+ printf(" %s%s\n", prefix, buf);
+ } else if(swp->minchars == 0)
+ printf(" %s%s\n", prefix, swp->sw);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * putenv(name, arg)
+ * replaces or adds the `name' entry with "name=arg";
+ *
+ * Uses malloc() for space for new vector and new entry;
+ *
+ * Bruce Borden January 1980
+ * The Rand Corporation
+ */
+
+#include <stdio.h>
+
+extern char **environ;
+
+putenv(name, arg)
+char *name, *arg;
+{
+ register int i;
+ register char **ep, **nep, *cp;
+
+ if((cp = (char *) malloc(strlen(name) + strlen(arg) + 2)) == NULL)
+ return(1);
+ strcpy(cp, name);
+ strcat(cp, "=");
+ strcat(cp, arg);
+ for(ep = environ, i = 0; *ep; ep++, i++)
+ if(nvmatch(name, *ep)) {
+ *ep = cp;
+ return(0);
+ }
+ if((nep = (char **) malloc((i+2) * sizeof *nep)) == NULL)
+ return(1);
+ for(ep = environ, i = 0; *ep; )
+ nep[i++] = *ep++;
+ nep[i++] = cp;
+ nep[i] = 0;
+ environ = nep;
+ return(0);
+}
+
+/*
+ * s1 is either name, or name=value
+ * s2 is name=value
+ * if names match, return value of s2, else NULL
+ * used for environment searching: see getenv
+ */
+
+static
+nvmatch(s1, s2)
+register char *s1, *s2;
+{
+
+ while (*s1 == *s2++)
+ if (*s1++ == '=')
+ return(1);
+ if (*s1 == '\0' && *(s2-1) == '=')
+ return(1);
+ return(0);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <stdio.h>
+#include <strings.h>
+
+extern FILE *popen ();
+
+char *
+pwd()
+{
+ register FILE *pp;
+ static char curpath[128];
+
+ if((pp = popen("pwd", "r")) == NULL ||
+ fgets(curpath, sizeof curpath, pp) == NULL ||
+ pclose(pp) != 0) {
+ fprintf(stderr, "Can't find current directory!\n");
+ done(1);
+ }
+ *rindex(curpath, '\n') = 0; /* Zap the lf */
+ return curpath;
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * r1bindex(str, chr) stands for Right plus 1 or Beginning index of
+ * chr in str. I.e. return ptr 1 past LAST occurrence of chr in
+ * str, OR beginning of the string if str doesn't contain chr.
+ */
+
+char *
+r1bindex(str, chr)
+register char *str;
+register int chr;
+{
+ register char *cp;
+
+ for(cp = str; *cp; cp++)
+ continue;
+ --cp;
+ while(cp >= str && *cp != chr)
+ --cp;
+ return ++cp;
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+#include <signal.h>
+#include <stdio.h>
+
+showfile(file)
+char *file;
+{
+ int pid, wpid, (*intr)(), status;
+ char *vec[4];
+
+ intr = signal(SIGINT, SIG_IGN);
+ m_update();
+ VOID fflush(stdout);
+ if((pid = fork()) == 0) {
+ vec[0] = r1bindex(lproc, '/');
+ vec[1] = file;
+ vec[2] = 0;
+ VOID signal(SIGINT, intr);
+ execv(lproc, vec);
+ fprintf(stderr, "Can't exec ");
+ perror(lproc);
+ goto badleave;
+ } else if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ goto badleave;
+ } else
+ while((wpid = wait(&status)) != -1 && wpid != pid) ;
+ VOID signal(SIGINT, intr);
+ if(status & 0377)
+ goto badleave;
+ return(0);
+
+ badleave:
+ VOID fflush(stdout);
+ return(1);
+
+}
+
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include "../mh.h"
+
+/* switch match, or any unambiguous abbreviation */
+/* exact match always wins, even if shares same root */
+/* returns subscript in zero-terminated tbl[] of strings */
+/* returns -1 if no match, -2 if ambiguous */
+
+#define abs(i) (i < 0 ? -i : i)
+
+smatch(string, swp)
+char *string;
+struct swit *swp;
+{
+ register char *sp, *tcp;
+ struct swit *tp;
+ int firstone, stringlen;
+
+ firstone = -1;
+
+ for (stringlen = strlen(string), tp = swp; tcp = tp->sw; tp++) {
+ if(stringlen < abs(tp->minchars)) continue; /* no match */
+ for (sp = string; *sp == *tcp++; ) {
+ if (*sp++ == 0) return(tp-swp); /* exact match */
+ }
+ if (*sp != 0) {
+ if (*sp != ' ') continue; /* no match */
+ if (*--tcp == 0) return(tp-swp); /* exact match */
+ }
+ if (firstone == -1) firstone = tp-swp; /* possible match */
+ else firstone = -2; /* ambiguous */
+ }
+
+ return (first
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+ssequal(substr, str)
+char *substr, *str;
+{
+ while(*substr)
+ if(*substr++ != *str++)
+ return(0);
+ return(1);
+}
--- /dev/null
+/*LINTLIBRARY*/
+#include "../mh.h"
+#include "../folder.h"
+#include <stdio.h>
+char *invo_name;
+
+char *add(a, b) char *a, *b; { return a; }
+int ambigsw(a, s) char *a; struct swit *s; { ; }
+int atooi(s) char *s; { return 1; }
+char **brkstring(s,b,t) char *s,*b,*t; { return &s; }
+char *cdate(d) long *d; { return cdate(d); }
+ cndfree(a) char *a; { ; }
+ /*VARARGS3*/
+char *concat(s1,s2,s3) char *s1,*s2,*s3; { return s1; }
+char *copy(f,t) char *f,*t; { return f; }
+char **copyip(f,t) char **f,**t; { return t; }
+ cputc(c,f) FILE *f; { ; }
+/*
+ * done should not be defined here because it is designed to be
+ * redefined by the parent routines if they need special exit
+ * processing. Definition here causes multiply defined messages
+ * from lint.
+ *
+ * done(s) { ; }
+ */
+int fdcompare(f1,f2) { return f1; }
+int gans(p,s) char *p; struct swit *s; { return 1; }
+char **getans(p,s) char *p; struct swit *s; { return &p; }
+char *getcpy(s) char *s; { return s; }
+ help(s,sw) char *s; struct swit *sw; { ; }
+char *locv(l) long l; { return locv(l); }
+int m_convert(s) char *s; { return 0; }
+int m_delete(s) char *s; { return 1; }
+int m_edit(e,f,u,a) char **e,*f,*a; { return 0; }
+int m_file(folder, msg, folders, nfolders, prsrvf, setcur)
+ char *folder, *msg; struct st_fold folders[];
+ int nfolders, prsrvf, setcur;
+ { return 0; }
+char *m_find(s) char *s; { return s; }
+int m_getcur(s) char *s; { return 0; }
+ m_getdefs() { ; }
+int m_getfld(s,n,b,bs,i) char *n,*b; FILE *i; { return 0; }
+char *m_getfolder() { return m_getfolder(); }
+int m_gmprot() { return 0; }
+struct msgs *m_gmsg(s) char *s; { return m_gmsg(s); }
+char *m_mailder(s) char *s; { return s; }
+char *m_name(i) { return m_name(0); }
+ m_replace(k,v) char *k,*v; { ; }
+int m_send(a,f) char **a,*f; { return 0; }
+ m_setcur(i) { ; }
+ m_update() { ; }
+int m_makedir(s) char *s; { return 1; }
+char *makename(p,s) char *p,*s; { return p; }
+char *path(n,t) char *n; { return n; }
+int peekc(i) FILE *i; { return 1; }
+ printsw(s,sw,p) char *s,*p; struct swit *sw; { ; }
+char *pwd() { return pwd(); }
+char *r1bindex(s,c) char *s; { return s; }
+int showfile(f) char *f; { return 1; }
+int smatch(s,sw) char *s; struct swit *sw; { return 1; }
+char *trimcpy(s) char *s; { return s; }
+int type(fd,s) char *s; { return 1; }
+int uleq(s1,s2) char *s1,*s2; { return 1; }
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+char *malloc();
+extern char *strcpy();
+
+
+char *trimcpy(cp)
+register char *cp;
+{
+ register char *sp;
+
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+
+ /* Zap trailing NL */
+ cp[strlen(cp) - 1] = '\0';
+
+ /* Replace embedded NL's with blanks */
+ for(sp = cp; *sp; sp++)
+ if(*sp == '\n')
+ *sp = ' ';
+ sp = malloc((unsigned)(sp - cp + 1));
+ strcpy(sp, cp);
+ return(sp);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#include <stdio.h>
+
+type(ch, s)
+char *s;
+{
+ register char *p;
+
+ for (p = s; *p++; );
+ --p;
+ if(write(ch, s, p-s) != p-s) {
+ fprintf(stderr, "type: write error!");
+ perror("");
+ return 0;
+ }
+ return(p-s);
+}
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+uleq(c1, c2)
+ register char *c1, *c2;
+{
+ register int c;
+
+ while(c = *c1++)
+ if((c|040) != (*c2|040))
+ return(0);
+ else
+ c2++;
+ return(*c2 == 0);
+}
--- /dev/null
+; See comments at end of this file
+Everyone: *
+news.*: news
+
+; Blank lines & lines beginning with a ; are ignored.
+; foo: fum -> simple replacement
+; foo: fum, fie -> list replacement
+; foo: < file -> list replacement from file
+; foo: = group -> list replacement from UNIX group
+; foo: * -> list replacement by ALL users in /etc/passwd
+; with uid >= 10
+; foo*: fum -> matches foo<anything> (incl null)
+
--- /dev/null
+#
+# Proprietary Rand Corporation, 1981.
+# Further distribution of this software
+# subject to the terms of the Rand
+# license agreement.
+#
+
+
+# The following must match entry in ../Makefile
+MHDIR = /etc/mh
+PROGS = l c
+
+all: $(PROGS)
+
+#define TERMCAP in l.c if you have TERMCAP
+#otherwise, you'll have to look at l.c and figure out what you want to do
+#about the things that will be ifdeffed out
+l: l.c
+ -rm -f l
+ $(CC) -o l $(CFLAGS) -DTERMCAP l.c -ltermcap
+
+c: l
+ ln l c
+
+install:
+ cd news; make install
+ -install -c ../support/components $(MHDIR)/components
+ -install -c ../support/distcomps $(MHDIR)/distcomps
+ -install -c ../support/mhl.format $(MHDIR)/mhl.format
+
+uninstall:
+ cd news; make uninstall
+ -cd $(MHDIR); rm -f components distcomps mhl.format
+
+distribution: clean
+
+clean:
+ -rm $(PROGS)
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * aliascheck(name) will return an indication of whether name is
+ * a valid alias from AliasFile. The return values are:
+ *
+ * 1 -> yes
+ * 0 -> no
+ * -1 -> an error in the alias file
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+char *AliasFile = "/etc/MailAliases";
+
+char *
+parse(ptr, buf)
+ register char *ptr;
+ char *buf;
+{
+ register char *cp = buf;
+
+ while(isalnum(*ptr) || *ptr == '/' || *ptr == '-' ||
+ *ptr == '.' || *ptr == '*')
+ *cp++ = *ptr++;
+ *cp = 0;
+ if(cp == buf)
+ return 0;
+ return buf;
+}
+
+
+aliascheck(name)
+ char *name;
+{
+ register char *pp;
+ char line[256], pbuf[64];
+ register FILE *a;
+
+ if((a = fopen(AliasFile, "r")) == NULL)
+ return -1;
+ while(fgets(line, sizeof line, a)) {
+ if(line[0] == ';' || line[0] == '\n') /* Comment Line */
+ continue;
+ if((pp = parse(line, pbuf)) == NULL) {
+ fclose(a);
+ return -1;
+ }
+ if(aleq(name, pp)) {
+ fclose(a);
+ return 1;
+ }
+ }
+ fclose(a);
+ return 0;
+}
+
+
+aleq(string, aliasent)
+ register char *string, *aliasent;
+{
+ register int c;
+
+ while(c = *string++)
+ if(*aliasent == '*')
+ return 1;
+ else if((c|040) != (*aliasent|040))
+ return(0);
+ else
+ aliasent++;
+ return *aliasent == 0 || *aliasent == '*';
+}
--- /dev/null
+To:
+Cc:
+Subject:
+-------
--- /dev/null
+Distribution-to:
+Distribution-cc:
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/* Added termcap (termlib): BSB:3Com 9/17/80 */
+/* Rewrite for VAX: BSB 9/9/79 */
+/* Compiled with V7 cc: BSB 6/2/79 */
+
+#include <stdio.h>
+#include <sgtty.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define YES 1
+#define NO 0
+
+#ifdef TERMCAP
+# define CLEARPAGE { tputs(cl, 1, toutc); putchar('\000'); }
+#else
+# define CLEARPAGE putchar('\014');
+#endif
+#define discard(io) { io->_cnt = BUFSIZ; io->_ptr = io->_base; }
+
+#define PAUSE 0
+#define NOTIFY 1
+#define CLEAR 2
+#define NOTICLEAR 3
+
+int spage;
+int page;
+short width;
+short noclr = 0;
+short first = 0;
+short numop = 0;
+short wrap = 0;
+short flagctl = 1;
+short ontty = 1; /* assume we're outputting to a tty */
+short delflg; /* a <DEL> was typed. */
+char bp[1024];
+char cl[40]; /* Clear Screen string */
+char *clp = cl;
+int toutc();
+
+FILE *fin;
+jmp_buf envir;
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ register int i,k;
+ register char *c1, *c2;
+ int j, clrflag;
+ int int2(), getout();
+ struct sgttyb sg;
+ struct stat st;
+ extern char _sibuf[], _sobuf[];
+ extern char *getenv();
+
+#ifdef TERMCAP
+ if((c1 = getenv("TERM")) == NULL)
+ c1 = "aa"; /* RAND */
+ if(tgetent(bp, c1) != 1) {
+ fprintf(stderr, "l: TERM env not in termcap\n");
+ exit(1);
+ }
+ if((width = tgetnum("co")) == -1 ||
+ (spage = tgetnum("li")) == -1) {
+ fprintf(stderr, "l: Can't find term width/length\n");
+ exit(1);
+ }
+ tgetstr("cl", &clp);
+#else
+ width = 80;
+ spage = 24;
+#endif
+ width--;
+ spage -= 2;
+ if(gtty(1, &sg) == -1) {
+ ontty = 0;
+ flagctl = 0;
+ }
+ c1 = c2 = argv[0];
+ do
+ if(*c1++ == '/')
+ c2 = c1;
+ while(*c1);
+ if(*c2 == 'c')
+ noclr++;
+ k=0;
+ for( i=1; i<argc; i++ ) {/* look for - args */
+ if(argv[i][0] == '-' ) {
+ switch( argv[i][1] ) {
+ case 'c': noclr++; break;
+ case 'f': first=num(&argv[i][2]); /* set first line */
+ break;
+ case 'n': numop=1; /* set number option */
+ break;
+ case 'l':
+ case 'p': spage =num(&argv[i][2]); /* set page size */
+ break;
+ case 'w': width =num(&argv[i][2]);
+ break;
+ case 'x': flagctl = !flagctl;
+ break;
+ default: printf("Unknown switch: %s\n", argv[i]);
+ return;
+ }
+ } else
+ argv[k++] = argv[i];
+ }
+
+ if (spage<=0)
+ spage = 0x07fffffff; /* largest positive number! */
+ setbuf(stdout, _sobuf);
+ if(ontty)
+ signal(SIGINT,int2);
+ signal(SIGQUIT,getout);
+ page = spage;
+ if(k == 0) { /* filter */
+ if(!setjmp(envir)) {
+ fin = stdin;
+ setbuf(fin, _sibuf);
+ pfile(0);
+ }
+ getout();
+ }
+ j = 0;
+ setjmp(envir);
+ while((i=j++) < k) {
+ page = spage;
+ clrflag = 0;
+ if(fin != NULL) { fclose(fin); fin = NULL; }
+ if(stat(argv[i], &st) == 0 && (st.st_mode&S_IFMT) == S_IFDIR){
+ printf("%s: Is a directory!\n", argv[i]);
+ continue;
+ }
+ if((fin = fopen(argv[i],"r")) == NULL) {
+ printf("Cannot open \"%s\" for reading!\n", argv[i]);
+ continue;
+ }
+ if(st.st_size == 0) {
+ printf("File \"%s\" is empty.\n", argv[i]);
+ continue;
+ }
+ if(k>1) {
+ if(i && delflg <= 0)
+ printf("\n\n");
+ delflg = 0;
+ if(ontty) {
+ printf("Press <RETURN> to list \"%s\"\n", argv[i]);
+ clrflag = 1;
+ } else
+ printf(">>>>> File \"%s\"\n", argv[i]);
+ }
+
+ pfile(clrflag);
+ }
+ getout();
+}
+
+int linpos, line, ct;
+
+pfile(flg)
+{
+ register int c;
+
+ if(flg)
+ nextpage(NOTICLEAR);
+ delflg = -1;
+ line = 1;
+ ct = page;
+ while (line < first) /* Dcrocker: skip to first line */
+ if((c = getch()) == EOF)
+ return;
+ else if(c == '\n')
+ line++;
+ linpos = 0;
+
+ if ((c = getch()) != EOF) {
+ if(!flg && !noclr && ontty)
+ CLEARPAGE;
+ do
+ putch(c);
+ while ((c = getch()) != EOF);
+ }
+ fflush(stdout);
+}
+
+num(s) /* computes the internal form of a number */
+register char *s; /* bad chars are ignored */
+{
+ register int c, i, sign;
+
+ sign=1; i=0;
+ while(c = *s++) {
+ if(c=='-' && sign==1) sign = -1;
+ c -= '0';
+ if(c>=0 && c<=9) i=i*10+c;
+ }
+ return(i*sign);
+}
+
+nextpage (clearpage)
+{ char c;
+
+ if(!ontty)
+ return;
+ if (clearpage & NOTIFY)
+ putchar('\007');
+ fflush(stdout);
+ c = 0;
+ while(read(2, &c, 1) && c != '\n') ;
+ if (clearpage & CLEAR && c) {
+ CLEARPAGE;
+ page = spage;
+ } else {
+ page = (spage>>1) + (spage>>3);
+/*** page = spage * .6; ***/
+ }
+ return;
+}
+
+int2()
+{
+ signal(SIGINT,int2);
+ discard(stdout);
+ if(delflg)
+ putchar('\n');
+ delflg++;
+ longjmp(envir, 1);
+}
+
+int peekc = -2;
+
+peekch()
+{
+ return(peekc = getch());
+}
+
+getch()
+{
+ register int c;
+
+ if(peekc != -2) {
+ c = peekc;
+ peekc = -2;
+ return(c);
+ };
+ c = getc(fin);
+ if(c != EOF)
+ c &= 0177;
+ return(c);
+}
+
+putch(c)
+register int c;
+{
+ if(linpos == 0 && numop) {
+ if(!wrap)
+ printf("%5d\t", line);
+ else
+ printf("\t");
+ linpos += 8;
+ }
+ if(c < 040 || c == 0177) {
+ switch(c) {
+ case '\n':
+ line++;
+ linpos = 0;
+ wrap = 0;
+ putchar(c);
+ break;
+ case '\f':
+ goto npage;
+ case '\t':
+ linpos += 8;
+ linpos &= ~07;
+ putchar(c);
+ break;
+ case '\b': /* ignore backspaces */
+ break;
+ default:
+ if(flagctl) {
+ if(c == '\7')
+ putchar(c);
+ putch('^');
+ if(c != 0177)
+ c += '@';
+ else
+ c = 'd';
+ }
+ putchar(c);
+ break;
+ }
+ }
+ else {
+ putchar(c);
+ linpos++;
+ }
+ if(width && linpos >= width && peekch() != '\n') {
+ putchar('\n'); linpos = 0;
+ }
+ if(linpos == 0 && --ct <= 0) {
+ npage: nextpage(NOTICLEAR);
+ ct = page;
+ }
+}
+
+
+getout()
+{
+ exit(0);
+}
+
+toutc(ch)
+{
+ putchar
\ No newline at end of file
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+#define MSGRETTIME (5*24*60*60) /* How long to keep trying */
+#define MAILQDIR "/usr/spool/netmail/"
+#define MAILDROP "/usr/spool/mail/"
+#define TMAILQDIR "/usr/spool/mailt/"
+#define MAILLOCKDIR "/usr/spool/locks/"
+#define MAILALIASES "/etc/MailAliases"
+
+/* Exit codes from net mailer */
+#define NM_OK 0 /* Delivered */
+#define NM_BAD 1 /* Not delivered to some addresses (perm failure) */
+#define NM_MORE 2 /* Some addresses not yet processed (temp failure) */
+#define NM_BADMORE 3 /* Both of above */
--- /dev/null
+ignores=Message-id
+;for pagination, use length=30 or whatever
+width=134,length=0,overflowtext=***>,overflowoffset=0
+ignores=.
+MessageName:nocomponent
+:
+Date:nocomponent,leftadjust
+:
+From:leftadjust,compwidth=6
+To:leftadjust,compwidth=6
+cc:leftadjust,compress,width=80,compwidth=5
+bcc:leftadjust,compress,width=80,compwidth=6
+:
+Subject:leftadjust,width=80,compwidth=9
+Re:leftadjust,width=80,compwidth=4
+In-reply-to:leftadjust,width=80,compwidth=13
+:
+body:nocomponent,width=134,length=0,overflowtext=***>,overflowoffset=0
+:
+width=80,length=0,overflowtext=,overflowoffset=11
+extras:leftadjust,compwidth=11
+:
+reply-to:leftadjust,compwidth=11
+sender:leftadjust,compwidth=11
+received:leftadjust,compwidth=11
+via:leftadjust,compwidth=11
+timestamp:leftadjust,compwidth=11
+mail-from:leftadjust,compwidth=11
+MessageName:noco
\ No newline at end of file
--- /dev/null
+#
+# Proprietary Rand Corporation, 1981.
+# Further distribution of this software
+# subject to the terms of the Rand
+# license agreement.
+#
+
+
+NEWSDIR = /usr/news
+
+install:
+ cp 1char $(NEWSDIR)/.1char
+ cp mh_profile $(NEWSDIR)/.mh_profile
+ cp mh_receive $(NEWSDIR)/.mh_receive
+
+uninstall:
+ cd $(NEWSDIR); rm -f .1char .mh_profile .mh_receive
--- /dev/null
+Path: /usr/news
--- /dev/null
+F=`echo $4 | sed '
+s/news\.//
+'`
+if [ -d /usr/news/$F ] ; then
+ cat /usr/news/.1char >> /usr/news/.$F
+ /usr/local/file -link -file $1 +/usr/news/$F
+elif [ -d /usr/news/Lost+Found ] ; then
+ /usr/local/file -link -file $1 +/usr/news/Lost+Found
+else
+ mkdir /usr/news/Lost+Found
+ /usr/local/file -link -file $1 +/usr/news/Lost+Found
+fi
+
+
+: BUGS: mail directory must be in /usr/news.
+: .mh_receive should be a C program that
+: searches news's .mh_profile for the mail path.
--- /dev/null
+#ifdef COMMENT
+ Proprietary Rand Corporation, 1981.
+ Further distribution of this software
+ subject to the terms of the Rand
+ license agreement.
+#endif
+
+/*
+ * putenv(name, arg)
+ * replaces or adds the `name' entry with "name=arg";
+ *
+ * Uses malloc() for space for new vector and new entry;
+ *
+ * Bruce Borden January 1980
+ * The Rand Corporation
+ */
+
+#include <stdio.h>
+
+extern char **environ;
+
+putenv(name, arg)
+char *name, *arg;
+{
+ register int i;
+ register char **ep, **nep, *cp;
+
+ if((cp = (char *) malloc(strlen(name) + strlen(arg) + 2)) == NULL)
+ return(1);
+ strcpy(cp, name);
+ strcat(cp, "=");
+ strcat(cp, arg);
+ for(ep = environ, i = 0; *ep; ep++, i++)
+ if(nvmatch(name, *ep)) {
+ *ep = cp;
+ return(0);
+ }
+ if((nep = (char **) malloc((i+2) * sizeof *nep)) == NULL)
+ return(1);
+ for(ep = environ, i = 0; *ep; )
+ nep[i++] = *ep++;
+ nep[i++] = cp;
+ nep[i] = 0;
+ environ = nep;
+ return(0);
+}
+
+/*
+ * s1 is either name, or name=value
+ * s2 is name=value
+ * if names match, return value of s2, else NULL
+ * used for environment searching: see getenv
+ */
+
+static
+nvmatch(s1, s2)
+register char *s1, *s2;
+{
+
+ while (*s1 == *s2++)
+ if (*s1++ == '=')
+ return(1);
+ if (*s1 == '\0' && *(s2-1) == '=')
+ return(1);
+ return(0);
+}
--- /dev/null
+/*
+ * Type definitions for the strings(3) subroutines.
+ */
+
+char *strcat();
+char *strncat();
+char *strcpy();
+char *strncpy();
+int strcmp();
+int strncmp();
+char *index();
+char *rindex();
--- /dev/null
+# %M% %I% %E%
+#
+DESTDIR=
+
+all:
+ cd cmds; make ${MFLAGS}
+
+install: all
+ cd cmds; make DESTDIR=${DESTDIR} install
+ cd man; make DESTDIR=${DESTDIR} install
+
+clean:
+ cd cmds; make ${MFLAGS} clean
--- /dev/null
+Title: MH
+
+Authors: Bruce Borden
+ Stockton Gaines
+ Norman Shapiro
+
+Help from: Phyllis Kantar
+ Robert Anderson
+ David Crocker
+
+
+Description:
+
+The user command interface to MH is the UNIX ``shell'' (the standard
+UNIX command interpreter). Each separable component of message handling,
+such as message composition or message display, is a separate command.
+Each program is driven from and updates a private user environment,
+which is stored as a file between program invocations. This private
+environment also contains information to ``custom tailor'' MH to the
+individuals's tastes. MH stores each message as a separate file under
+UNIX, and it utilizes the tree-structured UNIX file system to organize
+groups of files within separate directories or ``folders.'' All of
+the UNIX facilities for dealing with files and directories, such as
+renaming, copying, deleting, cataloging, off-line printing, etc., are
+applicable to messages and directories of messages (folders). Thus,
+important capabilities needed in a message system are available in MH
+without the need (often seen in other message systems) for code that
+duplicates the facilities of the supporting operating system. It also
+allows users familiar with the shell to use MH with minimal effort.
--- /dev/null
+# @(#)Makefile 4.9 (Berkeley) 83/07/07
+#
+# define UCB to get #files instead of ,files
+#
+CFLAGS= -O -DUNIXCOMP -DUCB -I.
+BINDIR= /usr/new/mh
+MHDIR= /usr/new/lib/mh
+SUBS = ../subs
+STRINGS = ../strings
+PROGS= comp refile folder forw inc install-mh \
+ next news pick prev prompter repl rescue rmf rmm scan \
+ send show unixtomh
+DESTDIR=
+
+all: ${PROGS}
+
+subs.a: mh.h
+ rm -f ${SUBS}/subs.a subs.a
+ cd ${SUBS}; make
+ ranlib ${SUBS}/subs.a
+ ln -s ${SUBS}/subs.a subs.a
+
+strings.a:
+ rm -f ${STRINGS}/strings.a strings.a
+ cd ${STRINGS}; make
+ ranlib ${STRINGS}/strings.a
+ ln -s ${STRINGS}/strings.a strings.a
+
+comp: mh.h comp.o subs.a strings.a
+ ${CC} -o comp comp.o subs.a strings.a
+
+refile: mh.h refile.o subs.a strings.a
+ ${CC} -o refile refile.o subs.a strings.a
+
+folder: mh.h folder.o subs.a strings.a
+ ${CC} -o folder folder.o subs.a strings.a
+
+forw: mh.h forw.o annotate.o subs.a strings.a
+ ${CC} -o forw forw.o annotate.o subs.a strings.a
+
+inc: mh.h inc.o scansub.o subs.a strings.a
+ ${CC} -o inc inc.o scansub.o subs.a strings.a
+
+install-mh: mh.h install-mh.o subs.a strings.a
+ ${CC} -o install-mh install-mh.o subs.a strings.a
+
+news: mh.h news.o subs.a strings.a
+ ${CC} -o news news.o subs.a strings.a
+
+next: mh.h nexthdr.o next.o subs.a strings.a
+ ${CC} -o next nexthdr.o next.o subs.a strings.a
+
+pick: mh.h pick.o grep.o subs.a strings.a
+ ${CC} -o pick pick.o grep.o subs.a strings.a
+
+prev: mh.h prevhdr.o next.o subs.a strings.a
+ ${CC} -o prev prevhdr.o next.o subs.a strings.a
+
+prompter: mh.h prompter.o subs.a strings.a
+ ${CC} -o prompter prompter.o subs.a strings.a
+
+repl: mh.h reply.o replsubs.o annotate.o subs.a strings.a
+ ${CC} -o repl reply.o replsubs.o annotate.o subs.a strings.a
+
+rescue: rescue.o emitl.o
+ ${CC} -o rescue rescue.o
+
+rmf: mh.h rmf.o subs.a strings.a
+ ${CC} -o rmf rmf.o subs.a strings.a
+
+rmm: mh.h rmm.o subs.a strings.a
+ ${CC} -o rmm rmm.o subs.a strings.a
+
+scan: mh.h scan.o scansub.o subs.a strings.a
+ ${CC} -o scan scan.o scansub.o subs.a strings.a
+
+send: mh.h send.o subs.a strings.a
+ ${CC} -o send send.o subs.a strings.a
+
+show: mh.h show.o subs.a strings.a
+ ${CC} -o show show.o subs.a strings.a
+
+unixtomh: unixtomh.o
+ ${CC} -o unixtomh unixtomh.o subs.a
+
+onceonly:
+ -@if [ ! -f ${DESTDIR}/usr/bin/filetype -a \
+ ! -f ${DESTDIR}/bin/filetype -a -f ${DESTDIR}/bin/file ] ; then \
+ mv ${DESTDIR}/bin/file ${DESTDIR}/bin/filetype; \
+ echo "${DESTDIR}/bin/file => ${DESTDIR}/bin/filetype" ; \
+ else true ; \
+ fi
+ -@if [ ! -f ${DESTDIR}/bin/filetype -a \
+ ! -f ${DESTDIR}/usr/bin/filetype -a \
+ -f ${DESTDIR}/usr/bin/file ] ; then \
+ mv ${DESTDIR}/usr/bin/file ${DESTDIR}/usr/bin/filetype; \
+ echo "${DESTDIR}/usr/bin/file => ${DESTDIR}/usr/bin/filetype"; \
+ else true ; \
+ fi
+ -@if [ ! -f ${DESTDIR}/bin/bellmail -a -f ${DESTDIR}/bin/mail ] ; then \
+ mv ${DESTDIR}/bin/mail ${DESTDIR}/bin/bellmail; \
+ echo "${DESTDIR}/bin/mail => ${DESTDIR}/bin/bellmail" ;\
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/comp ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/comp" ; \
+ else true ; \
+ fi
+# -@if [ -f ${DESTDIR}/${BINDIR}/dist ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/dist" ; \
+ else true ; \
+ fi
+# -@if [ -f ${DESTDIR}/${BINDIR}/file ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/file" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/folder ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/folder" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/forw ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/forw" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/inc ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/inc" ; \
+ else true ; \
+ fi
+# -@if [ -f ${DESTDIR}/${BINDIR}/mail ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/mail" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/news ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/news" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/next ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/next" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/pick ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/pick" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/prev ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/prev" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/prompter ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/prompter" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/repl ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/repl" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/rmf ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/rmf" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/rmm ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/rmm" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/scan ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/scan" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/send ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/send" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${BINDIR}/show ] ; then \
+ echo "Collision on ${DESTDIR}/${BINDIR}/show" ; \
+ else true ; \
+ fi
+ -@if [ -f ${DESTDIR}/${MHDIR} -o -d ${DESTDIR}/${MHDIR} ] ; then \
+ echo "${DESTDIR}/${MHDIR} already exists!"; \
+ else true ; \
+ fi
+
+install:
+ -mkdir ${DESTDIR}/${BINDIR}
+ -mkdir ${DESTDIR}/${MHDIR}
+ install -s -m 1755 comp ${DESTDIR}/${BINDIR}/comp;
+ install -s refile ${DESTDIR}/${BINDIR}/refile;
+ install -s folder ${DESTDIR}/${BINDIR}/folder;
+ install -s forw ${DESTDIR}/${BINDIR}/forw;
+ install -s -m 1755 inc ${DESTDIR}/${BINDIR}/inc;
+ install -s install-mh ${DESTDIR}/${MHDIR}/install-mh;
+ install -s -m 1755 next ${DESTDIR}/${BINDIR}/next;
+ install -s news ${DESTDIR}/${BINDIR}/news;
+ install -s pick ${DESTDIR}/${BINDIR}/pick;
+ install -s prev ${DESTDIR}/${BINDIR}/prev;
+ install -s -m 1755 prompter ${DESTDIR}/${BINDIR}/prompter;
+ install -s repl ${DESTDIR}/${BINDIR}/repl;
+ install -s rmf ${DESTDIR}/${BINDIR}/rmf;
+ install -s rmm ${DESTDIR}/${BINDIR}/rmm;
+ install -s scan ${DESTDIR}/${BINDIR}/scan;
+ install -s send ${DESTDIR}/${BINDIR}/send;
+ install -s -m 1755 show ${DESTDIR}/${BINDIR}/show;
+ install -s unixtomh ${DESTDIR}/${MHDIR}/unixtomh;
+ rm -f ${DESTDIR}/${BINDIR}/folders
+ ln ${DESTDIR}/${BINDIR}/folder ${DESTDIR}/${BINDIR}/folders
+ install -c ../support/components ${DESTDIR}/${MHDIR}/components;
+ install -c ../support/distcomps ${DESTDIR}/${MHDIR}/distcomps;
+
+cleanup:
+ rm -f ${PROGS}
+
+clean:
+ cd ${SUBS}; make ${MFLAG} clean
+ cd ${STRINGS}; make ${MFLAG} clean
+ rm -f ${PROGS} subs.a strings.a *.o
--- /dev/null
+#include <stdio.h>
+#include <ctype.h>
+#include <grp.h>
+#include <sys/param.h>
+#include <dir.h>
+
+char *AliasFile = "/usr/local/lib/MailAliases";
+char *Password = "/etc/passwd";
+char *MailDir = "/usr/spool/mail";
+
+char *termptr;
+
+struct mailname {
+ struct mailname *m_next;
+ char *m_name;
+ int m_seen;
+} users, bad;
+
+
+char *parse(ptr, buf)
+register char *ptr;
+char *buf;
+{
+ register char *cp;
+
+ cp = buf;
+ while(isspace(*ptr) || *ptr == ',' || *ptr == ':')
+ ptr++;
+ while(isalnum(*ptr) || *ptr == '/' || *ptr == '-' || *ptr == '.')
+ *cp++ = *ptr++;
+ if(cp == buf) {
+ switch(*ptr) {
+ case '<':
+ case '*':
+ case '=':
+ *cp++ = *ptr++;
+ }
+ }
+ *cp = 0;
+ if(cp == buf)
+ return 0;
+ termptr = ptr;
+ return buf;
+}
+
+
+char *mail = 0;
+FILE *out;
+int donecd = 0;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register char *cp, *pp, **cpp;
+ register struct mailname *lp;
+ register struct group *gp;
+ struct direct *dir;
+ DIR *dirp;
+ char line[256], pbuf[64];
+ FILE *a;
+
+ if(argc == 3 && strcmp(argv[1], "-mail") == 0)
+ mail = argv[2];
+ if(!mail)
+ out = stdout;
+ if((a = fopen(Password, "r")) == NULL) {
+ om();
+ fprintf(out, "Can't open password file ");
+ perror(Password);
+ done(1);
+ }
+ while(fgets(line, sizeof line, a)) {
+ if(line[0] == '\n' || line[0] == ';')
+ continue;
+ cp = parse(line, pbuf);
+ add(cp, &users);
+ }
+ fclose(a);
+ if((a = fopen(AliasFile, "r")) == NULL) {
+ om();
+ fprintf(out, "Can't open alias file: %s\n", AliasFile);
+ donecd = 1;
+ } else {
+ while(fgets(line, sizeof line, a)) {
+ if(line[0] == '\n' || line[0] == ';')
+ continue;
+ cp = parse(line, pbuf);
+ if(check(cp, 0)) {
+ add(line, &bad);
+ donecd = 1;
+ }
+ }
+ fclose(a);
+ if(donecd < 1) {
+ if(out)
+ fprintf(out, "No Alias Inconsistencies.\n");
+ } else {
+ om();
+ fprintf(out, "%s :: %s Collisions:\n",
+ Password, AliasFile);
+ fprintf(out, "Colliding alias lines:\n");
+ for(lp = bad.m_next; lp; lp = lp->m_next)
+ fprintf(out, "%s", lp->m_name);
+ donecd = 1;
+ }
+ }
+ while(gp = getgrent()) {
+ for(cpp = gp->gr_mem; *cpp; cpp++)
+ if(!check(*cpp, 1)) {
+ om();
+ fprintf(out, "Group: %s--User: %s not in /etc/passwd\n",
+ gp->gr_name, *cpp);
+ donecd = 2;
+ }
+ }
+ if(donecd < 2 && out)
+ fprintf(out, "No extraneous group entries.\n");
+#ifdef RAND
+ for(lp = users.m_next; lp; lp = lp->m_next)
+ if(lp->m_seen == 0) {
+ om();
+ fprintf(out, "User: %s not in a group.\n", lp->m_name);
+ donecd = 3;
+ }
+ if(donecd < 3 && out)
+ fprintf(out, "No Users not in any group.\n");
+#endif
+ if ((dirp = opendir(MailDir)) == 0) {
+ om();
+ fprintf(out, "Can't open mail directory: %s\n", MailDir);
+ donecd = 4;
+ } else {
+ (void) readdir(dirp); /* skip . */
+ (void) readdir(dirp); /* skip .. */
+ while (dir = readdir(dirp)) {
+ if (!check(dir->d_name, 0)) {
+ om();
+ fprintf(out, "Mail drop: %s--Nonexistent user.\n",
+ dir->d_name);
+ donecd = 4;
+ }
+ }
+ closedir(dirp);
+ }
+ if(donecd < 4 && out)
+ fprintf(out, "No Extra mail drops.\n");
+
+ done(donecd);
+}
+
+
+add(name, list)
+char *name;
+struct mailname *list;
+{
+ register struct mailname *mp;
+ char *getcpy();
+
+ for(mp = list; mp->m_next; mp = mp->m_next)
+ ;
+ mp->m_next = (struct mailname *) malloc(sizeof *mp->m_next);
+ mp = mp->m_next;
+ mp->m_next = 0;
+ mp->m_name = getcpy(name);
+}
+
+check(name, mark)
+ char *name;
+ int mark;
+{
+ register struct mailname *mp;
+
+ for(mp = users.m_next; mp; mp = mp->m_next)
+ if(uleq(name, mp->m_name)) {
+ if(mark)
+ mp->m_seen = 1;
+ return 1;
+ }
+ return 0;
+}
+
+
+om()
+{
+ int pipes[2], child;
+
+ if(out)
+ return;
+ if(mail) {
+ pipe(pipes);
+ out = fdopen(pipes[1], "w");
+ if((child = fork()) == -1) {
+ fprintf(stderr, "Aliascheck: no forks!\n");
+ done(1);
+ }
+ if(child == 0) {
+ close(pipes[1]);
+ close(0);
+ dup(pipes[0]);
+ close(pipes[0]);
+ execl("/bin/mail", "mail", mail, 0);
+ execl("/usr/bin/mail", "mail", mail, 0);
+ perror("mail");
+ done(1);
+ }
+ fprintf(out, "Aliascheck: ");
+ }
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)annotate.c 4.1 2/23/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* annotate file component data
+ *
+ * prepends Component: data
+ * date stamp
+ */
+
+annotate(file, comp, text, inplace)
+ char *file, *comp, *text;
+{
+ register int src;
+ register char *cp;
+ register FILE *tmp;
+ int cnt, fd;
+ char buf[BUFSIZ], *sp, tmpfil[128];
+ long now;
+ struct stat stbuf;
+ char *cdate();
+
+ if((src = open((cp = file), 2)) == -1) { /* this should be an X-open*/
+ fprintf(stderr, "Can't open ");
+ perror(cp);
+ return(1);
+ }
+ copy(cp, buf);
+ sp = r1bindex(buf);
+ if(sp != buf) {
+ *sp = 0;
+ cp = copy(buf, tmpfil);
+ } else
+ cp = tmpfil;
+ copy(makename("ano",".tmp"), cp);
+ fstat(src, &stbuf);
+ if((tmp = fopen(tmpfil, "w")) == NULL) {
+ fprintf(stderr, "Can't create ");
+ perror(tmpfil);
+ return(1);
+ }
+ chmod(tmpfil, stbuf.st_mode&0777);
+ cp = comp;
+ if(*cp >= 'a' && *cp <= 'z') *cp -= 040;
+ time(&now);
+ cp = cdate(&now);
+ cp[9] = ' '; cp[15] = 0;
+ if(*cp == ' ') cp++;
+ fprintf(tmp, "%s: <<%s>>\n", comp, cp);
+ cp = text;
+ do {
+ if(*cp == ' ' || *cp == '\t') cp++;
+ sp = cp;
+ while(*cp && *cp++ != '\n') ;
+ if(cp - sp)
+ fprintf(tmp, "%s: %*s", comp, cp-sp, sp);
+ } while(*cp);
+ if(cp[-1] != '\n' && cp != text) putc('\n', tmp);
+ do
+ if((cnt = read(src, buf, sizeof buf)) > 0)
+ fwrite(buf, cnt, 1, tmp);
+ while(cnt == sizeof buf);
+ fclose(tmp);
+ if(inplace) {
+ fd = open(tmpfil, 0); /* reopen for reading */
+ lseek(src, 0l, 0);
+ do
+ if((cnt = read(fd, buf, sizeof buf)) > 0)
+ write(src, buf, cnt);
+ while(cnt == sizeof buf);
+ close(fd);
+ } else {
+ /* cp = copy(file, buf); */
+ /* *--cp =| 0200; */
+ /* copy(".bak", copy(file, buf)); */
+ cp = copy(file, buf);
+ cp[1] = 0;
+ do
+ *cp = cp[-1];
+ while(--cp >= buf && *cp != '/');
+ *++cp =
+#ifdef UCB
+ '#';
+#else
+ ',';
+#endif
+ unlink(buf);
+ if(link(file, buf) == -1) {
+ fprintf(stderr, "Can't rename %s to bak file.\n", file);
+ return(1);
+ }
+ if(unlink(file) == -1) {
+ fprintf(stderr, "Can't unlink %s\n", file);
+ return(1);
+ }
+ if(link(tmpfil, file) == -1) {
+ fprintf(stderr, "Can't lnk temp file \"%s\" to %s\n",
+ tmpfil, file);
+ return(1);
+ }
+ }
+ close(src);
+ unlink(tmpfil);
+ return(0);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <strings.h>
+#include <signal.h>
+
+/* #define NEWS 1 */
+#define NONE 0
+
+/* #define TEST 1 */
+
+char *anyul[] = {
+ "no", 0,
+ "yes", 0,
+ "use", 0,
+ "list", 0,
+ 0
+};
+
+char *aleqs[] = {
+ "list", 0, /* 0 */
+ "edit [<editor>]", 0, /* 1 */
+ "quit [delete]", 0, /* 2 */
+ "send [verbose]", 0, /* 3 */
+ 0
+};
+
+
+struct swit switches[] = {
+ "editor editor", 0, /* 0 */
+ "form formfile", 0, /* 1 */
+ "use", 0, /* 2 */
+ "nouse", 0, /* 3 */
+ "help", 4, /* 4 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp;
+ register int in, out;
+ int use, cnt, status, intr;
+ char buf[BUFSIZ], *ed, *file, *form;
+ static char path[128];
+ char **ap;
+ char *arguments[50], **argp;
+
+/*** setbuf(stdout, _sobuf); ***/
+#ifdef NEWS
+ m_news();
+#endif
+ form = 0; use = 0; file = 0; ed = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-') {
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "comp: -%s unknown\n", cp);
+ goto leave;
+ case 0: if(!(ed = *argp++)) { /* -editor */
+ missing: fprintf(stderr, "comp: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 1: if(!(form = *argp++)) /* -form */
+ goto missing;
+ continue;
+ case 2: use = 1; continue; /* -use */
+ case 3: use = 0; continue; /* -nouse */
+ case 4: help("comp [file] [switches]",
+ switches);
+ goto leave;
+ }
+ }
+ file = cp;
+ }
+ if(form) {
+ if((in = open(m_maildir(form), 0)) < 0) {
+ fprintf(stderr, "comp: Can't open form file: %s\n", form);
+ goto leave;
+ }
+ } else if((in = open(m_maildir(components), 0)) < 0 &&
+ (in = open(stdcomps, 0)) < 0) {
+ fprintf(stderr, "comp: Can't open default components file!!\n");
+ goto leave;
+ }
+ if(!file)
+ file = draft;
+ copy(m_maildir(file), path);
+ if((out = open(path, 0)) >= 0) {
+ cp = concat("\n\"", path, "\" exists; delete? ", 0);
+ if(use || fdcompare(in, out))
+ goto editit;
+ while((status = gans(cp, anyul)) == 3)
+ showfile(path);
+ if(status == 2) {
+ use++;
+ goto editit;
+ }
+ if(status == 0)
+ goto leave;
+ close(out);
+ } else if(use) {
+ fprintf(stderr, "comp: \"%s\" doesn't exist!\n", path);
+ goto leave;
+ }
+ if((out = creat(path, m_gmprot())) < 0) {
+ fprintf(stderr, "comp: Can't create \"%s\"\n", path);
+ goto leave;
+ }
+ do
+ if(cnt = read(in, buf, sizeof buf))
+ write(out, buf, cnt);
+ while(cnt == sizeof buf);
+ close(in);
+editit:
+ close(out);
+ if(m_edit(&ed, path, use, NONE) < 0)
+ goto leave;
+#ifdef TEST
+ fprintf(stderr, "!! Test Version of SEND Being Run !!\n");
+ fprintf(stderr, " Send verbose !\n\n");
+#endif
+
+ for(;;) {
+ if(!(argp = getans("\nWhat now? ", aleqs)))
+ goto leave;
+ switch(smatch(*argp, aleqs)) {
+ case 0: showfile(path); /* list */
+ break;
+ case 1: if(*++argp) /* edit */
+ ed = *argp;
+ if(m_edit(&ed, path, use, NONE) == -1)
+ goto leave;
+ break;
+ case 2: if(*++argp && *argp[0] == 'd') /* quit */
+ if(unlink(path) == -1) {
+ fprintf(stderr, "Can't unlink %s ", path);
+ perror("");
+ }
+ goto leave;
+ case 3: if(*++argp) cp = *argp; else cp = ""; /* send */
+ if(! m_send(cp, path))
+ goto leave;
+ default:fprintf(stderr, "comp: illegal option\n"); /*##*/
+ break;
+ }
+ }
+
+leave:
+ m_update();
+ done(0);
+}
+
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)deliver.c 4.4 9/25/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <strings.h>
+
+#define DELIVERMAIL "/usr/lib/sendmail"
+#define EVERYONE 10
+#define RECVPROG "/.mh_receive"
+#define FCCS 10 /* Max number of fcc's allowed */
+
+struct shome { /* Internal name/uid/home database */
+ struct shome *h_next;
+ char *h_name;
+ int h_uid;
+ int h_gid;
+ char *h_home;
+} *homes, *home();
+
+struct swit switches[] = {
+ "debug", -1, /* 0 */
+ "format", 0, /* 1 */
+ "noformat", 0, /* 2 */
+ "msgid", 0, /* 3 */
+ "nomsgid", 0, /* 4 */
+ "verbose", 0, /* 5 */
+ "noverbose", 0, /* 6 */
+ "help", 4, /* 7 */
+ 0, 0
+};
+
+int verbose, format, msgid, debug, myuid, addrp;
+int lockwait; /* Secs to wait for mail lock (From strings/lockdir.c) */
+#define LOCKWAIT (lockwait * 5) /* Ignore lock if older than this */
+int donecd;
+long now;
+char tmpfil[32], fccfold[FCCS][128];
+char tmp2fil[32];
+int fccind;
+char *rindex();
+
+struct mailname {
+ struct mailname *m_next;
+ char *m_name;
+} addrlist;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register char *cp, *addrs, **argp;
+ register struct mailname *lp;
+ char buf[BUFSIZ], name[NAMESZ];
+ char *msg;
+ int state, compnum, fd;
+ FILE *in, *out;
+ char *getname();
+
+ msg = 0;
+ argp = argv + 1;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ done(1);
+ /* unknown */
+ case -1:fprintf(stderr, "sndmsg: -%s unknown switch.\n", cp);
+ done(1);
+ case 0: verbose++; debug++; continue; /* -debug */
+ case 1: fprintf(stderr, "Deliver: -format not yet.\n");
+ done(1);
+/*** case 1: format = 1; continue; /* -format */
+ case 2: format = 0; continue; /* -noformat */
+ case 3: msgid = 1; continue; /* -msgid */
+ case 4: msgid = 0; continue; /* -nomsgid */
+ case 5: verbose = 1; continue; /* -verbose */
+ case 6: verbose = 0; continue; /* -noverbose */
+ case 7: help("deliver [switches] file",
+ switches);
+ done(1);
+ }
+ if(msg) {
+ fprintf(stderr, "Deliver: Only one message at a time!\n");
+ done(1);
+ } else
+ msg = cp;
+ }
+ if(!msg) {
+ fprintf(stderr, "Deliver: No Message specified.\n");
+ fprintf(stderr, "Deliver: Usage: deliver [switches] file\n");
+ done(1);
+ }
+ if((in = fopen(msg, "r")) == NULL) {
+ fprintf(stderr, "Deliver: Can't open ");
+ perror(msg);
+ done(1);
+ }
+ copy(makename("locs", ".tmp"), copy("/tmp/", tmpfil));
+ if(!debug) {
+ if((out = fopen(tmpfil, "w")) == NULL) {
+ fprintf(stderr, "Can't create %s\n", tmpfil);
+ done(1);
+ }
+ chmod(tmpfil, 0744);
+ } else
+ out = stdout;
+
+ gethomes();
+ myuid = getuid();
+#ifndef UNIXCOMP
+ putdate(0, out); /* Tack on the date */
+ putfrom(out); /* Tack on the from */
+#endif
+ putmsgid(out); /* and msg id if desired */
+ for(addrs = 0, compnum = 1, state = FLD;;) {
+ state = m_getfld(state, name, buf, sizeof buf, in);
+ swt: switch(state) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ compnum++;
+ if(uleq(name, "to") || uleq(name, "cc") ||
+ uleq(name, "bcc"))
+ addrs = add(buf, addrs);
+ if(!uleq(name, "bcc")) {
+ cp = buf;
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+ fprintf(out, "%s: %s", name, cp);
+ if(uleq(name, "fcc")) {
+ if(fccind >= FCCS) {
+ fprintf(stderr, "Deliver: too many fcc's.\n");
+ done(1);
+ }
+ copy(cp, fccfold[fccind]);
+ if(cp = rindex(fccfold[fccind], '\n'))
+ *cp = 0;
+ fccind++;
+ }
+ }
+ while(state == FLDPLUS || state == FLDEOF) {
+ state = m_getfld(state, name, buf, sizeof buf, in);
+ addrs = add(buf, addrs);
+ fputs(buf, out);
+ }
+ if(state == FLDEOF)
+ goto process;
+ break;
+
+ case BODY:
+ case BODYEOF:
+ fprintf(out, "\n%s", buf);
+ while(state == BODY) {
+ state=m_getfld(state,name,buf,sizeof buf,in);
+ fputs(buf, out);
+ }
+
+ case FILEEOF:
+ goto process;
+
+ case LENERR:
+ case FMTERR:
+ fprintf(stderr, "??Message Format Error ");
+ fprintf(stderr, "in Component #%d.\n", compnum);
+ done(1);
+
+ default:
+ fprintf(stderr, "Getfld returned %d\n", state);
+ done(1);
+ }
+ }
+process:
+ if(!debug)
+ fclose(out);
+ else
+ printf("-----\n");
+ fclose(in);
+ while(cp = getname(addrs)) /* Put addrs in chain */
+ insert(cp);
+ if(debug) {
+ printf("Before alias(): "); pl();
+ }
+
+ alias(); /* Map names if needed */
+
+ for(lp = addrlist.m_next; lp; lp = lp->m_next) {
+#ifdef UNIXCOMP
+ if (netname(lp->m_name))
+ continue;
+#endif
+#ifndef DELIVERMAIL
+ if(home(lp->m_name) == NULL) {
+ fprintf(stderr, "Deliver: Unknown User: %s.\n", lp->m_name);
+ fprintf(stderr, "Deliver: Message Not Delivered.\n");
+ if(!debug)
+ unlink(tmpfil);
+ done(1);
+ }
+#endif DELIVERMAIL
+ }
+ if(debug) {
+ printf("Addrs: "); pl();
+ }
+
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ if(!debug) { /* Send the mail */
+ fd = open(tmpfil, 0);
+ for(lp = addrlist.m_next; lp; lp = lp->m_next)
+ sendmail(lp->m_name, fd);
+ stflush(fd);
+ close(fd);
+ if(fccind) {
+#ifdef UNIXCOMP
+ strcpy(tmp2fil, "/tmp/mhFXXXXXX");
+ mktemp(tmp2fil);
+ out = fopen(tmp2fil, "w");
+ putdate(0, out); /* Tack on the date */
+ putfrom(out); /* Tack on the from */
+ appendfile(tmpfil, out);
+ fclose(out);
+ for(state = 0; state < fccind; state++)
+ fcc(tmp2fil, fccfold[state]);
+ unlink(tmp2fil);
+#else
+ for(state = 0; state < fccind; state++)
+ fcc(tmp2fil, fccfold[state]);
+#endif
+ }
+ unlink(tmpfil);
+ }
+ done(donecd);
+}
+
+#ifdef UNIXCOMP
+
+appendfile(name, fout)
+ char name[];
+ register FILE *fout;
+{
+ register int c;
+ register FILE *fin;
+
+ if ((fin = fopen(name, "r")) == NULL) {
+ perror(name);
+ return;
+ }
+ while ((c = getc(fin)) != EOF)
+ putc(c, fout);
+ fclose(fin);
+}
+
+netname(name)
+ char name[];
+{
+ register char *cp;
+ char *index();
+
+ cp = name;
+ if (index(cp, ':') || index(cp, '!') ||
+ index(cp, '@') || index(cp, '^'))
+ return(1);
+ return(0);
+}
+#endif
+
+
+gethomes()
+{
+ register struct passwd *pw;
+ register struct shome *h, *ph;
+ struct passwd *getpwent();
+
+ ph = (struct shome *) &homes;
+ while((pw = getpwent()) != NULL) {
+ h = (struct shome *) malloc(sizeof *h);
+ h->h_next = NULL;
+ h->h_name = (char *) malloc(strlen(pw->pw_name)+1);
+ strcpy(h->h_name, pw->pw_name);
+ h->h_uid = pw->pw_uid;
+ h->h_gid = pw->pw_gid;
+ h->h_home = (char *) malloc(strlen(pw->pw_dir)+1);
+ strcpy(h->h_home, pw->pw_dir);
+ ph->h_next = h;
+ ph = h;
+ }
+}
+
+
+struct shome *
+home(name)
+ register char *name;
+{
+ register struct shome *h;
+
+ for(h = homes; h; h = h->h_next)
+ if(uleq(name, h->h_name))
+ return(h);
+ return(NULL);
+}
+
+
+char *
+getname(addrs)
+ char *addrs;
+{
+ register char *tp;
+ static char name[32];
+ static char *getaddrs;
+
+ if(!getaddrs)
+ getaddrs = addrs;
+ tp = name;
+
+ while(*getaddrs && !isalpha(*getaddrs))
+ getaddrs++;
+ if(!*getaddrs) {
+ getaddrs = 0;
+ return NULL;
+ }
+#ifdef UNIXCOMP
+ while(!isspace(*getaddrs))
+ *tp++ = *getaddrs++;
+#else
+ while(isalnum(*getaddrs) || index(".:@/-", *getaddrs))
+ *tp++ = *getaddrs++;
+#endif
+ *tp = 0;
+ if(name[0] == 0)
+ return NULL;
+ return name;
+}
+
+char *bracket = "\1\1\1\1\n";
+
+sendmail(name, fd) /* Runs with signals ignored! */
+ char *name;
+ register int fd;
+{
+ char buf[BUFSIZ], *myname;
+ register int i, m, c;
+ register char *mail, *receive, *lock = 0;
+ register struct shome *h;
+ int pid, status;
+ struct stat stbuf;
+
+ if(verbose) {
+ printf("%s: ", name);
+ fflush(stdout);
+ }
+ lseek(fd, 0l, 0);
+ h = home(name);
+
+ /*
+ * If no home for this user, as in network address
+ * being forced down this path, just assume normal
+ * delivery
+ */
+
+ if (h == NULL)
+ goto force;
+
+ mail = concat(mailboxes, h->h_name, 0);
+/*** mail = concat(h->h_home, mailbox, 0); ***/
+ receive = concat(h->h_home, RECVPROG, 0);
+ if(access(receive, 1) == 0) { /* User has a receive prog */
+
+ calluserprog(receive, mail, fd, h);
+
+ } else {
+
+force:
+
+#ifdef UNIXCOMP
+#ifdef DELIVERMAIL
+ nstash(name);
+ if (verbose)
+ printf("Sent.\n");
+ return;
+#endif DELIVERMAIL
+#ifndef DELIVERMAIL
+ myname = getenv("USER");
+ if (myname == (char *) 0)
+ myname = "nobody";
+ pid = fork();
+ switch (pid) {
+ case 0:
+ /* fiddle with files, then . . . */
+ lseek(fd, 0L, 0);
+ close(0);
+ dup(fd);
+ close(fd);
+ execl(Mailprog, "Mail", "-r", myname, name, 0);
+ execl("/bin/mail", "mail", "-r", myname, name, 0);
+ perror(Mailprog);
+ _exit(1);
+
+ case -1:
+ perror("fork");
+ return;
+
+ default:
+ while (wait(&status) != pid)
+ ;
+ }
+#endif DELIVERMAIL
+#endif UNIXCOMP
+#ifndef UNIXCOMP
+ if((m = open(mail, 2)) < 0) {
+ if((m = creat(mail, 0600)) < 0) {
+ fprintf(stderr, "Deliver: Can't write ");
+ perror(mail);
+ goto out;
+ }
+ chown(mail, h->h_uid, h->h_gid);
+ if(verbose) {
+ fprintf(stderr, "Creating %s ", mail);
+ fflush(stdout);
+ }
+ }
+ lock = concat(lockdir, h->h_name, ".lock", 0);
+ for(i = 0; i < lockwait; i += 2) {
+ if(link(mail, lock) >= 0)
+ break;
+ if(i == 0 && stat(mail, &stbuf) >= 0 &&
+ stbuf.st_ctime + LOCKWAIT < time((long *) 0)) {
+ i = lockwait;
+ break;
+ }
+ if(verbose) {
+ printf("Busy ");
+ fflush(stdout);
+ }
+ sleep(2);
+ }
+ if(i >= lockwait) {
+ unlink(lock);
+ if(verbose) {
+ printf("Removing lock. ");
+ fflush(stdout);
+ }
+ if(link(mail, lock) < 0) {
+ fprintf(stderr, "Can't lock %s to %s\n",
+ mail, lock);
+ donecd = 1;
+ goto out1;
+ }
+ }
+ lseek(m, 0l, 2);
+ write(m, bracket, 5);
+ do
+ if((c = read(fd, buf, sizeof buf)) > 0)
+ if(write(m, buf, c) != c) {
+ fprintf(stderr, "Write error on ");
+ perror(mail);
+ donecd = 1;
+ goto out1;
+ }
+ while(c == sizeof buf);
+ write(m, bracket, 5);
+out1: close(m);
+out: cndfree(mail);
+ if(lock) {
+ unlink(lock);
+ cndfree(lock);
+ }
+#endif UNIXCOMP
+ }
+ if(verbose && !donecd)
+ printf("Sent.\n");
+}
+
+#ifdef DELIVERMAIL
+
+/*
+ * Salt away a name to send to, ultimately.
+ */
+
+char *stashname[100];
+char **stashp;
+
+nstash(name)
+ char name[];
+{
+ register char *cp;
+
+ cp = (char *) calloc(1, strlen(name) + 1);
+ strcpy(cp, name);
+ if (stashp == 0) {
+ stashp = stashname;
+ *stashp++ = "sendmail";
+ *stashp++ = "-i";
+ if (verbose)
+ *stashp++ = "-v";
+ }
+ *stashp++ = cp;
+}
+
+stflush(fd)
+{
+ int pid;
+
+ if (stashp == 0)
+ return;
+ while ((pid = fork()) == -1)
+ sleep(2);
+ if (pid == 0) {
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ close(0);
+ dup(fd);
+ close(fd);
+ execv(DELIVERMAIL, stashname);
+ perror(DELIVERMAIL);
+ _exit(1);
+ }
+}
+#endif
+
+putfrom(out)
+ register FILE *out;
+{
+ register struct shome *h;
+
+ for(h = homes; h; h = h->h_next)
+ if(h->h_uid == myuid) {
+ fprintf(out, "From: %s\n", h->h_name);
+ return;
+ }
+ fprintf(stderr, "Deliver: WHO ARE YOU?\n");
+ done(1);
+}
+
+
+putmsgid(sp)
+ FILE *sp;
+{
+
+ if(!msgid)
+ return;
+ if(!now)
+ time(&now);
+ fprintf(sp, "Message-ID: <%u.%u.%ld.%s@%s>\n", getpid(), myuid,
+ now, localname, hostname);
+}
+
+/***/
+pl()
+{
+ register struct mailname *mp;
+
+ for(mp = addrlist.m_next; mp; mp=mp->m_next)
+ printf("%s%s", mp->m_name, mp->m_next?", ":"");
+ printf("\n");
+}
+/***/
+
+insert(name)
+ char *name;
+{
+ register struct mailname *mp;
+ char *getcpy();
+
+/*** printf("insert(%s)\n", name); ***/
+
+ for(mp = &addrlist; mp->m_next; mp = mp->m_next)
+ if(uleq(name, mp->m_next->m_name))
+ return; /* Don't insert existing name! */
+ mp->m_next = (struct mailname *) malloc(sizeof *mp->m_next);
+ mp = mp->m_next;
+ mp->m_next = 0;
+ mp->m_name = getcpy(name);
+}
+
+
+/* alias implementation below...
+ */
+
+
+
+#define GROUP "/etc/group"
+char *AliasFile = "/usr/local/lib/MailAliases";
+
+char *termptr;
+
+char *
+parse(ptr, buf)
+ register char *ptr;
+ char *buf;
+{
+ register char *cp;
+
+ cp = buf;
+ while(isspace(*ptr) || *ptr == ',' || *ptr == ':')
+ ptr++;
+ while(isalnum(*ptr) || *ptr == '/' || *ptr == '-' ||
+ *ptr == '.' || *ptr == '*')
+ *cp++ = *ptr++;
+ if(cp == buf) {
+ switch(*ptr) {
+ case '<':
+ case '=':
+ *cp++ = *ptr++;
+ }
+ }
+ *cp = 0;
+ if(cp == buf)
+ return 0;
+ termptr = ptr;
+ return buf;
+}
+
+char *
+advance(ptr)
+ register char *ptr;
+{
+ return(termptr);
+}
+
+alias()
+{
+ register char *cp, *pp;
+ register struct mailname *lp;
+ char line[256], pbuf[64];
+ FILE *a;
+
+ if((a = fopen(AliasFile, "r")) == NULL)
+ return;
+ while(fgets(line, sizeof line, a)) {
+ if(line[0] == ';' || line[0] == '\n') /* Comment Line */
+ continue;
+ if((pp = parse(line, pbuf)) == NULL) {
+ oops: fprintf(stderr, "Bad alias file %s\n", AliasFile);
+ fprintf(stderr, "Line: %s", line);
+ done(1);
+ }
+ for(lp = &addrlist; lp->m_next; lp = lp->m_next) {
+ if(aleq(lp->m_next->m_name, pp)) {
+ remove(lp);
+ if(!(cp = advance(line)) ||
+ !(pp = parse(cp, pbuf)))
+ goto oops;
+ switch(*pp) {
+ case '<': /* From file */
+ cp = advance(cp);
+ if((pp = parse(cp, pbuf)) == NULL)
+ goto oops;
+ addfile(pp);
+ break;
+ case '=': /* UNIX group */
+ cp = advance(cp);
+ if((pp = parse(cp, pbuf)) == NULL)
+ goto oops;
+ addgroup(pp);
+ break;
+ case '*': /* ALL Users */
+ addall();
+ break;
+ default: /* Simple list */
+ for(;;) {
+ insert(pp);
+ if(!(cp = advance(line)) ||
+ !(pp = parse(cp, pbuf)))
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+addfile(file)
+ char *file;
+{
+ register char *cp, *pp;
+ char line[128], pbuf[64];
+ FILE *f;
+
+/*** printf("addfile(%s)\n", file); ***/
+ if((f = fopen(file, "r")) == NULL) {
+ fprintf(stderr, "Can't open ");
+ perror(file);
+ done(1);
+ }
+ while(fgets(line, sizeof line, f)) {
+ cp = line;
+ while(pp = parse(cp, pbuf)) {
+ insert(pp);
+ cp = advance(cp);
+ }
+ }
+ fclose(f);
+}
+
+addgroup(group)
+ char *group;
+{
+ register char *cp, *pp;
+ int found = 0;
+ char line[128], pbuf[64], *rindex();
+ FILE *f;
+
+/*** printf("addgroup(%s)\n", group); ***/
+ if((f = fopen(GROUP, "r")) == NULL) {
+ fprintf(stderr, "Can't open ");
+ perror(GROUP);
+ done(1);
+ }
+ while(fgets(line, sizeof line, f)) {
+ pp = parse(line, pbuf);
+ if(strcmp(pp, group) == 0) {
+ cp = rindex(line, ':');
+ while(pp = parse(cp, pbuf)) {
+ insert(pp);
+ cp = advance(cp);
+ }
+ found++;
+ }
+ }
+ if(!found) {
+ fprintf(stderr, "Group: %s non-existent\n", group);
+ done(1);
+ }
+ fclose(f);
+}
+
+addall()
+{
+ register struct shome *h;
+
+/*** printf("addall()\n"); ***/
+ for(h = homes; h; h = h->h_next)
+ if(h->h_uid >= EVERYONE)
+ insert(h->h_name);
+}
+
+remove(mp) /* Remove NEXT from argument node! */
+ register struct mailname *mp;
+{
+ register struct mailname *rp;
+
+ rp = mp->m_next;
+ mp->m_next = rp->m_next;
+ cndfree(rp->m_name);
+ cndfree(rp);
+}
+
+int alarmed;
+
+alarmclock()
+{
+ alarmed++;
+}
+
+extern char **environ;
+char envhome[60] = "HOME=";
+char envname[60] = "NAME=";
+char *envinit[] = {envhome, envname, (char *) 0};
+
+calluserprog(prog, mail, fd, h)
+ char *prog, *mail;
+ int fd;
+ register struct shome *h;
+{
+ register int pid, child, i;
+ int status;
+
+ if(verbose) {
+ printf("Invoking %s ", prog);
+ fflush(stdout);
+ }
+ i = 0;
+ while((child = fork()) == -1)
+ if(++i > 10) {
+ fprintf(stderr, "Can't get a fork to invoke %s!\n",
+ prog);
+ donecd = 1;
+ return;
+ } else
+ sleep(2);
+ if(child == 0) { /* In child... */
+ if(fd != 3)
+ dup2(fd, 3);
+ for(i = 4; i < 15; i++)
+ close(i);
+ strcat(envname, h->h_name);
+ strcat(envhome, h->h_home);
+ environ = envinit;
+ setgid(h->h_gid);
+ setuid(h->h_uid);
+ execlp(prog, prog, tmpfil, mail, h->h_home, 0);
+ perror(prog);
+ done(-1);
+ }
+ signal(SIGALRM, alarmclock);
+ alarmed = 0;
+ alarm(30); /* Give receive proc 30 secs */
+ status = 0;
+ while((pid = wait(&status)) != -1 && pid != child && !alarmed) ;
+ if(alarmed) {
+ kill(0, SIGINT);
+ signal(SIGALRM, alarmclock);
+ alarmed = 0;
+ alarm(30);
+ while((pid = wait(&status)) != -1 && pid != child && !alarmed) ;
+ if(alarmed) {
+ kill(child, SIGKILL);
+ signal(SIGALRM, alarmclock);
+ alarmed = 0;
+ alarm(30);
+ while((pid = wait(&status)) != -1 && pid != child && !alarmed) ;
+ }
+ fprintf(stderr, "Deliver: Killed %s--Took more than 30 seconds!\n",
+ prog);
+ donecd = 1;
+ status = 0;
+ } else
+ alarm(0);
+ if(status) {
+ printf("Deliver: %s error %d from %s on delivery to %s\n",
+ status&0377? "System" : "User",
+ status&0377? status&0377 : status>>8,
+ prog, h->h_name);
+ donecd = 1;
+ }
+ if(pid == -1) {
+ fprintf(stderr, "Deliver: wait on receive process returned -1\n");
+ perror("");
+ donecd = 1;
+ }
+}
+
+aleq(string, aliasent)
+ register char *string, *aliasent;
+{
+ register int c;
+
+ while(c = *string++)
+ if(*aliasent == '*')
+ return 1;
+ else if((c|040) != (*aliasent|040))
+ return(0);
+ else
+ aliasent++;
+ return(*aliasent == 0 | *aliasent == '*');
+}
+
+fcc(file, folder)
+ char *file, *folder;
+{
+ int child, pid, status;
+ char fold[128];
+
+ if(verbose) {
+ printf("Fcc: %s...", folder);
+ fflush(stdout);
+ }
+ while((child = fork()) == -1) sleep(5);
+ if(child == 0) {
+ if(*file != '+')
+ strcpy(fold, "+");
+ strcat(fold, folder);
+ setuid(myuid);
+ execl(fileproc, "file", "-link", "-file", file, fold, 0);
+ exit(-1);
+ } else while((pid = wait(&status)) != -1 && pid != child) ;
+ if(status)
+ fprintf(stderr, "Deliver: Error on fcc to %s\n", folder);
+ else if(verbose)
+ putchar('\n');
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)dist.c 4.1 2/23/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+
+#define NONE 0
+#define NOUSE 0
+
+/* #define TEST 1 */
+
+char *anyl[] = {
+ "no", 0,
+ "yes", 0,
+ "list", 0,
+ 0,
+};
+
+char *anyv[] = {
+ "no", 0,
+ "yes", 0,
+ "verbose", 0,
+ 0,
+};
+
+char *aleqs[] = {
+ "list", 0, /* 0 */
+ "edit [<editor>]", 0, /* 1 */
+ "quit [delete]", 0, /* 2 */
+ "send [verbose]", 0, /* 3 */
+ 0
+};
+
+struct msgs *mp;
+char drft[128];
+char *vec[MAXARGS];
+int inplace; /* preserve links in anno */
+
+struct swit switches[] = {
+ "annotate", 0, /* 0 */
+ "noannotate", 0, /* 1 */
+ "editor editor", 0, /* 2 */
+ "form formfile", 0, /* 3 */
+ "inplace", 0, /* 4 */
+ "noinplace", 0, /* 5 */
+ "help", 4, /* 6 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100], *ed, *form;
+ register int msgnum;
+ register char *cp, **ap;
+ int msgp, anot, curf;
+ int in, out, intr;
+ int pid, wpid, status;
+ char *arguments[50], **argp;
+
+#ifdef NEWS
+ m_news();
+#endif
+ anot = 0; folder = 0; curf = 0; msgp = 0; ed = 0; form = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "dist: -%s unknown\n", cp);
+ goto leave;
+ case 0: anot = 1; continue; /* -annotate */
+ case 1: anot = 0; continue; /* -noannotate */
+ case 2: if(!(ed = *argp++)) { /* -editor */
+ missing: fprintf(stderr, "dist: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 3: if(!(form = *argp++)) /* -form */
+ goto missing;
+ continue;
+ case 4: inplace = 1; continue; /* -inplace */
+ case 5: inplace = 0; continue; /* -noinplace */
+ /* -help */
+ case 6: help("dist [+folder] [msg] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert((cp = msgs[msgnum])))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "dist: Tuna Melt\n"); /* never get here */
+ goto leave;
+ }
+ if(mp->numsel > 1) {
+ fprintf(stderr, "Only one message at a time.\n");
+ goto leave;
+ }
+ if(form) {
+ if((in = open(m_maildir(form), 0)) < 0) {
+ fprintf(stderr, "dist: Can't open form file: %s\n", form);
+ goto leave;
+ }
+ } else if(/***(in = open(m_maildir(distcomps), 0)) < 0 && ***/
+ (in = open(stddcomps, 0)) < 0) {
+ fprintf(stderr, "dist: Can't open default components file!!\n");
+ goto leave;
+ }
+ copy(m_maildir(draft), drft);
+ if((out = open(drft, 0)) >= 0) {
+ if(!fdcompare(in, out)) {
+ cp = concat("\"", drft, "\" exists; Delete? ", 0);
+ while((msgnum = gans(cp, anyl)) == 2)
+ showfile(drft);
+ if(!msgnum)
+ return;
+ }
+ close(out);
+ }
+ if((out = creat(drft, m_gmprot())) < 0) {
+ fprintf(stderr, "Can't create \"%s\"\n", drft);
+ goto leave;
+ }
+ cpydata(in, out);
+ close(in);
+ if((in = open(cp = m_name(mp->lowsel), 0)) < 0) {
+ fprintf(stderr, "Can't open message \"%s\"\n", cp);
+ unlink(drft);
+ goto leave;
+ }
+ cpydata(in, out);
+ close(in);
+ close(out);
+ m_replace(pfolder, folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ if(m_edit(&ed, drft, NOUSE, NONE) < 0)
+ goto leave;
+#ifdef TEST
+ fprintf(stderr, "!! Test Version of SEND Being Run !!\n");
+ fprintf(stderr, " Send verbose !\n\n");
+#endif
+
+ for(;;) {
+ if(!(argp = getans("\nWhat now? ", aleqs)))
+ goto leave;
+ switch(smatch(*argp, aleqs)) {
+ case 0: showfile(drft); /* list */
+ break;
+ case 1: if(*++argp) /* edit */
+ ed = *argp;
+ if(m_edit(&ed, drft, NOUSE, NONE) == -1)
+ goto leave;
+ break;
+ case 2: if(*++argp && *argp[0] == 'd') /* quit */
+ if(unlink(drft) == -1) {
+ fprintf(stderr, "Can't unlink %s ", drft);
+ perror("");
+ }
+ goto leave;
+ case 3: if(*++argp) cp = *argp; else cp = ""; /* send */
+
+ if(!mp->msgflags&READONLY) { /* annotate first */
+ if(anot > 0) {
+ while((pid = fork()) == -1) sleep(5);
+ if(pid) {
+ while(wpid=wait((int *)NULL)!= -1 && wpid!= pid);
+ doano();
+ goto leave;
+ }
+ }
+ }
+ if(!m_send(cp, drft))
+ goto leave;
+ default:fprintf(stderr, "dist: illegal option\n"); /*##*/
+ break;
+ }
+ }
+
+ leave:
+ m_update();
+ done(0);
+}
+
+
+cpydata(in, out)
+{
+ char buf[BUFSIZ];
+ register int i;
+
+ do
+ if((i = read(in, buf, sizeof buf)) > 0)
+ write(out, buf, i);
+ while(i == sizeof buf);
+}
+
+
+doano()
+{
+ register FILE *in;
+ char name[NAMESZ], field[256];
+ register int ind, state;
+ register char *text;
+
+ if(stat(drft, field) != -1) {
+ fprintf(stderr, "%s not sent-- no annotations made.\n", drft);
+ return;
+ }
+ text = copy(drft, field);
+ text[1] = 0;
+ do
+ *text = text[-1];
+ while(--text >= field && *text != '/');
+ *++text =
+#ifdef UCB
+ '#';
+#else
+ ',';
+#endif
+ if((in = fopen(field, "r")) == NULL) {
+ fprintf(stderr, "Can't open %s\n", field);
+ return;
+ }
+ state = FLD;
+ text = 0;
+ for(;;) switch(state = m_getfld(state, name, field, sizeof field, in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(uleq(name, "distribute-to") ||
+ uleq(name, "distribute-cc") == 0) {
+ if(state == FLD) {
+ text = add(name, text);
+ text = add(":", text);
+ }
+ text = add(field, text);
+ }
+ if(state == FLDEOF)
+ goto out;
+ continue;
+ case BODY:
+ case BODYEOF:
+ goto out;
+ default:
+ fprintf(stderr, "Getfld returned %d\n", state);
+ return;
+ }
+
+out:
+ fclose(in);
+ annotate(m_name(mp->lowsel), "Distributed", text, inplace);
+
+
+}
--- /dev/null
+/*
+ * Routine to convert a localtime(3) format date back into
+ * a system format date.
+ *
+ * Hats off to Bob Kridle for the insight that the way to do
+ * this is by binary search of the system date space.
+ */
+
+#include <sys/time.h>
+
+struct tm *localtime();
+
+long
+emitl(dp)
+ struct tm *dp;
+{
+ long conv;
+ register int i, bit;
+ struct tm dcopy;
+
+ dcopy = *dp;
+ dp = &dcopy;
+ conv = 0;
+ for (i = 31; i >= 0; i--) {
+ bit = 1 << i;
+ conv |= bit;
+ if (dcmp(localtime(&conv), dp) > 0)
+ conv &= ~bit;
+ }
+ return(conv);
+}
+
+/*
+ * Compare two localtime dates, return result.
+ */
+
+#define DECIDE(a) \
+ if (dp->a > dp2->a) \
+ return(1); \
+ if (dp->a < dp2->a) \
+ return(-1)
+
+static
+dcmp(dp, dp2)
+ register struct tm *dp, *dp2;
+{
+
+ DECIDE(tm_year);
+ DECIDE(tm_mon);
+ DECIDE(tm_mday);
+ DECIDE(tm_hour);
+ DECIDE(tm_min);
+ DECIDE(tm_sec);
+ return(0);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/dir.h>
+#include <strings.h>
+
+#define NFOLDERS 100
+
+int all, hdrflag, foldp;
+struct msgs *mp;
+char folder[128], *folds[NFOLDERS];
+int msgtot, foldtot, totonly, fshort;
+int fpack;
+struct swit switches[] = {
+ "all", 0, /* 0 */
+ "down", 0, /* 1 */
+ "fast", 0, /* 2 */
+ "nofast", 0, /* 3 */
+ "header", 0, /* 4 */
+ "noheader", 0, /* 5 */
+ "pack", 0, /* 6 */
+ "nopack", 0, /* 7 */
+ "short", -1, /* 8 */
+ "total", 0, /* 9 */
+ "nototal", 0, /*10 */
+ "up", 0, /*11 */
+ "help", 4, /*12 */
+ "debug", 5, /*13 */
+ 0, 0
+};
+
+int debug;
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp, *curm;
+ register int i;
+ char *argfolder;
+ int up, down, j, def_short;
+ char *arguments[50], **argp, **ap;
+ struct stat stbf;
+ struct node *np;
+ extern char _sobuf[];
+ register struct direct *dir;
+ DIR *dirp;
+
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ up = down = 0;
+ argfolder = NULL;
+ curm = 0;
+ if(argv[0][strlen(argv[0])-1] == 's') /* Plural name?? */
+ all++;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "folder: -%s unknown\n", cp);
+ goto leave;
+ case 0: all++; continue; /* -all */
+ case 1: down++; continue; /* -down */
+ case 2: /* -fast */
+ case 3: fshort = 0; continue; /* -nofast */
+ case 4: hdrflag = -1; continue; /* -header */
+ case 5: hdrflag = 0; continue; /* -noheader */
+ case 6: fpack = 1; continue; /* -pack */
+ case 7: fpack = 0; continue; /* -nopack */
+ case 8: fshort = 1; continue; /* -short */
+ case 9: all++; totonly = 1; /* -total */
+ continue;
+ case 10:if(totonly) all--; /* -nototal */
+ totonly =0; continue;
+ case 11:up++; continue; /* -up */
+ /* -help */
+ case 12:help("folder [+folder] [msg] [switches]",
+ switches);
+ goto leave;
+ case 13:debug++; /* -debug */
+ continue;
+ }
+ if(*cp == '+') {
+ if(argfolder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ argfolder = cp + 1;
+ } else if(curm) {
+ fprintf(stderr, "Only one current may be given.\n");
+ goto leave;
+ } else
+ curm = cp;
+ }
+ if(all) {
+ hdrflag = 0;
+ cp = m_maildir("");
+ m_getdefs();
+ for(np = m_defs; np; np = np->n_next) {
+ if(!ssequal("cur-", np->n_name))
+ continue;
+ if(fshort) {
+ def_short++;
+ printf("%s\n", np->n_name+4);
+ } else
+ addfold(np->n_name+4);
+ }
+ if(def_short)
+ putchar('\n');
+ if(fshort) {
+ m_update();
+ fflush(stdout);
+ execl(lsproc, "mh-ls", "-x", cp, 0);
+ fprintf(stderr, "Can't exec: ");
+ perror(lsproc);
+ goto leave;
+ }
+ if(chdir(cp) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(cp);
+ goto leave;
+ }
+ if((cp = m_find(pfolder)) == NULL)
+ *folder = 0;
+ else
+ copy(cp, folder);
+ dirp = opendir(".");
+ (void) readdir(dirp);
+ (void) readdir(dirp);
+ while (dir = readdir(dirp)) {
+ if (stat(dir->d_name, &stbf) < 0 ||
+ (stbf.st_mode & S_IFMT) != S_IFDIR)
+ continue;
+ addfold(dir->d_name);
+ }
+ closedir(dirp);
+ for(i = 0; i < foldp; i++) {
+ pfold(folds[i], 0); fflush(stdout);
+ }
+ if(!totonly)
+ printf("\n\t\t ");
+ printf("TOTAL= %3d message%c in %d Folder%s.\n",
+ msgtot, msgtot!=1? 's':' ',
+ foldtot, foldtot!=1? "s":"");
+ } else {
+ hdrflag++;
+ if(argfolder)
+ cp = copy(argfolder, folder);
+ else
+ cp = copy(m_getfolder(), folder);
+ if(up) {
+ while(cp > folder && *cp != '/') --cp;
+ if(cp > folder)
+ *cp = 0;
+ argfolder = folder;
+ } else if(down) {
+ copy(listname, copy("/", cp));
+ argfolder = folder;
+ }
+ if(pfold(folder, curm) && argfolder)
+ m_replace(pfolder, argfolder);
+ }
+
+ leave:
+ m_update();
+ done(0);
+}
+
+
+addfold(fold)
+char *fold;
+{
+ register int i,j;
+ register char *cp;
+
+ if(foldp >= NFOLDERS) {
+ fprintf(stderr, "More than %d folders!!\n", NFOLDERS);
+ return(1);
+ }
+ cp = getcpy(fold);
+ for(i = 0; i < foldp; i++)
+ if(compare(cp, folds[i]) < 0) {
+ for(j = foldp - 1; j >= i; j--)
+ folds[j+1] = folds[j];
+ foldp++;
+ folds[i] = cp;
+ return(0);
+ }
+ folds[foldp++] = cp;
+ return(0);
+}
+
+
+pfold(fold, curm)
+char *fold;
+{
+ register char *mailfile;
+ register int msgnum, hole;
+ char newmsg[8], oldmsg[8];
+
+ mailfile = m_maildir(fold);
+ if(chdir(mailfile) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(mailfile);
+ return(0);
+ }
+ if(fshort) {
+ printf("%s\n", fold);
+ return(0);
+ }
+ mp = m_gmsg(fold);
+ foldtot++;
+ msgtot += mp->nummsg;
+ if (debug)
+ printf("pfold: %s message flags: 0%o\n", fold, mp->msgflags);
+ if(fpack && (mp->msgflags & READONLY) == 0) {
+ if (debug) {
+ printf("Would normally be packing folder %s\n", fold);
+ return;
+ }
+ for(msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++) {
+ if(mp->msgstats[msgnum]&EXISTS) {
+ if(msgnum != hole) {
+ copy(m_name(hole), newmsg);
+ copy(m_name(msgnum), oldmsg);
+ if(link(oldmsg, newmsg) == -1 ||
+ unlink(oldmsg) == -1) {
+ fprintf(stderr, "Error moving %s to ", oldmsg);
+ perror(newmsg);
+ done(1);
+ }
+ mp->msgstats[hole] = mp->msgstats[msgnum];
+ if(msgnum == mp->lowsel)
+ mp->lowsel = hole;
+ if(msgnum == mp->hghsel)
+ mp->hghsel = hole;
+ }
+ hole++;
+ }
+ }
+ if(mp->nummsg > 0) {
+ mp->lowmsg = 1;
+ mp->hghmsg = hole - 1;
+ }
+ }
+ if(totonly)
+ goto out;
+ if(curm) {
+ if(!m_convert(curm))
+ return(0);
+ if(mp->numsel > 1) {
+ fprintf(stderr, "Can't set current msg to range: %s\n", curm);
+ return(0);
+ }
+ m_setcur(mp->curmsg = mp->hghsel);
+ }
+ if(!hdrflag++)
+ printf("\t\tFolder # of messages ( range ); cur msg (other files)\n");
+ printf("%22s", fold);
+ if(strcmp(folder, fold) == 0)
+ printf("+ ");
+ else
+ printf(" ");
+ if(mp->hghmsg == 0)
+ printf("has no messages");
+ else {
+ printf("has %3d message%s (%3d-%3d)",
+ mp->nummsg, (mp->nummsg==1)?" ":"s",
+ mp->lowmsg, mp->hghmsg);
+ if(mp->curmsg >= mp->lowmsg && mp->curmsg <= mp->hghmsg)
+ printf("; cur=%3s", m_name(mp->curmsg));
+ }
+ if(mp->selist || mp->others) {
+ printf("; (");
+ if(mp->selist) {
+ printf("%s", listname);
+ if(mp->others)
+ printf(", ");
+ }
+ if(mp->others)
+ printf("others");
+ putchar(')');
+ }
+ putchar('.');
+ putchar('\n');
+out:
+ free(mp);
+ mp = 0;
+ return(1);
+}
+
+
+compare(s1, s2)
+char *s1, *s2;
+{
+ register char *c1, *c2;
+ register int i;
+
+ c1 = s1; c2 = s2;
+ while(*c1 || *c2)
+ if(i = *c1++ - *c2++)
+ return(i);
+ return(0);
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)forw.c 4.1 2/23/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+
+#define NONE 0
+#define NOUSE 0
+
+/* #define TEST 1 */
+
+int *vec[MAXARGS];
+struct msgs *mp;
+char drft[128];
+int inplace; /* preserve links in anno */
+
+char *anyl[] = {
+ "no", 0,
+ "yes", 0,
+ "list", 0,
+ 0,
+};
+
+char *anyv[] = {
+ "no", 0,
+ "yes", 0,
+ "verbose", 0,
+ 0,
+};
+
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "annotate", 0, /* 1 */
+ "noannotate", 0, /* 2 */
+ "editor editor", 0, /* 3 */
+ "form formfile", 0, /* 4 */
+ "inplace", 0, /* 5 */
+ "noinplace", 0, /* 6 */
+ "help", 4, /* 7 */
+ 0, 0
+};
+
+char *aleqs[] = {
+ "list", 0, /* 0 */
+ "edit [<editor>]", 0, /* 1 */
+ "quit [delete]", 0, /* 2 */
+ "send [verbose]", 0, /* 3 */
+ 0
+};
+
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100], *ed, *form;
+ register int msgnum;
+ register char *cp, **ap;
+ int msgp, status, anot;
+ int in, out, intr;
+ int pid, wpid, msgcnt;
+ char *arguments[50], **argp;
+ char numbuf[5];
+
+#ifdef NEWS
+ m_news();
+#endif
+ form = 0; anot = 0; folder = 0; msgp = 0; ed = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "forw: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: anot = 1; continue; /* -annotate */
+ case 2: anot = 0; continue; /* -noannotate */
+ case 3: if(!(ed = *argp++)) { /* -editor */
+ missing: fprintf(stderr, "forw: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 4: if(!(form = *argp++)) /* -form */
+ goto missing;
+ continue;
+ case 5: inplace = 1; continue; /* -inplace */
+ case 6: inplace = 0; continue; /* -noinplace */
+ /* -help */
+ case 7: help("forw [+folder] [msgs] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "forw: italian salami.\n"); /* never get here */
+ goto leave;
+ }
+ if(form) {
+ if((in = open(m_maildir(form), 0)) < 0) {
+ fprintf(stderr, "forw: Can't open form file: %s\n", form);
+ goto leave;
+ }
+ } else if((in = open(m_maildir(components), 0)) < 0 &&
+ (in = open(stdcomps, 0)) < 0) {
+ fprintf(stderr, "forw: Can't open default components file!!\n");
+ goto leave;
+ }
+ copy(m_maildir(draft), drft);
+ if((out = open(drft, 0)) >= 0) {
+ if(!fdcompare(in, out)) {
+ cp = concat("\"", drft, "\" exists; Delete? ", 0);
+ while((msgnum = gans(cp, anyl)) == 2)
+ showfile(drft);
+ if(!msgnum)
+ return;
+ }
+ close(out);
+ }
+ if((out = creat(drft, m_gmprot())) < 0) {
+ fprintf(stderr, "Can't create \"%s\"\n", drft);
+ goto leave;
+ }
+ cpydata(in, out);
+ close(in);
+ for(msgcnt = 1, msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED) {
+ if((in = open(cp = m_name(msgnum), 0)) < 0) {
+ fprintf(stderr, "Can't open message \"%s\"\n", cp);
+ unlink(drft);
+ goto leave;
+ }
+ type(out, "\n\n-------");
+ if(msgnum == mp->lowsel) {
+ type(out, " Forwarded Message");
+ if(mp->numsel > 1)
+ type(out, "s");
+ } else {
+ type(out, " Message ");
+ sprintf(numbuf, "%d", msgcnt);
+ type(out, numbuf);
+ }
+ type(out, "\n\n");
+ cpydata(in, out);
+ close(in);
+ msgcnt++;
+ }
+ type(out, "\n\n------- End of Forwarded Message");
+ if(mp->numsel > 1)
+ type(out, "s");
+ type(out, "\n");
+ close(out);
+ m_replace(pfolder, folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ if(m_edit(&ed, drft, NOUSE, NONE) < 0)
+ goto leave;
+
+#ifdef TEST
+ fprintf(stderr, "!! Test Version of SEND Being Run !!\n");
+ fprintf(stderr, " Send verbose !\n\n");
+#endif
+ for(;;) {
+ if(!(argp = getans("\nWhat now? ", aleqs)))
+ goto leave;
+ switch(smatch(*argp, aleqs)) {
+ case 0: showfile(drft); /* list */
+ break;
+ case 1: if(*++argp) /* edit */
+ ed = *argp;
+ if(m_edit(&ed, drft, NOUSE, NONE) == -1)
+ goto leave;
+ break;
+ case 2: if(*++argp && *argp[0] == 'd') /* quit */
+ if(unlink(drft) == -1) {
+ fprintf(stderr, "Can't unlink %s ", drft);
+ perror("");
+ }
+ goto leave;
+ case 3: if(*++argp) cp = *argp; else cp = ""; /* send */
+
+ if(!mp->msgflags&READONLY) { /* annotate first */
+ if(anot > 0) {
+ while((pid = fork()) == -1) sleep(5);
+ if(pid) {
+ while(wpid=wait((int *)NULL)!= -1 && wpid!= pid);
+ doano();
+ goto leave;
+ }
+ }
+ }
+ if(!m_send(cp, drft))
+ goto leave;
+ default:fprintf(stderr, "forw: illegal option\n"); /*##*/
+ break;
+ }
+ }
+
+ leave:
+ m_update();
+ done(0);
+}
+
+
+cpydata(in, out)
+{
+ char buf[BUFSIZ];
+ register int i;
+
+ do
+ if((i = read(in, buf, sizeof buf)) > 0)
+ write(out, buf, i);
+ while(i == sizeof buf);
+}
+
+
+doano()
+{
+ FILE *in;
+ char name[NAMESZ], field[256];
+ register int ind, state;
+ register char *text;
+
+ if(stat(drft, field) != -1) {
+ fprintf(stderr, "%s not sent-- no annotations made.\n", drft);
+ return;
+ }
+ text = copy(drft, field);
+ text[1] = 0;
+ do
+ *text = text[-1];
+ while(--text >= field && *text != '/');
+ *++text =
+#ifdef UCB
+ '#';
+#else
+ ','; /* New backup convention */
+#endif
+ if((in = fopen(field, "r")) == NULL) {
+ fprintf(stderr, "Can't open "); perror(field);
+ return;
+ }
+ state = FLD;
+ text = 0;
+ for(;;) switch(state = m_getfld(state, name, field, sizeof field, in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(uleq(name, "to") || uleq(name, "cc") == 0) {
+ if(state == FLD) {
+ text = add(name, text);
+ text = add(":", text);
+ }
+ text = add(field, text);
+ }
+ if(state == FLDEOF)
+ goto out;
+ continue;
+ case BODY:
+ case BODYEOF:
+ goto out;
+ default:
+ fprintf(stderr, "Getfld returned %d\n", state);
+ return;
+ }
+
+out:
+ fclose(in);
+
+ for(ind = mp->lowsel; ind <= mp->hghsel; ind++)
+ if(mp->msgstats[ind] & SELECTED)
+ annotate(m_name(ind), "Forwarded", text, inplace);
+}
--- /dev/null
+#include <stdio.h>
+#define CCHR 2
+#define CDOT 4
+#define CCL 6
+#define NCCL 8
+#define CDOL 10
+#define CEOF 11
+
+#define STAR 01
+
+#define LBSIZE 1024
+#define ESIZE 256
+
+char ibuf[BUFSIZ];
+char expbuf[ESIZE];
+char linebuf[LBSIZE+1];
+int circf;
+
+char cc[] = {
+ 0000,0001,0002,0003,0004,0005,0006,0007,
+ 0010,0011,0012,0013,0014,0015,0016,0017,
+ 0020,0021,0022,0023,0024,0025,0026,0027,
+ 0030,0031,0032,0033,0034,0035,0036,0037,
+ 0040,0041,0042,0043,0044,0045,0046,0047,
+ 0050,0051,0052,0053,0054,0055,0056,0057,
+ 0060,0061,0062,0063,0064,0065,0066,0067,
+ 0070,0071,0072,0073,0074,0075,0076,0077,
+ 0100,0141,0142,0143,0144,0145,0146,0147,
+ 0150,0151,0152,0153,0154,0155,0156,0157,
+ 0160,0161,0162,0163,0164,0165,0166,0167,
+ 0170,0171,0172,0133,0134,0135,0136,0137,
+ 0140,0141,0142,0143,0144,0145,0146,0147,
+ 0150,0151,0152,0153,0154,0155,0156,0157,
+ 0160,0161,0162,0163,0164,0165,0166,0167,
+ 0170,0171,0172,0173,0174,0175,0176,0177,
+};
+
+
+compile(astr)
+char *astr;
+{
+ register c;
+ register char *ep, *sp;
+ char *lastep;
+ int cclcnt;
+
+ ep = expbuf;
+ sp = astr;
+ if (*sp == '^') {
+ circf++;
+ sp++;
+ }
+ for (;;) {
+ if (ep >= &expbuf[ESIZE])
+ goto cerror;
+ if ((c = *sp++) != '*')
+ lastep = ep;
+ switch (c) {
+
+ case '\0':
+ *ep++ = CEOF;
+ return(1);
+
+ case '.':
+ *ep++ = CDOT;
+ continue;
+
+ case '*':
+ if (lastep==0)
+ goto defchar;
+ *lastep |= STAR;
+ continue;
+
+ case '$':
+ if (*sp != '\0')
+ goto defchar;
+ *ep++ = CDOL;
+ continue;
+
+ case '[':
+ *ep++ = CCL;
+ *ep++ = 0;
+ cclcnt = 1;
+ if ((c = *sp++) == '^') {
+ c = *sp++;
+ ep[-2] = NCCL;
+ }
+ do {
+ *ep++ = c;
+ cclcnt++;
+ if (c=='\0' || ep >= &expbuf[ESIZE])
+ goto cerror;
+ } while ((c = *sp++) != ']');
+ lastep[1] = cclcnt;
+ continue;
+
+ case '\\':
+ if ((c = *sp++) == '\0')
+ goto cerror;
+ defchar:
+ default:
+ *ep++ = CCHR;
+ *ep++ = c;
+ }
+ }
+ cerror:
+ return(0);
+}
+
+
+execute(file)
+char *file;
+{
+ register char *p1, *p2;
+ register c;
+ int f, body, lf;
+ char *ebp, *cbp;
+
+ if ((f = open(file, 0)) < 0) {
+ fprintf(stderr, "Grep: Can't open %s\n", file);
+ return(0);
+ }
+ body = 0;
+ ebp = ibuf;
+ cbp = ibuf;
+ for (;;) {
+ p1 = linebuf;
+ p2 = cbp;
+ lf = 0;
+ for (;;) {
+ if (p2 >= ebp) {
+ if ((c = read(f, ibuf, sizeof ibuf)) <= 0) {
+ close(f);
+ if(lf) break; /* bodyless comp! */
+ return(0);
+ }
+ p2 = ibuf;
+ ebp = ibuf+c;
+ }
+ c = *p2++;
+ if(lf) if(c != ' ' && c != '\t') {
+ --p2;
+ break;
+ } else
+ lf = 0;
+ if (c == '\n')
+ if(body)
+ break;
+ else {
+ if(lf) {
+ body++;
+ break;
+ }
+ lf++;
+ c = ' ';
+ }
+ if(c && p1 < &linebuf[LBSIZE-1])
+ *p1++ = c;
+ }
+ *p1++ = 0;
+ cbp = p2;
+ p1 = linebuf;
+ p2 = expbuf;
+ if (circf) {
+ if (advance(p1, p2))
+ goto found;
+ continue;
+ }
+ /* fast check for first character */
+ if (*p2==CCHR) {
+ c = p2[1];
+ do {
+ if(*p1==c || cc[*p1]==c)
+ if (advance(p1, p2))
+ goto found;
+ } while (*p1++);
+ continue;
+ }
+ /* regular algorithm */
+ do {
+ if (advance(p1, p2))
+ goto found;
+ } while (*p1++);
+ continue;
+ found:
+ close(f);
+ return(1);
+ }
+}
+
+
+advance(alp, aep)
+char *alp, *aep;
+{
+ register char *lp, *ep, *curlp;
+ char *nextep;
+
+ lp = alp;
+ ep = aep;
+ for (;;) switch (*ep++) {
+
+ case CCHR:
+ if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
+ continue;
+ return(0);
+
+ case CDOT:
+ if (*lp++)
+ continue;
+ return(0);
+
+ case CDOL:
+ if (*lp==0)
+ continue;
+ return(0);
+
+ case CEOF:
+ return(1);
+
+ case CCL:
+ if (cclass(ep, *lp++, 1)) {
+ ep += *ep;
+ continue;
+ }
+ return(0);
+
+ case NCCL:
+ if (cclass(ep, *lp++, 0)) {
+ ep += *ep;
+ continue;
+ }
+ return(0);
+
+ case CDOT|STAR:
+ curlp = lp;
+ while (*lp++);
+ goto star;
+
+ case CCHR|STAR:
+ curlp = lp;
+ while (*lp++ == *ep || cc[lp[-1]] == *ep) ;
+ ep++;
+ goto star;
+
+ case CCL|STAR:
+ case NCCL|STAR:
+ curlp = lp;
+ while (cclass(ep, *lp++, ep[-1]==(CCL|STAR)));
+ ep += *ep;
+ goto star;
+
+ star:
+ do {
+ lp--;
+ if (advance(lp, ep))
+ return(1);
+ } while (lp > curlp);
+ return(0);
+
+ default:
+ printf("RE botch\n");
+ return(0);
+ }
+}
+
+
+cclass(aset, ac, af)
+char *aset;
+{
+ register char *set, c;
+ register n;
+
+ set = aset;
+ if ((c = ac) == 0)
+ return(0);
+ n = *set++;
+ while (--n)
+ if (*set++ == c)
+ return(af);
+ return(!af);
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)inc.c 1.2 9/25/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <strings.h>
+#include <signal.h>
+
+char *anoyes[]; /* Std no/yes gans array */
+
+extern int errno;
+char scanl[];
+struct msgs *mp;
+FILE *in, *aud;
+struct stat stbuf;
+char *locknode;
+int lockwait; /* Secs to wait for lock-Def in strings/lockdir.c */
+#define LOCKWAIT (lockwait*5) /* If lock is this old, simply ignore it! */
+
+struct swit switches[] = {
+ "audit audit-file", 0, /* 0 */
+ "ms ms-folder", 0, /* 1 */
+ "help", 4, /* 2 */
+ "file mail-file", 0, /* 3 */
+ 0, 0
+};
+
+#ifdef UNIXCOMP
+char unixtmp[] = "/tmp/mhXXXXXX";
+#endif
+
+main(argc, argv)
+char *argv[];
+{
+
+ char *newmail, maildir[128], *folder, *from, *audfile, *srcfile;
+ char mailspace[128];
+ char *myname, *savemail;
+ register char *cp;
+ register int i, msgnum;
+ long now;
+ char **ap;
+ char *arguments[50], **argp;
+ int done();
+ long time();
+ int pid, status, fildes;
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+
+ from = 0; folder = 0; audfile = 0; srcfile = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "inc: -%s unknown\n", cp);
+ goto leave;
+ case 0: if(!(audfile = *argp++)) { /* -audit */
+ missing: fprintf(stderr, "inc: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 1: if(!(from = *argp++)) /* -ms */
+ goto missing;
+ continue;
+ case 2: /* -help */
+ help("inc [+folder] [switches]", switches);
+ goto leave;
+ case 3: /* -file */
+ if (!(srcfile = *argp++))
+ goto missing;
+ continue;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else {
+ fprintf(stderr, "Bad arg: %s\n", argp[-1]);
+ fprintf(stderr, "Usage: inc [+folder] [-ms ms-folder] [-audit audit-file]\n");
+ goto leave;
+ }
+ }
+ if (from && srcfile) {
+ fprintf(stderr, "Only one of \"-ms\" and \"-file\" allowed\n");
+ goto leave;
+ }
+ if(from)
+ newmail = from;
+ else {
+ if((myname = getenv("USER")) == 0) {
+ fprintf(stderr,
+"Environment Variable \"USER\" Must be set to your login name!\n");
+ done(1);
+ }
+ if (srcfile) {
+ newmail = srcfile;
+ goto statit;
+ }
+ newmail = concat(mailboxes, myname, 0);
+ if (stat(newmail, &stbuf) >= 0
+ && (stbuf.st_mode & S_IFMT) == S_IFDIR) {
+ strcpy(mailspace, newmail);
+ newmail = mailspace;
+ strcat(newmail, "/");
+ strcat(newmail, myname);
+ }
+statit:
+ if(stat(newmail, &stbuf) < 0 ||
+ stbuf.st_size == 0) {
+ fprintf(stderr, "No Mail to incorporate.\n");
+ goto leave;
+ }
+ }
+ fildes = -1;
+ if (srcfile)
+ if ((fildes = open(srcfile, 0)) < 0) {
+ perror(srcfile);
+ goto leave;
+ }
+ if(!folder) {
+ folder = defalt;
+ if(from && strcmp(from, "inbox") == 0) {
+ cp = concat("Do you really want to convert from ",
+ from, " into ", folder, "?? ", 0);
+ if(!gans(cp, anoyes))
+ goto leave;
+ cndfree(cp);
+ }
+ }
+ copy(m_maildir(folder), maildir);
+ if(stat(maildir, &stbuf) < 0) {
+ if(errno != ENOENT) {
+ fprintf(stderr, "Error on folder ");
+ perror(maildir);
+ goto leave;
+ }
+ cp = concat("Create folder \"", maildir, "\"? ", 0);
+ if(!gans(cp, anoyes))
+ goto leave;
+ if(!makedir(maildir)) {
+ fprintf(stderr, "Can't create folder \"%s\"\n", maildir);
+ goto leave;
+ }
+ }
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ /* Lock the mail file */
+ if(!from && !srcfile) {
+ signal(SIGINT, done);
+ cp = concat(lockdir, myname, ".lock", 0);
+ for(i = 0; i < lockwait; i += 2) {
+ if(link(newmail, cp) == -1) {
+ fprintf(stderr, "Mailbox busy...\n");
+ if(i == 0 && stat(newmail, &stbuf) >= 0)
+ if(stbuf.st_ctime + LOCKWAIT < time((long *)0)) {
+ unlink(cp);
+ fprintf(stderr, "Removing lock.\n");
+ continue;
+ }
+ sleep(2);
+ } else {
+ locknode = cp; /* We own the lock now! */
+ break;
+ }
+ }
+ if(i >= lockwait) {
+ fprintf(stderr, "Try again.\n");
+ done(1);
+ }
+ }
+
+#ifdef UNIXCOMP
+ /*
+ * If trying to be compatible with standard
+ * UNIX mailing scheme, call the program unixtomh
+ * to convert the mailbox to some temporary name.
+ */
+
+ mktemp(unixtmp);
+ switch (pid = fork()) {
+ case 0:
+ if (srcfile) {
+ int nout;
+
+ if ((nout = creat(unixtmp, 0600)) < 0) {
+ perror(unixtmp);
+ _exit(1);
+ }
+ close(0);
+ dup(fildes);
+ close(fildes);
+ close(1);
+ dup(nout);
+ close(nout);
+ execl(unixtomh, "unixtomh", 0);
+ perror(unixtomh);
+ _exit(1);
+ }
+ execl(unixtomh, "unixtomh", newmail, unixtmp, 0);
+ perror(unixtomh);
+ _exit(1);
+ break;
+
+ case -1:
+ perror("fork");
+ goto leave;
+
+ default:
+ while (wait(&status) != pid)
+ ;
+ if (status != 0) {
+ fprintf(stderr, "unixtomh failed!?\n");
+ goto leave;
+ }
+ }
+ if (fildes >= 0)
+ close(fildes);
+ savemail = newmail;
+ newmail = unixtmp;
+ if((in = fopen(newmail, "r")) == NULL) {
+ fprintf(stderr, "Can't open "); perror(newmail);
+ goto leave;
+ }
+#else
+ if (srcfile)
+ in = fdopen(fildes, "r");
+ else
+ if((in = fopen(newmail, "r")) == NULL) {
+ fprintf(stderr, "Can't open "); perror(newmail);
+ goto leave;
+ }
+#endif
+
+ if(audfile) {
+ cp = m_maildir(audfile);
+ if((i = stat(cp, &stbuf)) < 0)
+ fprintf(stderr, "Creating Receive-Audit: %s\n", cp);
+ if((aud = fopen(cp, "a")) == NULL) {
+ fprintf(stderr, "Can't append to ");
+ perror(cp);
+ goto leave;
+ } else if(i < 0)
+ chmod(cp, 0600);
+ time(&now);
+ fputs("<<inc>> ", aud);
+ cp = cdate(&now);
+ cp[9] = ' ';
+ fputs(cp, aud);
+ if(from) {
+ fputs(" -ms ", aud);
+ fputs(from, aud);
+ }
+ putc('\n', aud);
+ }
+ printf("Incorporating new mail into %s...\n\n", folder);
+ fflush(stdout);
+ msgnum = mp->hghmsg;
+
+ while((i = scan(in, msgnum+1, msgnum+1, msgnum == mp->hghmsg))) {
+ if(i == -1) {
+ fprintf(stderr, "inc aborted!\n");
+ if(aud)
+ fputs("inc aborted!\n", aud);
+ goto leave;
+ }
+ if(aud)
+ fputs(scanl, aud);
+ fflush(stdout);
+ msgnum++;
+ }
+
+ fclose(in);
+ if(aud)
+ fclose(aud);
+
+#ifdef UNIXCOMP
+ unlink(newmail);
+ newmail = savemail;
+#endif
+
+ if(!from && !srcfile) {
+ if (unlink(newmail) < 0) {
+ if((i = creat(newmail, 0600)) >= 0)
+ close(i);
+ else
+ fprintf(stderr, "Error zeroing %s\n", newmail);
+ }
+ }
+
+ i = msgnum - mp->hghmsg;
+ if(!i)
+ fprintf(stderr, "[No messages incorporated.]\n");
+ else {
+ m_replace(pfolder, folder);
+ m_setcur(mp->hghmsg + 1);
+ }
+leave:
+ m_update();
+ done(0);
+}
+
+
+done(status)
+{
+ if(locknode);
+ unlink(locknode);
+ exit(status);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+char *anoyes[]; /* Std no/yes gans array */
+
+char defpath[128];
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp, *path;
+ register struct node *np;
+ int autof, exitstat;
+ struct stat stbuf;
+ char *geta();
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+ autof = (argc == 2 && strcmp(argv[1], "-auto") == 0);
+ exitstat = 1; /* Assume errors will occur */
+ mypath = getenv("HOME");
+/*** mypath = getpath(getruid()); /* to prevent recursion via m_getdefs */
+ copy(mh_prof, copy(mypath, defpath));
+ if(stat(defpath, &stbuf) != -1) {
+ if(autof)
+ printf("Install-defs invocation error!\n");
+ else
+ printf("You already have an MH profile... use an editor \
+to modify it.\n");
+ goto leave;
+
+ }
+ if(autof || gans("Do you want help? ", anoyes)) {
+printf("\nPrior to using MH, it is necessary to have a file in your login\n");
+printf("directory (%s) named %s which contains information\n",mypath,mh_prof+1);
+printf("to direct certain MH operations. The only item which is required\n");
+printf("is the path to use for all MH folder operations. The suggested MH\n");
+printf("path for you is %s/Mail...\n\n", mypath);
+ }
+ cp = concat(mypath, "/", "Mail", 0);
+ if(stat(cp, &stbuf) != -1) {
+ if((stbuf.st_mode&S_IFMT) == S_IFDIR) {
+ cp = concat("You already have the standard MH directory \"",
+ cp, "\".\nDo you want to use it for MH? ", 0);
+ if(gans(cp, anoyes))
+ path = "Mail";
+ else
+ goto xyz;
+ }
+ } else {
+ cp = concat("Do you want the standard MH path \"", mypath,
+ "/", "Mail\"? ", 0);
+ if(gans(cp, anoyes))
+ path = "Mail";
+ else {
+ xyz: if(gans("Do you want a path below your login directory? ",
+ anoyes)) {
+ printf("What is the path ?? %s/", mypath);
+ path = geta();
+ } else {
+ printf("What is the whole path?? /");
+ path = concat("/", geta(), 0);
+ }
+ }
+ }
+ chdir(mypath);
+ if(chdir(path) == -1) {
+ cp = concat("\"", path, "\" doesn't exist; Create it? ", 0);
+ if(gans(cp, anoyes))
+ if(makedir(path) == 0) {
+ printf("Can't create it!\n");
+ goto leave;
+ }
+ } else
+ printf("[Using existing directory]\n");
+
+ np = m_defs = (struct node *) malloc(sizeof *np);
+ np->n_name = "Path";
+ np->n_field = path;
+ np->n_next = 0;
+ m_replace(pfolder, defalt);
+ exitstat = 0;
+
+leave:
+ m_update();
+ done(exitstat);
+}
+
+
+char *geta()
+{
+ static char line[128];
+ register char *cp;
+ register int c;
+
+ fflush(stdout);
+ cp = line;
+ while((c = getchar()) != EOF) {
+ if(c == '\n') {
+ *cp = 0;
+ return(line);
+ }
+ if(cp < &line[128])
+ *cp++ = c;
+ }
+ done(1);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <signal.h>
+
+#define NUMTOS 10 /* Number of to's & cc's accepted */
+
+char tmpfil[32];
+int exitstat = 1;
+char *subject, *cc, *body;
+
+struct swit switches[] = {
+ "body", 0, /* 0 */
+ "cc", 0, /* 1 */
+ "subject", 0, /* 2 */
+ "help", 4, /* 3 */
+ 0, 0
+};
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ register FILE *out;
+ register int i, cnt;
+ register char *cp;
+ int pid, status, top, ccp, sig(), somebody = 0;
+ char buf[BUFSIZ], *tos[NUMTOS], *ccs[NUMTOS], **argp;
+
+ top = 0;
+ ccp = -1; /* -1 -> collecting TOs */
+ if(argc == 1) { /* Just call inc to read mail */
+ execl("/bin/inc", "inc", 0);
+ execl("/usr/bin/inc", "inc", 0);
+ perror("inc");
+ done(exitstat);
+ }
+ argp = argv + 1;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ done(exitstat);
+ /* unknown */
+ case -1:fprintf(stderr, "send: -%s unknown\n", cp);
+ done(exitstat);
+ /* -body */
+ case 0: if((body = *argp++) == 0) {
+ missing: fprintf(stderr, "Mail: Missing %s arg\n", cp);
+ done(exitstat);
+ }
+ continue;
+ /* -cc */
+ case 1: ccp = 0; /* Now collecting ccs */
+ continue;
+ /* -subject */
+ case 2: if((subject = *argp++) == 0)
+ goto missing;
+ continue;
+ /* -help */
+ case 3: help("mail [switches] users ...",
+ switches);
+ done(0);
+ }
+ else {
+ if(ccp >= 0) { /* If getting ccs..*/
+ if(ccp < NUMTOS)
+ ccs[ccp++] = cp;
+ else {
+ fprintf(stderr, "Mail: Too many ccs\n");
+ done(exitstat);
+ }
+ } else { /* Else, to */
+ if(top < NUMTOS)
+ tos[top++] = cp;
+ else {
+ fprintf(stderr, "Mail: Too many tos\n");
+ done(exitstat);
+ }
+ }
+ }
+ }
+ /* Create a mail temp file */
+ sprintf(tmpfil, "/tmp/%s", makename("mail", ".tmp"));
+ if((out = fopen(tmpfil, "w")) == NULL) {
+ perror(tmpfil);
+ done(exitstat);
+ }
+ signal(SIGINT, sig); /* Clean up if user <del>s out */
+ fprintf(out, "To: "); /* Create to list */
+ for(i = 0; i < top;) {
+ fprintf(out, "%s", tos[i]);
+ if(++i < top)
+ fprintf(out, ", ");
+ }
+ fprintf(out, "\n");
+ if(ccp > 0) {
+ fprintf(out, "Cc: "); /* Create cc list if needed */
+ for(i = 0; i < ccp;) {
+ fprintf(out, "%s", ccs[i]);
+ if(++i < ccp)
+ fprintf(out, ", ");
+ }
+ fprintf(out, "\n");
+ }
+ if(subject) /* Create subject if needed */
+ fprintf(out, "Subject: %s\n", subject);
+
+ fprintf(out, "\n");
+
+ if(body) { /* Use body if I have it, */
+ somebody++;
+ fprintf(out, "%s\n", body);
+ } else { /* Otherwise, get a body */
+ while((cnt = read(0, buf, sizeof buf)) > 0) {
+ somebody++;
+ if(!fwrite(buf, cnt, 1, out)) {
+ perror(tmpfil);
+ sig();
+ }
+ }
+ }
+
+ if(ferror(out)) { /* Check that all wrote well */
+ fprintf(stderr, "Error writing tmp file\n");
+ sig();
+ }
+ fclose(out);
+ if(!somebody) /* If NO body, then don't send */
+ sig(); /* To be compatible with BELL mail */
+ while((i = fork()) == -1) { /* Now, deliver the mail */
+ fprintf(stderr, "Waiting for a fork...\n");
+ sleep(2);
+ }
+ if(i == 0) { /* Call deliverer in child */
+ execl(mh_deliver, mh_deliver, tmpfil, 0);
+ perror(mh_deliver);
+ done(exitstat);
+ }
+ signal(SIGINT, SIG_IGN);
+ while((pid = wait(&status)) != -1 && pid != i) ;
+ if(status) { /* And save mail if delivery failed */
+ signal(SIGINT, SIG_DFL);
+ fprintf(stderr, "Letter saved in dead.letter\n");
+ execl("/bin/mv", "mv", tmpfil, "dead.letter", 0);
+ execl("/usr/bin/mv", "mv", tmpfil, "dead.letter", 0);
+ perror("/bin/mv");
+ done(exitstat);
+ }
+ exitstat = 0;
+ sig();
+}
+
+sig()
+{
+ unlink(tmpfil);
+ done(exitstat);
+}
--- /dev/null
+#define ALL ""
+
+#define MAXARGS 1000 /* Max messages to exec */
+
+#define EXISTS 01 /* Flag bits in msgstats-- Deleted is */
+#define DELETED 02 /* undefined currently */
+#define SELECTED 04 /* Message selected by an arg */
+
+#define READONLY 01 /* No write access to folder */
+#define DEFMOD 01 /* In-core profile has been modified */
+
+/*#define NEWS 1 /* Define for news inclusion */
+
+struct swit {
+ char *sw;
+ int minchars;
+};
+
+/*
+ * m_gmsg() returns this structure. It contains the per folder
+ * information which is obtained from reading the folder directory.
+ */
+
+struct msgs {
+ int hghmsg; /* Highest msg in directory */
+ int nummsg; /* Actual Number of msgs */
+ int lowmsg; /* Lowest msg number */
+ int curmsg; /* Number of current msg if any */
+ int lowsel; /* Lowest selected msg number */
+ int hghsel; /* Highest selected msg number */
+ int numsel; /* Number of msgs selected */
+ char *foldpath; /* Pathname of folder */
+ char selist, /* Folder has a "select" file */
+ msgflags, /* Folder status bits */
+ filler,
+ others; /* Folder has other file(s) */
+ char msgstats[1]; /* Stat bytes for each msg */
+};
+
+ /* m_getfld definitions and return values */
+
+#define NAMESZ 64 /* Limit on component name size */
+#define LENERR -2 /* Name too long error from getfld */
+#define FMTERR -3 /* Message Format error */
+
+ /* m_getfld return codes */
+#define FLD 0 /* Field returned */
+#define FLDPLUS 1 /* Field " with more to come */
+#define FLDEOF 2 /* Field " ending at eom */
+#define BODY 3 /* Body " with more to come */
+#define BODYEOF 4 /* Body " ending at eom */
+#define FILEEOF 5 /* Reached end of input file */
+
+/*
+ * These standard strings are defined in strings.a. They are the
+ * only system-dependent parameters in MH, and thus by redefining
+ * their values and reloading the various modules, MH will run
+ * on any system.
+ */
+
+char
+ *components, /* Name of user's component file (in mh dir) */
+ *current, /* Name of current msg file in a folder */
+ *defalt, /* Name of the std folder (inbox) */
+ *distcomps, /* Name of `dist' components file */
+ *draft, /* Name of the normal draft file */
+ *fileproc, /* Path of file program */
+ *foldprot, /* Default folder protection */
+ *hostname, /* Local net host name */
+ *installproc, /* Name of auto-install program path */
+ *listname, /* Default selection list folder name */
+ *lockdir, /* Dir for lock files (Same fs as mailboxes)*/
+ *lsproc, /* Path of the Harvard ls program */
+ *mailboxes, /* Incoming mail directory */
+ *mh_prof, /* Name of users profile file */
+ *mh_deliver, /* Name of deliverer for mh */
+ *mhnews, /* Name of MH news file */
+ *msgprot, /* Default message protection (s.a. 0664) */
+ *pfolder, /* Name of current folder profile entry */
+ *prproc, /* Path of the pr program */
+ *scanproc, /* Path of the scan program */
+ *showproc, /* Path of the type (l) program */
+ *sendproc, /* Path of the send message program */
+ *stdcomps, /* Std comp file if missing user's own */
+ *stddcomps, /* Std dist file if missing user's own */
+ *sysed, /* Path of the std (ned) editor */
+/* Just about every program uses this also */
+ *mypath; /* User's log-on path */
+
+#ifdef UNIXCOMP
+char *unixtomh; /* Path of program to convert UNIX style
+ mailboxes to MH style mailboxes */
+char *Mailprog; /* Path of program to do actual mailing */
+char *localname; /* Name of local machine on local net */
+#endif
+
+/*
+ * node structure used to hold a linked list of the users profile
+ * information taken from logpath/.mh_prof.
+ */
+
+struct node {
+ struct node *n_next;
+ char *n_name,
+ *n_field;
+} *m_defs;
+
+char def_flags;
+
+
+/*
+ * The first char in the mhnews file indicates whether the program
+ * calling m_news() should continue running or halt.
+ */
+
+#define NEWSHALT '!' /* Halt after showing the news */
+#define NEWSCONT ' ' /* Continue (ditto) */
+#define NEWSPAUSE '\001' /* Pause during news output... */
+
+
+/*
+ * Miscellaneous Defines to speed things up
+ */
+
+#define error(str) { fprintf(stderr, "%s\n", str); exit(-1); }
+
+/*
+ * Routine type declarations -- needed by version 7 compiler
+ */
+
+char **brkstring();
+char *m_maildir();
+char *m_find();
+char *m_name();
+char *concat();
+char *getcpy();
+char *trimcpy();
+char *add();
+char *invo_name();
+char **copyip();
+char *getcpy();
+char *m_getfolder();
+struct msgs *m_gmsg();
+char *copy();
+char **getans();
+char *cdate();
+char *makename();
+char *r1bindex();
+
+/*
+ * Routine type declarations -- SHOULD BE GLOBAL
+ */
+char *getenv();
+
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/dir.h>
+#include <strings.h>
+#define max(a,b) (a > b ? a : b)
+
+#define NEWSP "/usr/spool/newnews"
+#define MAXTOPICS 20 /* Enough for a while */
+
+int vecp, topicp;
+char *topics[MAXTOPICS+1];
+char *vec[MAXARGS];
+struct msgs *mp;
+int fdisplay, fcheck, fupdate, fsend, freview, fbody; /* flags */
+int frevback;
+int hit;
+
+struct nts {
+ char *t_name;
+ int t_num;
+} nts[MAXTOPICS+1], *check();
+
+struct swit switches[] = {
+ "add", -1, /* 0 */
+ "body", -1, /* 1 */
+ "check", 0, /* 2 */
+ "display", 0, /* 3 */
+ "review [#]", 0, /* 4 */
+ "send topic ...",0, /* 5 */
+ "topics", 0, /* 6 */
+ "update", 0, /* 7 */
+ "help", 4, /* 8 */
+ 0, 0,
+};
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int i;
+ register char *cp, **ap;
+ char *arguments[50], **argp;
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ vecp = 2;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ done(0);
+ /* unknown */
+ case -1:vec[vecp++] = --cp; continue;
+ case 0:
+ case 5: fsend++; continue;
+ case 1: fbody++;
+ vec[vecp++] = --cp; continue;
+ case 2: fcheck++; continue;
+ case 3: fdisplay++; continue;
+ case 4: freview++;
+ if(**argp >= '0' && **argp <= '9')
+ frevback = atoi(*argp++);
+ continue;
+ case 7: fupdate++; continue;
+
+ case 8:
+ help("news [topic ...] [switches] [switches for \"c\" or \"mail\" ]",
+ switches);
+ putchar('\n');
+ case 6:
+ printf("Topic items\n\n"); fflush(stdout);
+ getnts();
+ for(i = 0; nts[i].t_name[0]; i++)
+ printf("%-9s%3d\n", nts[i].t_name,
+ nts[i].t_num);
+ done(0);
+ }
+ else
+ if(vecp == 2)
+ topics[topicp++] = cp;
+ else
+ vec[vecp++] = cp;
+ }
+ getnts();
+ if(fsend) {
+ if(topicp == 0) {
+ fprintf(stderr, "Usage: news -send topic [mail switches]\n");
+ done(1);
+ }
+ for(i = 0; i < topicp; i++)
+ if(check(topics[i]))
+ send(topics[i]);
+ else
+ printf("Unknown topic: %s\n", topics[i]);
+ done(0);
+ }
+ if(!topicp)
+ for(i = 0; nts[i].t_name[0]; i++)
+ disp(nts[i].t_name, 0);
+ else
+ for(i = 0; i < topicp; i++)
+ if(check(topics[i]) == NULL)
+ printf("Topic: %s unknown.\n", topics[i]);
+ else
+ disp(topics[i], 1);
+ if(fcheck) {
+ if(hit)
+ printf(".\n");
+ } else if(!hit && !topicp && !fupdate && !fdisplay)
+ nonews();
+ m_update();
+ done(0);
+}
+
+
+getnts()
+{
+ struct direct *dir;
+ struct stat st;
+ register struct nts *t;
+ register DIR *d;
+ char tbuf[16 + 16];
+
+ t = nts;
+ if((d = opendir(NEWSP)) == 00) {
+ fprintf(stderr, "Can't open ");
+ perror(NEWSP);
+ done(1);
+ }
+ while (dir = readdir(d))
+ if(dir->d_ino && dir->d_name[0] != '.') {
+ t->t_name = (char *)malloc(dir->d_namlen + 1);
+ if (t->t_name == 0)
+ break;
+ strcpy(t->t_name, dir->d_name);
+ t++;
+ }
+ closedir(d);
+ for(t = nts; t->t_name[0]; t++) {
+ sprintf(tbuf, "%s/.%.14s", NEWSP, t->t_name);
+ if(stat(tbuf, &st) != -1)
+ t->t_num = st.st_size;
+ }
+}
+
+struct nts *
+check(topic)
+ char *topic;
+{
+ register struct nts *t;
+
+ for(t = nts; t->t_name[0]; t++)
+ if(strcmp(topic, t->t_name) == 0)
+ return t;
+ return 0;
+}
+
+
+disp(topic, argflg)
+ register char *topic;
+ int argflg;
+{
+ register struct nts *t;
+ register char *cp, *np;
+ register int msgnum;
+ int high;
+ char buf[128];
+
+ if((t = check(topic)) == 0)
+ fprintf(stderr, "HUH?\n");
+ if((cp = m_find(np = concat("news-", topic, 0))) == NULL)
+ cp = "0";
+ high = atoi(cp);
+ if(fcheck) {
+ if(t->t_num > high) {
+ if(!hit++)
+ printf("Unread news in");
+ if(hit > 1)
+ printf(",");
+ printf(" %s", topic);
+ }
+ return;
+ }
+ if(fupdate) {
+ if(t->t_num > high) {
+ m_replace(np, getcpy(m_name(t->t_num)));
+ printf("Skipping %d items in %s.\n",
+ t->t_num - high, topic);
+ }
+ return;
+ }
+ if(freview)
+ if(frevback)
+ msgnum = max(high - frevback, 0);
+ else
+ msgnum = 0;
+ else
+ msgnum = high;
+/*** msgnum = freview? frevback? high - frevback : 0 : high; */
+ if(msgnum >= t->t_num) {
+ if(argflg)
+ printf("%s: no new news.\n", topic);
+ return;
+ }
+ sprintf(buf, "%s/%s", NEWSP, topic);
+ if(chdir(buf) == -1) {
+ perror(buf);
+ return;
+ }
+ vec[1] = showproc;
+ for( ; msgnum < t->t_num;) {
+ cp = m_name(++msgnum);
+ if(hit) {
+ printf("\nPress <return> for %s:%s...", topic, cp);
+ fflush(stdout);
+ read(0, buf, sizeof buf);
+ } else
+ printf("News item %s:%s\n", topic, cp);
+ if(msgnum > high) {
+ m_replace(np, getcpy(cp));
+ m_update();
+ }
+ vec[vecp] = cp;
+ putchar('\n');
+ call(vec + 1);
+ hit = 1;
+ }
+}
+
+
+call(vector)
+ char **vector;
+{
+ register int pid, child;
+ char path[32];
+ int status;
+
+ fflush(stdout);
+ while((child = fork()) == -1) {
+ printf("No forks...\n"); fflush(stdout);
+ sleep(2);
+ }
+ if(child == 0) {
+ execv(vector[0], vector);
+ perror(vector[0]);
+ done(1);
+ }
+ while((pid = wait(&status)) != -1 && pid != child) ;
+ if(pid == -1 || status) {
+ fprintf(stderr, "Abnormal termination from %s\n", vector[0]);
+ done(1);
+ }
+}
+
+char *mailproc;
+
+send(topic)
+ register char *topic;
+{
+ vec[0] = mailproc;
+ vec[1] = concat("news.", topic, 0);
+ if(!fbody)
+ printf("Enter text for %s\n", topic);
+ call(vec);
+ free(vec[1]);
+}
+
+
+char *nons[] = {
+ "No new news",
+ "No news to peruse",
+ "Only old news",
+ "News shortage",
+ "News reporters on strike",
+ "Report your own news",
+ "News presses broken"
+};
+#define NONS (sizeof nons/ sizeof nons[0])
+
+nonews()
+{
+#include <sys/timeb.h>
+ struct timeb tb;
+
+ ftime(&tb);
+ printf("%s.\n", nons[tb.millitm % NONS]);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <strings.h>
+
+int glbtype;
+struct msgs *mp;
+
+struct swit switches[] = {
+ "help", 4, /* 0 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *maildir, *vec[20], *folder, *nfolder;
+ register int msgnum;
+ register char *cp;
+ int next;
+ int vecp;
+ char **ap;
+ char *arguments[50], **argp;
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ next = glbtype;
+ folder = 0; vecp = 2;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:vec[vecp++] = --cp; continue;
+ case 0: if(next > 0) /* -help */
+ help("next [+folder] [switches] [switches for \"type\" ]", switches);
+ else
+ help("prev [+folder] [switches] [switches for \"type\" ]", switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else {
+ fprintf(stderr, "Bad arg: %s\n", cp);
+ fprintf(stderr, "Usage: %s [+folder] [-l.switches]\n",
+ next>0? "next" : "prev");
+ goto leave;
+ }
+ }
+ vec[vecp] = 0;
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!m_convert(next > 0 ? "next" : "prev"))
+ goto leave;
+ m_replace(pfolder, folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ vec[1] = m_name(mp->lowsel);
+ printf("(Message %s:%s)\n", folder, vec[1]);
+ fflush(stdout);
+ vec[0] = "mh-type";
+ m_update();
+ execv(showproc, vec);
+ perror("Can't exec type");
+ leave:
+ m_update();
+ done(0);
+}
--- /dev/null
+int glbtype = 1;
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <strings.h>
+
+#define NFOLD 20 /* Allow 20 folder specs */
+
+char *anoyes[]; /* Std no/yes gans array */
+
+/*
+ * pick [-src folder] [msgs] search [-scan] [-show] [file-op]
+ *
+ * search = -from \
+ * -to \
+ * -cc \
+ * -subject \ pattern
+ * -sub /
+ * -date /
+ * -search /
+ * --component /
+ *
+ * file-op = -file [-preserve] [-link] +folder ...
+ * -keep [-stay] [+folder ...]
+ */
+
+extern int errno;
+int nvecp, foldp;
+char **nvec;
+struct msgs *mp;
+char grep[256], *grepp, *folder, maildir[128];
+int showf, scanf, filef, keepf, linkf, noteold, prsrvf, stayf;
+int grep_lowsel = 5000,
+ grep_hghsel = 0;
+char *delprog;
+
+char _sobuf[BUFSIZ];
+
+struct st_fold {
+ char *f_name;
+ int f_reused;
+ struct msgs *f_mp;
+} folders[NFOLD], *fptr;
+
+struct swit switches[] = {
+ "cc pattern", 0, /* 0 */
+ "date pattern", 0, /* 1 */
+ "from pattern", 0, /* 2 */
+ "search pattern", 0, /* 3 */
+ "subject pattern", 0, /* 4 */
+ "to pattern", 0, /* 5 */
+ "-othercomponent pattern", 15, /* 6 */
+ "all", -3, /* 7 */
+ "file +folder ...", 0, /* 8 */
+ "nofile", 0, /* 9 */
+ "keep [+folder ...]", 0, /* 10 */
+ "nokeep", 0, /* 11 */
+ "link", 0, /* 12 */
+ "nolink", 0, /* 13 */
+ "preserve", 0, /* 14 */
+ "nopreserve", 0, /* 15 */
+ "scan", 0, /* 16 */
+ "noscan", 0, /* 17 */
+ "show", 0, /* 18 */
+ "noshow", 0, /* 19 */
+ "src +folder", 0, /* 20 */
+ "stay", 0, /* 21 */
+ "nostay", 0, /* 22 */
+ "help", 4, /* 23 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *msgs[128], buf[128];
+ register int msgnum;
+ register char *cp;
+ int msgp, i;
+ char **ap;
+ char *arguments[50], **argp, **arrp;
+
+ setbuf(stdout, _sobuf);
+
+#ifdef NEWS
+ m_news();
+#endif
+
+ nvecp = 1;
+ msgp = 0;
+ grepp = grep;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-') {
+ if(*++cp == '-') { /* --component */
+ toomany: if(grepp != grep) {
+ fprintf(stderr, "Only one search string.\n");
+ goto leave;
+ }
+ grepp = copy("^", grepp);
+ grepp = copy(++cp, grepp);
+ grepp = copy(":.*", grepp);
+ goto pattern;
+ }
+ switch(i = smatch(cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "pick: -%s unknown\n", cp);
+ goto leave;
+ /* -component */
+ case 0: case 1: case 2: case 4: case 5:
+ if(grepp != grep)
+ goto toomany;
+ grepp = copy("^", grepp);
+ arrp = brkstring(switches[i].sw, " ", 0);
+ grepp = copy(*arrp, grepp);
+ grepp = copy(":.*", grepp);
+ case 3: /* -search */
+ pattern: grepp = copy(*argp++, grepp);
+ continue;
+ case 6: fprintf(stderr, "pick: can't get here\n");
+ goto leave;
+ /* -all */
+ case 7: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 8: filef = 1; continue; /* -file */
+ case 9: filef = 0; continue; /* -nofile */
+ case 10:keepf = 1; continue; /* -keep */
+ case 11:keepf = 0; continue; /* -nokeep */
+ case 12:linkf = 1; continue; /* -link */
+ case 13:linkf = 0; continue; /* -nolink */
+ case 14:prsrvf = 1; continue; /* -preserve */
+ case 15:prsrvf = 0; continue; /* -nopreserve */
+ case 16:scanf = 1; continue; /* -scan */
+ case 17:scanf = 0; continue; /* -noscan */
+ case 18:showf = 1; continue; /* -show */
+ case 19:showf = 0; continue; /* -noshow */
+ case 21:stayf = 1; continue; /* -stay */
+ case 22:stayf = 0; continue; /* -nostay */
+ case 20:if(folder) { /* -src */
+ fprintf(stderr, "Only one src folder.\n");
+ goto leave;
+ }
+ if(!(folder = *argp++) || *folder == '-') {
+ fprintf(stderr, "pick: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ if(*folder == '+')
+ folder++;
+ continue;
+ /* -help */
+ case 23:help("pick [msgs] [switches]", switches);
+ goto leave;
+ }
+ } else if(*cp == '+') {
+ if(foldp < NFOLD)
+ folders[foldp++].f_name = cp + 1;
+ else {
+ fprintf(stderr, "Only %d folders allowed.\n", NFOLD);
+ goto leave;
+ }
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(grepp == grep) {
+ fprintf(stderr, "No search pattern specified.\n");
+ goto leave;
+ }
+ if(filef && keepf) {
+ fprintf(stderr, "-file and -keep don't go together.\n");
+ goto leave;
+ }
+ if(!scanf && !showf && !filef)
+ keepf++; /* The default is -keep */
+ if(keepf) {
+ prsrvf++; /* -keep forces -preserve */
+ linkf++; /* and -link */
+ }
+ if(!folder)
+ folder = m_getfolder(); /* use cur folder if no -src */
+ copy(m_maildir(folder), maildir);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!foldp) { /* if no +folder given... */
+ if(filef) { /* -file requires one */
+ fprintf(stderr, "-file requires at least one folder arg.\n");
+ goto leave;
+ }
+ if(keepf) { /* use default selection-list name */
+ copy(listname, copy("/", copy(folder, buf)));
+ folders[foldp++].f_name = getcpy(buf);
+ noteold++; /* tell user if existing folder */
+ }
+ } else if(keepf) { /* make folders sub-folders */
+ for(msgnum = 0; msgnum < foldp; msgnum++)
+ if(*(cp = folders[msgnum].f_name) != '.' &&
+ *cp != '/') {
+ copy(cp, copy("/", copy(folder, buf)));
+ folders[msgnum].f_name = getcpy(buf);
+ }
+ noteold++;
+ }
+ if(!msgp)
+ msgs[msgp++] = "first-last";
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "pick: Peanut butter 'n jelly\n");/* never get here */
+ goto leave;
+ }
+ if(!compile(grep)) {
+ fprintf(stderr, "Pattern Error.\n");
+ goto leave;
+ }
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ grepfn(msgnum);
+ if(mp->numsel == 0) {
+ fprintf(stderr, "No messages match specification.\n");
+ goto leave;
+ }
+ mp->lowsel = grep_lowsel;
+ mp->hghsel = grep_hghsel;
+ /* all the exec's */
+ if((((delprog = m_find("delete-prog")) != NULL) &&
+ ((filef || keepf) && !linkf)) ||
+ scanf || showf) {
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "pick: more than %d messages for %s exec\n",
+ MAXARGS-2,
+ scanf ? "scan" : showf ? "show" : delprog);
+ goto leave;
+ }
+ nvec = (char **) malloc(MAXARGS * sizeof nvec[0]);
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ nvec[nvecp++] = getcpy(m_name(msgnum));
+ nvec[nvecp] = 0;
+ }
+ if(keepf || filef)
+ if(opnfolds())
+ goto leave;
+ if(!noteold || foldp > 1)
+ m_replace(pfolder, folder);
+ if(scanf)
+ scanfn(showf|filef|keepf);
+ else {
+ printf("%d hits.\n", mp->numsel); fflush(stdout);
+ }
+ if(showf)
+ showfn(filef|keepf);
+ if(!(filef|keepf))
+ goto leave;
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ if(process(cp = getcpy(m_name(msgnum))))
+ goto leave;
+ else
+ free (cp);
+ if(!linkf)
+ remove();
+ if(noteold) {
+ if(!stayf && foldp == 1) {
+ m_replace(pfolder, cp = folders[0].f_name);
+ printf("[+%s now current]\n", cp); fflush(stdout);
+ }
+ for(fptr = folders; fptr < &folders[foldp]; fptr++)
+ if(!fptr->f_reused) {
+ chdir(m_maildir(fptr->f_name));
+ m_setcur(fptr->f_mp->curmsg);
+ }
+ }
+ leave:
+ m_update();
+}
+
+
+grepfn(msg)
+{
+ if(execute(m_name(msg))) { /* a match */
+ if(msg < grep_lowsel)
+ grep_lowsel = msg;
+ if(msg > grep_hghsel)
+ grep_hghsel = msg;
+ } else {
+ mp->msgstats[msg] &= ~SELECTED; /* clear SELECTED bit */
+ mp->numsel--;
+ }
+}
+
+
+opnfolds()
+{
+ register int i;
+ register char *cp, *ap;
+ char nmaildir[128];
+ struct stat stbuf;
+
+ for(i = 0; i < foldp; i++) {
+ copy(m_maildir(cp = folders[i].f_name), nmaildir);
+ if(stat(nmaildir, &stbuf) < 0) {
+ if(!noteold) {
+ ap = concat("Create folder \"",
+ nmaildir, "\"? ", 0);
+ if(!gans(ap, anoyes))
+ return(1);
+ }
+ if(!makedir(nmaildir)) {
+ fprintf(stderr, "Can't create folder.\n");
+ return(1);
+ }
+ } else if(noteold) {
+ printf("[Folder %s being re-used.]\n", cp);
+ fflush(stdout);
+ folders[i].f_reused++; /* Don't change cur in old fold */
+ }
+ if(chdir(nmaildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(nmaildir);
+ return(1);
+ }
+ if(!(folders[i].f_mp = m_gmsg(folders[i].f_name))) {
+ fprintf(stderr, "Can't read folder %s\n", folders[i].f_name);
+ return(1);
+ }
+ folders[i].f_mp->curmsg = 0;
+ }
+ chdir(maildir); /* return to src folder */
+ return(0);
+}
+
+
+scanfn(forkf)
+{
+ register int pid, i;
+
+ nvec[0] = "mh-scan";
+ if(forkf && (pid = fork())) {
+ if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ done(1);
+ }
+ while(wait((int *)NULL) != pid) ;
+ } else {
+ m_update();
+ fflush(stdout);
+ execv(scanproc, nvec);
+ perror(scanproc);
+ done(1);
+ }
+}
+
+
+showfn(forkf)
+{
+ register int pid, i;
+ int sint, sqit;
+
+ nvec[0] = "c:mh-type";
+ if(forkf) {
+ sint = (int) signal(SIGINT, SIG_IGN);
+ sqit = (int) signal(SIGQUIT, SIG_IGN);
+ }
+ if(forkf && (pid = fork())) {
+ if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ done(1);
+ }
+ while(wait((int *)NULL) != pid) ;
+ signal(SIGINT, sint);
+ signal(SIGQUIT, sqit);
+ } else {
+ m_update();
+ fflush(stdout);
+ execv(showproc, nvec);
+ perror(showproc);
+ done(1);
+ }
+}
+
+
+remove()
+{
+ register int i, j;
+ register char *cp;
+
+ if(delprog != NULL) {
+ nvec[0] = delprog;
+ m_update();
+ fflush(stdout);
+ execv(nvec[0], nvec);
+ fprintf(stderr, "Can't exec deletion-prog--");
+ perror(delprog);
+ } else {
+ for(i= mp->lowsel; i<= mp->hghsel; i++)
+ if(mp->msgstats[i]&SELECTED)
+ if(unlink(cp = m_name(i)) == -1) {
+ fprintf(stderr, "Can't unlink %s:",folder);
+ perror(cp);
+ }
+ }
+}
+
+process(msg)
+char *msg;
+{
+ char newmsg[256], buf[BUFSIZ];
+ register int i;
+ register char *nmsg;
+ register struct st_fold *fp;
+ struct stat stbuf, stbf1;
+ int n, o, linkerr;
+
+ for(fp = folders; fp < &folders[foldp]; fp++) {
+ if(prsrvf)
+ nmsg = msg;
+ else
+ nmsg = m_name(fp->f_mp->hghmsg++ + 1);
+ copy(nmsg, copy("/", copy(m_maildir(fp->f_name), newmsg)));
+ if(link(msg, newmsg) < 0) {
+ linkerr = errno;
+ if(linkerr == EEXIST ||
+ (linkerr == EXDEV && stat(newmsg, &stbuf) != -1)) {
+ if(linkerr != EEXIST || stat(msg, &stbf1) < 0 ||
+ stat(newmsg, &stbuf) < 0 ||
+ stbf1.st_ino != stbuf.st_ino) {
+ fprintf(stderr, "Message %s:%s already exists.\n",
+ fp->f_name, msg);
+ return(1);
+ }
+ continue;
+ }
+ if(linkerr == EXDEV) {
+ if((o = open(msg, 0)) == -1) {
+ fprintf(stderr, "Can't open %s:%s.\n",
+ folder, msg);
+ return(1);
+ }
+ fstat(o, &stbuf);
+ if((n = creat(newmsg, stbuf.st_mode&0777)) == -1) {
+ fprintf(stderr, "Can't create %s:%s.\n",
+ fp->f_name, nmsg);
+ close(o);
+ return(1);
+ }
+ do
+ if((i=read(o, buf, sizeof buf)) < 0 ||
+ write(n, buf, i) == -1) {
+ fprintf(stderr, "Copy error on %s:%s to %s:%s!\n",
+ folder, msg, fp->f_name, nmsg);
+ close(o); close(n);
+ return(1);
+ }
+ while(i == sizeof buf);
+ close(n); close(o);
+ } else {
+ fprintf(stderr, "Error on link %s:%s to %s:",
+ folder, msg, fp->f_name);
+ perror(nmsg);
+ return(1);
+ }
+ }
+ if((i = atoi(nmsg)) < fp->f_mp->curmsg || !fp->f_mp->curmsg)
+ fp->f_mp->curmsg = i;
+cont: ;
+ }
+ return(0);
+}
--- /dev/null
+int glbtype = -1;
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <errno.h>
+#include <sgtty.h>
+#include <signal.h>
+#include <strings.h>
+
+extern int errno;
+int wtuser; /* waiting for user input */
+int sigint; /* sensed an interrupt */
+FILE *in, *out;
+struct sgttyb sg;
+struct swit switches[] = {
+ "erase chr", 2, /* 0 */ /* "2" can become "0",since no ed */
+ "kill chr", 0, /* 1 */
+ "help", 4, /* 2 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char tmpfil[32], *drft, name[NAMESZ], field[BUFSIZ];
+ int exitstat;
+ char skill, serase;
+ char *killp, *erasep;
+ register int i, state;
+ register char *cp;
+ char **ap;
+ char *arguments[50], **argp;
+ int sig();
+ int status, pid, wpid, intr;
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+ tmpfil[0] = 0;
+ skill = 0; exitstat = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++)
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto badleave;
+ /* unknown */
+ case -1:fprintf(stderr, "prompter: -%s unknown\n", cp);
+ goto badleave;
+ case 0: if(!(erasep = *argp++)) { /* -erase */
+ missing: fprintf(stderr, "prompter: Missing argument for %s switch\n", argp[-2]);
+ goto badleave;
+ }
+ continue;
+ case 1: if(!(killp= *argp++)) /* -kill */
+ goto missing;
+ continue;
+ /* -help */
+ case 2: help("prompter [switches]",
+ switches);
+ goto badleave;
+ }
+ else
+ drft = cp;
+ if(!drft) {
+ fprintf(stderr, "prompter: missing skeleton\n");
+ goto badleave;
+ }
+ if((in = fopen(drft, "r")) == NULL) {
+ fprintf(stderr, "Can't open %s\n", drft);
+ goto badleave;
+ }
+ copy(makename("prmt", ".tmp"), copy("/tmp/", tmpfil));
+ if((out = fopen(tmpfil, "w")) == NULL) {
+ fprintf(stderr, "Can't create %s\n", tmpfil);
+ goto badleave;
+ }
+ chmod(tmpfil, 0700);
+ signal(SIGINT, sig);
+ gtty(0, &sg);
+ skill = sg.sg_kill;
+ serase = sg.sg_erase;
+ sg.sg_kill = killp ? chrcnv(killp) : skill;
+ sg.sg_erase = erasep ? chrcnv(erasep) : serase;
+/*** stty(0, &sg); ***/
+ ioctl(0, TIOCSETN, &sg);
+ if(killp || erasep) {
+ printf("Erase Char="); chrdisp(sg.sg_erase);
+ printf("; Kill Line="); chrdisp(sg.sg_kill);
+ printf(".\n"); fflush(stdout);
+ }
+ state = FLD;
+ for(;;) switch(state = m_getfld(state,name,field,sizeof field,in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(field[0] != '\n' || field[1] != 0) {
+ printf("%s:%s", name, field);
+ fprintf(out, "%s:%s", name, field);
+ while(state == FLDPLUS) {
+ state=m_getfld(state,name,field,sizeof field,in);
+ printf("%s", field);
+ printf(out, "%s", field);
+ }
+ } else {
+ printf("%s: ", name);
+ fflush(stdout);
+ i = getln(field);
+ if(i == -1)
+ goto badleave;
+ if(i == 0 && (field[0] == '\n' || !field[0]))
+ continue;
+ fprintf(out, "%s:", name);
+ do {
+ if(field[0] != ' ' && field[0] != '\t')
+ putc(' ', out);
+ fputs(field, out);
+ } while(i == 1 && (i = getln(field)) >= 0);
+ if(i == -1)
+ goto badleave;
+ }
+ field[0] = 0;
+ if(state == FLDEOF)
+ goto body;
+ continue;
+
+ case BODY:
+ case BODYEOF:
+ case FILEEOF:
+ body: fputs("--------\n", out);
+ printf("--------\n");
+ if(field[0]) {
+ do {
+ fputs(field, out);
+ if(!sigint)
+ printf("%s", field);
+ } while(state == BODY &&
+ (state=m_getfld(state,name,field,sizeof field,in)));
+ printf("\n--------Enter additional text\n\n");
+ }
+ fflush(stdout);
+ for(;;) {
+ getln(field);
+ if(field[0] == 0)
+ break;
+ fputs(field, out);
+ }
+ goto finish;
+
+ default:
+ fprintf(stderr, "Bad format file!\n");
+ goto badleave;
+ }
+
+
+finish:
+ printf("--------\n"); fflush(stdout);
+ fclose(out);
+ out = fopen(tmpfil, "r");
+ fclose(in);
+ in = fopen(drft, "w"); /* Truncate prior to copy back */
+ do
+ if((i = read(fileno(out), field, sizeof field)) > 0)
+ write(fileno(in), field, i);
+ while(i == sizeof field);
+ goto leave;
+
+badleave:
+ exitstat = 1;
+
+leave:
+ if(in)
+ fclose(in);
+ if(out)
+ fclose(out);
+ if(tmpfil[0])
+ unlink(tmpfil);
+ m_update();
+ if(killp || erasep) {
+ sg.sg_kill = skill;
+ sg.sg_erase = serase;
+/*** stty(0, &sg); ***/
+ ioctl(0, TIOCSETN, &sg);
+ }
+ done(exitstat);
+}
+
+
+getln(buf)
+char *buf;
+{
+ register char *cp;
+ register int c;
+ int stat;
+
+ cp = buf;
+ *cp = 0;
+ wtuser = 1;
+ for(;;) {
+ c = getchar();
+/*** fprintf(stderr,"getchar()=\\%o,errno=%d,EINTR=%d\n",c,errno,EINTR);/***/
+ if(c == EOF)
+ if(errno == EINTR) {
+ stat = -1;
+ goto leave;
+ } else {
+ stat = 0;
+ goto leave;
+ }
+ if(c == '\n') {
+ if(cp[-1] == '\\') {
+ cp[-1] = c;
+ stat = 1;
+ goto leave;
+ }
+ *cp++ = c;
+ *cp = 0;
+ stat = 0;
+ goto leave;
+ }
+ if(cp < buf + 500)
+ *cp++ = c;
+ *cp = 0;
+ }
+ leave: wtuser = 0;
+ return(stat);
+ }
+
+
+sig()
+{
+ signal(SIGINT, sig);
+ if(!wtuser)
+ sigint = 1;
+ return;
+}
+
+
+chrcnv(str)
+char *str;
+{
+ register char *cp;
+ register int c;
+
+ cp = str;
+ if((c = *cp++) != '\\')
+ return(c);
+ c = 0;
+ while(*cp && *cp != '\n') {
+ c *= 8;
+ c += *cp++ - '0';
+ }
+ return c;
+}
+
+
+chrdisp(chr)
+{
+ register int c;
+
+ c = chr;
+ if(c < ' ')
+ printf("<CTRL-%c>", c + '@');
+ else
+ printf("%c", c);
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)refile.c 1.1 5/26/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <strings.h>
+
+#define NFOLD 20 /* Allow 20 folder specs */
+
+/* file [-src folder] [msgs] +folder [+folder ...]
+ *
+ * moves messages from src folder (or current) to other one(s).
+ *
+ * all = 1-999 for a message sequence
+ * -preserve says preserve msg numbers
+ * -link says don't delete old msg
+ */
+
+char *anoyes[]; /* Std no/yes gans array */
+
+int vecp, foldp, prsrvf;
+char **vec, maildir[128], *folder, *file;
+struct msgs *mp;
+
+struct st_fold {
+ char *f_name;
+ struct msgs *f_mp;
+} folders[NFOLD];
+
+char *files[NFOLD + 1]; /* Vec of files to process--starts at 1! */
+int filec = 1;
+char *bellfile = "/usr/bin/file";
+extern int errno;
+char *rindex();
+
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "link", 0, /* 1 */
+ "nolink", 0, /* 2 */
+ "preserve", 0, /* 3 */
+ "nopreserve", 0, /* 4 */
+ "src +folder", 0, /* 5 */
+ "file", 0, /* 6 */
+ "help", 4, /* 7 */
+ 0, 0
+};
+main(argc, argv)
+char *argv[];
+{
+ register int i, msgnum;
+ register char *cp;
+ char *msgs[128];
+ int msgp, linkf;
+ int ismhfile = 0;
+ char **ap;
+ char *arguments[50], **argp;
+ char *pwd(), *pwds;
+
+ /*
+ * Rand has committed the sin of picking a name that already is
+ * used (file). We fix this here since we can tell the difference
+ * between the two (mh file has -'s and +'s always, bell file never
+ * has them.)
+ */
+ for (i=1; i<argc; i++)
+ if (argv[i][0] == '-' || argv[i][0]=='+')
+ ismhfile++;
+ if (!ismhfile) {
+ execv(bellfile, argv);
+ fprintf(stderr, "Cannot find %s\n", bellfile);
+ exit(1);
+ }
+
+#ifdef NEWS
+ m_news();
+#endif
+ folder = 0; msgp = 0; linkf = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-') {
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "file: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: linkf = 1; continue; /* -link */
+ case 2: linkf = 0; continue; /* -nolink */
+ case 3: prsrvf = 1; continue; /* -preserve */
+ case 4: prsrvf = 0; continue; /* -nopreserve */
+ case 5: if(folder) { /* -src */
+ fprintf(stderr, "Only one src folder.\n");
+ goto leave;
+ }
+ if(!(folder = *argp++) || *folder == '-') {
+missing: fprintf(stderr, "file: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ if(*folder == '+')
+ folder++;
+ continue;
+ /* -help */
+ case 6:
+ if(filec >= NFOLD) {
+ fprintf(stderr, "Too many src files.\n");
+ goto leave;
+ }
+ if(!(files[filec++] = *argp) || **argp++ == '-')
+ goto missing;
+ continue;
+
+ case 7: help("file [msgs] [switches] +folder ...",
+ switches);
+ goto leave;
+ }
+ }
+ if(*cp == '+') {
+ if(foldp < NFOLD)
+ folders[foldp++].f_name = cp + 1;
+ else {
+ fprintf(stderr, "Only %d folders allowed.\n", NFOLD);
+ goto leave;
+ }
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!foldp) {
+ fprintf(stderr, "No folder specified.\n");
+fprintf(stderr, "Usage: file [-src folder] [msg ...] [switches] +folder [+folder]\n");
+ goto leave;
+ }
+ if(filec > 1) {
+ if(msgp) {
+ fprintf(stderr, "File: Can't mix files and messages.\n");
+ goto leave;
+ }
+ for(i = 1; i < filec; i++)
+ if(*files[i] != '/') {
+ if(!pwds)
+ pwds = pwd();
+ files[i] = concat(pwds, "/", files[i], 0);
+ }
+ if(opnfolds())
+ goto leave;
+ for(i = 1; i < filec; i++) {
+ if(process(files[i]))
+ goto leave;
+ }
+ if(!linkf) {
+ if((cp = m_find("delete-prog")) != NULL) {
+ files[0] = cp;
+ execvp(cp, files);
+ fprintf(stderr, "Can't exec deletion-prog--");
+ perror(cp);
+ } else for(i = 1; i < filec; i++) {
+ if(unlink(files[i]) == -1) {
+ fprintf(stderr, "Can't unlink ");
+ perror(files[i]);
+ }
+ }
+ }
+ goto leave;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ copy(m_maildir(folder), maildir);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder %s!?\n",folder);
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert((cp = msgs[msgnum])))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "file: ham 'n cheese\n"); /* never get here */
+ goto leave;
+ }
+ m_replace(pfolder, folder);
+ if(mp->hghsel != mp->curmsg && ((mp->numsel != mp->nummsg) || linkf))
+ m_setcur(mp->hghsel);
+ if(opnfolds())
+ goto leave;
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum] & SELECTED)
+ if(process(cp = getcpy(m_name(msgnum))))
+ goto leave;
+ else
+ cndfree(cp);
+ if(!linkf) {
+ if((cp = m_find("delete-prog")) != NULL) {
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "file: more than %d messages for deletion-prog\n",MAXARGS-2);
+ printf("[messages not unlinked]\n");
+ goto leave;
+ }
+ vecp = 1;
+ vec = (char **) calloc(MAXARGS + 2, sizeof *vec);
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ vec[vecp++] = getcpy(m_name(msgnum));
+ vec[vecp] = 0;
+ m_update();
+ fflush(stdout);
+ vec[0] = cp;
+ execv(vec[0], vec);
+ fprintf(stderr, "Can't exec deletion-prog--");
+ perror(cp);
+ } else {
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum] & SELECTED)
+ if(unlink(cp = m_name(msgnum))== -1) {
+ fprintf(stderr, "Can't unlink %s:",folder);
+ perror(cp);
+ }
+ }
+ }
+leave:
+ m_update();
+ done(0);
+}
+
+
+opnfolds()
+{
+ register int i;
+ register char *cp;
+ char nmaildir[128];
+
+ for(i = 0; i < foldp; i++) {
+ copy(m_maildir(folders[i].f_name), nmaildir);
+ if(access(nmaildir, 5) < 0) {
+ cp = concat("Create folder \"", nmaildir, "\"? ", 0);
+ if(!gans(cp, anoyes))
+ goto bad;
+ free(cp);
+ if(!makedir(nmaildir)) {
+ fprintf(stderr, "Can't create folder.\n");
+ goto bad;
+ }
+ }
+ if(chdir(nmaildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(nmaildir);
+ goto bad;
+ }
+ if(!(folders[i].f_mp = m_gmsg())) {
+ fprintf(stderr, "Can't read folder %s\n", folders[i].f_name);
+ goto bad;
+ }
+ }
+ chdir(maildir); /* return to src folder */
+ return(0);
+bad:
+ return(1);
+}
+
+
+process(msg)
+char *msg;
+{
+ char newmsg[256], buf[BUFSIZ];
+ register int i;
+ register char *nmsg;
+ register struct st_fold *fp;
+ struct stat stbuf, stbf1;
+ int n, o, linkerr;
+
+ for(fp = folders; fp < &folders[foldp]; fp++) {
+ if(prsrvf)
+ nmsg = msg;
+ else
+ nmsg = m_name(fp->f_mp->hghmsg++ + 1);
+ copy(nmsg, copy("/", copy(m_maildir(fp->f_name), newmsg)));
+ if(link(msg, newmsg) < 0) {
+ linkerr = errno;
+ if(linkerr == EEXIST ||
+ (linkerr == EXDEV && stat(newmsg, &stbuf) != -1)) {
+ if(linkerr != EEXIST || stat(msg, &stbf1) < 0 ||
+ stat(newmsg, &stbuf) < 0 ||
+ stbf1.st_ino != stbuf.st_ino) {
+ fprintf(stderr, "Message %s:%s already exists.\n",
+ fp->f_name, msg);
+ return(1);
+ }
+ continue;
+ }
+ if(linkerr == EXDEV) {
+ if((o = open(msg, 0)) == -1) {
+ fprintf(stderr, "Can't open %s:%s.\n",
+ folder, msg);
+ return(1);
+ }
+ fstat(o, &stbuf);
+ if((n = creat(newmsg, stbuf.st_mode&0777)) == -1) {
+ fprintf(stderr, "Can't create %s:%s.\n",
+ fp->f_name, nmsg);
+ close(o);
+ return(1);
+ }
+ do
+ if((i=read(o, buf, sizeof buf)) < 0 ||
+ write(n, buf, i) == -1) {
+ fprintf(stderr, "Copy error on %s:%s to %s:%s!\n",
+ folder, msg, fp->f_name, nmsg);
+ close(o); close(n);
+ return(1);
+ }
+ while(i == sizeof buf);
+ close(n); close(o);
+ } else {
+ fprintf(stderr, "Error on link %s:%s to %s:",
+ folder, msg, fp->f_name);
+ perror(nmsg);
+ return(1);
+ }
+ }
+cont: ;
+ }
+ return(0);
+}
+
+
+char *
+pwd()
+{
+ register FILE *pp;
+ static char curpath[128];
+ register int i;
+ FILE *popen();
+
+ if((pp = popen("pwd", "r")) == NULL ||
+ fgets(curpath, sizeof curpath, pp) == NULL ||
+ pclose(pp) != 0) {
+ fprintf(stderr, "Can't find current directory!\n");
+ done(1);
+ }
+ *rindex(curpath, '\n') = 0; /* Zap the lf */
+ return curpath;
+}
--- /dev/null
+#include "mh.h"
+
+char *ltrim(cp)
+char *cp;
+{
+ /* Return pointer to 1st non-blank char in string;
+ * If ptr ==> 0 or ptr ==> '\n'0, return NUL;
+ */
+
+ register char *cp1;
+
+ cp1 = cp;
+ while((*cp1 == ' ') || (*cp1 == '\t')) cp1++;
+ if((*cp1 == 0) || (*cp1 == '\n' && cp1[1] == 0))
+ cp1 = 0;
+ return(cp1);
+}
+
+char *rtrim(cp)
+char *cp;
+{
+ /* trim newline and blanks from the right */
+
+ register char *cp1;
+
+ cp1 = cp+strlen(cp)-1;
+ if(*cp1 == '\n') *cp1 = 0;
+ while(*--cp1 == ' ') ;
+ *++cp1 = 0;
+ return(cp);
+}
+
+char *niceadd(this, that)
+char *this, *that;
+{
+ register char *from, *to;
+
+ if(!(from = ltrim(this))) /* nothing to add */
+ return(that);
+
+ if(to = that)
+ to = add(",\n ", rtrim(to)); /* enuf blanks for "cc: " */
+ return(add(from, to));
+}
+
+#define ADDRLEN (needadr ? addrlen : 0)
+
+char *fix(field, address)
+char *field, *address;
+{
+ /* Appends address to each needy addressee in "field".
+ * Returns pointer to copy of new string. (HUH?)
+ * "field" should never be 0
+ */
+
+ register int len;
+ register char *newp;
+ int addrlen;
+ int needadr;
+ int fieldlen;
+ char *cp;
+
+ addrlen = strlen(address);
+ len = 0;
+ newp = "";
+
+ for(cp = field; ;cp += fieldlen + 1) {
+ needadr = needsaddr(&cp, &fieldlen); /* cp may be changed */
+ if(fieldlen == 0) {
+ cndfree(field);
+ newp = add("\n", newp);
+ return(newp);
+ }
+ if((len + fieldlen + ADDRLEN) > 70) {
+ newp = add(",\n ", newp);
+ len = 4;
+ } else if (*newp) {
+ newp = add(", ", newp);
+ len += 2;
+ }
+ *(cp + fieldlen) = 0;
+ newp = add(cp, newp);
+ if(needadr)
+ newp = add(address, newp);
+ len += fieldlen + ADDRLEN;
+ }
+}
+
+anychar(fchars, field)
+char *fchars, *field;
+{
+ /* Returns 1 if any fancy char appears in "field"
+ * Returns 0 if either "field" is nul or contains no fancy chars
+ */
+
+ register char *fp;
+
+ if(!field)
+ return(0);
+ for(fp = fchars; *fp; fp++)
+ if(r_any(*fp, field))
+ return(1);
+ return(0);
+}
+
+
+r_any(chr,stg)
+char chr, *stg;
+{
+ register char c, *s;
+
+ c = chr;
+ for (s = stg; (*s) && (*s != ',') && (*s != '\n');)
+ if (*s++ == c) return (1);
+ return (0);
+}
+
+char *addr(text)
+char *text;
+{
+ static char buf[128];
+ register char *cp, *bufp;
+ int textseen, blankseen;
+ char *copyaddr();
+
+ textseen = blankseen = 0;
+ bufp = buf;
+ if(!text)
+ return(0);
+ for(cp = text; (*cp == ' ' || *cp == '\t'); cp++);
+ for(;;cp++) {
+ switch(*cp) {
+ default:
+ textseen++;
+ break;
+ case ' ': case '\t':
+ blankseen++;
+ break;
+ case 'a':
+ if(!blankseen || !textseen || !ssequal("at ",cp)){
+ textseen++;
+ break;
+ }
+ bufp = copy(" at ", buf);
+ copyaddr(cp+3, bufp);
+ return(buf);
+ case '@':
+ if(!textseen)
+ return(0);
+ bufp = copy(" @ ", buf);
+ copyaddr(cp+1, bufp);
+ return(buf);
+ case ',': case '\n': case 0:
+ return(0);
+ }
+ }
+}
+
+#define ND1 (*fp) && (*fp != ' ') && (*fp != '\t')
+#define ND2 (*fp != '<') && (*fp != '(') && (*fp != '>') && (*fp != ')')
+#define ND3 (*fp != '\n') && (*fp!= ',') && (*fp != ':')
+#define NOTDELIM ND1 && ND2 && ND3
+
+char *copyaddr(from, to)
+char *from, *to;
+{
+ /* Copies left-trimmed "from" to "to".
+ * Copy terminates on any delimiter.
+ * Returns pointer to NUL terminator in destination string
+ */
+
+ register char *fp, *tp;
+
+ for(fp = from; (*fp == ' ') && (*fp == '\t'); fp++) ;
+ for( ; NOTDELIM; *tp++ = *fp++);
+ *tp = 0;
+ return(tp);
+}
+#define NOTRELEVANT (*cp == ' ' || *cp == '\t' || *cp == '\n'|| *cp == ',')
+
+needsaddr(field, fieldlen)
+char **field;
+int *fieldlen;
+{
+ /* Returns 1 if this field needs an address
+ * Returns 0 if field contains any funny chars or has
+ * an address of the form "xxxx at " or "xxxx[<b>]@"
+ * "field": on input -- addr of pointer to start of field
+ * on output -- val of ptr moved to 1st meaty char
+ * "fieldlen" returns the length of the new field
+ * (it terminates on ',' or '\n' or 0)
+ */
+
+ register char *cp;
+ int textseen, blankseen;
+ int retval;
+ /* find 1st relevant char in field */
+ for(cp = *field; NOTRELEVANT ; cp++);
+
+ *field = cp; /* return it to caller */
+ if(anychar("(<:", cp)) {
+ retval = 0;
+ goto leave;
+ }
+ for(;;cp++) {
+ switch(*cp) {
+ default:
+ textseen++;
+ break;
+ case ' ': case '\t':
+ blankseen++;
+ break;
+ case 'a':
+ if(!blankseen || !textseen || !ssequal("at ",cp)){
+ textseen++;
+ break;
+ }
+ case '@':
+ retval = 0;
+ goto leave;
+ case ',': case '\n': case 0:
+ retval = 1;
+ goto leave;
+
+ }
+ }
+ leave:
+ for(; (*cp) && (*cp != ',') && (*cp != '\n'); cp++) ;
+ *fieldlen = cp- *field;
+ return(retval);
+}
+
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+
+/*#define NEWS 1*/
+
+#define NOUSE 0
+
+/* #define TEST 1 */
+
+char *anyl[] = {
+ "no", 0,
+ "yes", 0,
+ "list", 0,
+ 0
+};
+
+char *aleqs[] = {
+ "list", 0, /* 0 */
+ "edit [<editor>]", 0, /* 1 */
+ "quit [delete]", 0, /* 2 */
+ "send [verbose]", 0, /* 3 */
+ 0
+};
+
+int *vec[MAXARGS], anot;
+int ccme = 1;
+struct msgs *mp;
+char *ed;
+int inplace; /* preserve links in anno */
+
+struct swit switches[] = {
+ "annotate", 0, /* 0 */
+ "noannotate", 0, /* 1 */
+ "ccme", -1, /* 2 */
+ "noccme", -1, /* 3 */
+ "editor editor", 0, /* 4 */
+ "inplace", 0, /* 5 */
+ "noinplace", 0, /* 6 */
+ "help", 4, /* 7 */
+ 0, 0
+};
+
+char *ltrim();
+char *rtrim();
+char *niceadd();
+char *fix();
+char *addr();
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *nfolder, *msg, *maildir;
+ register char *cp, **ap;
+ register int cur;
+ char *arguments[50], **argp;
+
+#ifdef NEWS
+ m_news();
+#endif
+ msg = 0; anot = 0; folder = 0;
+
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "repl: -%s unknown\n", cp);
+ goto leave;
+ case 0: anot = 1; continue; /* -annotate */
+ case 1: anot = 0; continue; /* -noannotate */
+ case 2: ccme = 1; continue; /* -ccme */
+ case 3: ccme = 0; continue; /* -noccme */
+ case 4: if(!(ed = *argp++)) { /* -editor */
+ fprintf(stderr, "repl: Missing argument for %s switch\n", argp[-2]);
+ goto leave;
+ }
+ continue;
+ case 5: inplace = 1; continue; /* -inplace */
+ case 6: inplace = 0; continue; /* -noinplace */
+ /* -help */
+ case 7: help("repl [+folder] [msg] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else if(msg) {
+ fprintf(stderr, "Only one message per reply.\n");
+ goto leave;
+ } else
+ msg = cp;
+ }
+ if(!msg)
+ msg = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!m_convert(msg))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "repl: pepperoni pizza\n");/* never get here */
+ goto leave;
+ }
+ if(mp->numsel > 1) {
+ fprintf(stderr, "Only one message at a time.\n");
+ goto leave;
+ }
+ m_replace(pfolder, folder);
+ if(mp->lowsel != mp->curmsg)
+ m_setcur(mp->lowsel);
+ repl(getcpy(m_name(mp->lowsel)));
+ leave:
+ m_update();
+ done(0);
+}
+
+
+repl(msg)
+{
+ register char *cp;
+ register int i,j;
+ register FILE *in;
+ char name[NAMESZ], field[BUFSIZ];
+ char *drft, *msgid, *replto, *from, *cc, *sub, *date, *to;
+ int state, out, status, intr;
+ int pid, wpid;
+ char **argp, *address;
+
+ if((in = fopen(msg, "r")) == NULL) {
+ fprintf(stderr, "Can't open "); perror(msg);
+ return;
+ }
+ drft = m_maildir(draft);
+ if((out = open(drft, 0)) >= 0) {
+ cp = concat("\"", drft, "\" exists; delete? ", 0);
+ while((i = gans(cp, anyl)) == 2)
+ showfile(drft);
+ if(!i)
+ return;
+ free(cp);
+ close(out);
+ }
+ if((out = creat(drft, m_gmprot())) < 0) {
+ fprintf(stderr, "Can't create \"%s\".\n", drft);
+ return;
+ }
+
+ state = FLD;
+ replto = msgid = to = from = cc = sub = date = 0;
+
+ for(;;) {
+
+ switch(state = m_getfld(state, name, field, sizeof field, in)) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ if(uleq(name, "from"))
+ from = niceadd(field, from);
+ if(uleq(name, "cc"))
+ cc = niceadd(field, cc);
+ if(uleq(name, "subject"))
+ sub = niceadd(field, sub);
+ if(uleq(name, "date"))
+ date = niceadd(field, date);
+ if(uleq(name, "to"))
+ to = niceadd(field, to);
+ if(uleq(name, "message-id"))
+ msgid = niceadd(field, msgid);
+ if(uleq(name, "reply-to"))
+ replto = niceadd(field, replto);
+ /* if(uleq(name, "sender"))
+ sender = niceadd(field, sender); */
+ if(state == FLDEOF)
+ goto done;
+ break;
+
+ case BODY:
+ case BODYEOF:
+ case FILEEOF:
+ goto done;
+
+ default:
+ fprintf(stderr, "getfld returned %d\n", state);
+ return;
+ }
+
+ }
+
+done:
+
+ /* if(!(address = addr(sender)))
+ if(!(address = addr(from)))
+ address = addr(replto);
+ */
+ /* if(!(address = addr(replto)))
+ address = addr(from);
+ */
+ address = replto ? addr(replto) : addr(from);
+ if(!ccme)
+ to = 0;
+ if(!(from || replto)) {
+ fprintf(stderr, "No one to reply to!!!\n");
+ return;
+ }
+ fclose(in);
+ type(out, "To: "); /* To: */
+ type(out, replto ? replto : from);
+ if(cc || to ) /* cc: */
+ type(out, "cc: ");
+ if(cc) {
+ if(address)
+ cc = fix(cc, address);
+ if(to)
+ rtrim(cc);
+ type(out, cc);
+ }
+ if(to) {
+ if(cc)
+ type(out, ",\n ");
+ if(address)
+ to = fix(to, address);
+ type(out, to);
+ }
+ if(sub) { /* Subject: Re: */
+ type(out, "Subject: ");
+ if(*sub == ' ') sub++;
+ if((sub[0] != 'R' && sub[0] != 'r') ||
+ (sub[1] != 'E' && sub[1] != 'e') ||
+ sub[2] != ':')
+ type(out, "Re: ");
+ type(out, sub);
+ } /* In-reply-to: */
+ if(date) {
+ type(out, "In-reply-to: Your message of ");
+ date[strlen(date)-1] = '.';
+ if(*date == ' ') date++;
+ type(out, date);
+ type(out, "\n");
+ if(msgid) {
+ type(out, " ");
+ if(*msgid == ' ') msgid++;
+ type(out, msgid);
+ }
+ }
+ type(out, "----------\n");
+ close(out);
+ if(m_edit(&ed, drft, NOUSE, msg) < 0)
+ return;
+#ifdef TEST
+ fprintf(stderr, "!! Test Version of SEND Being Run !!\n");
+ fprintf(stderr, " Send verbose !\n\n");
+#endif
+
+ for(;;) {
+ if(!(argp = getans("\nWhat now? ", aleqs))) {
+ unlink("@");
+ return;
+ }
+ switch(smatch(*argp, aleqs)) {
+ case 0: showfile(drft); /* list */
+ break;
+ case 1: if(*++argp) /* edit */
+ ed = *argp;
+ if(m_edit(&ed, drft, NOUSE, msg) == -1)
+ return;
+ break;
+ case 2: if(*++argp && *argp[0] == 'd') /* quit */
+ if(unlink(drft) == -1) {
+ fprintf(stderr, "Can't unlink %s ", drft);
+ perror("");
+ }
+ return;
+ case 3: if(*++argp) cp = *argp; else cp = ""; /* send */
+
+ if(!mp->msgflags&READONLY) { /* annotate first */
+ if(anot > 0) {
+ while((pid = fork()) == -1) sleep(5);
+ if(pid) {
+ while(wpid=wait((int *)NULL)!= -1 && wpid!= pid);
+ if(stat(drft, field) == -1)
+ annotate(msg, "Replied", "", inplace);
+ return;
+ }
+ }
+ }
+ if(!m_send(cp, drft))
+ return;
+ default:fprintf(stderr, "repl: illegal option\n"); /*##*/
+ break;
+ }
+ }
+}
--- /dev/null
+/*
+ * Read up the messages in the named files and rehabilitate them into
+ * UNIX+ style messages on standard output.
+ *
+ * +Unix is a trademark of Bell Laboratories.
+ * The optional -d flag tests the arpa net to unix date format
+ * transformer by reading lines from standard input, modifying them
+ * to unix format, and outputing them on standard output.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+char *index(), *rindex(), *reform();
+long emitl();
+int errs;
+int dateerrs;
+int dflag;
+int lastblank;
+
+main(argc, argv)
+ char **argv;
+{
+ register char *cp, *fname;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: rescue name ...\n");
+ _exit(1);
+ }
+ lastblank = 1;
+ while (--argc) {
+ fname = *++argv;
+ if (strcmp(fname, "-d") == 0) {
+ dflag++;
+ dtest();
+ exit(0);
+ }
+ cp = rindex(fname, '/');
+ if (cp == 0)
+ cp = fname;
+ else
+ cp++;
+ if (strcmp(cp, "cur") == 0)
+ continue;
+ if (strcmp(cp, "select") == 0)
+ continue;
+ if (*cp == '#')
+ continue;
+ while (*cp)
+ if (!isdigit(*cp++)) {
+ fprintf(stderr, "%s: not mh message file\n",
+ fname);
+ goto blog;
+ }
+ fix(fname);
+blog: ;
+ }
+ if (dateerrs)
+ fprintf(stderr, "%d bad date(s) replaced by current date\n",
+ dateerrs);
+ exit(errs);
+}
+
+/*
+ * Fix the named file by putting together a reasonable header
+ * and outputing the stuff onto standard output.
+ */
+fix(name)
+ char name[];
+{
+ register FILE *in;
+ char linebuf[BUFSIZ], from[BUFSIZ], date[BUFSIZ];
+ register int inhead;
+ register char *cp;
+ int i;
+
+ if ((in = fopen(name, "r")) == NULL) {
+ perror(name);
+ errs++;
+ return;
+ }
+ from[0] = date[0] = 0;
+ for (; from[0] == 0 || date[0] == 0;) {
+ if (fgets(linebuf, BUFSIZ, in) == NULL)
+ goto noheader;
+ if (strlen(linebuf) == 1)
+ goto noheader;
+ if (linebuf[0] == '-')
+ goto noheader;
+ if (isfield(linebuf, "from")) {
+ cp = index(linebuf, ':');
+ if (cp == 0)
+ goto noheader;
+ cp++;
+ while (*cp && isspace(*cp))
+ cp++;
+ /*
+ ** the below was: strcpy(from, cp);
+ ** but this will not work, since
+ ** headers can be like this:
+ ** From: foo (foo bar)
+ ** which /usr/ucb/Mail gags on... -layer
+ */
+ i = 0;
+ while(*cp && !isspace(*cp))
+ from[i++] = *cp++;
+ from[i] = '\0';
+ continue;
+ }
+ if (isfield(linebuf, "date")) {
+ cp = index(linebuf, ':');
+ if (cp == 0)
+ goto noheader;
+ cp++;
+ while (*cp && isspace(*cp))
+ cp++;
+ strcpy(date, cp);
+ continue;
+ }
+ }
+ /*
+ * Ready to print the from line
+ */
+ zap(from);
+ zap(date);
+ if (!lastblank)
+ printf("\n");
+ printf("From %s %s\n", from, reform(date));
+ lastblank = 0;
+ rewind(in);
+ inhead = 1;
+ while (fgets(linebuf, BUFSIZ, in) != NULL) {
+ if (inhead &&
+ (isfield(linebuf, "from") || isfield(linebuf, "date")))
+ continue;
+ if (strlen(linebuf) == 1)
+ inhead = 0;
+ fputs(linebuf, stdout);
+ lastblank = 0;
+ if (linebuf[0] == '\n' && linebuf[1] == 0)
+ lastblank = 1;
+ }
+ fclose(in);
+ return;
+noheader:
+ fprintf(stderr, "%s: Missing, bad, or incomplete header\n", name);
+ errs++;
+ fclose(in);
+}
+
+/*
+ * Determine if the passed line is a header of the given field name
+ */
+isfield(buf, field)
+ char buf[];
+ char field[];
+{
+ register char *cp, *cp2;
+
+ cp = buf;
+ cp2 = field;
+ while (lower(*cp++) == lower(*cp2++))
+ ;
+ if (*--cp == ':' && *--cp2 == 0)
+ return(1);
+ return(0);
+}
+
+/*
+ * Lower case the given character
+ */
+lower(c)
+ register int c;
+{
+
+ if (isupper(c))
+ return(tolower(c));
+ return(c);
+}
+
+/*
+ * Remove trailing newline from str, if present.
+ */
+zap(str)
+ char str[];
+{
+ register char *cp;
+
+ cp = index(str, '\n');
+ if (cp != 0)
+ *cp = 0;
+}
+
+/*
+ * Reformat the given Arpa net style date
+ * back into a unix ctime(3) date.
+ * Unfortunately, there appears to be NO standard arpa net
+ * date format.
+ */
+
+char *month = "janfebmaraprmayjunjulaugsepoctnovdec";
+
+char *
+reform(date)
+ char date[];
+{
+ static char retdate[35];
+ char dbuf[BUFSIZ];
+ register char *cp, *cp2, *mptr;
+ struct tm d;
+ long x, then;
+
+ cp = date;
+ cp2 = dbuf;
+ while (*cp) {
+ if (*cp == '(') {
+ while (*cp != ')' && *cp)
+ cp++;
+ if (*cp)
+ cp++;
+ goto more;
+ }
+ if (*cp == '\t') {
+ *cp2++ = ' ';
+ cp++;
+ continue;
+ }
+ if (*cp == '-') {
+ *cp2++ = ' ';
+ cp++;
+ continue;
+ }
+ if (isupper(*cp)) {
+ *cp2++ = tolower(*cp++);
+ continue;
+ }
+ *cp2++ = *cp++;
+more: ;
+ }
+ *cp2 = 0;
+ /*
+ * Okie dokie. Now pick off the date part and store
+ * it away. Only possible formats here are:
+ * mm/dd/yy
+ * and
+ * dd monthname year
+ */
+ if (index(dbuf, '/')) {
+ d.tm_mon = atoi(dbuf) - 1;
+ cp = index(dbuf, '/') + 1;
+ d.tm_mday = atoi(cp);
+ if ((cp = index(cp, '/')) == 0)
+ goto baddate;
+ cp++;
+ d.tm_year = atoi(cp);
+ if (d.tm_year > 1900)
+ d.tm_year -= 1900;
+ cp = index(cp, ' ');
+ if (cp == 0)
+ goto baddate;
+ }
+ else {
+ d.tm_mday = atoi(dbuf);
+ cp = index(dbuf, ' ');
+ if (cp == 0)
+ goto baddate;
+ while (*cp && isspace(*cp))
+ cp++;
+ if (*cp == 0)
+ goto baddate;
+ for (mptr = month; *mptr; mptr += 3)
+ if (strcmpn(mptr, cp, 3) == 0)
+ break;
+ if (*mptr == 0)
+ goto baddate;
+ d.tm_mon = (mptr - month)/3;
+ cp = index(cp, ' ');
+ if (cp == 0)
+ goto baddate;
+ while (*cp && isspace(*cp))
+ cp++;
+ if (*cp == 0)
+ goto baddate;
+ d.tm_year = atoi(cp);
+ if (d.tm_year > 1900)
+ d.tm_year -= 1900;
+ cp = index(cp, ' ');
+ if (cp == 0)
+ goto baddate;
+ }
+ /*
+ * Got the month part, now fix up the time.
+ * Possibilities are:
+ * hh:mm
+ * hh:mm [am|pm]
+ * hhmm edt
+ * hh:mm:ss edt
+ * Basically, we lose by ignoring time zone.
+ */
+ for (;;) {
+ while (*cp && isspace(*cp))
+ cp++;
+ if (*cp == 0)
+ goto baddate;
+ if (strcmpn(cp, "at ", 3) != 0)
+ break;
+ cp += 3;
+ }
+ d.tm_sec = 0;
+ if (index(cp, ':')) {
+ d.tm_hour = atoi(cp);
+ cp = index(cp, ':') + 1;
+ d.tm_min = atoi(cp);
+ if (index(cp, ':')) {
+ cp = index(cp, ':') + 1;
+ d.tm_sec = atoi(cp);
+ }
+ while (*cp && !isspace(*cp))
+ cp++;
+ while (*cp && isspace(*cp))
+ cp++;
+ if (strcmpn(cp, "pm", 2) == 0 && d.tm_hour < 12)
+ d.tm_hour += 12;
+ }
+ else {
+ x = atoi(cp);
+ d.tm_hour = x / 100;
+ d.tm_min = x % 100;
+ }
+ then = emitl(&d);
+ strcpy(retdate, ctime(&then));
+ zap(retdate);
+ return(retdate);
+
+baddate:
+ dateerrs++;
+ if (dflag)
+ strcpy(retdate, "************************");
+ else {
+ then = time(0);
+ strcpy(retdate, ctime(&then));
+ zap(retdate);
+ }
+ return(retdate);
+}
+
+/*
+ * Test the arpa net to UNIX date modifier.
+ * Reads lines from standard input, converting them
+ * to unix format, and displaying both on stdout.
+ */
+dtest()
+{
+ char buf[BUFSIZ];
+ register char *cp;
+
+ while (gets(buf)) {
+ cp = reform(buf);
+ printf("\"%s\" \"%s\"\n", buf, cp);
+ }
+}
+
+/*
+ * Routine to convert a localtime(3) format date back into
+ * a system format date.
+ *
+ * Hats off to Bob Kridle for the insight that the way to do
+ * this is by binary search of the system date space.
+ */
+
+struct tm *localtime();
+
+long
+emitl(dp)
+ struct tm *dp;
+{
+ long conv;
+ register int i, bit;
+ struct tm dcopy;
+
+ dcopy = *dp;
+ dp = &dcopy;
+ conv = 0;
+ for (i = 31; i >= 0; i--) {
+ bit = 1 << i;
+ conv |= bit;
+ if (dcmp(localtime(&conv), dp) > 0)
+ conv &= ~bit;
+ }
+ return(conv);
+}
+
+/*
+ * Compare two localtime dates, return result.
+ */
+
+#define DECIDE(a) \
+ if (dp->a > dp2->a) \
+ return(1); \
+ if (dp->a < dp2->a) \
+ return(-1)
+
+dcmp(dp, dp2)
+ register struct tm *dp, *dp2;
+{
+
+ DECIDE(tm_year);
+ DECIDE(tm_mon);
+ DECIDE(tm_mday);
+ DECIDE(tm_hour);
+ DECIDE(tm_min);
+ DECIDE(tm_sec);
+ return(0);
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)rmf.c 1.4 7/7/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include "strings.h"
+
+char *anoyes[]; /* Std no/yes gans array */
+
+int subf;
+
+struct msgs *mp;
+
+struct swit switches[] = {
+ "help", 4, /* 0 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ register char *cp, **ap;
+ char *folder, buf[128];
+ int i, def_fold;
+ char *arguments[50], **argp;
+
+#ifdef NEWS
+ m_news();
+#endif
+ folder = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "rmf: -%s unknown\n", cp);
+ goto leave;
+ /* -help */
+ case 0: help("rmf [+folder] [switches]", switches);
+ goto leave;
+ }
+ if(*cp == '+')
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ else {
+ fprintf(stderr, "Usage: rmf [+folder]\n");
+ goto leave;
+ }
+ }
+ if(!folder) {
+ folder = m_getfolder();
+ def_fold++;
+ }
+ subf = !((!index(folder, '/')) | (*folder == '/') | (*folder == '.'));
+ if(def_fold && !subf) {
+ cp = concat("Remove folder \"", folder, "\" ?? ", 0);
+ if(!gans(cp, anoyes))
+ goto leave;
+ free(cp);
+ }
+ if(rmfold(folder))
+ goto leave;
+ if(subf) { /* make parent "current" */
+ cp = copy(folder, buf);
+ while(cp > buf && *cp != '/') --cp;
+ if(cp > buf) {
+ *cp = 0;
+ if(strcmp(m_find(pfolder), buf) != 0) {
+ printf("[+%s now current]\n", buf);
+ m_replace(pfolder, buf);
+ }
+ }
+ }
+ leave:
+ m_update();
+ done(0);
+}
+
+rmfold(fold)
+char *fold;
+{
+ register char *maildir;
+ struct direct *ent;
+ int i, leftover, cd;
+ register char *cp, *sp;
+ char nambuf[10];
+ register DIR *dirp;
+
+ leftover = 0;
+ if(!subf && strcmp(m_find(pfolder), fold) == 0) /* make default "current"*/
+ if(strcmp(m_find(pfolder), defalt) != 0) {
+ printf("[+%s now current]\n", defalt);
+ fflush(stdout); /*??*/
+ m_replace(pfolder, defalt);
+ }
+ maildir = m_maildir(fold);
+ if((cd = chdir(maildir)) < 0)
+ goto funnyfold;
+ if(access(".", 2) == -1) {
+ funnyfold: if(!m_delete(concat("cur-", fold, 0)))
+ printf("[Folder %s de-referenced]\n", fold);
+ else
+ fprintf(stderr, "You have no profile entry for the %s folder %s\n",
+ cd < 0 ? "unreadable" : "read-only", fold);
+ return(1);
+ }
+ dirp = opendir(".");
+ ent = readdir(dirp); /* move pointer past "." */
+ ent = readdir(dirp); /* move pointer past ".." */
+ while(ent = readdir(dirp)) {
+ if (ent->d_ino==0) continue;
+ switch (ent->d_name[0]) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '#':
+ case ',':
+ if(unlink(ent->d_name) == -1) {
+ fprintf(stderr, "Can't unlink %s:%s\n", fold,ent->d_name);
+ leftover++;
+ }
+ break;
+ default:
+ if (strcmp(ent->d_name, "cur") == 0 ||
+ strcmp(ent->d_name, "@") == 0) {
+ if(unlink(ent->d_name) == -1) {
+ fprintf(stderr, "Can't unlink %s:%s\n", fold,ent->d_name);
+ leftover++;
+ }
+ } else {
+ fprintf(stderr, "File \"%s/%s\" not deleted!\n", fold, ent->d_name);
+ leftover++;
+ }
+ }
+ }
+ closedir(dirp);
+ chdir(".."); /* Move out of dir to be deleted */
+ if (leftover) {
+ fprintf(stderr, "Folder %s not removed!\n", fold);
+ return(1);
+ }
+ if(rmdir(maildir))
+ fprintf(stderr, "rmdir failed!\n");
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)rmm.c 4.1 2/23/83";
+#endif
+
+#include "mh.h"
+#include <stdio.h>
+#include <strings.h>
+
+int vecp;
+char **vec;
+struct msgs *mp;
+
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "help", 4, /* 1 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *nfolder, *maildir, *msgs[100], buf[32];
+ register int msgnum;
+ register char *cp, *sp;
+ int msgp;
+ char **ap;
+ char *arguments[50], **argp;
+
+#ifdef NEWS
+ m_news();
+#endif
+ folder = 0; msgp = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "rmm: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ /* -help */
+ case 1: help("rmm [+folder] [msgs] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "rmm: lasagne 'n sausage\n"); /* never get here */
+ goto leave;
+ }
+ m_replace(pfolder, folder);
+ if((cp = m_find("delete-prog")) == NULL) {
+ for(msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum] & SELECTED) {
+ sp = getcpy(m_name(msgnum));
+ cp = copy(sp, buf);
+ cp[1] = 0;
+ do
+ *cp = cp[-1];
+ while(--cp >= buf && *cp != '/');
+#ifdef UCB
+ *++cp = '#';
+#else
+ *++cp = ',';
+#endif
+ unlink(buf);
+ if(link(sp, buf) == -1 || unlink(sp) == -1)
+ fprintf(stderr, "Can't rename %s to %s.\n", sp, buf);
+ }
+ } else {
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "rmm: more than %d messages for deletion-prog\n",MAXARGS-2);
+ goto leave;
+ }
+ vec = (char **) calloc(MAXARGS +2, sizeof *vec);
+ vecp = 1;
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ vec[vecp++] = getcpy(m_name(msgnum));
+ vec[vecp] = 0;
+ vec[0] = cp;
+ m_update();
+ fflush(stdout);
+ execv(vec[0], vec);
+ fprintf(stderr, "Can't exec deletion prog--");
+ perror(cp);
+ }
+leave:
+ m_update();
+ done(0);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <strings.h>
+
+int hdrflag = 1;
+int reverse = 0;
+struct msgs *mp;
+
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "ff", 0, /* 1 */
+ "noff", 0, /* 2 */
+ "header", 0, /* 3 */
+ "noheader", 0, /* 4 */
+ "reverse", 0, /* 5 */
+ "help", 4, /* 6 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100];
+ register int msgnum;
+ register char *cp, **ap;
+ int msgp, ff;
+ FILE *in;
+ long now;
+ char *arguments[50], **argp;
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ ff = 0; msgp = 0; folder = 0;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:fprintf(stderr, "scan: -%s unknown\n", cp);
+ goto leave;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: ff = 1; continue; /* -ff */
+ case 2: ff = 0; continue; /* -noff */
+ case 3: hdrflag = 0; continue; /* -header */
+ case 4: hdrflag = 1; continue; /* -noheader */
+ case 5: reverse = 1; continue; /* -reverse */
+ case 6: help("scan [+folder] [msgs] [switches]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(!msgp)
+ msgs[msgp++] = "first-last";
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "scan: matzo balls.\n"); /* never get here */
+ goto leave;
+ }
+ m_replace(pfolder,folder);
+ for( msgnum = (reverse ? mp->hghsel : mp->lowsel);
+ (reverse ? msgnum >= mp->lowsel : msgnum <= mp->hghsel);
+ (reverse ? msgnum-- : msgnum++)) {
+ if(mp->msgstats[msgnum]&SELECTED) {
+ if((in = fopen(cp = m_name(msgnum), "r")) == NULL)
+ fprintf(stderr, "--Can't open %s\n", cp);
+ else {
+ if(!hdrflag++) {
+ time(&now);
+ cp = cdate(&now);
+ cp[9] = ' '; cp[15] = 0;
+printf("\
+ Folder %-32s%s\n\n\
+ # Date From Subject [<<Body]\n\n", folder, cp);
+ }
+ scan(in, msgnum, 0, msgnum == mp->curmsg);
+ fclose(in);
+ if(stdout->_cnt < 80)
+ fflush(stdout);
+ }
+ }
+ }
+ if(ff)
+ putchar('\014');
+leave:
+ m_update();
+ done(0);
+}
+
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+#define _FROM 1
+#define _NOTFROM 0
+
+
+#define FROM 13 /* Start of From field */
+#define SFROM 16 /* Length of " " */
+#define DATE 5 /* Start of Date field */
+#define SDATE 7 /* Length */
+#define SUBJ 31 /* Start of Subject field */
+#define SSUBJ (79-SUBJ) /* Size of Subject field */
+#define BSUBJ 20 /* Room needed in Sub field to */
+ /* add stuff from the body */
+#define MSGN 0 /* Start of msg name field */
+#define SMSGN 3 /* Length */
+#define FLGS 3 /* Start of flags field */
+#define SFLGS 2 /* Width of flag field */
+
+FILE *scnout;
+char scanl[82];
+int local;
+int hostseen;
+char *frmtok();
+
+scan(inb, innum, outnum, curflg)
+struct iobuf *inb;
+int outnum;
+{
+
+ char buf[BUFSIZ], name[NAMESZ], tobuf[32], frombuf[32];
+ register char *cp, **tok1;
+ int state, subsz, first, compnum;
+ static char *myname;
+
+ local = 0; hostseen = 0;
+ if(!myname)
+ myname = getenv("USER");
+ tobuf[0] = 0; frombuf[0] = 0;
+ first = 0;
+ state = FLD;
+ compnum = 1;
+
+ for(;;) {
+
+ state = m_getfld(state, name, buf, sizeof buf, inb);
+ if(!first++ && state != FILEEOF) { /*##*/
+ if(outnum) {
+ if((scnout = fopen(cp = m_name(outnum), "w")) == NULL) {
+ fprintf(stderr, "Error creating msg ");
+ perror(cp); done(-1);
+ }
+ chmod(cp, m_gmprot());
+ }
+ sfill(scanl, sizeof scanl);
+ scanl[sizeof scanl - 1] = 0;
+ subsz = 0;
+ tobuf[0] = 0;
+ }
+
+ switch(state) {
+
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ compnum++;
+ if(uleq(name, "from"))
+ frombuf[
+ cpyfrm(buf,frombuf,sizeof frombuf,_FROM)]=0;
+ else if(uleq(name, "date"))
+ cpydat(buf, scanl+DATE, SDATE);
+ else if(uleq(name, "subject") && scanl[SUBJ] == ' ')
+ subsz = cpy(buf, scanl+SUBJ, SSUBJ);
+ else if(uleq(name, "to") && !tobuf[0])
+ tobuf[
+ cpyfrm(buf,tobuf,sizeof tobuf-1,_NOTFROM)]=0;
+ else if(uleq(name, "replied"))
+ cpy("-", scanl+FLGS+1, 1);
+ put(name, buf, scnout);
+ while(state == FLDPLUS) {
+ state=m_getfld(state,name,buf,sizeof buf,inb);
+ if(scnout)
+ fputs(buf, scnout);
+ }
+ if(state == FLDEOF)
+ goto putscan;
+ continue;
+
+ case BODY:
+ case BODYEOF:
+ compnum = -1;
+ if(buf[0] && subsz < SSUBJ - BSUBJ) {
+ scanl[SUBJ+subsz+1] = '<';
+ scanl[SUBJ+subsz+2] = '<';
+ cpy(buf, scanl+SUBJ+subsz+3, SSUBJ-subsz-3);
+ subsz = SSUBJ;
+ }
+ if(buf[0] && scnout) {
+ putc('\n', scnout);
+ fputs(buf, scnout);
+ if(ferror(scnout)) {
+ fprintf(stderr, "Write error on ");
+ perror(m_name(outnum));done(-1);
+ }
+ }
+ body: while(state == BODY) {
+ state=m_getfld(state,name,buf,sizeof buf,inb);
+ if(scnout)
+ fputs(buf, scnout);
+ }
+ if(state == BODYEOF) {
+ putscan: cpymsgn(m_name(innum), scanl+MSGN, SMSGN);
+ tok1= brkstring(getcpy(frombuf), " ", "\n");
+ if(!frombuf[0] || uleq(frombuf, myname) ||
+ (local && uleq(*tok1, myname))) {
+ cpy("To:", scanl+FROM, 3);
+ cpy(tobuf, scanl+FROM+3, SFROM-3);
+ } else
+ cpy(frombuf, scanl+FROM, SFROM);
+ if(curflg)
+ cpy("+", scanl+FLGS, SFLGS);
+ trim(scanl);
+ fputs(scanl, stdout);
+
+ if(scnout) {
+ fflush(scnout);
+ if(ferror(scnout)) {
+ perror("Write error on ");
+ perror(m_name(outnum));
+ done(-1);
+ }
+ fclose(scnout);
+ scnout = NULL;
+ }
+ return(1);
+ }
+ break;
+
+ case LENERR:
+ case FMTERR:
+ fprintf(stderr, "??Message Format Error ");
+ fprintf(stderr, "(Message %d) ", outnum ? outnum :innum);/*##*/
+ if(compnum < 0) fprintf(stderr, "in the Body.\n");
+ else fprintf(stderr, "in Component #%d.\n", compnum);
+ fprintf(stderr, "-----------------------------------------");
+ fprintf(stderr, "-------------------------------------\n");
+ goto badret;
+ default:
+ fprintf(stderr, "Getfld returned %d\n", state);
+
+
+ badret: if(outnum) {
+ fputs("\n\nBAD MSG:\n", scnout);
+ if(compnum < 0)
+ fputs(buf, scnout);
+ else
+ fputs(name, scnout);
+ /*** ungetc(inb); ***/
+ state = BODY;
+ goto body;
+
+ }
+ if(scnout)
+ fflush(scnout);
+ return(-1);
+ case FILEEOF:
+ return(0);
+
+ }
+
+ }
+}
+
+
+trim(str)
+char *str;
+{
+ register char *cp;
+
+ cp = str;
+ while(*cp) cp++;
+ while(*--cp == ' ') ;
+ cp++;
+ *cp++ = '\n';
+ *cp++ = 0;
+}
+
+sfill(str, cnt)
+char *str;
+{
+ register char *cp;
+ register int i;
+
+ cp = str; i = cnt;
+ do
+ *cp++ = ' ';
+ while(--i);
+}
+
+
+put(name, buf, ip)
+register FILE *ip;
+{
+ if(ip) {
+ fputs(name, ip);
+ putc(':', ip);
+ fputs(buf, ip);
+ if(ferror(ip)) { perror("Write error");done(-1);}
+ }
+}
+
+
+cpy(from, to, cnt)
+register char *from, *to;
+register int cnt;
+{
+ register int c;
+ char *sfrom;
+
+ sfrom = from;
+ while(*from == ' ' || *from == '\t' || *from == '\n')
+ from++;
+ while(cnt--)
+ if(c = *from) {
+ if(c == '\t' || c == ' ' || c == '\n') {
+ *to++ = ' ';
+ do
+ from++;
+ while((c= *from)==' '||c=='\t'||c=='\n');
+ continue;
+ } else
+ *to++ = c;
+ from++;
+ } else
+ break;
+ return(from - sfrom - 1);
+}
+
+int *localtime();
+char *findmonth();
+
+cpydat(sfrom, sto, cnt)
+char *sfrom, *sto;
+{
+ register char *from, *cp;
+ register int c;
+ static int *locvec;
+ long now;
+ char *to;
+
+ if(!locvec) {
+ time(&now);
+ locvec = localtime(&now);
+ }
+ to = sto;
+ for(from = sfrom; (c = *from) < '0' || c > '9'; from++)
+ if(!c)
+ return;
+ c = cnt;
+ for(cp = from; (*cp >= '0' && *cp <= '9') || *cp == ' '; cp++);
+ if(cp = findmonth(cp)) {
+ if(!cp[1]) {
+ *to++ = ' ';
+ c--;
+ }
+ while(*cp && c--)
+ *to++ = *cp++;
+ c--; *to++ = '/';
+ if(from[1] == ' ') {
+ *to++ = ' ';
+ c--;
+ }
+ while(*from >= '0' && *from <= '9' && c--)
+ *to++ = *from++;
+ if(c >= 2) {
+ while(*from < '0' || *from > '9') from++;
+ if(((c = atoi(from)) > 1970 && c-1900 < locvec[5])
+ || c < locvec[5]) {
+ *to++ = '/';
+ *to++ = (c < 100) ? (c - 70 + '0')
+ : (c - 1970 + '0');
+ }
+ }
+ return;
+ }
+ if(from[1] == ' ') {
+ *to++ = ' ';
+ c--;
+ }
+ while(*from && c--)
+ *to++ = *from++;
+}
+
+
+char *fromp, fromdlm, pfromdlm;
+
+cpyfrm(sfrom, sto, cnt, fromcall)
+char *sfrom, *sto;
+{
+ register char *to, *cp;
+ register int c;
+
+ fromdlm = ' ';
+ fromp = sfrom; to = sto;
+ cp = frmtok();
+ do
+ if(c = *cp++)
+ *to++ = c;
+ else
+ break;
+ while(--cnt);
+ for(;;) {
+ if(cnt < 3) break;
+ if(*(cp = frmtok()) == 0) break;
+ if(*cp == '@' || uleq(cp, "at")) {
+ cp = frmtok();
+ if(uleq(cp, "berkeley")) {
+ /* if the first "From:" host is local */
+ if(fromcall && !hostseen++)
+ local++;
+ } else {
+ *to++ = '@';
+ cnt--;
+ do
+ if(c = *cp++)
+ *to++ = c;
+ else
+ break;
+ while(--cnt);
+ }
+ } else if(cnt > 4) {
+ cnt--; *to++ = pfromdlm;
+ do
+ if(c = *cp++)
+ *to++ = c;
+ else
+ break;
+ while(--cnt);
+ }
+ }
+ if(fromcall)
+ hostseen++;
+ return(to - sto);
+}
+
+
+char *frmtok()
+{
+ static char tokbuf[64];
+ register char *cp;
+ register int c;
+
+ pfromdlm = fromdlm;
+ cp = tokbuf; *cp = 0;
+ while(c = *fromp++) {
+ if(c == '\t')
+ c = ' ';
+ if(c == ' ' && cp == tokbuf)
+ continue;
+ if(c == ' ' || c == '\n' || c == ',')
+ break;
+ *cp++ = c;
+ *cp = 0;
+ if(c == '@' || *fromp == '@' || cp == &tokbuf[63])
+ break;
+ }
+ fromdlm = c;
+ return(tokbuf);
+}
+
+
+/* num specific! */
+
+cpymsgn(msgnam, addr, len)
+char *msgnam, *addr;
+{
+ register char *cp, *sp;
+
+ sp = msgnam;
+ cp = addr + (len - strlen(sp));
+ while(*sp)
+ *cp++ = *sp++;
+}
+
+char *monthtab[] = {
+ "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec",
+};
+
+char *findmonth(str)
+char *str;
+{
+ register char *cp, *sp;
+ register int i;
+ static char buf[4];
+ char *locv();
+
+ for(cp=str, sp=buf; (*sp++ = *cp++) && sp < &buf[3] && *cp != ' '; );
+ *sp = 0;
+ for(i = 0; i < 12; i++)
+ if(uleq(buf, monthtab[i])) {
+ sprintf(buf, "%2d", i+1);
+ return buf;
+ }
+ return(0);
+}
--- /dev/null
+#ifndef lint
+static char sccsid[] = "@(#)send.c 4.6 7/7/83";
+#endif
+
+#include "mh.h"
+#include <sys/wait.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <strings.h>
+
+#define SENDMAIL "/usr/lib/sendmail"
+#define FCCS 10 /* Max number of fcc's allowed */
+
+struct swit switches[] = {
+ "debug", -1, /* 0 */
+ "draft", 0, /* 1 */
+ "format", 0, /* 2 */
+ "noformat", 0, /* 3 */
+ "msgid", 0, /* 4 */
+ "nomsgid", 0, /* 5 */
+ "verbose", 0, /* 6 */
+ "noverbose", 0, /* 7 */
+ "help", 4, /* 8 */
+ "wait", 0, /* 9 */
+ "nowait", 0, /* 10 */
+ 0, 0
+};
+
+int verbose, format, msgid, debug, myuid;
+int waitfor = 1;
+char *anoyes[]; /* Std no/yes gans array */
+int donecd;
+long now;
+char tmpfil[32], fccfold[FCCS][128];
+int fccind;
+char *rindex();
+
+main(argc, argv)
+char *argv[];
+{
+ register char *drft, *cp, *addrs;
+ register int i;
+ int pid;
+ struct stat stbuf;
+ char **ap, *msg;
+ char *arguments[50], **argp;
+ char buf[BUFSIZ], name[NAMESZ];
+ int state, compnum, fd;
+ FILE *in, *out;
+ char *getname();
+
+#ifdef NEWS
+ m_news();
+#endif
+ drft = 0;
+ cp = r1bindex(argv[0], '/');
+ if ((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ done(1);
+ /* unknown */
+ case -1:fprintf(stderr, "send: -%s unknown\n", cp);
+ done(1);
+ case 0: verbose++; debug++; continue; /* -debug */
+ case 1: drft = m_maildir(draft); /* -draft */
+ continue;
+ case 2: fprintf(stderr, "Send: -format not yet.\n");
+ done(1);
+ case 3: format = 0; continue; /* -noformat */
+ case 4: msgid = 1; continue; /* -msgid */
+ case 5: msgid = 0; continue; /* -nomsgid */
+ case 6: verbose = 1; continue; /* -verbose */
+ case 7: verbose = 0; continue; /* -noverbose */
+ case 8: help("send [file] [switches]", switches);
+ done(1);
+ case 9: waitfor = 1; continue; /* -wait */
+ case 10:waitfor = 0; continue; /* -nowait */
+ }
+ if(drft) {
+ fprintf(stderr, "send: Only 1 message at a time!\n");
+ done(1);
+ } else
+ drft = cp;
+ }
+ if(!drft) {
+ drft = m_maildir(draft);
+ if(stat(drft, &stbuf) == -1) {
+ fprintf(stderr,
+ "Draft file: %s doesn't exist.\n", drft);
+ done(1);
+ }
+ cp = concat("Use \"", drft, "\"? ", 0);
+ if(!gans(cp, anoyes))
+ done(0);
+ } else {
+ if(stat(drft, &stbuf) == -1) {
+ fprintf(stderr,
+ "Draft file: %s doesn't exist.\n", drft);
+ done(1);
+ }
+ }
+ m_update();
+
+ /* open files... */
+ if((in = fopen(drft, "r")) == NULL) {
+ fprintf(stderr, "Send: Can't open ");
+ perror(drft);
+ done(1);
+ }
+ copy(makename("locs", ".tmp"), copy("/tmp/", tmpfil));
+ if(!debug) {
+ if((out = fopen(tmpfil, "w")) == NULL) {
+ fprintf(stderr, "Can't create %s\n", tmpfil);
+ done(1);
+ }
+ chmod(tmpfil, 0744);
+ } else
+ out = stdout;
+
+ myuid = getuid();
+ putdate(0, out); /* Tack on the date */
+ /* putfrom(out);*/ /* let sendmail do this */
+ putmsgid(out); /* and message id if desired */
+
+ /*
+ ** Delivery phase
+ */
+ for(compnum = 1, state = FLD;;) {
+ state = m_getfld(state, name, buf, sizeof buf, in);
+ switch (state)
+ {
+ case FLD:
+ case FLDEOF:
+ case FLDPLUS:
+ compnum++;
+ cp = buf;
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+ fprintf(out, "%s: %s", name, cp);
+ if(uleq(name, "fcc")) {
+ if(fccind >= FCCS) {
+ fprintf(stderr, "Send: too many fcc's.\n");
+ done(1);
+ }
+ copy(cp, fccfold[fccind]);
+ if(cp = rindex(fccfold[fccind], '\n'))
+ *cp = 0;
+ fccind++;
+ }
+ while(state == FLDPLUS || state == FLDEOF) {
+ state = m_getfld(state, name, buf, sizeof buf, in);
+ fputs(buf, out);
+ }
+ if(state == FLDEOF)
+ goto process;
+ break;
+
+ case BODY:
+ case BODYEOF:
+ fprintf(out, "\n%s", buf);
+ while(state == BODY) {
+ state=m_getfld(state,name,buf,sizeof buf,in);
+ fputs(buf, out);
+ }
+
+ case FILEEOF:
+ goto process;
+
+ case LENERR:
+ case FMTERR:
+ fprintf(stderr, "??Message Format Error ");
+ fprintf(stderr, "in Component #%d.\n", compnum);
+ done(1);
+
+ default:
+ fprintf(stderr, "Getfld returned %d\n", state);
+ done(1);
+ }
+ }
+process:
+ if(!debug)
+ fclose(out);
+ else
+ printf("-----\n");
+ fclose(in);
+
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ if(!debug) { /* Send the mail */
+ fd = open(tmpfil, 0);
+ sendmail(fd);
+ close(fd);
+ if(fccind) {
+ for(state = 0; state < fccind; state++)
+ fcc(tmpfil, fccfold[state]);
+ }
+ unlink(tmpfil);
+ }
+ if (!debug)
+ backup(drft);
+ done(donecd);
+}
+
+sendmail(fd)
+{
+ int pid;
+ char *stashname[10];
+ char **stashp;
+
+ stashp = stashname;
+ *stashp++ = "sendmail";
+ *stashp++ = "-i";
+ *stashp++ = "-t";
+ if (verbose)
+ *stashp++ = "-v";
+ *stashp = 0;
+
+ while ((pid = fork()) == -1)
+ sleep(2);
+ if (pid == 0) {
+ close(0);
+ dup(fd);
+ close(fd);
+ execv(SENDMAIL, stashname);
+ perror(SENDMAIL);
+ _exit(1);
+ }
+ else if (waitfor)
+ (void) wait(0);
+}
+
+putfrom(out)
+ register FILE *out;
+{
+ register struct passwd *pw;
+
+ pw = getpwuid(myuid);
+ if (pw == NULL)
+ {
+ fprintf(stderr, "Send: WHO ARE YOU?\n");
+ done(1);
+ }
+ fprintf(out, "From: %s\n", pw->pw_name);
+}
+
+putmsgid(sp)
+ FILE *sp;
+{
+ char hostname[32];
+ auto int i = sizeof hostname;
+
+ if(!msgid)
+ return;
+ if(!now)
+ time(&now);
+ gethostname(hostname, &i);
+ fprintf(sp,
+ "Message-Id: <%u.%u.%ld@%s>\n", getpid(), myuid, now, hostname);
+}
+
+fcc(file, folder)
+ char *file, *folder;
+{
+ int child, pid;
+ union wait status;
+ char fold[128];
+
+ if(verbose) {
+ printf("Fcc: %s...", folder);
+ fflush(stdout);
+ }
+ while ((child = fork()) == -1)
+ sleep(5);
+ if(child == 0) {
+ if(*file != '+')
+ strcpy(fold, "+");
+ strcat(fold, folder);
+ execl(fileproc, "file", "-link", "-file", file, fold, 0);
+ exit(-1);
+ } else
+ while((pid = wait(&status)) != -1 && pid != child);
+ if (status.w_status)
+ fprintf(stderr, "Send: Error on fcc to %s\n", folder);
+ else if(verbose)
+ putchar('\n');
+}
+
+backup(file)
+char *file;
+{
+ char buf[128];
+ register char *cp;
+
+ buf[0] = 0;
+ if(cp = rindex(file, '/'))
+ sprintf(buf, "%.*s", (++cp)-file, file);
+ else
+ cp = file;
+#ifdef UCB
+ strcat(buf, "#");
+#else
+ strcat(buf, ",");
+#endif
+ strcat(buf, cp);
+ unlink(buf);
+ if(link(file, buf) < 0 || unlink(file) < 0) {
+ fprintf(stderr, "Send: Backup rename failure ");
+ perror(buf);
+ done(1);
+ }
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <strings.h>
+
+int vecp;
+char *vec[MAXARGS];
+struct msgs *mp;
+struct swit switches[] = {
+ "all", -3, /* 0 */
+ "draft", 2, /* 1 */
+ "pr", 2, /* 2 */
+ "nopr", 2, /* 3 */
+ "help", 4, /* 4 */
+ 0, 0
+};
+
+main(argc, argv)
+char *argv[];
+{
+ char *folder, *maildir, *msgs[100];
+ register int msgnum;
+ register char *cp, **ap;
+ int msgp, all, drft, pr;
+ char *arguments[50], **argp;
+ extern char _sobuf[];
+
+ setbuf(stdout, _sobuf);
+#ifdef NEWS
+ m_news();
+#endif
+ folder = (char *) 0;
+ pr = all = msgp = 0;
+ vecp = 1;
+ cp = r1bindex(argv[0], '/');
+ if((cp = m_find(cp)) != NULL) {
+ ap = brkstring(cp = getcpy(cp), " ", "\n");
+ ap = copyip(ap, arguments);
+ } else
+ ap = arguments;
+ copyip(argv+1, ap);
+ argp = arguments;
+ while(cp = *argp++) {
+ if(*cp == '-')
+ switch(smatch(++cp, switches)) {
+ case -2:ambigsw(cp, switches); /* ambiguous */
+ goto leave;
+ /* unknown */
+ case -1:vec[vecp++] = --cp; continue;
+ /* -all */
+ case 0: fprintf(stderr, "\"-all\" changed to \"all\"\n");
+ goto leave;
+ case 1: drft = 1; continue; /* -draft */
+ case 2: pr = 1; continue; /* -pr */
+ case 3: pr = 0; vecp = 1; continue;/* -nopr */
+ case 4: /* -help */
+ help("show [+folder] [msgs] [switches] [switches for \"type\" or \"pr\" ]",
+ switches);
+ goto leave;
+ }
+ if(*cp == '+') {
+ if(folder) {
+ fprintf(stderr, "Only one folder at a time.\n");
+ goto leave;
+ } else
+ folder = cp + 1;
+ } else
+ msgs[msgp++] = cp;
+ }
+ if(drft)
+ maildir = m_maildir("");
+ else {
+ if(!msgp)
+ msgs[msgp++] = "cur";
+ if(!folder)
+ folder = m_getfolder();
+ maildir = m_maildir(folder);
+ }
+ if(chdir(maildir) < 0) {
+ fprintf(stderr, "Can't chdir to: ");
+ perror(maildir);
+ goto leave;
+ }
+ if(drft) {
+ vec[vecp++] = draft;
+ goto doit;
+ }
+ if(!(mp = m_gmsg(folder))) {
+ fprintf(stderr, "Can't read folder!?\n");
+ goto leave;
+ }
+ if(mp->hghmsg == 0) {
+ fprintf(stderr, "No messages in \"%s\".\n", folder);
+ goto leave;
+ }
+ if(msgp)
+ for(msgnum = 0; msgnum < msgp; msgnum++)
+ if(!m_convert(msgs[msgnum]))
+ goto leave;
+ if(mp->numsel == 0) {
+ fprintf(stderr, "show: potato pancakes.\n"); /* never get here */
+ goto leave;
+ }
+ if(mp->numsel > MAXARGS-2) {
+ fprintf(stderr, "show: more than %d messages for show-exec\n", MAXARGS-2);
+ goto leave;
+ }
+ for(msgnum= mp->lowsel; msgnum<= mp->hghsel; msgnum++)
+ if(mp->msgstats[msgnum]&SELECTED)
+ vec[vecp++] = getcpy(m_name(msgnum));
+ m_replace(pfolder, folder);
+ if(mp->hghsel != mp->curmsg)
+ m_setcur(mp->hghsel);
+ if(vecp == 2 ) {
+ printf("(Message %s:%s)\n", folder, vec[1]);
+ }
+doit: m_update();
+ fflush(stdout);
+ vec[vecp] = 0;
+ if(!pr) {
+ vec[0] = "c:mh-type";
+ execv(showproc, vec);
+ } else {
+ vec[0] = "mh-pr";
+ execv(prproc, vec);
+ }
+ perror(pr ? prproc : showproc);
+ leave:
+ m_update();
+ done(0);
+}
+
+
--- /dev/null
+/*
+ * This file gives extern declarations to all the strings
+ * that we might ever reference.
+ *
+ * I don't know if this what strings.h is supposed to be,
+ * but this is as good a first guess as I can handle.
+ */
+
+extern char *anoyes[];
+extern char *components;
+extern char *current;
+extern char *defalt;
+extern char *distcomps;
+extern char *draft;
+extern char *fileproc;
+extern char *foldprot;
+extern char *hostname;
+extern char *installproc;
+extern char *listname;
+extern char *lockdir;
+extern int lockwait;
+extern char *lsproc;
+extern char *mailboxes;
+extern char *mailproc;
+extern char *mh_deliver;
+extern char *mh_prof;
+extern char *mhnews;
+extern char *msgprot;
+extern char *pfolder;
+extern char *prproc;
+extern char *scanproc;
+extern char *sendproc;
+extern char *showproc;
+extern char *stdcomps;
+extern char *stddcomps;
+extern char *sysed;
+
+#ifdef UNIXCOMP
+extern char *unixtomh;
+extern char *Mailprog;
+extern char *localname;
+#endif
--- /dev/null
+#
+
+/*
+ * This program copies the mail file in standard unix format
+ * given as $1 to the file $2 in Rand Message Handler format.
+ * The change made is to bracket each message with a line
+ * containing 4 control-A's and to split the From line into
+ * a From: field and a Date: field, with the date in Arpanet
+ * standard format.
+ *
+ * This program is designed to be called from the rand mh program
+ * ``inc''
+ *
+ * Set SENDMAIL if you are running sendmail -- this guarantees that
+ * From: and Date: lines will appear already, and will put the info
+ * in the UNIX-From line into a Received-From: field.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <ctype.h>
+
+#define SENDMAIL
+
+struct headline {
+ char *l_from; /* The name of the sender */
+ char *l_tty; /* His tty string (if any) */
+ char *l_date; /* The entire date string */
+};
+
+char *savestr(), *copyin(), *copy(), *nextword(), *calloc();
+char *index();
+
+#define NOSTR ((char *) 0)
+#define UUCP /* Undo strange uucp naming */
+
+main(argc, argv)
+ char **argv;
+{
+ char linebuf[BUFSIZ];
+ register int maybe;
+ register FILE *inf, *outf;
+ int inhdr, infld;
+
+ if (argc > 3) {
+ fprintf(stderr, "Usage: unixtomh name1 name2\n");
+ exit(1);
+ }
+ outf = inf = NULL;
+ if (argc < 3)
+ outf = stdout;
+ if (argc < 2)
+ inf = stdin;
+ if (inf == NULL && (inf = fopen(argv[1], "r")) == NULL) {
+ perror(argv[1]);
+ exit(1);
+ }
+ if (outf == NULL && (outf = fopen(argv[2], "w")) == NULL) {
+ perror(argv[2]);
+ exit(1);
+ }
+ maybe = 1;
+ inhdr = 0;
+ infld = 0;
+ while (nullgets(linebuf, BUFSIZ, inf) > 0) {
+ if (maybe && ishead(linebuf)) {
+ fputs("\1\1\1\1\n", outf);
+ inhdr++;
+ dohead(linebuf, inf, outf);
+ continue;
+ }
+ if (strlen(linebuf) == 0) {
+ maybe = 1;
+ inhdr = 0;
+ infld = 0;
+ putc('\n', outf);
+ continue;
+ }
+ else
+ maybe = 0;
+#ifndef SENDMAIL
+ if (inhdr && strcmpn(linebuf, "Date: ", 6) == 0)
+ continue;
+ if (inhdr && strcmpn(linebuf, "From: ", 6) == 0)
+ continue;
+#endif SENDMAIL
+ if (infld && isspace(linebuf[0])) {
+ fputs(linebuf, outf);
+ putc('\n', outf);
+ continue;
+ }
+ if (inhdr && !isspace(linebuf[0])) {
+ char *colp, *sp;
+
+ colp = index(linebuf, ':');
+ sp = index(linebuf, ' ');
+ if (colp == NOSTR || sp == NOSTR || sp < colp) {
+ putc('\n', outf);
+ inhdr = 0;
+ }
+ else
+ infld = 1;
+ }
+ fputs(linebuf, outf);
+ putc('\n', outf);
+ }
+ fputs("\1\1\1\1\n", outf);
+ fflush(outf);
+ if (ferror(outf)) {
+ fprintf(stderr, "unixtomh: write: ");
+ perror(argv[2]);
+ exit(1);
+ }
+ exit(0);
+}
+
+/*
+ * Get a line from the given file descriptor, don't return the
+ * terminating newline.
+ */
+
+nullgets(linebuf, sz, file)
+ char linebuf[];
+ register FILE *file;
+{
+ register char *cp;
+ register int c, cnt;
+
+ cp = linebuf;
+ cnt = sz;
+ do {
+ if (--cnt <= 0) {
+ *cp = 0;
+ return(1);
+ }
+ c = getc(file);
+ *cp++ = c;
+ } while (c != EOF && c != '\n');
+ if (c == EOF && cp == linebuf+1)
+ return(0);
+ *--cp = 0;
+ return(1);
+}
+
+/*
+ * Output the fields extracted from the From line --
+ * From: and Date: Untangle UUCP stuff if appropriate.
+ */
+
+dohead(line, infile, outfile)
+ char line[];
+ register FILE *infile, *outfile;
+{
+ register char *cp;
+ struct headline hl;
+ char parbuf[BUFSIZ];
+#ifdef UUCP
+ char *word();
+ char namebuf[BUFSIZ];
+ char linebuf[BUFSIZ];
+ int first;
+ long curoff;
+#endif UUCP
+
+ parse(line, &hl, parbuf);
+#ifndef SENDMAIL
+ putdate(hl.l_date, outfile);
+#endif SENDMAIL
+#ifdef UUCP
+ if (strcmp(hl.l_from, "uucp") == 0) {
+ strcpy(namebuf, "");
+ first = 1;
+ for (;;) {
+ curoff = ftell(infile);
+ if (fgets(linebuf, BUFSIZ, infile) == NULL)
+ break;
+ if (strcmp(word(1, linebuf), ">From") != 0)
+ break;
+ if (strcmp(word(-3, linebuf), "remote") != 0)
+ break;
+ if (strcmp(word(-2, linebuf), "from") != 0)
+ break;
+ if (first) {
+ strcpy(namebuf, word(-1, linebuf));
+ strcat(namebuf, "!");
+ strcat(namebuf, word(2, linebuf));
+ first = 0;
+ }
+ else {
+ strcpy(rindex(namebuf, '!')+1,
+ word(-1, linebuf));
+ strcat(namebuf, "!");
+ strcat(namebuf, word(2, linebuf));
+ }
+ }
+ fseek(infile, curoff, 0);
+#ifdef SENDMAIL
+ if (!first)
+ fprintf(outfile, "Return-Path: <%s>\n", namebuf);
+#else SENDMAIL
+ if (first)
+ fprintf(outfile, "From: uucp\n");
+ else
+ fprintf(outfile, "From: %s\n", namebuf);
+#endif SENDMAIL
+ return;
+ }
+#endif UUCP
+#ifdef SENDMAIL
+ if (hl.l_from[0] == '<')
+ fprintf(outfile, "Return-Path: %s\n", hl.l_from);
+ else
+ fprintf(outfile, "Return-Path: <%s>\n", hl.l_from);
+#else SENDMAIL
+ fprintf(outfile, "From: %s\n", hl.l_from);
+#endif SENDMAIL
+}
+
+#ifdef UUCP
+
+/*
+ * Return liberal word i from the given string.
+ * The words are numbered 1, 2, 3, . . . from the left
+ * and -1, -2, . . . from the right.
+ */
+
+char *
+word(index, str)
+ char str[];
+{
+ register char *cp;
+ char *secbuf;
+ register int c;
+ static char retbuf[100];
+ char *gword();
+
+ cp = str;
+ if ((c = index) > 0) {
+ while (c-- > 0)
+ cp = gword(cp, retbuf);
+ return(retbuf);
+ }
+ if (c == 0)
+ return("");
+ secbuf = (char *) alloca(strlen(str) + 1);
+ strcpy(secbuf, str);
+ rev(secbuf);
+ cp = word(-index, secbuf);
+ rev(cp);
+ return(cp);
+}
+
+/*
+ * Skip leading blanks in the string, return
+ * first liberal word collected.
+ */
+
+char *
+gword(cp, buf)
+ register char *cp;
+ char buf[];
+{
+ register char *cp2;
+
+ cp2 = buf;
+ while (*cp && any(*cp, " \t\n"))
+ cp++;
+ while (*cp && !any(*cp, " \t\n"))
+ *cp2++ = *cp++;
+ *cp2 = 0;
+ return(cp);
+}
+
+/*
+ * Reverse the characters in the string in place
+ */
+
+rev(str)
+ char str[];
+{
+ register char *cpl, *cpr;
+ register int s;
+
+ s = strlen(str);
+ cpl = str;
+ cpr = &str[s-1];
+ while (cpl < cpr) {
+ s = *cpl;
+ *cpl++ = *cpr;
+ *cpr-- = s;
+ }
+}
+#endif UUCP
+
+/*
+ * Save a string in dynamic space.
+ * This little goodie is needed for
+ * a headline detector in head.c
+ */
+
+char *
+savestr(str)
+ char str[];
+{
+ register char *top;
+
+ top = calloc(strlen(str) + 1, 1);
+ if (top == NOSTR) {
+ fprintf(stderr, "unixtomh: Ran out of memory\n");
+ exit(1);
+ }
+ copy(str, top);
+ return(top);
+}
+
+/*
+ * See if the passed line buffer is a mail header.
+ * Return true if yes. Note the extreme pains to
+ * accomodate all funny formats.
+ */
+
+ishead(linebuf)
+ char linebuf[];
+{
+ register char *cp;
+ struct headline hl;
+ char parbuf[BUFSIZ];
+
+ cp = linebuf;
+ if (!isname("From ", cp, 5))
+ return(0);
+ parse(cp, &hl, parbuf);
+ if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
+ fail(linebuf, "No from or date field");
+ return(0);
+ }
+ if (!isdate(hl.l_date)) {
+ fail(linebuf, "Date field not legal date");
+ return(0);
+ }
+
+ /*
+ * I guess we got it!
+ */
+
+ return(1);
+}
+
+fail(linebuf, reason)
+ char linebuf[], reason[];
+{
+ return;
+}
+
+/*
+ * Split a headline into its useful components.
+ * Copy the line into dynamic string space, then set
+ * pointers into the copied line in the passed headline
+ * structure. Actually, it scans.
+ */
+
+parse(line, hl, pbuf)
+ char line[], pbuf[];
+ struct headline *hl;
+{
+ register char *cp, *dp;
+ char *sp;
+ char word[BUFSIZ];
+
+ hl->l_from = NOSTR;
+ hl->l_tty = NOSTR;
+ hl->l_date = NOSTR;
+ cp = line;
+ sp = pbuf;
+
+ /*
+ * Skip the first "word" of the line, which should be "From"
+ * anyway.
+ */
+
+ cp = nextword(cp, word);
+ dp = nextword(cp, word);
+ if (word[0] != 0)
+ hl->l_from = copyin(word, &sp);
+ if (isname(dp, "tty", 3)) {
+ cp = nextword(dp, word);
+ hl->l_tty = copyin(word, &sp);
+ if (cp != NOSTR)
+ hl->l_date = copyin(cp, &sp);
+ }
+ else
+ if (dp != NOSTR)
+ hl->l_date = copyin(dp, &sp);
+}
+
+/*
+ * Copy the string on the left into the string on the right
+ * and bump the right (reference) string pointer by the length.
+ * Thus, dynamically allocate space in the right string, copying
+ * the left string into it.
+ */
+
+char *
+copyin(src, space)
+ char src[];
+ char **space;
+{
+ register char *cp, *top;
+ register int s;
+
+ s = strlen(src);
+ cp = *space;
+ top = cp;
+ strcpy(cp, src);
+ cp += s + 1;
+ *space = cp;
+ return(top);
+}
+
+/*
+ * See if the two passed strings agree in the first n characters.
+ * Return true if they do, gnu.
+ */
+
+isname(as1, as2, acount)
+ char *as1, *as2;
+{
+ register char *s1, *s2;
+ register count;
+
+ s1 = as1;
+ s2 = as2;
+ count = acount;
+ if (count > 0)
+ do
+ if (*s1++ != *s2++)
+ return(0);
+ while (--count);
+ return(1);
+}
+
+/*
+ * Test to see if the passed string is a ctime(3) generated
+ * date string as documented in the manual. The template
+ * below is used as the criterion of correctness.
+ * Also, we check for a possible trailing time zone using
+ * the auxtype template.
+ */
+
+#define L 1 /* A lower case char */
+#define S 2 /* A space */
+#define D 3 /* A digit */
+#define O 4 /* An optional digit or space */
+#define C 5 /* A colon */
+#define N 6 /* A new line */
+#define U 7 /* An upper case char */
+
+char ctypes[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,D,D,D,D,0};
+char tmztypes[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,U,U,U,S,D,D,D,D,0};
+
+isdate(date)
+ char date[];
+{
+ register char *cp;
+
+ cp = date;
+ if (cmatch(cp, ctypes))
+ return(1);
+ return(cmatch(cp, tmztypes));
+}
+
+/*
+ * Match the given string against the given template.
+ * Return 1 if they match, 0 if they don't
+ */
+
+cmatch(str, temp)
+ char str[], temp[];
+{
+ register char *cp, *tp;
+ register int c;
+
+ cp = str;
+ tp = temp;
+ while (*cp != '\0' && *tp != 0) {
+ c = *cp++;
+ switch (*tp++) {
+ case L:
+ if (!islower(c))
+ return(0);
+ break;
+
+ case S:
+ if (c != ' ')
+ return(0);
+ break;
+
+ case D:
+ if (!isdigit(c))
+ return(0);
+ break;
+
+ case O:
+ if (c != ' ' && !isdigit(c))
+ return(0);
+ break;
+
+ case C:
+ if (c != ':')
+ return(0);
+ break;
+
+ case N:
+ if (c != '\n')
+ return(0);
+ break;
+
+ case U:
+ if (!isupper(c))
+ return(0);
+ break;
+ }
+ }
+ if (*cp != '\0' || *tp != 0)
+ return(0);
+ return(1);
+}
+
+/*
+ * Collect a liberal (space, tab delimited) word into the word buffer
+ * passed. Also, return a pointer to the next word following that,
+ * or NOSTR if none follow.
+ */
+
+char *
+nextword(wp, wbuf)
+ char wp[], wbuf[];
+{
+ register char *cp, *cp2;
+
+ if ((cp = wp) == NOSTR) {
+ copy("", wbuf);
+ return(NOSTR);
+ }
+ cp2 = wbuf;
+ while (!any(*cp, " \t") && *cp != '\0')
+ *cp2++ = *cp++;
+ *cp2 = '\0';
+ while (any(*cp, " \t"))
+ cp++;
+ if (*cp == '\0')
+ return(NOSTR);
+ return(cp);
+}
+
+/*
+ * Copy str1 to str2, return pointer to null in str2.
+ */
+
+char *
+copy(str1, str2)
+ char *str1, *str2;
+{
+ register char *s1, *s2;
+
+ s1 = str1;
+ s2 = str2;
+ while (*s1)
+ *s2++ = *s1++;
+ *s2 = 0;
+ return(s2);
+}
+
+/*
+ * Is ch any of the characters in str?
+ */
+
+any(ch, str)
+ char *str;
+{
+ register char *f;
+ register c;
+
+ f = str;
+ c = ch;
+ while (*f)
+ if (c == *f++)
+ return(1);
+ return(0);
+}
+
+/*
+ * Convert lower case letters to upper case.
+ */
+
+raise(c)
+ register int c;
+{
+ if (c >= 'a' && c <= 'z')
+ c += 'A' - 'a';
+ return(c);
+}
--- /dev/null
+ register char *cp;
+ register int i,j;
+ register FILE *in;
+ char name[NAMESZ], field[BUFSIZ];
+ char *drft, *msgid, *replto, *from, *cc, *sub, *date, *to;
+ int state, out, status, intr;
+ int pid, wpid;
+ char **argp, *address;
+ char ackfile[10];
+ char buf[BUFSIZ];
--- /dev/null
+The Alias file for mail delivery is the file
+
+ /etc/MailAliases
+
+Each line of the alias file has the format:
+
+match : alias
+
+Where:
+
+ alias := simple-list
+ | "<" alias-file
+ | "=" UNIX-group
+ | "*"
+
+ simple-list := simple-name
+ | simple-list, simple-name
+
+Alias-file is a fully qualified UNIX file name. UNIX-group is a
+group name from /etc/group. A simple-name is a local user login
+name, including only alphanumerics, `.' and `-'. Throughout this
+file case is ignored, except for alias-file.
+
+In match, a trailing * on a name will match anything. (See example
+below.)
+
+The procedure for mail aliasing is:
+
+1) Build a list of all addresses from the message to be
+ delivered, eliminating duplicates.
+
+2) For each line in the alias file, compare "match" against all
+ of the existing addresses. If a match, remove the matched
+ name from the address list, and add each new alias name to the
+ address list if it is not already on the list.
+
+Since the alias file is read line by line, forward references
+work, but backward references are not recognized, thus, there is
+no recursion.
+
+E.g.:
+
+Borden: bruce
+Bruce: bsb
+Wharman: mike
+ASRL: bsb, mike, obrien, giarla
+UNIX-committee: < /usr/people/unix-committee
+System: = sys
+Everyone: *
+news.*: news
+ ...
+
+In the "unix-committee" example, the file "/usr/people/unix-
+committee" contains one simple-name, or a list of comma separated
+simple-names. A new-line will be treated as a blank in this
+file, s.a.
+
+ foo, fie,
+ fum, fiddle
+
+In the "system" case, the names from the group "sys" will be used
+as the expanded name list.
+
+In the "news.*" case, all names of the form "news.<anything>" will
+be mapped to "news". This is used for the MH news facility.
+
+Bruce Borden October 1979
--- /dev/null
+vgrind aliascheck.c annotate.c comp.c deliver.c dist.c emitl.c\
+ errno.h file.c folder.c forw.c grep.c inc.c install-mh.c\
+ mail.c mh.h news.c next.c nexthdr.c pick.c prevhdr.c\
+ prompter.c replsubs.c reply.c rescue.c rmf.c rmm.c scan.c\
+ scansub.c send.c show.c strings.h strings/Mailprog.c strings/anoyes.c\
+ strings/components.c strings/current.c strings/defalt.c\
+ strings/distcomps.c strings/draft.c strings/fileproc.c\
+ strings/foldprot.c strings/hostname.c strings/installproc.c\
+ strings/listname.c strings/localname.c strings/lockdir.c\
+ strings/lsproc.c strings/mailboxes.c strings/mailproc.c\
+ strings/mh_defs.c strings/mh_deliver.c strings/mh_prof.c\
+ strings/mhnews.c strings/msgprot.c strings/pfolder.c\
+ strings/prproc.c strings/scanproc.c strings/sendproc.c\
+ strings/showproc.c strings/stdcomps.c strings/stddcomps.c\
+ strings/strings.h strings/sysed.c strings/unixtomh.c\
+ subs/add.c subs/ambigsw.c subs/atooi.c subs/brkstring.c\
+ subs/cdate.c subs/cndfree.c subs/concat.c subs/copy.c subs/copyip.c\
+ subs/cputc.c subs/crpbrkstring.c subs/done.c subs/fdcompare.c\
+ subs/gans.c subs/getans.c subs/getcpy.c subs/help.c subs/invo_name.c\
+ subs/locv.c subs/m_convert.c subs/m_delete.c subs/m_edit.c\
+ subs/m_find.c subs/m_getdefs.c subs/m_getfld.c subs/m_getfolder.c\
+ subs/m_gmprot.c subs/m_gmsg.c subs/m_maildir.c subs/m_name.c\
+ subs/m_replace.c subs/m_send.c subs/m_setcur.c subs/m_update.c\
+ subs/makedir.c subs/makename.c subs/mh.h subs/peekc.c\
+ subs/pr_array.c subs/printsw.c subs/putdate.c subs/r1bindex.c\
+ subs/showfile.c subs/smatch.c subs/ssequal.c subs/trimcpy.c\
+ subs/type.c subs/uleq.c support/l.c unixtomh.c vars.c
--- /dev/null
+ HOW TO GENERATE AN MH
+
+ASSUMPTIONS/RESTRICTIONS:
+
+ All of the code is written for Version 7 C, and assumes
+the existence of appropriate Version 7 /usr/include files. It
+also uses the Version 7 stdio package, which is somewhat
+different than the Phototypesetter stdio!
+
+ There is moderate usage of Version 7 UNIX features,
+including:
+
+ ftime() system call
+ execlp() & execvp() environment exec calls
+ getenv() environment access
+
+also, login has to be changed to add the environment entry
+"USER=name". This is used during scan listings to see if the
+message "From" should be replaced by "To:name". This string is
+NOT used to determine the "From: name" stamp on outgoing mail.
+
+ All of these usages ARE replaceable by subroutines which
+do the same thing, only slower. That is, a line of the form:
+
+ homedir = getenv("HOME");
+
+should be replaced by something like:
+
+ homedir = gethome();
+
+and the routine gethome() written to return the home directory by
+looking through /etc/passwd for the line matching the process'
+getuid(). This goes for the environment variable "USER" as well.
+
+The routines execlp() & execvp() are simply fancy exec's, which
+use the "PATH" environment variable to determine the search path
+by which to find the executable image. They can be replaced by
+routines which use a default search list. They also call a shell
+to execute the file in the same way the shell handles shell
+scripts.
+
+
+
+PROCEDURE:
+
+
+1) Read the MH directory tree onto a file system.
+
+2) Examine all of the files in directory strings. These are the
+ names and paths of all of the programs MH calls upon. Change
+ them to suit your installation. Most of the files contain
+ short descriptions of what the strings are.
+
+3) In the top level directory, utter:
+
+ make strings.a subs.a all
+
+ This will make both of the libraries: strings.a and subs.a,
+ and ALL of the executable modules.
+
+4) AS SU:
+
+ make onceonly This renames conflicting bell
+ programs, and makes requisite
+ directories.
+
+ make install This puts all of the programs
+ into appropriate directories.
+
+That's it. Take a close look at the Makefile--it does LOTS of
+work. If you don't want to install everything in standard
+places, run "make install" with the variables MHDIR=newdir and
+BINDIR=newdir pointing wherever you wish. If you do this, you
+probably have to change some of the path names in the strings
+files. For most of them, you can get away with adding profile
+entries to change where the default paths are sought.
+
+If you don't have `make':
+
+ You'll have to use the make file as a template for commands
+ to give by hand. Basically each section of the make file
+ defines the sequence of shell commands needed to create the
+ object before the `:'. The list immediately after the `:'
+ specifies the dependencies for the object--that is, those
+ objects which either must be made first, or those modules
+ that if they've changed, the object must be rebuilt. The
+ following lines (up to the next object) are simply shell
+ commands to be executed. Make knows how to create .o's from
+ .c's, and the "CFLAGS= -O" at the beginning tells it to
+ include optimization when it does a c compile.
+
+If you don't have stdio (i.e. some version 7 C compiler):
+
+ Punt. I recently converted the whole package from the old
+ getc/putc/iobuf subroutines--including lots of upgrades/
+ improvements, it took me about a week. Expect it to take a
+ couple of weeks for someone good to convert back.
+ Basically, convert the subroutines, then once you've
+ converted one module (start with show or comp), you'll find
+ all the rest VERY similar. Some day I may split out all of
+ the system dependencies, but don't hold your breath.
+
+
+
+As a last resort:
+
+ Feel free to call me, but please don't expect me to spend
+hours helping. Collect your questions/problems, and get in touch
+and I'll see what I can do. I can be reached:
+
+ via ARPANET: Borden at Rand-UNIX
+
+ Mail: The Rand Corporation
+ 1700 Main Street
+ Santa Monica, CA 90406
+
+ Phone: (213) 399-0568 x 7463
+
+
+
+Bruce Borden
+October, 1979
--- /dev/null
+This file contains some notes on features/bugs/etc which are
+not documented in the "MH User's Manual", as well as some notes
+on future directions. See MHgenerate for more info. Some of
+these notes assume VAX/V7 UNIX--as noted by {V/V7}.
+
+0) Directories:
+ support contains files which get copied to /etc/mh, as
+ well as some miscellaneous Rand support programs
+ subs contains support subroutines--built into subs.a
+ strings contains c files which define all of the default
+ names and paths used by the package->strings.a
+ Extras old and un-supported code--much of it not
+ converted to V7. Look at libg/libh for help in
+ getting around V7 features.
+ DOC contains the MH User's Manual document in nroff/
+ troff form. This requires the Phototypesetter or
+ V7 version of nroff/troff, AND the Berkeley -me
+ macros.
+
+1) Undocumented Feature: The paths to the various programs which
+ MH exec's are kept in variables named something like "lsproc".
+ (See the strings directory.) While reading in the user's
+ profile, (m_getdefs()) a component matching one of these exec
+ path names, will cause the default string to be replaced by
+ the profile entry argument. Thus, the profile entry "lsproc:
+ /usr/foo/bin/newls" will cause all MH programs using "lsproc"
+ to get a new ls. At least for now, there is no way to specify
+ switches. This mapping is arranged by the "procs" structure
+ in m_getdefs.c--keep it up to date if new exec procs are
+ added.
+
+2) Collision: Take a close look at the "onceonly" entry of the
+ Makefile. Bell already has a program named `file', which the
+ makefile will rename to `filetype', which is what it tries to
+ indicate. If you really want to, you might rename the MH
+ command `file', but I have yet to hear of an even vaguely
+ reasonable alternative.
+
+3) Different Approach: Using the Berkeley C shell (csh),
+ "multiple links to the same file with different profile
+ entries" is better served with aliases.
+
+4) Collision: {V/V7} BELL mail cannot co-exist with MH--IF THEY
+ SHARE THE SAME MAILBOXES, otherwise they co-exist fine! If
+ you use the standard (VAX) mail directory /usr/spool/mail for
+ MH, you should also install the MH version of the mail
+ program. It is much nicer, and integrates with MH cleanly.
+ The advantage of using /usr/spool/mail is that login will
+ notify of new mail.
+
+5) Feature: If you add a line like:
+
+ 30 1 * * * /etc/mh/aliascheck -mail bsb
+
+ to crontab, then every morning at 1:30 AM, the alias file will
+ be checked against the /etc/passwd file to see that
+ inconsistencies haven't been introduced. In particular, a
+ line in the alias file may be "tom: jones" (because Tom Jones
+ likes to be called Tom), but if tom is also a valid user name,
+ tom will no longer receive any mail! This program also prints
+ any mail drops in /usr/spool/mail which don't belong to a
+ valid user (i.e. a deleted or renamed user id).
+
+ "Aliascheck -mail name" will check the consistency and mail
+ the specified user a short status message.
+
+ This program also checks to see if there are any users who do
+ not belong to any group, or any user in a group which is missing
+ from the passwd file. This latter is an inconsistency on all
+ systems, whereas the former is not required except at Rand, and
+ won't be compiled without the "-DRAND" cc flag in the makefile.
+
+6) Hidden Feature: At the request of some of the Rand staff,
+ there is the ability to invoke a user-specified deletion-
+ program to implement message deletion, rather than getting the
+ default comma renaming convention (see next item). If a
+ user's profile contains the line: "Delete-prog: path", the
+ specified path will be called with a list of files needing
+ deletion. All this code works...
+
+7) Feature: When a message (draft or in a folder) is "removed",
+ it is really renamed with a leading comma. E.g. foo -> ,foo.
+ At Rand we have a program called the midnight skulker which
+ goes through the whole system and removes all backup (starting
+ with comma), a.out, and core files. This backup convention
+ gives users a chance to undo spurious removes, at least all
+ day. You may want to replace these renames with a simple
+ unlink(), or each user may get this effect by specifying
+ "Delete-prog: /bin/rm" in his/her profile.
+
+8) Feature: NEWS. The news facility is undocumented in the MH
+ manual, because it is a very new addition to the package. SO,
+ here it is...
+
+ The directory /usr/news should be created--it will
+ contain the folders for news topics, and various support
+ files. The news items are strictly MH folders, and users
+ can utilize all of the MH commands on them. The news
+ program is similar to "show", but it shows `unseen' news
+ as the default, keeping a separate entry in the users
+ profile for each news topic indicating the highest item
+ the user has seen. These entries look like
+ "news-<topic>: highest-seen".
+
+ Rather than read through the news folders to determine
+ the number of entries, a file with name .<topic> (i.e.
+ period followed by the topic name) is kept with length
+ equal to highest message number. Thus, to determine if a
+ user hasn't seen some news, the news directory
+ (/usr/news) is read, and for each non-period beginning
+ file (i.e. each folder), stat the associated period
+ beginning file, and compare its length with the users
+ profile news entry for the same name. If the user has no
+ entry, or it is less than the length of the period-file,
+ then show him the remainder of the news in each such
+ topic.
+
+ The program `l' is used to display each message, and the
+ highest item profile entry is updated prior to each
+ individual message displayed, so <del> will leave the
+ user's profile in the proper state for the next news
+ request.
+
+ Add a user to the system called news, with home directory
+ /usr/news and add the line:
+
+ news.*: news
+
+ to /etc/MailAlias. Thus, to add news to a topic, it is
+ only necessary to mail to news.topic, and it will happen.
+ To make the automatic filing into folders happen, copy
+ the file support/news-mh_receiv to /usr/news/.mh_receive.
+ This is a shell script which will get invoked whenever
+ mail is sent to the user news (see next "undocumented
+ feature").
+
+ Problems: I have yet to write the program which packs
+ news folders. Items can be readily removed (as long as
+ they are not the last item in the folder), but if the
+ folder is packed (after some months/years the item
+ numbers will reach the 999 limit), it is necessary to go
+ through everyones .mh_profile files and reset the
+ highest-seen numbers. Not hard to write, I just haven't
+ done it yet. Also, the receive shell script should be
+ recoded in C to speed it up considerably.
+
+9) Undocumented Feature: If a user has an executable program or
+ shell script named ".mh_receive" in his home directory, then
+ it will be executed by the mail deliverer RATHER than
+ appending mail items to the user's mail file
+ (/usr/spool/mail/name). This program will be called with:
+
+ execlp(prog, prog, tmpfil, mail, home, 0);
+
+ where prog is the receive program, tmpfil is a file in
+ /usr/tmp which is the mail to be received, mail is the path of
+ the user's mail drop (/usr/spool/mail/name), and home is the
+ $HOME directory of the user. File descriptor 3 will have
+ tmpfil opened on it read only. These are all the RECEIVER'S
+ parameters, not the sender's. Also, the environment is set up
+ with appropriate values for HOME and USER.
+
+ Eventually, the goal is to have received mail LINKED into
+ user's inbox folders, rather than appended to their mailboxes.
+ This will facilitate the sending of mail to large distribution
+ lists (Rand is always tight on space!) Have a look at the news
+ .mh_receive file for an example of this facility.
+
+ Warning: appropriate interlocks are implemented in "deliver"
+ to prevent collisions when it appends to mailboxes, but it is
+ up to the users's .mh_receive program to provide its own
+ interlocks!
+
+
+
+
+Bruce Borden
+February 1980
--- /dev/null
+manual:
+ itroff -me titlepage mh.me
--- /dev/null
+.de $c \" Major Heading printer
+.ce
+.b "\\s12\\n+(ch.\\ \\$1\\s0" \" 12 Point Bold Header
+.(x
+
+\ \ \ \\n(ch.\\ \\ \\$1
+.)x
+.sp 45p \" 45 point space or about 1/2 inch
+..
+\".nr xs .15v \" Put index entries closer together
+.(x
+
+Section
+.)x _
+.de $0 \" Sub-Heading macro called AFTER printing the heading
+.(x
+.sp .3v
+.ti .5i
+\\$1
+.)x
+..
+.de $s \" Macro to print footnote separator
+\"\l'2i' \" No line drawn
+.if n \
+. sp 1.3 \" But extra space to make up for it.
+..
+.fc ^ ~ \" The characters ^ and ~ CANNOT BE USED
+\" throughout this document except as field
+\" delimiter & pad indicator!
+.he ''-%-''
+.ll 32P \" 32 Picas or about 5+1/3 inch Line Length
+.if n .ll 72m \" Use 72 ems for nroff
+.nr ss 30p \" 30 point space before section titles
+.nr fm 5v \" Rand likes bigger than normal [3v] bottom margins
+.nr bm 7v \" ditto
+.ds . \\fB.\\fP\\h'-(1m/3)' \" Bold period to stand out.
+.ds << <\\h!-(\\w'<'/2)!<
+.ds >> >\\h!-(\\w'>'/2)!>
+.ds ** \v'-3p'\s+1*\s0\v'+3p'
+.++ C
+.+c INTRODUCTION
+.pp
+Although people can travel cross-country in hours and can
+reach others by telephone in seconds, communications still depend
+heavily upon paper, most of which is distributed through the mails.
+.pp
+There are several major reasons for this continued dependence on
+written documents.
+First, a written document may be proofread
+and corrected prior to its distribution, giving the author
+complete control over his words.
+Thus, a written document is
+better than a telephone conversation in this respect.
+Second,
+a carefully written document is far less likely to be
+misinterpreted or poorly translated than a phone conversation.
+Third, a signature offers reasonable verification of authorship,
+which cannot be provided with media such as telegrams.
+.pp
+However, the need for
+.u fast ,
+accurate, and reproducible document distribution is
+obvious.
+One solution in widespread use is the telefax.
+Another
+that is rapidly gaining popularity is electronic mail.
+Electronic mail is similar to telefax in that the data to be sent
+are digitized, transmitted via phone lines, and
+turned back into a document at the receiver.
+The advantage of
+electronic mail is in its compression factor.
+Whereas a telefax
+must scan a page in very fine lines and send all of the black and
+white information, electronic mail assigns characters fixed
+codes which can be transmitted as a few bits of information.
+Telefax presently has the advantage of being able to transmit an
+arbitrary page, including pictures, but electronic mail is
+beginning to deal with this problem.
+Electronic mail also integrates well
+with current directions in office automation, allowing documents
+prepared with sophisticated equipment at one site to be quickly
+transferred and printed at another site.
+.pp
+Currently, most electronic mail is intraorganizational,
+with mail transfer remaining within one computer.
+As computer
+networking becomes more common, however, it is becoming more feasible to
+communicate with anyone whose computer can be linked to your
+own via a network.
+.pp
+The pioneering efforts on general-purpose electronic mail
+were by organizations using the Defense Department's ARPANET.[1]
+The capability to send messages between computers existed before
+the ARPANET was developed, but it was used only in limited ways.
+With the advent of the
+ARPANET, tools began to be developed which made it convenient for
+individuals or organizations to distribute messages
+over broad geographic areas, using
+diverse computer facilities.
+The interest and activity in
+message systems has now reached such proportions that steps
+have been taken within the DoD to coordinate and
+unify the development of military message systems.
+The use of electronic mail is expected to increase
+dramatically in the next few years.
+The utility of such systems
+in the command and control and intelligence environments is
+clear, and applications in these areas will probably lead the
+way.
+As the costs for sending and handling electronic messags
+continue their rapid decrease, such uses can be
+expected to spread rapidly into other areas and, of course, will
+not be limited to the DoD.
+.pp
+A message system provides tools that help users (individuals
+or organizations) deal with messages in various ways.
+Messages
+must be composed, sent, received, stored, retrieved,
+forwarded, and replied to.
+Today's best interactive computer
+systems provide a variety of word-processing and information
+handling capabilities.
+The message handling facilities should be
+well integrated with the rest of the system, so as to be a
+graceful extension of overall system capability.
+.pp
+The message system described in this report, MH, provides most of the
+features that can be found in other message systems and also
+incorporates some new ones.
+It has been built on the UNIX time-sharing
+system,[2] a popular operating system for the DEC PDP-11
+and VAX classes of computers.
+A \*(lqsecure\*(rq operating
+system similar to UNIX is currently being developed,[3]
+and that system will also run MH.
+.pp
+This report provides a complete description of MH and
+thus may serve as a user's manual, although parts of the report
+will be of interest to non-users as well.
+Sections 2 and 3, the
+Overview and Tutorial, present the key
+ideas of MH and will give those not familiar with message systems
+an idea of what such systems are like.
+.pp
+MH consists of a set of commands which use some special
+files and conventions.
+Section 4 covers the information
+a user needs to know in addition to the
+commands.
+The final section, Sec. 5, describes each of
+the MH commands in detail.
+A summary of the commands is given in
+Appendix A, and Appendixes B and C describe the ARPANET
+conventions for messages (we expect that many users of MH
+will be using the ARPANET) and the formal syntax of such
+messages, respectively.
+Finally, Appendix D provides
+an illustration of how MH commands may be used in
+conjunction with other UNIX facilities.
+.pp
+A novel approach has been taken in the design of MH.
+The
+design concept will be reported in detail in a forthcoming Rand
+report, but it can be described briefly as follows.
+Instead of creating a large subsystem that appears as a single
+command to the user, (such as MS[4])
+MH is a collection of separate commands
+which are run as separate programs.
+The file and directory
+system of UNIX are used directly.
+Messages are stored as
+individual files (datasets), and collections of them are grouped
+into directories.
+In contrast, most other message systems store
+messages in a complicated data structure within a monolithic
+file.
+With the MH approach, UNIX commands can be
+interleaved with commands invoking the functions of the message
+handler.
+Conversely, existing UNIX commands
+can be used in connection with messages.
+For
+example, all the usual UNIX editing, text-formatting, and printing
+facilities can be applied directly to individual messages.
+MH,
+therefore, consists of a relatively small amount of new code; it
+makes extensive use of other UNIX software to provide the
+capabilities found in other message systems.
+.+c OVERVIEW
+.pp
+There are three main aspects of MH: the way messages are
+stored (the message database), the user's profile (which directs
+how certain actions of the message handler take place), and the
+commands for dealing with messages.
+.pp
+Under MH, each message is stored as a separate file.
+A user
+can take any action with a message that he could with an ordinary
+file in UNIX.
+A UNIX directory in which messages are stored is
+called a folder.
+Each folder contains some standard entries to support
+the message-handling functions.
+The messages in a folder have numerical
+names.
+These folders (directories)
+are entries in a particular directory path, described in
+the user profile, through which MH can find message folders.
+Using the UNIX \*(lqlink\*(rq facility, it is possible for one copy of a
+message to be \*(lqfiled\*(rq in more than one folder, providing a
+message index facility.
+Also, using the UNIX tree-structured
+file system, it is possible to have a folder within a folder.
+This two-level organization provides a \*(lqselection-list\*(rq
+facility, with the full power of the MH commands available on
+selected sublists of messages.
+.pp
+Each user of MH has a user profile, a file in his $HOME (initial
+login)
+directory called \*(lq\*.mh\(ruprofile\*(rq.
+This profile contains several
+pieces of information used by the MH commands: a
+path name to the directory that contains the message folders,
+information concerning which folder the user last referenced (the
+\*(lqcurrent\*(rq folder), and parameters that tailor MH commands
+to the individual user's requirements.
+It also contains
+most of the necessary state information concerning how
+the user is dealing with his messages, enabling MH to be
+implemented as a set of individual UNIX commands, in contrast to the
+usual approach of a monolithic subsystem.
+.pp
+In MH, incoming mail is appended
+to the end of a file called \*.mail in a user's $HOME
+directory.
+The user adds the new messages to his collection of MH messages
+by invoking the command
+.i inc .
+.i Inc
+(incorporate) adds the new
+messages to a folder called \*(lqinbox\*(rq, assigning them names which
+are consecutive integers starting with the next highest integer
+available in inbox.
+.i Inc
+also produces a
+.i scan
+summary of
+the messages thus incorporated.
+.pp
+There are four commands for examining the messages in a
+folder:
+.i show ,
+.i prev ,
+.i next ,
+and
+.i scan .
+.i Show
+displays a
+message in a folder,
+.i prev
+displays the message preceding the
+current message, and
+.i next
+displays the message following the
+current message.
+.i Scan
+summarizes the messages in a folder,
+producing one line per message, showing who the message is from,
+the date, the subject, etc.
+.pp
+The user may move a message from one folder to another with
+the command
+.i file .
+Messages may be removed from a folder
+by means of the command
+.i rmm .
+In addition, a user may query
+what the current folder is and may specify that a new folder
+become the current folder, through the command
+.i folder .
+.pp
+A set of messages based on content may be selected by
+use of the command
+.i pick .
+This command searches through
+messages in a folder and selects those that match a given
+criterion.
+A subfolder is created within the original folder,
+containing links to all the messages that satisfy the selection
+criteria.
+.pp
+A message folder (or subfolder) may be removed by means of
+the command
+.i rmf .
+.pp
+There are five commands enabling the user to create new
+messages and send them:
+.i comp ,
+.i dist ,
+.i forw ,
+.i repl ,
+and
+.i send .
+.i Comp
+provides the facility for the user to compose a
+new message;
+.i dist
+redistributes mail to additional addressees;
+.i forw
+enables the user to forward messages; and
+.i repl
+facilitates the generation of a reply to an incoming message.
+If
+a message is not sent directly by one of these commands, it may
+be sent at a later time using the command
+.i send .
+.pp
+All of the elements summarized above
+are described in more detail in the following sections.
+Many of the
+normal facilities of UNIX provide additional capabilities for
+dealing with messages in various ways.
+For example, it is
+possible to print messages
+on the line-printer without requiring any additional code within
+MH.
+Using standard UNIX facilities, any terminal output can be
+redirected to a file for repeated or future viewing.
+In general,
+the flexibility and capabilities of the UNIX interface with the
+user are preserved as a result of the integration of MH into the UNIX
+structure.
+.+c TUTORIAL
+.pp
+This tutorial provides a brief introduction to the MH commands.
+It should be sufficient
+to allow the user to read his mail, do some simple manipulations of
+it, and create and send messages.
+.pp
+A message has two major pieces: the
+header and the body.
+The body consists of the text of the message
+(whatever you care to type in).
+It follows the header and is separated from
+it by an empty line.
+(When you compose a message, the form that appears
+on your terminal shows a line of dashes after the header.
+This is for
+convenience and is replaced by an empty line when the message is
+sent.) The header is composed of several components, including the
+subject of the message and the person to whom it is addressed.
+Each component starts with a name
+and a colon; components must not start with a blank.
+The text of the
+component may take more than one line, but each continuation line must
+start with a blank.
+Messages typically have \*(lqto:\*(rq, \*(lqcc:\*(rq, and
+\*(lqsubject:\*(rq components.
+When composing a message, you should include
+the \*(lqto:\*(rq and \*(lqsubject:\*(rq components; the \*(lqcc:\*(rq (for people
+you want to send copies to) is not necessary.
+.pp
+The basic MH commands are
+.i inc ,
+.i scan ,
+.i show ,
+.i next ,
+.i prev ,
+.i rmm ,
+.i comp ,
+and
+.i repl .
+These are described below.
+
+.i inc
+.pp
+When you get the message \*(lqYou have mail\*(rq, type the command
+.i inc .
+You will get a \*(lqscan listing\*(rq such as:
+
+.nf
+.if t .ta .4i 1.0i 2i
+.if n .ta .4i 1.2i 3i
+^7+~^^\07/13~^^Cas~^revival of measurement work
+^8~^^10/\09~^^Norm~^NBS people and publications
+^9~^^11/26~^^To:norm~^question \*(<<Are there any functions
+.re
+.fi
+.pp
+This shows the messages you received since the last time you
+executed this command (
+.i inc
+adds these new messages to
+your inbox folder).
+You can see this list again, plus a list of any
+other messages you have, by using the
+.i scan
+command.
+
+.i scan
+.pp
+The scan listing shows the message number, followed by the
+date and the sender.
+(If you are the sender, the addressee in the \*(lqto:\*(rq
+component is displayed.
+You may send yourself a message by including
+your name among the \*(lqto:\*(rq or \*(lqcc:\*(rq addressees.)
+It also shows the message's subject; if
+the subject is short, the first part of the body of the message is
+included after the characters \*(<<.
+
+.ne 5
+.i show
+.pp
+This command shows the current message, that is,
+the first one of the new messages after an
+.i inc .
+If the message is not
+specified by name (number), it is
+generally the last message referred to by an MH command.
+For example,
+
+.ta 1i
+.ti .5i
+^\fIshow\fP\05~^will show message 5.
+.pp
+You can use the show command to copy a message or print a
+message.
+
+.(b L
+.in .5i
+.if t .ta 1i
+.if n .ta 1.5i
+^\fIshow\fR\0>\0\fIx\fR~^will copy the message to file x.
+.br
+^\fIshow\fR\0|\0\fIprint\fR~^will print the message, using the \fIprint\fR command.
+.br
+^\fInext\fR~^will show the message that follows the current message.
+.br
+^\fIprev\fR~^will show the message previous to the current message.
+.br
+^\fIrmm\fR~^will remove the current message.
+.br
+^\fIrmm\03\fR~^will remove message 3.
+.)b
+
+.ne 5
+.i comp
+.pp
+The
+.i comp
+command puts you in the editor to write or edit a message.
+Fill in or
+delete the \*(lqto:\*(rq, \*(lqcc:\*(rq, and \*(lqsubject:\*(rq fields, as appropriate, and
+type the body of the message.
+Then
+exit normally from the editor.
+You will be asked
+\*(lqWhat now?\*(rq.
+Type a carriage return to see the options.
+Typing \fBsend\fR
+will cause the message to be sent; typing \fBquit\fR will cause an exit
+from
+.i comp ,
+with the message draft saved.
+.pp
+If you quit without sending the message, it will be saved in a file
+called /usr/<name>/Mail/draft (where /usr/<name> is your $HOME directory).
+You can edit this file and send the message later, using the
+.i send
+command.
+
+.ne 4
+.i "comp\0\-editor\0prompter"
+.pp
+This command uses a different editor and is useful for preparing
+\*(lqquick and dirty\*(rq messages.
+It prompts you for each component of the
+header.
+Type the information for that component, or type a carriage
+return to omit the component.
+After that, type the body of the
+message.
+Backspacing is the only form of editing allowed with this editor.
+When the body is complete, type a carriage return followed by <CTRL-D>
+(<OPEN> on Ann Arbor terminals).
+This completes the initial preparation of the message; from then on, use
+the same procedures as with
+.i comp
+(above).
+
+.ne 5
+.i repl
+.br
+.i "repl\0n"
+.pp
+This command makes up an initial message form with a header
+that is appropriate for
+replying to an existing message.
+The message being answered is the
+current message if no message number is mentioned, or n if a number
+is specified.
+After the header is completed, you can finish the message as in
+.i comp
+(above).
+.pp
+This is enough information to get you going using MH.
+There are more commands,
+and the commands described here have more features.
+Subsequent sections
+explain MH in complete detail.
+The system is quite powerful if you
+want to use its sophisticated features, but the foregoing commands
+suffice for sending and receiving messages.
+.pp
+There are numerous additional capabilities you may wish to explore.
+For example, the
+.i pick
+command will select a subset of messages
+based on specified criteria such as sender or subject.
+Groups of
+messages may be designated, as described in Sec. V, under \*(lqMessage
+Naming\*(rq.
+The file \*(lq\*.mh\(ruprofile\*(rq can be used to tailor your use of
+the message system to your needs and preferences, as described in Sec. V,
+under \*(lqThe User Profile\*(rq.
+In general, you may
+learn additional features of the system selectively, according to your
+requirements,
+by studying the relevant sections of this manual.
+There is no need to
+learn all the details of the system at once.
+.+c "DETAILED DESCRIPTION"
+.pp
+This section describes the MH system in detail, including the components
+of the user profile, the conventions for message naming, and some of
+the other MH conventions.
+Readers who are
+generally familiar with computer systems will be able to follow
+the principal ideas, although some details may be meaningful only to
+those familiar with UNIX.
+.uh "THE USER PROFILE"
+.pp
+The first time an MH command is issued by a new user, the system
+prompts for a \*(lqpath\*(rq and creates an MH \*(lqprofile\*(rq.
+.pp
+Each MH user has a profile which contains current
+state information for the MH package and, optionally, tailoring
+information for each individual program.
+When a folder becomes
+the current folder, it is recorded in the user's profile.
+Other profile entries control the MH path (where folders and
+special files are kept), folder and message protections, editor
+selection, and default arguments for each MH program.
+.pp
+The MH profile is stored in the file \*(lq\*.mh\(ruprofile\*(rq in the
+user's $HOME directory.
+It has the format of a message without
+any body.
+That is, each profile entry is on one line, with a
+keyword followed by a colon (:) followed by text particular to
+the keyword.
+.br
+\(rh\ \ \&
+.i "This file must not have blank lines."
+.br
+The keywords
+may have any combination of upper and lower case.
+(See Appendix
+B for a description of message formats.)
+.pp
+For the average MH user, the only profile entry of
+importance is \*(lqPath\*(rq.
+Path specifies a directory in which MH
+folders and certain files such as \*(lqdraft\*(rq are found.
+The
+argument to this keyword must be a legal UNIX path that names an
+existing directory.
+If this path is unrooted (i.e., does not
+begin with a \fB/\fR), it will be presumed to start from the
+user's $HOME directory.
+All folder and message references within
+MH will relate to this path unless full path names are used.
+.pp
+Message protection defaults to 664, and folder protection to
+751.
+These may be changed by profile entries \*(lqMsg-Protect\*(rq
+and \*(lqFolder-Protect\*(rq, respectively.
+The argument to these
+keywords is an octal number which is used as the UNIX file mode.\**
+.(f
+\**See
+.i chmod (I)
+in the
+.i "UNIX Programmer's Manual" .[5]
+.)f
+.pp
+When an MH program starts running, it looks through the
+user's profile for an entry with a keyword matching the program's
+name.
+For example, when
+.i comp
+is run, it looks for a \*(lqcomp\*(rq
+profile entry.
+If one is found, the text of the profile entry is
+used as the default switch setting until all defaults are overridden
+by explicit switches passed to the program as arguments.
+Thus the profile
+entry \*(lqcomp:\0\-form\0standard.list\*(rq would direct
+.i comp
+to use the
+file \*(lqstandard.list\*(rq as the message skeleton.
+If an explicit
+form switch is given to the
+.i comp
+command, it will override the
+switch obtained from the profile.
+.pp
+In UNIX, a program may exist under several names, either by
+linking or aliasing.
+The actual invocation name is used by an MH
+program when scanning for its profile defaults.
+Thus, each MH program
+may have several names by which it can be invoked, and each name
+may have a different set of default switches.
+For example, if
+.i comp
+is invoked by the name
+.i icomp ,
+the profile entry
+\*(lqicomp\*(rq will control the default switches for this invocation of
+the
+.i comp
+program.
+This provides a powerful
+definitional facility for commonly used switch settings.
+.pp
+The default editor
+for editing within
+.i comp ,
+.i repl ,
+.i forw ,
+and
+.i dist ,
+is \*(lq/bin/ned\*(rq.\**
+.(f
+\**See Ref. 6 for a description of
+the NED text editor.
+.)f
+A different editor may be used by specifying
+the profile entry
+\*(lqEditor: \*(rq.
+The argument to \*(lqEditor\*(rq is the name of an
+executable program or shell command file which can be found via
+the user's $PATH defined search path, excluding the current
+directory.
+The \*(lqEditor:\*(rq profile specification
+may in turn be overridden by a \*(lq\-editor\0<editor>\*(rq
+profile switch associated with
+.i comp ,
+.i repl ,
+.i forw ,
+or
+.i dist .
+Finally, an explicit editor switch specified with any
+of these four commands will have ultimate precedence.
+.pp
+During message composition, more than one editor may be
+used.
+For example, one editor (such as
+.i prompter )
+may be used
+initially, and a second editor may be invoked later to revise
+the message being composed
+(see the discussion of
+.i comp
+in Section 5 for details).
+A profile entry \*(lq<lasteditor>\-next:\0<editor>\*(rq specifies the name of
+the editor to be used after a particular editor.
+Thus \*(lqcomp:\0\-e\0prompter\*(rq
+causes the initial text to be collected by
+.i prompter ,
+and the profile entry \*(lqprompter\-next:\0ed\*(rq names ed as the
+editor to be invoked for the next round of editing.
+.pp
+Some of the MH commands, such as
+.i show ,
+can be used on
+message folders owned by others, if those folders are readable.
+However,
+you cannot write in someone else's folder.
+All the MH command
+actions not requiring write permission may be used with
+a \*(lqread-only\*(rq folder.
+In a writable folder, a file named
+\*(lqcur\*(rq is used to contain its current message name.
+For read-only folders, the current message name is
+stored in the user's profile.
+.pp
+Table 1 lists examples of the currently defined profile
+entries, typical arguments, and the programs that reference the
+entries.
+.in .9i
+.ll -.9i
+.ta 2.3i
+.sp 30p
+.ce
+Table 1
+.sp 8p
+.ce
+P\s-2ROFILE\s0 C\s-2OMPONENTS\s0
+.hl \" ~12p preceding + 1v (12p) after
+.nf
+^^MH Programs that
+^Keyword and Argument~^\ Use Component\h'|\n(.lu-.9i'\v'4p'\l'|0'\v'-4p' \" \l'..' does underlining
+.sp
+^Path:\0Mail~^All
+^Current-Folder:\0inbox~^Most
+^Editor:\0/bin/ed~^\fIcomp, dist, forw, repl\fR
+^Msg\-Protect:\0644~^\fIinc\fR
+^Folder\-Protect:\0711~^\fIfile, inc, pick\fR
+^<program>:\0default switches~^All
+^cur\-<read-onlyfolder>:\0172~^Most
+^prompter\-next:\0ed~^\fIcomp, dist, forw, repl\fR
+.hl
+.ll +.9i
+.in 0
+.fi
+.pp
+Path
+.u should
+be present.
+Folder is maintained
+automatically by many MH commands (see the \*(lqContext\*(rq sections of
+the individual commands in Sec. V).
+All other entries are optional,
+defaulting to the values described above.
+.uh "MESSAGE NAMING"
+.pp
+Messages may be referred to explicitly or implicitly when
+using MH commands.
+A formal syntax of message names is given in Appendix C, but the
+following description should be sufficient for most MH users.
+Some details of message naming that apply only to certain
+commands are included in the description of those
+commands.
+.pp
+Most of the MH commands accept arguments specifying one or
+more folders, and one or more messages to operate on.
+The use of
+the word \*(lqmsg\*(rq as an argument to a command means that exactly one
+message name may be specified.
+A message name may be a number,
+such as 1, 33, or 234, or it may be
+one of the \*(lqreserved\*(rq message names:
+first, last, prev, next, and cur.
+(As a shorthand, a
+period (\*.) is equivalent to cur.)
+The meanings of these names
+are straightforward: \*(lqfirst\*(rq is the first message in the
+folder; \*(lqlast\*(rq is the last
+message in the folder; \*(lqprev\*(rq is the
+message numerically previous to the current message; \*(lqnext\*(rq
+is the message numerically following the current message; \*(lqcur\*(rq
+(or \*(lq\*.\*(rq) is the current message in the folder.
+.pp
+The default in commands that take a \*(lqmsg\*(rq argument is
+always \*(lqcur\*(rq.
+.pp
+The word \*(lqmsgs\*(rq indicates that several messages may be
+specified.
+Such a specification consists of several message
+designations separated by spaces.
+A message designation is
+either a message name or a message range.
+A message range is a
+specification of the form name1\-name2 or name1:n, where name1 and
+name2 are message names and n is an integer.
+The first form
+designates all the messages from name1 to name2 inclusive; this
+must be a non-empty range.
+The second form specifies up to n
+messages, starting with name1 if name1 is a number, or first,
+cur, or next, and ending with name1 if name1 is last or
+prev.
+This interpretation of n is overridden if n is preceded
+by a plus sign or a minus sign;
++n always means up to n messages starting with
+name1, and \-n always means up to n messages ending with name1.
+Repeated specifications of the same message have the same effect
+as a single specification of
+the message.
+Examples of
+specifications are:
+
+.(b
+1 5 7\-11 22
+first 6 8 next
+first\-10
+last:5
+.)b
+.pp
+The message name \*(lqall\*(rq is a shorthand for \*(lqfirst\-last\*(rq,
+indicating all of the messages in the folder.
+.pp
+The limit on the number of messages in an expanded message
+list is generally 999\*-the maximum number of messages in a
+folder.
+However, the
+.i show
+command and the
+commands `\fIpick\0\-scan\fR' and `\fIpick\0\-show\fR'
+are constrained to have argument lists
+that are no more than 512 characters long.
+(Under Version 7 UNIX this limit is 4096.)
+.pp
+In commands that accept \*(lqmsgs\*(rq arguments, the default is
+either cur or all, depending on which makes more sense.
+.pp
+In all of the MH commands, a plus sign preceding an argument
+indicates a folder name.
+Thus, \*(lq+inbox\*(rq is the name of the
+user's standard inbox.
+If an explicit folder argument is given
+to an MH command, it will become the current folder (that is,
+the \*(lqCurrent-Folder:\*(rq entry
+in \*(lq\*.mh\(ruprofile\*(rq will be changed to this
+folder).
+In the case of the
+.i file
+and
+.i pick
+commands, which
+can have multiple output folders, a new source folder (other than
+the default current folder) is specified by \*(lq\-src\0+folder\*(rq.
+.uh "OTHER MH CONVENTIONS"
+.pp
+One very powerful feature of MH is that the MH commands may
+be issued from any current directory, and the proper path to
+the appropriate folder(s) will be taken from the user's profile.
+If the MH path is not appropriate for a specific folder or file,
+the automatic prepending of the MH path can be avoided by
+beginning a folder or file name with \fB/\fR.
+Thus any specific full
+path may be specified.
+.pp
+Arguments to the various programs may be given in any order,
+with the exception of a few switches whose arguments must follow
+immediately, such as \*(lq\-src\0+folder\*(rq for \fIpick\fR and \fIfile\fR.
+.pp
+Whenever an MH command prompts the user, the valid options
+will be listed in response to a <RETURN>.
+(The first of the
+listed options is the default if end-of-file is encountered, such
+as from a command file.) A valid response is any \fIunique\fR
+abbreviation of one of the listed options.
+.pp
+Standard UNIX documentation conventions are used in this report
+to describe MH command syntax.
+Arguments enclosed in brackets
+([ ]) are optional; exactly one of the arguments enclosed
+within braces ({ }) must be specified, and all other
+arguments are required.
+The use of ellipsis dots (...) indicates
+zero or more repetitions of the previous item.
+For example,
+\*(lq+folder ...\*(rq would indicate that one or more \*(lq+folder\*(rq arguments
+is required and \*(lq[+folder ...]\*(rq indicates that 0 or more
+\*(lq+folder\*(rq arguments may be given.
+.pp
+MH departs from UNIX standards by using switches that consist of
+more than one character, e.g. \*(lq\-header\*(rq.
+To minimize typing,
+only a unique abbreviation of a switch need be typed; thus, for
+\*(lq\-header\*(rq, \*(lq\-hea\*(rq is probably sufficient, depending on the
+other switches the command accepts.
+Each MH program
+accepts the switch \*(lq\-help\*(rq (which \fImust\fR be spelled out fully)
+and produces a syntax description and a list of switches.
+In the
+list of switches, parentheses indicate required characters.
+For example, all \*(lq\-help\*(rq switches will appear as \*(lq\-(help)\*(rq,
+indicating that no abbreviation is accepted.
+.pp
+Many MH switches have both on and off forms, such as
+\*(lq\-format\*(rq and \*(lq\-noformat\*(rq.
+In many of the descriptions in Sec. V,
+only one form is defined; the other form, often used to
+nullify profile switch settings, is assumed to be the opposite.
+.br
+.bp
+.uh "MH COMMANDS"
+.pp
+The MH package comprises 16 programs:
+
+.nf
+.in .5i
+.ta 1.5i
+^comp~^Compose a message
+^dist~^Redistribute a message
+^file~^Move messages between folders
+^folder~^Select/list status of folders
+^forw~^Forward a message
+^inc~^Incorporate new mail
+^next~^Show the next message
+^pick~^Select a set of messages by context
+^prev~^Show the previous message
+^prompter~^Prompting editor front end for composing messages
+^repl~^Reply to a message
+^rmf~^Remove a folder
+^rmm~^Remove messages
+^scan~^Produce a scan listing of selected messages
+^send~^Send a previously composed message
+^show~^Show messages
+.fi
+.re
+.pp
+These programs are described below.
+The form of the descriptions
+conforms to the standard
+form for the description of UNIX commands.
+.if t \{
+.ll 6.5i
+.lt 6.5i
+\}
+.fo '7th Edition'UNIX/32V(Rand)''
+.de SC
+.he '\\$1(1)'-%-'\\$1(1)'
+.bp
+.(x
+.ti .8i
+\\$1
+.)x
+..
+.de NA
+.b \\s-2NAME\\s0
+.ti .5i
+..
+.de SY
+.sp
+.b \\s-2SYNOPSIS\\s0
+.in 1i
+.ti .5i
+.na
+..
+.de DE
+.ad
+.sp
+.in 0
+.b \\s-2DESCRIPTION\\s0
+.sp
+.fi
+.in .5i
+..
+.de Fi
+.(b L
+.ti 0
+.b \\s-2Files\\s0
+.ta 2i
+..
+.de Pr
+.)b
+.(b L F
+.in 2.5i
+.ti 0
+.b "\\s-2Profile Components\\s0"
+.ti .5i
+..
+.de Ps
+.ti .5i
+..
+.de De
+.)b
+.(b L
+.in .5i
+.ti 0
+.b \\s-2Defaults\\s0
+..
+.de Co
+.)b
+.(b L F
+.ti 0
+.b \\s-2Context\\s0
+.br
+..
+.de En
+.)b
+.in 0
+..
+.SC COMP
+.NA
+comp \- compose a message
+
+.SY
+comp \%[\-editor\ editor] \%[\-form\ formfile] \%[file] \%[\-use]
+\%[\-nouse] \%[\-help]
+
+.DE
+\fIComp\fP is used to create a new message to be mailed.
+If
+\fIfile\fP is not specified, the file named \*(lqdraft\*(rq in the user's MH
+directory will be used.
+\fIComp\fR copies a message form to
+the file being composed and then invokes an editor on the
+file.
+The default editor is /bin/ned, which may be overridden with
+the `\-editor' switch or with a profile entry \*(lqEditor:\*(rq.
+(See Ref. 5 for a
+description of the NED text editing system.)
+The default
+message form contains the following elements:
+
+ To:
+ cc:
+ Subject:
+ ----------
+
+If the file named \*(lqcomponents\*(rq exists in the user's MH directory,
+it will be used instead of this form.
+If `\-form
+formfile' is specified, the specified formfile (from the MH
+directory) will be used as the skeleton.
+The line of dashes
+or a blank line must be left between the header and the
+body of the message for the message to be identified properly when it is
+sent (see \fIsend;\fR).
+The switch `\-use' directs \fIcomp\fR to
+continue editing an already started message.
+That is, if a
+\fIcomp\fR (or \fIdist\fR, \fIrepl\fR, or \fIforw\fR) is terminated without
+sending the message, the message can be edited again via
+\*(lqcomp \-use\*(rq.
+
+If the specified file (or draft) already exists, \fIcomp\fR will ask
+if you want to delete it before continuing.
+A reply of \fBNo\fR will abort the
+\fIcomp\fR, \fByes\fR will replace the existing draft with a blank
+skeleton, \fBlist\fR will display the draft, and \fBuse\fR will use it
+for further composition.
+
+Upon exiting from the editor, \fIcomp\fR will ask \*(lqWhat now?\*(rq.
+The valid
+responses are \fBlist\fR, to list the draft on the terminal; \fBquit\fR, to
+terminate the session and preserve the draft; \fBquit delete\fR, to terminate,
+then delete the draft; \fBsend\fR, to send the message; \fBsend verbose\fR, to
+cause the delivery process to be monitored; \fBedit <editor>\fR, to invoke
+<editor> for further editing; and \fBedit\fR, to re-edit using the
+same editor that was used on the preceding round unless a profile
+entry \*(lq<lasteditor>\-next: <editor>\*(rq names an alternative editor.
+
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`file' defaults to draft
+`\-editor' defaults to /bin/ned
+`\-nouse'
+.Co
+\fIComp\fR does not affect either the current folder or the current message.
+.En
+.SC DIST
+.NA
+dist \- redistribute a message to additional addresses
+.SY
+dist \%[+folder] \%[msg] \%[\-form\ formfile] \%[\-editor\ editor]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+.DE
+\fIDist\fR is similar to \fIforw\fR.
+It prepares the specified
+message for redistribution to addresses that (presumably) are
+not on the original address list.
+The file \*(lqdistcomps\*(rq in the
+user's MH directory, or a standard form, or the file specified by
+`\-form formfile' will be used as the blank components file to
+be prepended to the message being distributed.
+The standard form
+has the components \*(lqDistribute-to:\*(rq and \*(lqDistribute-cc:\*(rq.
+When
+the message is sent, \*(lqDistribution-Date:\0date\*(rq,
+\*(lqDistribution-From:\0name\*(rq, and
+\*(lqDistribution-Id:\0id\*(rq (if `\-msgid' is
+specified to \fIsend\fR;) will be prepended to the outgoing message.
+Only those addresses in \*(lqDistribute-To\*(rq, \*(lqDistribute-cc\*(rq, and
+\*(lqDistribute-Bcc\*(rq will be sent.
+Also, a \*(lqDistribute-Fcc:\0folder\*(rq
+will be honored (see \fIsend;\fR).
+
+\fISend\fR recognizes a message as a redistribution message by the
+existence of the field \*(lqDistribute-To:\*(rq, so don't try to
+redistribute a message with only a \*(lqDistribute-cc:\*(rq.
+
+If the `\-annotate' switch is given, each message being
+distributed will be annotated with the lines:
+
+ Distributed:\0\*(<<date\*(>>
+ Distributed:\0Distribute-to: names
+
+where each \*(lqto\*(rq list contains as many lines as required.
+This annotation
+will be done only if the message is sent directly from \fIdist\fR.
+If the
+message is not sent immediately from \fIdist\fR (i.e., if it is sent later
+via \fIsend;\fR),
+\*(lqcomp \-use\*(rq may be used to re-edit and send the constructed message, but
+the annotations won't take place.
+The '\-inplace' switch causes annotation to
+be done in place in order to preserve links to the annotated message.
+
+See \fIcomp\fR for a description of the `\-editor' switch and for options
+upon exiting from the editor.
+
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`+folder' defaults to the current folder
+`msg' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a +folder is specified, it will become the current
+folder, and the current message will be set to the message
+being redistributed.
+.En
+.SC FILE
+.NA
+file \- file message(s) in (an)other folder(s)
+.SY
+file \%[\-src\ +folder] \%[msgs] \%[\-link] \%[\-preserve] \%+folder\ ...
+\%[\-nolink] \%[\-nopreserve]
+\%[\-file\ file] \%[\-nofile] \%[\-help]
+.DE
+\fIFile\fR moves (\fImv\fR(I)) or links (\fIln\fR(I)) messages from a
+source folder into one or more destination folders.
+If you think
+of a message as a sheet of paper, this operation is not
+unlike filing the sheet of paper (or copies) in file cabinet
+folders.
+When a message is filed, it is linked into the
+destination folder(s) if possible, and is copied otherwise.
+As long
+as the destination folders are all on the same file system, multiple filing
+causes little storage overhead.
+This facility provides a good way to cross-file or multiply-index
+messages.
+For example, if a message is received from Jones about
+the ARPA Map Project, the command
+
+ file\0cur\0+jones\0+Map
+
+would allow the message to be found in either of the two
+folders `jones' or `Map'.
+
+The option `\-file file' directs \fIfile\fR to use the specified
+file as the source message to be filed, rather than a message from
+a folder.
+
+If a destination folder doesn't exist, \fIfile\fR will ask if you
+want to create one.
+A negative response will abort the file
+operation.
+
+`\-link' preserves the source folder copy of the message
+(i.e., it does a \fIln\fR(I) rather than a \fImv\fR(I)), whereas,
+`\-nolink' deletes the \*(lqfiled\*(rq messages from the source
+folder.
+Normally, when a message is filed, it is assigned the
+next highest number available in each of the destination folders.
+Use of the `\-preserve' switch will override this message
+\*(lqrenaming\*(rq, but name conflicts may occur, so
+use this switch cautiously.
+(See \fIpick\fR for more details on
+message numbering.)
+
+If `\-link' is not specified (or `\-nolink' is specified),
+the filed messages will be removed (unlink(II)) from the
+source folder.
+
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.Ps
+^Folder\-Protect:~^To set mode when creating a new folder
+.De
+`\-src +folder' defaults to the current folder
+`msgs' defaults to cur
+`\-nolink'
+`\-nopreserve'
+`\-nofile'
+.Co
+If `\-src +folder' is given, it will become the
+current folder for future MH commands.
+If neither `\-link' nor
+`all' are specified, the current message in the source
+folder will be set to the last message specified; otherwise, the
+current message won't be changed.
+.En
+.SC FOLDER
+.NA
+folder \- set/list current folder/message
+.SY
+folder \%[+folder] \%[msg] \%[\-all] \%[\-fast] \%[\-nofast] \%[\-up] \%[\-down]
+\%[\-header] \%[\-noheader] \%[\-total] \%[\-nototal] \%[\-pack] \%[\-nopack]
+\%[\-help]
+
+.ti .5i
+folders <equivalent to 'folder \-all'>
+.DE
+Since the MH environment is the shell, it is easy to lose
+track of the current folder from day to day.
+\fIFolder\fR will
+list the current folder, the number of messages in it, the
+range of the messages (low-high), and the current message within
+the folder, and will flag a selection list or extra files if they
+exist.
+An example of the output is:
+
+ inbox+ has 16 messages ( 3\- 22); cur= 5.
+
+If a `+folder' and/or `msg' are specified, they will
+become the current folder and/or message.
+An `\-all' switch
+will produce a line for each folder in the user's MH directory,
+sorted alphabetically.
+These folders are preceded by the read-only
+folders, which occur as \*.mh\(ruprofile \*(lqcur\-\*(rq entries.
+For example,
+
+.nf
+.ta 1.5i 2.1i 2.7i 3.5i
+^~Folder\ \ ^^~#\ of\ ^^messages~^^(~\ range\~ );\ ^cur msg (other files)
+^~/fsd/rs/m/tacc\ \ ^^has~35\ ^^messages~^^(~1\-\035);\ ^cur=\ 23.
+^~/rnd/phyl/Mail/EP\ \ ^^has~82\ ^^messages~^^(~1\-108);\ ^cur=\ 82.
+^~f\&f\ \ ^^has~4\ ^^messages~^^(~1\-\0\04);\ ^cur=\ \01.
+^~inbox+\ ^^has~16\ ^^messages~^^(~3\-\022);\ ^cur=\ \05.
+^~mh\ \ ^^has~76\ ^^messages~^^(~1\-\076);\ ^cur=\ 70.
+^~notes\ \ ^^has~2\ ^^messages~^^(~1\-\0\02);\ ^cur=\ \01.
+^~ucom\ \ ^^has~124\ ^^messages~^^(~1\-124);\ ^cur=\ \06; (select).
+
+^^^~TOTAL=\0339\ ^messages\0in\0\07\0Folders.
+.re
+.fi
+
+The \*(lq+\*(rq after inbox indicates that it is the current folder.
+The \*(lq(select)\*(rq indicates that the folder ucom has a selection
+list produced by \fIpick\fR.
+If \*(lqothers\*(rq had appeared in parentheses at
+the right of a line, it would indicate that there are files in
+the folder directory that don't belong under the MH file naming
+scheme.
+
+The header is output if either an `\-all' or a `\-header' switch
+is specified; it is suppressed by `\-noheader'.
+Also, if \fIfolder\fR
+is invoked by a name ending with \*(lqs\*(rq (e.g., \fIfolders\fR),
+`\-all' is assumed.
+A `\-total' switch will produce only the
+summary line.
+
+If `\-fast' is given, only the folder name (or names in the
+case of `\-all') will be listed.
+(This is faster because the
+folders need not be read.)
+
+The switches `\-up' and `\-down' change the folder to be the
+one above or below the current folder.
+That is, \*(lqfolder \-down\*(rq
+will set the folder to \*(lq<current\-folder>/select\*(rq, and if the
+current folder is a selection-list folder, \*(lqfolder \-up\*(rq will
+set the current folder to the parent of the selection-list.
+(See \fIpick\fR for details on selection-lists.)
+
+The `\-pack' switch will compress the message names in a folder, removing
+holes in message numbering.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^/bin/ls~^To fast-list the folders
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to the current folder
+`msg' defaults to none
+`\-nofast'
+`\-noheader'
+`\-nototal'
+`\-nopack'
+.Co
+If `+folder' and/or `msg' are given, they will become the
+current folder and/or message.
+.En
+.SC FORW
+.NA
+forw \- forward messages
+.SY
+forw \%[+folder] \%[msgs] \%[\-editor\ editor] \%[\-form\ formfile]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+.DE
+\fIForw\fR may be used to prepare a message containing other
+messages.
+It constructs the new message from the components file
+or `\-form formfile' (see \fIcomp\fR), with a body composed of the
+message(s) to be forwarded.
+An editor is invoked as in \fIcomp\fR,
+and after editing is complete, the user is prompted before the message
+is sent.
+
+If the `\-annotate' switch is given, each message being
+forwarded will be annotated with the lines
+
+ Forwarded: \*(<<date\*(>>
+ Forwarded: To: names
+ Forwarded: cc: names
+
+where each \*(lqTo:\*(rq and \*(lqcc:\*(rq list contains as many lines as required.
+This annotation will be done only if the message is sent directly
+from \fIforw\fR.
+If the message is not sent immediately from \fIforw\fR,
+\*(lqcomp \-use\*(rq may be used in a later session to re-edit and send
+the constructed message, but the annotations won't take place.
+The `\-inplace' switch permits annotating a message in place in
+order to preserve its links.
+
+See \fIcomp\fR for a description of the `\-editor' switch.
+.Fi
+^/etc/mh/components~^The message skeleton
+^or <mh-dir>/components~^Rather than the standard skeleton
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The default message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^Current-Folder:~^To find the default current folder
+.Ps
+^<lasteditor>\-next:~^To name an editor to be used after exit from <lasteditor>
+.De
+`+folder' defaults to the current folder
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a +folder is specified, it will become
+the current folder, and the current message will be set to
+the first message being forwarded.
+.En
+.SC INC
+.NA
+inc \- incorporate new mail
+.SY
+inc \%[+folder] \%[\-audit\ audit-file] \%[\-help]
+.DE
+\fIInc\fR incorporates mail from the user's incoming mail drop
+(\*.mail) into an MH folder.
+If `+folder' isn't specified,
+the folder named \*(lqinbox\*(rq in the user's MH directory will be used.
+The
+new messages being incorporated are assigned numbers starting
+with the next highest number in the folder.
+If the specified (or
+default) folder doesn't exist, the user will be queried prior to
+its creation.
+As the messages are processed, a \fIscan\fR listing
+of the new mail is produced.
+
+If the user's profile contains a \*(lqMsg\-Protect: nnn\*(rq entry, it
+will be used as the protection on the newly created messages,
+otherwise the MH default of 664 will be used.
+During all
+operations on messages, this initially assigned protection will
+be preserved for each message, so \fIchmod\fR(I) may be used to set a
+protection on an individual message, and its protection will be
+preserved thereafter.
+
+If the switch `\-audit audit-file' is specified (usually as a
+default switch in the profile), then \fIinc\fR will append a header
+line and a line per message to the end of the specified
+audit-file with the format:
+
+.nf
+.ti 1i
+\*(<<inc\*(>> date
+.ti 1.5i
+<scan line for first message>
+.ti 1.5i
+<scan line for second message>
+.ti 2.5i
+<etc.>
+.fi
+
+This is useful for keeping track of volume and source of incoming
+mail.
+Eventually, \fIrepl\fR, \fIforw\fR, \fIcomp\fR, and \fIdist\fR may also
+produce audits to this (or another) file, perhaps with
+\*(lqMessage-Id:\*(rq information to keep an exact correspondence history.
+\*(lqAudit-file\*(rq will be in the user's MH directory unless a full
+path is specified.
+
+\fIInc\fR will incorporate even illegally formatted messages into the
+user's MH folder, inserting a blank line prior to the offending
+component and printing a comment identifying the bad message.
+
+In all cases, the \*.mail file will be zeroed.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^$HOME/\*.mail~^The user's mail drop
+^<mh-dir>/audit-file~^Audit trace file (optional)
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Folder\-Protect:~^For protection on new folders
+.Ps
+^Msg\-Protect:~^For protection on new messages
+.De
+`+folder' defaults to \*(lqinbox\*(rq
+.Co
+The folder into which the message is
+being incorporated will become the
+current folder, and the first message incorporated will be the
+current message.
+This leaves the context ready for a \fIshow\fR
+of the first new message.
+.En
+.SC NEXT
+.NA
+next \- show the next message
+.SY
+next \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+.DE
+\fINext\fR performs a \fIshow\fR on the next message in the
+specified (or current) folder.
+Like \fIshow\fR, it passes any
+switches on to the program \fIl\fR, which is called to list the
+message.
+This command is exactly equivalent to \*(lqshow next\*(rq.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+.Co
+If a folder is specified, it will become the current folder, and the
+message that is shown (i.e., the next message in sequence)
+will become the current message.
+.En
+.SC PICK
+.NA
+pick \- select messages by content
+.SY
+.ta .4i 1.8i
+.nf
+.in .5i
+^pick~^^\0\-cc~^ \%[\-src\ +folder] \%[msgs] \%[\-help] \%[\-scan] \%[\-noscan]
+^^^\0\-date~^ \%[\-show] \%[\-noshow] \%[\-nofile] \%[\-nokeep]
+^^^\0\-from~^
+^^^\s+2\b'\(lt\(bv\(bv\(lk\(bv\(bv\(lb'\s0 \-search~\s+2\b'\(rt\(bv\(bv\(rk\(bv\(bv\(rb'\s0^ pattern
+^^^\0\-subject~^
+^^^\0\-to~^ \%[\-file \%[\-preserve] \%[\-link] \%+folder\ ... \%[\-nopreserve] \%[\-nolink] ]
+^^^\0\-\-component~^ \%[\-keep \%[\-stay] \%[\-nostay] \%[+folder\ ...]\ ]
+.fi
+
+.re
+.ti .5i
+typically:
+.in 1i
+pick\0\-from\0jones\0\-scan
+.br
+pick\0\-to\0holloway
+.br
+pick\0\-subject\0ned\0\-scan\0\-keep
+.DE
+\fIPick\fR searches messages within a folder for the specified
+contents, then performs several operations on the selected
+messages.
+
+A modified \fIgrep\fR(I) is used to perform the searching, so the
+full regular expression (see \fIed\fR(I)) facility is available
+within `pattern'.
+With `\-search', pattern is used directly,
+and with the others, the grep pattern constructed is:
+
+.ti +.5i
+\*(lq^component:\*.\*(**pattern\*(rq
+
+This means that the pattern specified for a `\-search' will be
+found everywhere in the message, including the header and the body,
+while the other search requests are limited to the single
+specified component.
+The expression `\-\-component pattern'
+is a shorthand for
+specifying `\-search \*(lqcomponent:\*.\*(**pattern\*(rq\ '; it is used to pick
+a component not in the set [cc date from subject to].
+An
+example is \*(lqpick \-\-reply\-to pooh \-show\*(rq.
+
+Searching is performed on a per-line basis.
+Within the header of
+the message, each component is treated as one long line, but in
+the body, each line is separate.
+Lower-case letters in the
+search pattern will match either lower or upper case in the
+message, while upper case will match only upper case.
+
+Once the search has been performed, the selected messages
+are scanned (see \fIscan\fR) if the `\-scan' switch is given, and
+then they are shown (see \fIshow\fR) if the `\-show' switch is
+given.
+After these two operations, the file operations (if
+requested) are performed.
+
+The `\-file' switch operates exactly like the \fIfile\fR command, with the
+same meaning for the `\-preserve' and `\-link' switches.
+
+The `\-keep' switch is similar to `\-file', but it produces a folder that
+is a subfolder of the folder being searched and defines it as
+the current folder (unless the `\-stay' flag is used).
+This
+subfolder contains the messages which matched the search
+criteria.
+All of the MH commands may be used with the sub-folder
+as the current folder.
+This gives the user considerable power
+in dealing with subsets of messages in a folder.
+
+The messages in a folder produced by `\-keep' will always have the
+same numbers as they have in the source folder (i.e., the
+`\-preserve' switch is automatic).
+This way, the message
+numbers are consistent with the folder from which the messages
+were selected.
+Messages are not removed from the source folder
+(i.e., the `\-link' switch is assumed).
+If a `+folder' is not
+specified, the standard name \*(lqselect\*(rq will be used.
+(This is the
+meaning of \*(lq(select)\*(rq when it appears in the output of the
+\fIfolder\fR command.) If `+folder' arguments are given to
+`\-keep', they will be used rather than \*(lqselect\*(rq for the names
+of the subfolders.
+This allows for several subfolders to be
+maintained concurrently.
+
+When a `\-keep' is performed, the subfolder becomes the current folder.
+This can be overridden by use
+of the `\-stay' switch.
+
+Here's an example:
+
+.nf
+\01 % folder +inbox
+\02 inbox+ has 16 messages ( 3\- 22); cur= 3.
+\03 % pick \-from dcrocker
+\04 6 hits.
+\05 [+inbox/select now current]
+\06 % folder
+\07 inbox/select+ has \06 messages ( 3\- 16); cur= 3.
+\08 % scan
+.ds p \\h'\\w'+'u'
+\09 \03+ 6/20 Dcrocker Re: ned file update issue...
+10 \06\*p 6/23 Dcrocker removal of files from /tm...
+11 \08\*p 6/27 Dcrocker Problems with the new ned...
+12 13\*p 6/28 d\h'\w'D'u-\w'd'u'crocker newest nned \*(<<I would ap...
+13 15\*p 7/\05 Dcrocker nned \*(<<Last week I asked...
+14 16\*p 7/\05 d\h'\w'D'u-\w'd'u'crocker message id format \*(<<I re...
+15 % show all | print
+16 [produce a full listing of this set of messages on the line printer.]
+17 % folder \-up
+18 inbox+ has 16 messages ( 3\- 22); cur= 3; (select).
+19 % folder \-down
+20 inbox/select+ has 6 messages ( 3\- 16); cur= 3.
+21 % rmf
+22 [+inbox now current]
+23 % folder
+24 inbox+ has 16 messages ( 3\- 22); cur= 3.
+.fi
+
+This is a rather lengthy example, but it shows the power of the
+MH package.
+In item 1, the current folder is set to inbox.
+In 3,
+all of the messages from dcrocker are found in inbox and linked
+into the folder \*(lqinbox/select\*(rq.
+(Since no action switch is
+specified, `\-keep' is assumed.) Items 6 and 7 show that this
+subfolder is now the current folder.
+Items 8 through 14 are a
+\fIscan\fR of the selected messages (note that they are all from dcrocker
+and are all in upper and lower case).
+Item 15 lists all of the messages to
+the high-speed printer.
+Item 17 directs \fIfolder\fR to set the
+current folder to the parent of the selection-list folder, which
+is now current.
+Item 18 shows that this has been done.
+Item 19 resets
+the current folder to the selection list, and 21 removes the
+selection-list folder and resets the current folder to the
+parent folder, as shown in 22 and 23.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Folder\-Protect:~^For protection on new folders
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`\-src +folder' defaults to current
+`msgs' defaults to all
+.fi
+`\-keep +select' is the default if no `\-scan', `\-show', or `\-file' is specified
+.Co
+If a `\-src +folder' is specified, it will
+become the current folder, unless a `\-keep' with 0 or 1
+folder arguments makes the selection-list subfolder the
+current folder.
+Each selection-list folder will have its
+current message set to the first of the messages linked into
+it unless the selection list already existed, in which case the
+current message won't be changed.
+.En
+.SC PREV
+.NA
+prev \- show the previous message
+.SY
+prev \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+.DE
+\fIPrev\fR performs a \fIshow\fR on the previous message in the specified
+(or current) folder.
+Like \fIshow\fR, it passes any switches on to the
+program \fIl\fR, which is called to list the message.
+This command
+is exactly equivalent to \*(lqshow prev\*(rq.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+.Co
+If a folder is specified, it will become current, and the
+message that is shown (i.e., the previous message in sequence)
+will become the current message.
+.En
+.SC PROMPTER
+.NA
+prompter \- prompting editor front end
+.SY
+This program is not called directly but takes the place
+of an editor and acts as an editor front end.
+
+.ti .5i
+prompter \%[\-erase\ chr] \%[\-kill\ chr] \%[\-help]
+.DE
+\fIPrompter\fR is an editor which allows rapid composition of
+messages.
+It is particularly useful to network and low-speed
+(less than 2400 baud) users of MH.
+It is an MH program in that
+it can have its own profile entry with switches, but it can't
+be invoked directly as all other MH commands can; it is an editor
+in that it is invoked by an \*(lq\-editor prompter\*(rq switch or by the
+profile entry \*(lqEditor: prompter\*(rq, but functionally it is merely
+a text-collector and not a true editor.
+
+\fIPrompter\fR expects to be called from \fIcomp\fR, \fIrepl\fR, \fIdist\fR, or
+\fIforw\fR, with a draft file as an argument.
+For example, \*(lqcomp
+\-editor prompter\*(rq will call \fIprompter\fR with the file \*(lqdraft\*(rq already set
+up with blank components.
+For each blank component it finds in
+the draft, it prompts the user and accepts a response.
+A
+<RETURN> will cause the whole component to be left out.
+A \*(lq\\\*(rq
+preceding a <RETURN> will continue the response on the next line,
+allowing for multiline components.
+
+Any component that is non-blank will be copied and echoed to the
+terminal.
+
+The start of the message body is prompted by a line of
+dashes.
+If the body is non-blank, the prompt is
+\*(lq--------Enter additional text\*(rq.
+Message-body typing is terminated with
+a <CTRL-D> (or <OPEN>).
+Control is returned to the calling
+program, where the user is asked \*(lqWhat now?\*(rq.
+See \fIcomp\fR for
+the valid options.
+
+The line editing characters for kill and erase may be
+specified by the user via the arguments \*(lq\-kill chr\*(rq and \*(lq\-erase
+chr\*(rq, where chr may be a character; or \*(lq\\nnn\*(rq, where nnn is the
+octal value for the character.
+(Again, these may come from the
+default switches specified in the user's profile.)
+
+A <DEL> during message-body typing is equivalent to
+<CTRL-D> for compatibility with NED.
+A <DEL> during
+component typing will abort the command that invoked
+\fIprompter\fR.
+.Fi
+None
+.Pr
+^prompter-next:~^To name the editor to be used on exit from \fIprompter\fR
+.De
+.Co
+None
+.En
+.SC REPL
+.NA
+repl \- reply to a message
+.SY
+repl \%[+folder] \%[msg] \%[\-editor\ editor] \%[\-inplace] \%[\-annotate]
+\%[\-help] \%[\-noinplace]
+\%[\-noannotate]
+.DE
+\fIRepl\fR aids a user in producing a reply to an existing
+message.
+In its simplest form (with no arguments), it will set up
+a message-form skeleton in reply to the current message in the
+current folder, invoke the editor, and send the composed
+message if so directed.
+The composed message is constructed as
+follows:
+
+.nf
+.in 1i
+To: <Reply-To> or <From>
+cc: <cc>, <To>
+Subject: Re: <Subject>
+In-reply-to: Your message of <Date>
+.ti +\w'In-reply-to: 'u
+<Message-Id>
+.in .5i
+.fi
+
+where field names enclosed in angle brackets (< >) indicate the
+contents of the named field from the message to which the reply
+is being made.
+Once the skeleton is constructed, an editor is
+invoked (as in \fIcomp\fR, \fIdist\fR, and \fIforw\fR).
+While in the editor,
+the message being replied to is available through a link named
+\*(lq@\*(rq.
+In NED, this means the replied-to message may be \*(lqused\*(rq
+with \*(lquse @\*(rq, or put in a window by \*(lqwindow @\*(rq.
+
+As in \fIcomp\fR, \fIdist\fR, and \fIforw\fR, the user will be queried
+before the message is sent.
+If `\-annotate' is
+specified, the replied-to message will be annotated with the
+single line
+
+.ti +.5i
+Replied: \*(<<Date\*(>>.
+
+The command
+\*(lqcomp \-use\*(rq may be used to pick up interrupted editing, as in
+\fIdist\fR and \fIforw\fR; the `\-inplace' switch annotates the message in place,
+so that all folders with links to it will see the annotation.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^<mh-dir>/draft~^The constructed message file
+^/usr/bin/send~^To send the composed message
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Editor:~^To override the use of /bin/ned as the default editor
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.Co
+If a `+folder' is specified, it will become the current
+folder, and the current message will be set to the replied-to
+message.
+.sp 2
+.En
+.SC RMF
+.NA
+rmf \- remove folder
+.SY
+rmf \%[+folder] \%[\-help]
+.DE
+\fIRmf\fR removes all of the files (messages) within the specified
+(or default) folder, and then removes the directory (folder).
+If
+there are any files within the folder which are not a part of MH,
+they will \fInot\fR be removed, and an error will be produced.
+If the
+folder is given explicitly or the current folder is a
+subfolder (i.e., a selection list from \fIpick\fR), it will be
+removed without confirmation.
+If no argument is specified and
+the current folder is not a selection-list folder, the
+user will be asked for confirmation.
+
+\fIRmf\fR irreversibly deletes messages that don't have other links,
+so use it with caution.
+
+If the folder being removed is a subfolder, the parent
+folder will become the new current folder, and \fIrmf\fR will
+produce a message telling the user this has happened.
+This
+provides an easy mechanism for selecting a set of messages,
+operating on the list, then removing the list and returning to
+the current folder from which the list was extracted.
+(See the
+example under \fIpick\fR.)
+
+The files that \fIrmf\fR will delete are cur, any file beginning
+with a comma, and files with purely numeric names.
+All others
+will produce error messages.
+
+\fIRmf\fR of a read-only folder will delete the \*(lqcur\-\*(rq entry from the
+profile without affecting the folder itself.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current, usually with confirmation
+.Co
+\fIRmf\fR will set the current folder to the parent folder if a
+subfolder is removed; or if the current folder is removed,
+it will make \*(lqinbox\*(rq current.
+Otherwise, it doesn't change the
+current folder or message.
+.En
+.SC RMM
+.NA
+rmm \- remove messages
+.SY
+rmm \%[+folder] \%[msgs] \%[\-help]
+.DE
+\fIRmm\fR removes the specified messages by renaming the message
+files with preceding commas.
+(This is the Rand-UNIX backup file
+convention.)
+
+The current message is not changed by \fIrmm\fR, so a \fInext\fR will
+advance to the next message in the folder as expected.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+.Co
+If a folder is given, it will become current.
+.En
+.SC SCAN
+.NA
+scan \- produce a one-line-per-message scan listing
+.SY
+scan \%[+folder] \%[msgs] \%[\-f\&f] \%[\-header] \%[\-help]
+\%[\-nof\&f] \%[\-noheader]
+.DE
+\fIScan\fR produces a one-line-per-message listing of the specified
+messages.
+Each \fIscan\fR line contains the message number (name),
+the date, the \*(lqFrom\*(rq field, the \*(lqSubject\*(rq field, and, if room
+allows, some of the body of the message.
+For example:
+
+.nf
+.ta .5i 1.2i 2.6i
+^ #~^^Date~^^ From~^Subject\ \ \ \ \[\*(<<Body]
+^15+~^^7/\05~^^Dcrocker~^nned \*(<<Last week I asked some of
+^16\ \-~^^7/\05~^^dcrocker~^message id format \*(<<I recommend
+^18~^^7/\06~^^Obrien~^Re: Exit status from mkdir
+^19~^^7/\07~^^Obrien~^"scan" listing format in MH
+.re
+.fi
+
+The `+' on message 15 indicates that it is the current message.
+The `\-' on message 16 indicates that it has been
+replied to, as indicated by a \*(lqReplied:\*(rq component produced by
+an `\-annotate' switch to the \fIrepl\fR command.
+
+If there is sufficient room left on the \fIscan\fR line after the
+subject, the line will be filled with text from the body,
+preceded by \*(<<.
+\fIScan\fR actually reads each of the specified
+messages and parses them to extract the desired fields.
+During parsing, appropriate error messages will be produced if
+there are format errors in any of the messages.
+
+The `\-header' switch produces a header line prior to the \fIscan\fR
+listing, and the `\-f\&f' switch will cause a form feed to be
+output at the end of the \fIscan\fR listing.
+See Appendix D.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+Defaults:
+`+folder' defaults to current
+`msgs' defaults to all
+`\-nof\&f'
+`\-noheader'
+.Co
+If a folder is given, it will become current.
+The current
+message is unaffected.
+.En
+.SC SEND
+.NA
+send \- send a message
+.SY
+send \%[file] \%[\-draft] \%[\-verbose] \%[\-format] \%[\-msgid]
+\%[\-help] \%[\-noverbose] \%[\-noformat] \%[\-nomsgid]
+.DE
+\fISend\fR will cause the specified file (default <mh-dir>/draft) to
+be delivered to each of the addresses in the \*(lqTo:\*(rq, \*(lqcc:\*(rq, and \*(lqBcc:\*(rq
+fields of the message.
+If `\-verbose' is specified, \fIsend;\fR
+will monitor the delivery of local and net mail.
+\fISend\fR with no
+argument will query whether the draft is the intended file, whereas
+`\-draft' will suppress this question.
+Once the message has
+been mailed (or queued) successfully, the file will be renamed
+with a leading comma, which allows it to be retreived until the
+next draft message is sent.
+If there are errors in the
+formatting of the message, \fIsend;\fR will abort with a (hopefully)
+helpful error message.
+
+If a \*(lqBcc:\*(rq field is encountered, its addresses will be used for
+delivery, but the \*(lqBcc:\*(rq field itself will be deleted from all
+copies of the outgoing message.
+
+Prior to sending the message, the fields \*(lqFrom: user\*(rq, and
+\*(lqDate: now\*(rq will be prepended to the message.
+If `\-msgid' is
+specified, then a \*(lqMessage-Id:\*(rq field will also be added to the
+message.
+If the message already contains a \*(lqFrom:\*(rq field, then a
+\*(lqSender: user\*(rq field will be added instead.
+(An already existing
+\*(lqSender:\*(rq field will be deleted from the message.)
+
+If the user doesn't specify `\-noformat', each of the entries in
+the \*(lqTo:\*(rq and \*(lqcc:\*(rq fields will be replaced with \*(lqstandard\*(rq format
+entries.
+This standard format is designed to be usable by all
+of the message handlers on the various systems around the
+ARPANET.
+
+If an \*(lqFcc: folder\*(rq is encountered, the message will be copied
+to the specified folder in the format in which it will appear to any
+receivers of the message.
+That is, it will have the prepended
+fields and field reformatting.
+
+If a \*(lqDistribute-To:\*(rq field is encountered, the message
+is handled as a redistribution message (see \fIdist\fR for
+details), with \*(lqDistribution-Date: now\*(rq and \*(lqDistribution-From: user\*(rq
+added.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+.Pr
+^Path:~^To determine the user's MH directory
+.De
+`file' defaults to draft
+`\-noverbose'
+`\-format'
+`\-nomsgid'
+.Co
+\fISend\fR has no effect on the current message or folder.
+.En
+.SC SHOW
+.NA
+show \- show (list) messages
+.SY
+show \%[+folder] \%[msgs] \%[\-pr] \%[\-nopr] \%[\-draft] \%[\-help]
+\%[\fIl\fR\ or\ \fIpr\fR\ switches]
+.DE
+\fIShow\fR lists each of the specified messages to the standard
+output (typically, the terminal).
+The messages are listed exactly
+as they are, with no reformatting.
+A program called \fIl\fR is
+invoked to do the listing, and any switches not recognized by
+\fIshow\fR are passed along to \fIl\fR.
+
+If no \*(lqmsgs\*(rq are specified, the current message is used.
+If
+more than one message is specified, \fIl\fR will prompt for a
+<return> prior to listing each message.
+
+\fIl\fR will list each message, a page at a time.
+When the end of
+page is reached, \fIl\fR will ring the bell and wait for a <RETURN>
+or <CTRL-D>.
+If a <return> is entered, \fIl\fR will clear the
+screen before listing the next page, whereas <CTRL-D> will not.
+The switches to \fIl\fR are
+`\-p#' to indicate the page length in lines, and `\-w#' to
+indicate the width of the page in characters.
+
+If the standard output is not a terminal, no queries are made,
+and each file is listed with a one-line header and two lines of
+separation.
+
+If `\-pr' is specified, then \fIpr\fR(I) will be invoked rather than
+\fIl\fR, and the switches (other than `\-draft') will be passed
+along.
+\*(lqShow \-draft\*(rq will list the file <mh-dir>/draft if it
+exists.
+.Fi
+^$HOME/\*.mh\(ruprofile~^The user profile
+^/bin/l~^Screen-at-a-time list program
+^/bin/pr~^\fIpr\fR(I)
+.Pr
+^Path:~^To determine the user's MH directory
+.Ps
+^Current-Folder:~^To find the default current folder
+.De
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-nopr'
+.Co
+If a folder is given, it will become the current message.
+The last message
+listed will become the current message.
+.En
+\"
+\" On to the Appendices
+\"
+.fo ''-%-''
+.he ''''
+.(x
+.sp
+Appendix
+.)x _
+.de $c \" Major Heading printer
+.ce
+Appendix \\n+(ch
+.sp 2p
+.ce
+.b "\\s12\\$1\\s0" \" 12 Point Bold Header
+.(x
+\ \ \ \\n(ch.\\ \\ \\$2
+.)x
+.sp 45p \" 45 points or about 1/2 inch
+..
+.++ A
+.bp
+.$c "COMMAND SUMMARY\\**" "Command Summary"
+.(f
+\**All commands accept a \-help switch.
+.)f
+.in 1i
+.na
+.ti .5i
+comp \%[\-editor\ editor] \%[\-form\ formfile] \%[file] \%[\-use]
+\%[\-nouse] \%[\-help]
+
+.ti .5i
+dist \%[+folder] \%[msg] \%[\-form\ formfile] \%[\-editor\ editor]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+
+.ti .5i
+file \%[\-src\ +folder] \%[msgs] \%[\-link] \%[\-preserve] \%+folder\ ...
+\%[\-nolink] \%[\-nopreserve]
+\%[\-file\ file] \%[\-nofile] \%[\-help]
+
+.ti .5i
+folder \%[+folder] \%[msg] \%[\-all] \%[\-fast] \%[\-nofast] \%[\-up] \%[\-down]
+\%[\-header] \%[\-noheader] \%[\-total] \%[\-nototal] \%[\-pack] \%[\-nopack]
+\%[\-help]
+
+.ti .5i
+forw \%[+folder] \%[msgs] \%[\-editor\ editor] \%[\-form\ formfile]
+\%[\-annotate] \%[\-noannotate]
+\%[\-inplace] \%[\-noinplace]
+\%[\-help]
+
+.ti .5i
+inc \%[+folder] \%[\-audit\ audit-file] \%[\-help]
+
+.ti .5i
+next \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+
+.ta .4i 1.8i
+.nf
+.in .5i
+^pick~^^\0\-cc~^ \%[\-src\ +folder] \%[msgs] \%[\-help] \%[\-scan] \%[\-noscan]
+^^^\0\-date~^ \%[\-show] \%[\-noshow] \%[\-nofile] \%[\-nokeep]
+^^^\0\-from~^
+^^^\s+2\b'\(lt\(bv\(bv\(lk\(bv\(bv\(lb'\s0 \-search~\s+2\b'\(rt\(bv\(bv\(rk\(bv\(bv\(rb'\s0^ pattern
+^^^\0\-subject~^
+^^^\0\-to~^ \%[\-file \%[\-preserve] \%[\-link] \%+folder\ ... \%[\-nopreserve] \%[\-nolink] ]
+^^^\0\-\-component~^ \%[\-keep \%[\-stay] \%[\-nostay] \%[+folder\ ...]\ ]
+.fi
+.re
+
+.ti .5i
+prev \%[+folder] \%[\-switches\ for\ \fIl\fR] \%[\-help]
+
+.ti .5i
+prompter \%[\-erase\ chr] \%[\-kill\ chr] \%[\-help]
+
+.ti .5i
+repl \%[+folder] \%[msg] \%[\-editor\ editor] \%[\-inplace] \%[\-annotate]
+\%[\-help] \%[\-noinplace]
+\%[\-noannotate]
+
+.ti .5i
+rmf \%[+folder] \%[\-help]
+
+.ti .5i
+rmm \%[+folder] \%[msgs] \%[\-help]
+
+.ti .5i
+scan \%[+folder] \%[msgs] \%[\-f\&f] \%[\-header] \%[\-help]
+\%[\-nof\&f] \%[\-noheader]
+
+.ti .5i
+send \%[file] \%[\-draft] \%[\-verbose] \%[\-format] \%[\-msgid]
+\%[\-help] \%[\-noverbose] \%[\-noformat] \%[\-nomsgid]
+
+.ti .5i
+show \%[+folder] \%[msgs] \%[\-pr] \%[\-nopr] \%[\-draft] \%[\-help]
+\%[\fIl\fR\ or\ \fIpr\fR\ switches]
+.ad
+.in 0
+\".+c "MESSAGE FORMAT" "Message Format"
+.if t \{
+.ll 32P
+.lt 32P
+\}
+.bp
+.$c "MESSAGE FORMAT" "Message Format"
+.pp
+This section paraphrases the format of ARPANET text messages
+given in Ref. 6.
+
+.lp
+ASSUMPTIONS
+.np
+Messages
+are expected to consist of lines of text.
+Graphics and binary data are not handled.
+.np
+No data compression is accepted.
+All text is clear
+ASCII 7-bit data.
+
+.lp
+LAYOUT
+.lp
+A general \*(lqmemo\*(rq framework is used.
+A message consists of a
+block of information in a rigid format, followed by general
+text with no specified format.
+The rigidly formatted first
+part of a message is called the header, and the free-format
+portion is called the body.
+The header must always
+exist, but the body is optional.
+
+.lp
+THE HEADER
+.lp
+Each header item can be viewed as a single logical line of ASCII
+characters.
+If the text of a header item extends across several
+real lines, the continuation lines are indicated by leading
+spaces or tabs.
+.lp
+Each header item is called a component and is composed of a
+keyword or name, along with associated text.
+The keyword begins at the
+left margin, may contain spaces or tabs, may not exceed 63
+characters, and is terminated by a colon (:).
+Certain
+components (as identified by their keywords) must follow rigidly
+defined formats in their text portions.
+.lp
+The text for most formatted components (e.g., \*(lqDate:\*(rq and \*(lqMessage-Id:\*(rq)
+is produced automatically.
+The only ones entered by the
+user are address fields such as \*(lqTo:\*(rq, \*(lqcc:\*(rq, etc.
+ARPA addresses
+are assigned mailbox names and host computer specifications.
+The
+rough format is \*(lqmailbox at host\*(rq, such as \*(lqBorden at Rand-Unix\*(rq.
+Multiple addresses are separated by commas.
+A missing host is
+assumed to be the local host.
+
+.ne 10
+.lp
+THE BODY
+.lp
+A blank line signals that all following text up to the end of the file
+is the body.
+(A blank line is defined as a pair of
+<end-of-line> characters with \fIno\fR characters in between.)
+No formatting is expected or enforced within the body.
+.lp
+Within MH, a line consisting of dashes is accepted
+as the header delimiter.
+This is a cosmetic feature applying
+only to locally composed mail.
+.bp
+.$c "MESSAGE NAME BNF" "Message Name BNF"
+
+.ta 1.2i 1.8i 3.2i
+.nf
+.in 1i
+^msgs~^^:=~^^msgspec~^|
+^^^^msgs msgspec
+
+^msgspec~^^:=~^^msg~^|
+^^^^^msg-range~^|
+^^^^msg-sequence
+
+^msg~^^:=~^^msg-name~^|
+^^^^<number>^
+
+^msg-name~^^:=~^^\*(lqfirst\*(rq~^|
+^^^^^\*(lqlast\*(rq~^|
+^^^^^\*(lqcur\*(rq~^|
+^^^^^\*(lq\*.\*(rq~^|
+^^^^^\*(lqnext\*(rq~^|
+^^^^\*(lqprev\*(rq
+
+^msg-range~^^:=~^^msg\*(lq-\*(rqmsg~^|
+^^^^^\*(lqall\*(rq
+
+^msg-sequence~^^:=~^msg\*(lq:\*(rqsigned-number
+
+^signed-number~^^:=~^^\*(lq+\*(rq<number>~^|
+^^^^^\*(lq\--\*(rq<number>~^|
+^^^^<number>
+.re \" Reset Tabs
+.fi
+.sp
+.pp
+Where <number> is a decimal number in the range 1 to 999.
+.pp
+Msg-range specifies all of the messages in the given range
+and must not be empty.
+.pp
+Msg-sequence specifies up to <number> of messages, beginning
+with \*(lqmsg\*(rq (in the case of first, cur, next, or <number>),
+or ending with \*(lqmsg\*(rq (in the case of prev or last).
++<number> forces \*(lqstarting with msg\*(rq, and \-<number> forces
+\*(lqending with number\*(rq.
+In all cases, \*(lqmsg\*(rq must exist.
+.bp
+.$c "EXAMPLE OF SHELL COMMANDS" "Example of Shell Commands"
+.pp
+UNIX commands may be mixed with MH commands to obtain additional
+functions.
+These may be prepared as files (known as
+shell command files or
+shell scripts).
+The following example is a useful function that
+illustrate the possibilities.
+Other functions, such as copying,
+deleting, renaming, etc., can be achieved in a similar fashion.
+
+HARDCOPY
+.pp
+The command:
+
+.ti +.5i
+(scan\0\-f\&f\0\-header;\0show\0all\0\-pr\0\-f)\0|\0print
+
+produces a scan listing of the current folder, followed by a
+form feed, followed by a formatted listing of all messages
+in the folder, one per page.
+Omitting \*(lq\-pr\0\-f\*(rq will cause the
+messages to be concatenated, separated by a one-line header
+and two blank lines.
+.pp
+You can create variations on this theme, using \fIpick\fR.
+.re
+.fi
+.in 0
+.bp
+.ce
+.b \\s12REFERENCES\\s0
+.(x
+.sp
+REFERENCES
+.)x
+.sp 3
+.in .4i
+.ti 0
+1. Crocker, D. H., J. J. Vittal, K. T. Pogran, and D. A. Henderson, Jr.,
+\*(lqStandard for the Format of ARPA Network Test Messages,\*(rq \fIArpanet Request
+for Comments\fR, No. 733, Network Information Center 41952, Augmentation
+Research Center, Stanford Research Institute,
+November 1977.
+
+.ti 0
+2. Thompson, K., and D. M. Ritchie, \*(lqThe UNIX Time-sharing System,\*(rq
+\fICommunications of the ACM\fR, Vol. 17, July 1974, pp. 365-375.
+
+.ti 0
+3. McCauley, E. J., and P. J. Drongowski, \*(lqKSOS\-The Design of a Secure
+Operating System,\*(rq \fIAFIPS Conference Proceedings\fR,
+National Computer Conference,
+Vol. 48, 1979, pp. 345-353.
+
+.ti 0
+4. Crocker, David H., \fIFramework and Functions of the \*(lqMS\*(rq Personal
+Message System\fR, The Rand Corporation, R-2134-ARPA, December 1977.
+
+.ti 0
+5. Thompson, K., and D. M. Ritchie, \fIUNIX Programmer's Manual\fR, 6th ed.,
+Western Electric Company, May 1975 (available only to UNIX licensees).
+
+.ti 0
+6. Bilofsky, Walter, \fIThe CRT Text Editor NED\-Introduction and
+Reference Manual\fR, The Rand Corporation, R-2176-ARPA, December 1977.
+.bp 3
+.de $c
+.ce
+.b "\\s12\\$1\\s0" \" 12 Point Bold Header
+.(x y
+.sp
+\\$1
+.)x
+.sp 3
+..
+.pn 3
+.++ P
+.fo ''''
+.he ''-%-''
+.+c PREFACE
+.pp
+This report describes a system for dealing with messages transmitted on a
+computer. Such messages might originate with other users of the same
+computer or might come from an outside source through a network to which the user's
+computer is connected. Such computer-based message systems are
+becoming increasingly widely used, both within and outside the Department
+of Defense.
+.pp
+The message handling system MH was developed for two reasons.
+One was to investigate some
+research ideas concerning how a message system might take advantage of
+the architecture of the UNIX time-sharing operating system for
+Digital Equipment Corporation PDP-11 and VAX computers, and the special
+features of UNIX's command-level interface with the user (the
+\*(lqshell\*(rq). The other reason was to provide a better and more
+adaptable base than that of conventional designs
+on which to build a command and control message system.
+The effort has succeeded in both
+regards, although this report mainly describes the message system itself
+and how it fits in with UNIX. The main research results are being
+described and analyzed in a forthcoming Rand report.
+The system is currently being used as part
+of a tactical command and control \*(lqlaboratory,\*(rq which is also being described
+in a separate report.
+.pp
+The present report should be of interest to three groups of readers. First,
+it is a complete reference manual for the users of MH (although
+users outside of Rand must take into
+account differences from the local Rand operating system). Second, it should be
+of interest to those who have a general knowledge of computer-based
+message systems, both in civilian and military applications. Finally,
+it should be of interest to those who build large subsystems that
+interface with users, since it illustrates a new approach to such
+interfaces.
+.pp
+The MH system was developed by the first
+author, using an approach suggested by the other two authors.
+Valuable assistance was provided by Phyllis Kantar in the later
+stages of the system's implementation.
+Several colleagues
+contributed to the ideas included in this system, particularly
+Robert Anderson and David Crocker.
+In addition, valuable experience
+in message systems, and a valuable source of ideas, was available
+to us in the form of a previous message system for UNIX called
+MS, designed at Rand by David Crocker.
+.pp
+This report was prepared as part of the Rand project entitled \*(lqData
+Automation Research\*(rq, sponsored by Project AIR FORCE.
+.pn 5
+.+c SUMMARY
+.pp
+Electronic communication of text messages is becoming
+commonplace. Computer-based message systems\-software
+packages that provide tools for dealing with messages\-are used in many
+contexts. In particular, message systems are becoming
+increasingly important in command and control and intelligence
+applications.
+.pp
+This report describes a message handling system called MH.
+This system provides the user
+with tools to compose, send, receive, store, retrieve, forward, and
+reply to messages. MH has been built on the UNIX time-sharing system,
+a popular operating system developed for the DEC PDP-11 and VAX classes of
+computers.
+.pp
+A complete description of MH is given for users of
+the system. For those who do not intend to use the system, this description
+gives a general idea of what a message system is like. The system involves
+some new ideas about how large subsystems can be constructed. These design
+concepts and a comparison of MH with other message systems
+will be published in a forthcoming Rand report.
+.pp
+The interesting and unusual features of MH include the
+following: The user command interface to MH is the UNIX \*(lqshell\*(rq
+(the standard UNIX command interpreter). Each separable
+component of message handling, such as message composition or
+message display, is a separate command. Each program is driven from
+and updates a private user environment, which is stored as a file
+between program invocations. This private environment also contains
+information to \*(lqcustom tailor\*(rq MH to the individual's tastes. MH
+stores each message as a separate file under UNIX, and it utilizes the
+tree-structured UNIX file system to organize groups of files within
+separate directories or \*(lqfolders.\*(rq All of the UNIX facilities
+for dealing with files and directories, such as
+renaming, copying, deleting, cataloging, off-line printing, etc., are
+applicable to messages and directories of messages (folders). Thus,
+important capabilities needed in a message system are available in MH without
+the need (often seen in other message systems) for code that
+duplicates the facilities of the supporting operating system.
+It also allows users familiar with the shell to use MH with minimal
+effort.
+.he ''''
+.fo ''''
+.bp
+.ce
+.b \\s12CONTENTS\\s0
+.sp 3
+.xp y
+.xp x
+
+.bp \" Spare numbers for cut and paste work!
+.ft B
+
+1 1 1 1 1 1 1 1
+
+1 1 1 1 1 1 1 1
+
+1 1 1 1 1 1 1 1
+
+1 1 1 1 1 1 1 1
+
+2 2 2 2 2 2 2 2
+
+2 2 2 2 2 2 2 2
+
+2 2 2 2 2 2 2 2
+
+3 3 3 3 3 3 3 3
+
+3 3 3 3 3 3 3 3
--- /dev/null
+.(l C
+.sp 1i
+.sz +8
+.b
+MH
+.sp 0.4i
+.sz -4
+.r
+A Mail Handling System
+.sp 0.2i
+for \s-1UNIX\s+1
+.sz -4
+.sp 1i
+October, 1979
+
+Bruce Borden
+.sp 1i
+The Rand Corporation
+1700 Main Street
+Santa Monica, CA 90406
+
+(213) 399-0568 x 7463
+.)l
--- /dev/null
+DEST = $(DESTDIR)/usr/man/mann
+
+MAKEFILE = Makefile
+
+PRINT = vtroff
+
+SRCS = comp.1 \
+ dist.1 \
+ file.1 \
+ folder.1 \
+ forw.1 \
+ inc.1 \
+ next.1 \
+ pick.1 \
+ prev.1 \
+ prompter.1 \
+ repl.1 \
+ rmf.1 \
+ rmm.1 \
+ scan.1 \
+ send.1 \
+ show.1
+
+SUFFIX = .1:s
+
+all:;
+
+clean:;
+
+depend:; @mkmf -f $(MAKEFILE)
+
+install:; @echo Installing $(SRCS) in $(DEST)
+ @for i in $(SRCS); do cp $$i $(DEST)/`basename $$i .1`.n; done
+
+print: $(SRCS)
+ @$(PRINT) -man $?
+ @touch print
+
+update:;
--- /dev/null
+.TH COMP 1 "3 August 1983"
+.UC 4
+.SH NAME
+comp \- compose a message
+.SH SYNOPSIS
+.B comp
+[ \-editor editor ] [ \-form formfile ] [ file ] [ \-use ]
+[ \-nouse ] [ \-help ]
+.SH DESCRIPTION
+\fIComp\fP is used to create a new message to be mailed.
+If
+\fIfile\fP is not specified, the file named \*(lqdraft\*(rq in the user's MH
+directory will be used.
+\fIComp\fR copies a message form to
+the file being composed and then invokes an editor on the
+file.
+The default editor is /bin/ned, which may be overridden with
+the `\-editor' switch or with a profile entry \*(lqEditor:\*(rq.
+The default message form contains the following elements:
+.nf
+
+ To:
+ cc:
+ Subject:
+ ----------
+
+.fi
+If the file named \*(lqcomponents\*(rq exists in the user's MH directory,
+it will be used instead of this form.
+If `\-form formfile' is specified, the specified formfile (from the MH
+directory) will be used as the skeleton.
+The line of dashes
+or a blank line must be left between the header and the
+body of the message for the message to be identified properly when it is
+sent (see
+.IR send (1)).
+The switch `\-use' directs \fIcomp\fR to
+continue editing an already started message.
+That is, if a
+\fIcomp\fR (or \fIdist\fR, \fIrepl\fR, or \fIforw\fR) is terminated without
+sending the message, the message can be edited again via
+\*(lqcomp \-use\*(rq.
+.PP
+If the specified file (or draft) already exists, \fIcomp\fR will ask
+if you want to delete it before continuing.
+A reply of \fBNo\fR will abort the
+\fIcomp\fR, \fByes\fR will replace the existing draft with a blank
+skeleton, \fBlist\fR will display the draft, and \fBuse\fR will use it
+for further composition.
+.PP
+Upon exiting from the editor, \fIcomp\fR will ask \*(lqWhat now?\*(rq.
+The valid
+responses are \fBlist\fR, to list the draft on the terminal; \fBquit\fR, to
+terminate the session and preserve the draft; \fBquit delete\fR, to terminate,
+then delete the draft; \fBsend\fR, to send the message; \fBsend verbose\fR, to
+cause the delivery process to be monitored; \fBedit <editor>\fR, to invoke
+<editor> for further editing; and \fBedit\fR, to re-edit using the
+same editor that was used on the preceding round unless a profile
+entry \*(lq<lasteditor>\-next: <editor>\*(rq names an alternative editor.
+.PP
+\fIComp\fR does not affect either the current folder or the current message.
+.SH FILES
+.nf
+.ta \w'or <mh-dir>/components 'u
+/etc/mh/components The message skeleton
+or <mh-dir>/components Rather than the standard skeleton
+$HOME/\*.mh_profile The user profile
+<mh-dir>/draft The default message file
+/usr/new/send To send the composed message
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'<lasteditor>\-next: 'u
+Path: To determine the user's MH directory
+Editor: To override the use of /bin/ned as the default editor
+<lasteditor>\-next: editor to be used after exit from <lasteditor>
+.SH DEFAULTS
+.nf
+`file' defaults to draft
+`\-editor' defaults to /bin/ned
+`\-nouse'
+.fi
--- /dev/null
+.TH DIST 1 "3 August 1983"
+.UC 4
+.SH NAME
+dist \- redistribute a message to additional addresses
+.SH SYNOPSIS
+.B dist
+[ +folder ] [ msg ] [ \-form formfile ] [ \-editor editor ]
+[ \-annotate ] [ \-noannotate ]
+[ \-inplace ] [ \-noinplace ] [ \-help ]
+.SH DESCRIPTION
+\fIDist\fR is similar to \fIforw\fR.
+It prepares the specified
+message for redistribution to addresses that (presumably) are
+not on the original address list.
+The file \*(lqdistcomps\*(rq in the
+user's MH directory, or a standard form, or the file specified by
+`\-form formfile' will be used as the blank components file to
+be prepended to the message being distributed.
+The standard form
+has the components \*(lqDistribute-to:\*(rq and \*(lqDistribute-cc:\*(rq.
+When
+the message is sent, \*(lqDistribution-Date:\0date\*(rq,
+\*(lqDistribution-From:\0name\*(rq, and
+\*(lqDistribution-Id:\0id\*(rq (if `\-msgid' is
+specified to \fIsend\fR;) will be prepended to the outgoing message.
+Only those addresses in \*(lqDistribute-To\*(rq, \*(lqDistribute-cc\*(rq, and
+\*(lqDistribute-Bcc\*(rq will be sent.
+Also, a \*(lqDistribute-Fcc:\0folder\*(rq
+will be honored (see \fIsend;\fR).
+.PP
+\fISend\fR recognizes a message as a redistribution message by the
+existence of the field \*(lqDistribute-To:\*(rq, so don't try to
+redistribute a message with only a \*(lqDistribute-cc:\*(rq.
+.PP
+If the `\-annotate' switch is given, each message being
+distributed will be annotated with the lines:
+.nf
+
+ Distributed:\0\*(<<date\*(>>
+ Distributed:\0Distribute-to: names
+
+.fi
+where each \*(lqto\*(rq list contains as many lines as required.
+This annotation
+will be done only if the message is sent directly from \fIdist\fR.
+If the
+message is not sent immediately from \fIdist\fR (i.e., if it is sent later
+via \fIsend;\fR),
+\*(lqcomp \-use\*(rq may be used to re-edit and send the constructed message,
+but the annotations won't take place.
+The '\-inplace' switch causes annotation to
+be done in place in order to preserve links to the annotated message.
+.PP
+See \fIcomp\fR for a description of the `\-editor' switch and for options
+upon exiting from the editor.
+.PP
+If a +folder is specified, it will become the current
+folder, and the current message will be set to the message
+being redistributed.
+.SH FILES
+.nf
+.ta \w'or <mh-dir>/components 'u
+/etc/mh/components The message skeleton
+or <mh-dir>/components Rather than the standard skeleton
+$HOME/\*.mh\(ruprofile The user profile
+<mh-dir>/draft The default message file
+/usr/bin/send To send the composed message
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'<lasteditor>\-next: 'u
+Path: To determine the user's MH directory
+Editor: To override the use of /bin/ned as the default editor
+<lasteditor>\-next: editor to be used after exit from <lasteditor>
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to the current folder
+`msg' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.fi
--- /dev/null
+.TH FILE 1 "3 August 1983"
+.UC 4
+.SH NAME
+file \- file message(s) in (an)other folder(s)
+.SH SYNOPSIS
+file [ \-src +folder ] [ msgs ] [ \-link ] [ \-preserve ] +folder ...
+[ \-nolink] [ \-nopreserve ]
+[ \-file file ] [ \-nofile ] [ \-help ]
+.SH DESCRIPTION
+\fIFile\fR moves (\fImv\fR(1)) or links (\fIln\fR(1)) messages from a
+source folder into one or more destination folders.
+If you think
+of a message as a sheet of paper, this operation is not
+unlike filing the sheet of paper (or copies) in file cabinet
+folders.
+When a message is filed, it is linked into the
+destination folder(s) if possible, and is copied otherwise.
+As long
+as the destination folders are all on the same file system, multiple filing
+causes little storage overhead.
+This facility provides a good way to cross-file or multiply-index
+messages.
+For example, if a message is received from Jones about
+the ARPA Map Project, the command
+.nf
+
+ file\0cur\0+jones\0+Map
+
+.fi
+would allow the message to be found in either of the two
+folders `jones' or `Map'.
+.PP
+The option `\-file file' directs \fIfile\fR to use the specified
+file as the source message to be filed, rather than a message from
+a folder.
+.PP
+If a destination folder doesn't exist, \fIfile\fR will ask if you
+want to create one.
+A negative response will abort the file
+operation.
+.PP
+`\-link' preserves the source folder copy of the message
+(i.e., it does a \fIln\fR(1) rather than a \fImv\fR(1)), whereas,
+`\-nolink' deletes the \*(lqfiled\*(rq messages from the source
+folder.
+Normally, when a message is filed, it is assigned the
+next highest number available in each of the destination folders.
+Use of the `\-preserve' switch will override this message
+\*(lqrenaming\*(rq, but name conflicts may occur, so
+use this switch cautiously.
+(See \fIpick\fR for more details on
+message numbering.)
+.PP
+If `\-link' is not specified (or `\-nolink' is specified),
+the filed messages will be removed (
+.IR unlink (2))
+from the source folder.
+.PP
+If `\-src +folder' is given, it will become the
+current folder for future MH commands.
+If neither `\-link' nor
+`all' are specified, the current message in the source
+folder will be set to the last message specified; otherwise, the
+current message won't be changed.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Folder\-Protect: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+Folder\-Protect: To set mode when creating a new folder
+.fi
+.SH DEFAULTS
+.nf
+`\-src +folder' defaults to the current folder
+`msgs' defaults to cur
+`\-nolink'
+`\-nopreserve'
+`\-nofile'
+.fi
+.SH CONTEXT
+If `\-src +folder' is given, it will become the
+current folder for future MH commands.
+If neither `\-link' nor
+`all' are specified, the current message in the source
+folder will be set to the last message specified; otherwise, the
+current message won't be changed.
--- /dev/null
+.TH FOLDER 1 "3 August 1983"
+.UC 4
+.SH NAME
+folder \- set/list current folder/message
+.SH SYNOPSIS
+.B folder
+[ +folder ] [ msg ] [ \-all ] [ \-fast ] [ \-nofast ] [ \-up ] [ \-down ]
+[ \-header ] [ \-noheader ] [ \-total ] [ \-nototal ] [ \-pack ] [ \-nopack ]
+[ \-help ]
+.PP
+folders <equivalent to 'folder \-all'>
+.SH DESCRIPTION
+Since the MH environment is the shell, it is easy to lose
+track of the current folder from day to day.
+\fIFolder\fR will
+list the current folder, the number of messages in it, the
+range of the messages (low-high), and the current message within
+the folder, and will flag a selection list or extra files if they
+exist.
+An example of the output is:
+.nf
+
+ inbox+ has 16 messages ( 3\- 22); cur= 5.
+
+.fi
+If a `+folder' and/or `msg' are specified, they will
+become the current folder and/or message.
+An `\-all' switch
+will produce a line for each folder in the user's MH directory,
+sorted alphabetically.
+These folders are preceded by the read-only
+folders, which occur as \*.mh\(ruprofile \*(lqcur\-\*(rq entries.
+For example,
+.nf
+
+.fc ^ ~
+.ta 1.5i 2.1i 2.7i 3.5i
+^~Folder\ \ ^^~#\ of\ ^^messages~^^(~\ range\~ );\ ^cur msg (other files)
+^~/fsd/rs/m/tacc\ \ ^^has~35\ ^^messages~^^(~1\-\035);\ ^cur=\ 23.
+^~/rnd/phyl/Mail/EP\ \ ^^has~82\ ^^messages~^^(~1\-108);\ ^cur=\ 82.
+^~f\&f\ \ ^^has~4\ ^^messages~^^(~1\-\0\04);\ ^cur=\ \01.
+^~inbox+\ ^^has~16\ ^^messages~^^(~3\-\022);\ ^cur=\ \05.
+^~mh\ \ ^^has~76\ ^^messages~^^(~1\-\076);\ ^cur=\ 70.
+^~notes\ \ ^^has~2\ ^^messages~^^(~1\-\0\02);\ ^cur=\ \01.
+^~ucom\ \ ^^has~124\ ^^messages~^^(~1\-124);\ ^cur=\ \06; (select).
+
+^^^~TOTAL=\0339\ ^messages\0in\0\07\0Folders.
+.re
+.fi
+.PP
+The \*(lq+\*(rq after inbox indicates that it is the current folder.
+The \*(lq(select)\*(rq indicates that the folder ucom has a selection
+list produced by \fIpick\fR.
+If \*(lqothers\*(rq had appeared in parentheses at
+the right of a line, it would indicate that there are files in
+the folder directory that don't belong under the MH file naming
+scheme.
+.PP
+The header is output if either an `\-all' or a `\-header' switch
+is specified; it is suppressed by `\-noheader'.
+Also, if \fIfolder\fR
+is invoked by a name ending with \*(lqs\*(rq (e.g., \fIfolders\fR),
+`\-all' is assumed.
+A `\-total' switch will produce only the
+summary line.
+.PP
+If `\-fast' is given, only the folder name (or names in the
+case of `\-all') will be listed.
+(This is faster because the
+folders need not be read.)
+.PP
+The switches `\-up' and `\-down' change the folder to be the
+one above or below the current folder.
+That is, \*(lqfolder \-down\*(rq
+will set the folder to \*(lq<current\-folder>/select\*(rq, and if the
+current folder is a selection-list folder, \*(lqfolder \-up\*(rq will
+set the current folder to the parent of the selection-list.
+(See \fIpick\fR for details on selection-lists.)
+.PP
+The `\-pack' switch will compress the message names in a folder, removing
+holes in message numbering.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+/bin/ls To fast-list the folders
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to the current folder
+`msg' defaults to none
+`\-nofast'
+`\-noheader'
+`\-nototal'
+`\-nopack'
+.fi
+.SH CONTEXT
+If `+folder' and/or `msg' are given, they will become the
+current folder and/or message.
--- /dev/null
+.TH FORW 1 "3 August 1983"
+.UC 4
+.SH NAME
+forw \- forward messages
+.SH SYNOPSIS
+.B forw
+[ +folder ] [ msgs ] [ \-editor editor ] [ \-form formfile ]
+[ \-annotate ] [ \-noannotate ]
+[ \-inplace ] [ \-noinplace ] [ \-help ]
+.SH DESCRIPTION
+\fIForw\fR may be used to prepare a message containing other
+messages.
+It constructs the new message from the components file
+or `\-form formfile' (see
+.IR comp (1)),
+with a body composed of the message(s) to be forwarded.
+An editor is invoked as in \fIcomp\fR,
+and after editing is complete, the user is prompted before the message
+is sent.
+.PP
+If the `\-annotate' switch is given, each message being
+forwarded will be annotated with the lines
+.nf
+
+ Forwarded: \*(<<date\*(>>
+ Forwarded: To: names
+ Forwarded: cc: names
+
+.fi
+where each \*(lqTo:\*(rq and \*(lqcc:\*(rq list contains as many lines as required.
+This annotation will be done only if the message is sent directly
+from \fIforw\fR.
+If the message is not sent immediately from \fIforw\fR,
+\*(lqcomp \-use\*(rq may be used in a later session to re-edit and send
+the constructed message, but the annotations won't take place.
+The `\-inplace' switch permits annotating a message in place in
+order to preserve its links.
+.PP
+See \fIcomp\fR for a description of the `\-editor' switch.
+.SH FILES
+.nf
+.ta \w'or <mh-dir>/components 'u
+/etc/mh/components The message skeleton
+or <mh-dir>/components Rather than the standard skeleton
+$HOME/\*.mh\(ruprofile The user profile
+<mh-dir>/draft The default message file
+/usr/bin/send To send the composed message
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'<lasteditor>\-next: 'u
+Path: To determine the user's MH directory
+Editor: To override the use of /bin/ned as the default editor
+Current-Folder: To find the default current folder
+<lasteditor>\-next: editor to be used after exit from <lasteditor>
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to the current folder
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.fi
+.SH CONTEXT
+If a +folder is specified, it will become
+the current folder, and the current message will be set to
+the first message being forwarded.
--- /dev/null
+.TH INC 1 "3 August 1983"
+.UC 4
+.SH NAME
+inc \- incorporate new mail
+.SH SYNOPSIS
+.B inc
+[ +folder ] [ \-audit audit-file ] [ \-help ]
+.SH DESCRIPTION
+\fIInc\fR incorporates mail from the user's incoming mail drop
+(\*.mail) into an MH folder.
+If `+folder' isn't specified,
+the folder named \*(lqinbox\*(rq in the user's MH directory will be used.
+The
+new messages being incorporated are assigned numbers starting
+with the next highest number in the folder.
+If the specified (or
+default) folder doesn't exist, the user will be queried prior to
+its creation.
+As the messages are processed, a \fIscan\fR listing
+of the new mail is produced.
+.PP
+If the user's profile contains a \*(lqMsg\-Protect: nnn\*(rq entry, it
+will be used as the protection on the newly created messages,
+otherwise the MH default of 664 will be used.
+During all
+operations on messages, this initially assigned protection will
+be preserved for each message, so \fIchmod\fR(I) may be used to set a
+protection on an individual message, and its protection will be
+preserved thereafter.
+.PP
+If the switch `\-audit audit-file' is specified (usually as a
+default switch in the profile), then \fIinc\fR will append a header
+line and a line per message to the end of the specified
+audit-file with the format:
+.nf
+
+.ti 1i
+\*(<<inc\*(>> date
+.ti 1.5i
+<scan line for first message>
+.ti 1.5i
+<scan line for second message>
+.ti 2.5i
+<etc.>
+
+.fi
+This is useful for keeping track of volume and source of incoming
+mail.
+Eventually, \fIrepl\fR, \fIforw\fR, \fIcomp\fR, and \fIdist\fR may also
+produce audits to this (or another) file, perhaps with
+\*(lqMessage-Id:\*(rq information to keep an exact correspondence history.
+\*(lqAudit-file\*(rq will be in the user's MH directory unless a full
+path is specified.
+.PP
+\fIInc\fR will incorporate even illegally formatted messages into the
+user's MH folder, inserting a blank line prior to the offending
+component and printing a comment identifying the bad message.
+.PP
+In all cases, the \*.mail file will be zeroed.
+.SH FILES
+.nf
+.ta \w'<mh-dir>/audit-file 'u
+$HOME/\*.mh\(ruprofile The user profile
+$HOME/\*.mail The user's mail drop
+<mh-dir>/audit-file Audit trace file (optional)
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Folder\-Protect: 'u
+Path: To determine the user's MH directory
+Folder\-Protect: For protection on new folders
+Msg\-Protect: For protection on new messages
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to \*(lqinbox\*(rq
+.fi
+.SH CONTEXT
+The folder into which the message is
+being incorporated will become the
+current folder, and the first message incorporated will be the
+current message.
+This leaves the context ready for a \fIshow\fR
+of the first new message.
--- /dev/null
+.TH NEXT 1 "3 August 1983"
+.UC 4
+.SH NAME
+next \- show the next message
+.SH SYNOPSIS
+.B next
+[ +folder ] [ \-switches for \fIl\fR ] [ \-help ]
+.SH DESCRIPTION
+\fINext\fR performs a \fIshow\fR on the next message in the
+specified (or current) folder.
+Like \fIshow\fR, it passes any
+switches on to the program \fIl\fR, which is called to list the
+message.
+This command is exactly equivalent to \*(lqshow next\*(rq.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH CONTEXT
+If a folder is specified, it will become the current folder, and the
+message that is shown (i.e., the next message in sequence)
+will become the current message.
--- /dev/null
+.TH PICK 1 "3 August 1983"
+.UC 4
+.SH NAME
+pick \- select messages by content
+.SH SYNOPSIS
+.fc ^ ~
+.ta .4i 1.8i
+.nf
+.in .5i
+^pick~^^\0\-cc~^ \%[\-src\ +folder] \%[msgs] \%[\-help] \%[\-scan] \%[\-noscan]
+^^^\0\-date~^ \%[\-show] \%[\-noshow] \%[\-nofile] \%[\-nokeep]
+^^^\0\-from~^
+^^^\s+2\b'\(lt\(bv\(bv\(lk\(bv\(bv\(lb'\s0 \-search~\s+2\b'\(rt\(bv\(bv\(rk\(bv\(bv\(rb'\s0^ pattern
+^^^\0\-subject~^
+^^^\0\-to~^ \%[\-file \%[\-preserve] \%[\-link] \%+folder\ ... \%[\-nopreserve] \%[\-nolink] ]
+^^^\0\-\-component~^ \%[\-keep \%[\-stay] \%[\-nostay] \%[+folder\ ...]\ ]
+.fi
+.fc
+
+.re
+.ti .5i
+typically:
+.in 1i
+pick\0\-from\0jones\0\-scan
+.br
+pick\0\-to\0holloway
+.br
+pick\0\-subject\0ned\0\-scan\0\-keep
+.SH DESCRIPTION
+\fIPick\fR searches messages within a folder for the specified
+contents, then performs several operations on the selected
+messages.
+.PP
+A modified \fIgrep\fR(I) is used to perform the searching, so the
+full regular expression (see \fIed\fR(I)) facility is available
+within `pattern'.
+With `\-search', pattern is used directly,
+and with the others, the grep pattern constructed is:
+.nf
+
+.ti +.5i
+\*(lq^component:\*.\*(**pattern\*(rq
+
+.fi
+This means that the pattern specified for a `\-search' will be
+found everywhere in the message, including the header and the body,
+while the other search requests are limited to the single
+specified component.
+The expression `\-\-component pattern'
+is a shorthand for
+specifying `\-search \*(lqcomponent:\*.\*(**pattern\*(rq\ '; it is used to pick
+a component not in the set [cc date from subject to].
+An
+example is \*(lqpick \-\-reply\-to pooh \-show\*(rq.
+.PP
+Searching is performed on a per-line basis.
+Within the header of
+the message, each component is treated as one long line, but in
+the body, each line is separate.
+Lower-case letters in the
+search pattern will match either lower or upper case in the
+message, while upper case will match only upper case.
+.PP
+Once the search has been performed, the selected messages
+are scanned (see \fIscan\fR) if the `\-scan' switch is given, and
+then they are shown (see \fIshow\fR) if the `\-show' switch is
+given.
+After these two operations, the file operations (if
+requested) are performed.
+.PP
+The `\-file' switch operates exactly like the \fIfile\fR command, with the
+same meaning for the `\-preserve' and `\-link' switches.
+.PP
+The `\-keep' switch is similar to `\-file', but it produces a folder that
+is a subfolder of the folder being searched and defines it as
+the current folder (unless the `\-stay' flag is used).
+This
+subfolder contains the messages which matched the search
+criteria.
+All of the MH commands may be used with the sub-folder
+as the current folder.
+This gives the user considerable power
+in dealing with subsets of messages in a folder.
+.PP
+The messages in a folder produced by `\-keep' will always have the
+same numbers as they have in the source folder (i.e., the
+`\-preserve' switch is automatic).
+This way, the message
+numbers are consistent with the folder from which the messages
+were selected.
+Messages are not removed from the source folder
+(i.e., the `\-link' switch is assumed).
+If a `+folder' is not
+specified, the standard name \*(lqselect\*(rq will be used.
+(This is the
+meaning of \*(lq(select)\*(rq when it appears in the output of the
+\fIfolder\fR command.) If `+folder' arguments are given to
+`\-keep', they will be used rather than \*(lqselect\*(rq for the names
+of the subfolders.
+This allows for several subfolders to be
+maintained concurrently.
+.PP
+When a `\-keep' is performed, the subfolder becomes the current folder.
+This can be overridden by use
+of the `\-stay' switch.
+.PP
+Here's an example:
+
+.nf
+\01 % folder +inbox
+\02 inbox+ has 16 messages ( 3\- 22); cur= 3.
+\03 % pick \-from dcrocker
+\04 6 hits.
+\05 [+inbox/select now current]
+\06 % folder
+\07 inbox/select+ has \06 messages ( 3\- 16); cur= 3.
+\08 % scan
+.ds p \\h'\\w'+'u'
+\09 \03+ 6/20 Dcrocker Re: ned file update issue...
+10 \06\*p 6/23 Dcrocker removal of files from /tm...
+11 \08\*p 6/27 Dcrocker Problems with the new ned...
+12 13\*p 6/28 d\h'\w'D'u-\w'd'u'crocker newest nned \*(<<I would ap...
+13 15\*p 7/\05 Dcrocker nned \*(<<Last week I asked...
+14 16\*p 7/\05 d\h'\w'D'u-\w'd'u'crocker message id format \*(<<I re...
+15 % show all | print
+16 [produce a full listing of this set of messages on the line printer.]
+17 % folder \-up
+18 inbox+ has 16 messages ( 3\- 22); cur= 3; (select).
+19 % folder \-down
+20 inbox/select+ has 6 messages ( 3\- 16); cur= 3.
+21 % rmf
+22 [+inbox now current]
+23 % folder
+24 inbox+ has 16 messages ( 3\- 22); cur= 3.
+.fi
+
+This is a rather lengthy example, but it shows the power of the
+MH package.
+In item 1, the current folder is set to inbox.
+In 3,
+all of the messages from dcrocker are found in inbox and linked
+into the folder \*(lqinbox/select\*(rq.
+(Since no action switch is
+specified, `\-keep' is assumed.) Items 6 and 7 show that this
+subfolder is now the current folder.
+Items 8 through 14 are a
+\fIscan\fR of the selected messages (note that they are all from dcrocker
+and are all in upper and lower case).
+Item 15 lists all of the messages to
+the high-speed printer.
+Item 17 directs \fIfolder\fR to set the
+current folder to the parent of the selection-list folder, which
+is now current.
+Item 18 shows that this has been done.
+Item 19 resets
+the current folder to the selection list, and 21 removes the
+selection-list folder and resets the current folder to the
+parent folder, as shown in 22 and 23.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Folder\-Protect: For protection on new folders
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`\-src +folder' defaults to current
+`msgs' defaults to all
+`\-keep +select' is the default if no `\-scan', `\-show', or `\-file' is specified
+.fi
+.SH CONTEXT
+If a `\-src +folder' is specified, it will
+become the current folder, unless a `\-keep' with 0 or 1
+folder arguments makes the selection-list subfolder the
+current folder.
+Each selection-list folder will have its
+current message set to the first of the messages linked into
+it unless the selection list already existed, in which case the
+current message won't be changed.
--- /dev/null
+.TH PREV 1 "3 August 1983"
+.UC 4
+.SH NAME
+prev \- show the previous message
+.SH SYNOPSIS
+.B prev
+[ +folder ] [ \-switches for \fIl\fR ] [ \-help ]
+.SH DESCRIPTION
+\fIPrev\fR performs a \fIshow\fR on the previous message in the specified
+(or current) folder.
+Like \fIshow\fR, it passes any switches on to the
+program \fIl\fR, which is called to list the message.
+This command
+is exactly equivalent to \*(lqshow prev\*(rq.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH CONTEXT
+If a folder is specified, it will become current, and the
+message that is shown (i.e., the previous message in sequence)
+will become the current message.
--- /dev/null
+.TH PROMPTER 1 "3 August 1983"
+.UC 4
+.SH NAME
+prompter \- prompting editor front end
+.SH SYNOPSIS
+.B prompter
+[ \-erase chr ] [ \-kill chr ] [ \-help ]
+.SH DESCRIPTION
+This program is not called directly but takes the place
+of an editor and acts as an editor front end.
+\fIPrompter\fR is an editor which allows rapid composition of
+messages.
+It is particularly useful to network and low-speed
+(less than 2400 baud) users of MH.
+It is an MH program in that
+it can have its own profile entry with switches, but it can't
+be invoked directly as all other MH commands can; it is an editor
+in that it is invoked by an \*(lq\-editor prompter\*(rq switch or by the
+profile entry \*(lqEditor: prompter\*(rq, but functionally it is merely
+a text-collector and not a true editor.
+.PP
+\fIPrompter\fR expects to be called from \fIcomp\fR, \fIrepl\fR, \fIdist\fR, or
+\fIforw\fR, with a draft file as an argument.
+For example, \*(lqcomp
+\-editor prompter\*(rq will call \fIprompter\fR with the file \*(lqdraft\*(rq already set
+up with blank components.
+For each blank component it finds in
+the draft, it prompts the user and accepts a response.
+A <RETURN> will cause the whole component to be left out.
+A \*(lq\\\*(rq
+preceding a <RETURN> will continue the response on the next line,
+allowing for multiline components.
+.PP
+Any component that is non-blank will be copied and echoed to the
+terminal.
+.PP
+The start of the message body is prompted by a line of
+dashes.
+If the body is non-blank, the prompt is
+\*(lq--------Enter additional text\*(rq.
+Message-body typing is terminated with
+a <CTRL-D> (or <OPEN>).
+Control is returned to the calling
+program, where the user is asked \*(lqWhat now?\*(rq.
+See \fIcomp\fR for
+the valid options.
+.PP
+The line editing characters for kill and erase may be
+specified by the user via the arguments \*(lq\-kill chr\*(rq and \*(lq\-erase
+chr\*(rq, where chr may be a character; or \*(lq\\nnn\*(rq, where nnn is the
+octal value for the character.
+(Again, these may come from the
+default switches specified in the user's profile.)
+.PP
+A <DEL> during message-body typing is equivalent to
+<CTRL-D> for compatibility with NED.
+A <DEL> during
+component typing will abort the command that invoked
+\fIprompter\fR.
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'prompter-next: 'u
+prompter-next: editor to be used on exit from \fIprompter\fR
+.fi
--- /dev/null
+.TH REPL 1 "3 August 1983"
+.UC 4
+.SH NAME
+repl \- reply to a message
+.SH SYNOPSIS
+.B repl
+[ +folder ] [ msg ] [ \-editor editor ] [ \-inplace ] [ \-annotate ]
+[ \-help ] [ \-noinplace ] [ \-noannotate ]
+.SH DESCRIPTION
+\fIRepl\fR aids a user in producing a reply to an existing
+message.
+In its simplest form (with no arguments), it will set up
+a message-form skeleton in reply to the current message in the
+current folder, invoke the editor, and send the composed
+message if so directed.
+The composed message is constructed as
+follows:
+.nf
+
+.in 1i
+To: <Reply-To> or <From>
+cc: <cc>, <To>
+Subject: Re: <Subject>
+In-reply-to: Your message of <Date>
+.ti +\w'In-reply-to: 'u
+<Message-Id>
+.in .5i
+
+.fi
+where field names enclosed in angle brackets (< >) indicate the
+contents of the named field from the message to which the reply
+is being made.
+Once the skeleton is constructed, an editor is
+invoked (as in \fIcomp\fR, \fIdist\fR, and \fIforw\fR).
+While in the editor,
+the message being replied to is available through a link named
+\*(lq@\*(rq.
+In NED, this means the replied-to message may be \*(lqused\*(rq
+with \*(lquse @\*(rq, or put in a window by \*(lqwindow @\*(rq.
+.PP
+As in \fIcomp\fR, \fIdist\fR, and \fIforw\fR, the user will be queried
+before the message is sent.
+If `\-annotate' is
+specified, the replied-to message will be annotated with the
+single line
+.nf
+
+.ti +.5i
+Replied: \*(<<Date\*(>>.
+
+.fi
+The command
+\*(lqcomp \-use\*(rq may be used to pick up interrupted editing, as in
+\fIdist\fR and \fIforw\fR; the `\-inplace' switch annotates the message in
+place, so that all folders with links to it will see the annotation.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+<mh-dir>/draft The constructed message file
+/usr/bin/send To send the composed message
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Editor: To override the use of /bin/ned as the default editor
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-editor' defaults to /bin/ned
+`\-noannotate'
+`\-noinplace'
+.fi
+.SH CONTEXT
+If a `+folder' is specified, it will become the current
+folder, and the current message will be set to the replied-to
+message.
--- /dev/null
+.TH RMF 1 "3 August 1983"
+.UC 4
+.SH NAME
+rmf \- remove folder
+.SH SYNOPSIS
+.B rmf
+[ +folder ] [ \-help ]
+.SH DESCRIPTION
+\fIRmf\fR removes all of the files (messages) within the specified
+(or default) folder, and then removes the directory (folder).
+If
+there are any files within the folder which are not a part of MH,
+they will \fInot\fR be removed, and an error will be produced.
+If the
+folder is given explicitly or the current folder is a
+subfolder (i.e., a selection list from \fIpick\fR), it will be
+removed without confirmation.
+If no argument is specified and
+the current folder is not a selection-list folder, the
+user will be asked for confirmation.
+.PP
+\fIRmf\fR irreversibly deletes messages that don't have other links,
+so use it with caution.
+.PP
+If the folder being removed is a subfolder, the parent
+folder will become the new current folder, and \fIrmf\fR will
+produce a message telling the user this has happened.
+This
+provides an easy mechanism for selecting a set of messages,
+operating on the list, then removing the list and returning to
+the current folder from which the list was extracted.
+(See the
+example under \fIpick\fR.)
+.PP
+The files that \fIrmf\fR will delete are cur, any file beginning
+with a comma, and files with purely numeric names.
+All others
+will produce error messages.
+.PP
+\fIRmf\fR of a read-only folder will delete the \*(lqcur\-\*(rq entry from the
+profile without affecting the folder itself.
+.SH FILES
+.nf
+.ta \w'or <mh-dir>/components 'u
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to current, usually with confirmation
+.fi
+.SH CONTEXT
+\fIRmf\fR will set the current folder to the parent folder if a
+subfolder is removed; or if the current folder is removed,
+it will make \*(lqinbox\*(rq current.
+Otherwise, it doesn't change the
+current folder or message.
--- /dev/null
+.TH RMM 1 "3 August 1983"
+.UC 4
+.SH NAME
+rmm \- remove messages
+.SH SYNOPSIS
+.B rmm
+[ +folder ] [ msgs ] [ \-help ]
+.SH DESCRIPTION
+\fIRmm\fR removes the specified messages by renaming the message
+files with preceding commas.
+(This is the Rand-UNIX backup file convention.)
+.PP
+The current message is not changed by \fIrmm\fR, so a \fInext\fR will
+advance to the next message in the folder as expected.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to current
+`msgs' defaults to cur
+.fi
+.SH CONTEXT
+If a folder is given, it will become current.
--- /dev/null
+.SC SCAN
+.TH SCAN 1 "3 August 1983"
+.UC 4
+.SH NAME
+scan \- produce a one-line-per-message scan listing
+.SH SYNOPSIS
+.B scan
+[ +folder ] [ msgs ] [ \-ff ] [ \-header ] [ \-help ]
+[ \-noff ] [ \-noheader ]
+.SH DESCRIPTION
+\fIScan\fR produces a one-line-per-message listing of the specified
+messages.
+Each \fIscan\fR line contains the message number (name),
+the date, the \*(lqFrom\*(rq field, the \*(lqSubject\*(rq field, and, if room
+allows, some of the body of the message.
+For example:
+.nf
+
+.ta .5i 1.2i 2.6i
+^ #~^^Date~^^ From~^Subject\ \ \ \ \[\*(<<Body]
+^15+~^^7/\05~^^Dcrocker~^nned \*(<<Last week I asked some of
+^16\ \-~^^7/\05~^^dcrocker~^message id format \*(<<I recommend
+^18~^^7/\06~^^Obrien~^Re: Exit status from mkdir
+^19~^^7/\07~^^Obrien~^"scan" listing format in MH
+.re
+
+.fi
+The `+' on message 15 indicates that it is the current message.
+The `\-' on message 16 indicates that it has been
+replied to, as indicated by a \*(lqReplied:\*(rq component produced by
+an `\-annotate' switch to the \fIrepl\fR command.
+.PP
+If there is sufficient room left on the \fIscan\fR line after the
+subject, the line will be filled with text from the body,
+preceded by \*(<<.
+\fIScan\fR actually reads each of the specified
+messages and parses them to extract the desired fields.
+During parsing, appropriate error messages will be produced if
+there are format errors in any of the messages.
+.PP
+The `\-header' switch produces a header line prior to the \fIscan\fR
+listing, and the `\-f\&f' switch will cause a form feed to be
+output at the end of the \fIscan\fR listing.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+^$HOME/\*.mh\(ruprofile~^The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to current
+`msgs' defaults to all
+`\-nof\&f'
+`\-noheader'
+.fi
+.SH CONTEXT
+If a folder is given, it will become current.
+The current message is unaffected.
--- /dev/null
+.SC SEND
+.TH SEND 1 "3 August 1983"
+.UC 4
+.SH NAME
+send \- send a message
+.SH SYNOPSIS
+.B send
+[ file ] [ \-draft ] [ \-verbose ] [ \-format ] [ \-msgid ]
+[ \-help ] [ \-noverbose ] [ \-noformat ] [ \-nomsgid ]
+.SH DESCRIPTION
+\fISend\fR will cause the specified file (default <mh-dir>/draft) to
+be delivered to each of the addresses in the \*(lqTo:\*(rq, \*(lqcc:\*(rq, and \*(lqBcc:\*(rq
+fields of the message.
+If `\-verbose' is specified, \fIsend;\fR
+will monitor the delivery of local and net mail.
+\fISend\fR with no
+argument will query whether the draft is the intended file, whereas
+`\-draft' will suppress this question.
+Once the message has
+been mailed (or queued) successfully, the file will be renamed
+with a leading comma, which allows it to be retreived until the
+next draft message is sent.
+If there are errors in the
+formatting of the message, \fIsend;\fR will abort with a (hopefully)
+helpful error message.
+.PP
+If a \*(lqBcc:\*(rq field is encountered, its addresses will be used for
+delivery, but the \*(lqBcc:\*(rq field itself will be deleted from all
+copies of the outgoing message.
+.PP
+Prior to sending the message, the fields \*(lqFrom: user\*(rq, and
+\*(lqDate: now\*(rq will be prepended to the message.
+If `\-msgid' is
+specified, then a \*(lqMessage-Id:\*(rq field will also be added to the
+message.
+If the message already contains a \*(lqFrom:\*(rq field, then a
+\*(lqSender: user\*(rq field will be added instead.
+(An already existing
+\*(lqSender:\*(rq field will be deleted from the message.)
+.PP
+If the user doesn't specify `\-noformat', each of the entries in
+the \*(lqTo:\*(rq and \*(lqcc:\*(rq fields will be replaced with \*(lqstandard\*(rq format
+entries.
+This standard format is designed to be usable by all
+of the message handlers on the various systems around the
+ARPANET.
+.PP
+If an \*(lqFcc: folder\*(rq is encountered, the message will be copied
+to the specified folder in the format in which it will appear to any
+receivers of the message.
+That is, it will have the prepended
+fields and field reformatting.
+.PP
+If a \*(lqDistribute-To:\*(rq field is encountered, the message
+is handled as a redistribution message (see \fIdist\fR for
+details), with \*(lqDistribution-Date: now\*(rq and \*(lqDistribution-From: user\*(rq
+added.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Path: 'u
+Path: To determine the user's MH directory
+.fi
+.SH DEFAULTS
+.nf
+`file' defaults to draft
+`\-noverbose'
+`\-format'
+`\-nomsgid'
+.fi
+.SH CONTEXT
+\fISend\fR has no effect on the current message or folder.
--- /dev/null
+.TH SHOW 1 "3 August 1983"
+.UC 4
+.SH NAME
+show \- show (list) messages
+.SH SYNOPSIS
+.B show
+[ +folder ] [ msgs ] [ \-pr ] [ \-nopr ] [ \-draft ] [ \-help ]
+[ \fIl\fR or \fIpr\fR switches ]
+.SH DESCRIPTION
+\fIShow\fR lists each of the specified messages to the standard
+output (typically, the terminal).
+The messages are listed exactly
+as they are, with no reformatting.
+A program called \fIl\fR is
+invoked to do the listing, and any switches not recognized by
+\fIshow\fR are passed along to \fIl\fR.
+.PP
+If no \*(lqmsgs\*(rq are specified, the current message is used.
+If
+more than one message is specified, \fIl\fR will prompt for a
+<return> prior to listing each message.
+.PP
+\fIl\fR will list each message, a page at a time.
+When the end of
+page is reached, \fIl\fR will ring the bell and wait for a <RETURN>
+or <CTRL-D>.
+If a <return> is entered, \fIl\fR will clear the
+screen before listing the next page, whereas <CTRL-D> will not.
+The switches to \fIl\fR are
+`\-p#' to indicate the page length in lines, and `\-w#' to
+indicate the width of the page in characters.
+.PP
+If the standard output is not a terminal, no queries are made,
+and each file is listed with a one-line header and two lines of
+separation.
+.PP
+If `\-pr' is specified, then \fIpr\fR(I) will be invoked rather than
+\fIl\fR, and the switches (other than `\-draft') will be passed
+along.
+\*(lqShow \-draft\*(rq will list the file <mh-dir>/draft if it
+exists.
+.SH FILES
+.nf
+.ta \w'$HOME/\*.mh\(ruprofile 'u
+$HOME/\*.mh\(ruprofile The user profile
+/bin/l Screen-at-a-time list program
+/bin/pr \fIpr\fR(1)
+.fi
+.SH "PROFILE COMPONENTS"
+.nf
+.ta \w'Current-Folder: 'u
+Path: To determine the user's MH directory
+Current-Folder: To find the default current folder
+.fi
+.SH DEFAULTS
+.nf
+`+folder' defaults to current
+`msgs' defaults to cur
+`\-nopr'
+.fi
+.SH CONTEXT
+If a folder is given, it will become the current message.
+The last message
+listed will become the current message.
--- /dev/null
+/*
+ * This is the program called to deliver mail
+ * on systems where we try to maintain compatibility
+ * with the standard message format.
+ */
+
+char *Mailprog = "/usr/ucb/Mail";
--- /dev/null
+CC = cc -I../cmds
+CFLAGS=-O
+
+strings.a: anoyes.o \
+ components.o \
+ current.o \
+ defalt.o \
+ distcomps.o \
+ draft.o \
+ fileproc.o \
+ foldprot.o \
+ hostname.o \
+ installproc.o \
+ listname.o \
+ lockdir.o \
+ lsproc.o \
+ mailboxes.o \
+ mailproc.o \
+ mh_prof.o \
+ mhnews.o \
+ msgprot.o \
+ pfolder.o \
+ prproc.o \
+ scanproc.o \
+ sendproc.o \
+ showproc.o \
+ stdcomps.o \
+ stddcomps.o \
+ sysed.o \
+ Mailprog.o \
+ unixtomh.o \
+ localname.o
+
+ ar cr strings.a *.o
+
+clean:
+ rm -f *.o strings.a
--- /dev/null
+char *anoyes[] = {
+ "no", 0,
+ "yes", 0,
+ 0,
+};
--- /dev/null
+char *components = "components";
--- /dev/null
+char *current = "cur";
--- /dev/null
+char *defalt = "inbox";
--- /dev/null
+char *distcomps = "distcomps";
--- /dev/null
+char *draft = "draft";
--- /dev/null
+/*
+ * This program is usually called directly by users, but it is
+ * also invoked by the deliver program to process an "fcc".
+ */
+
+char *fileproc = "/usr/new/mh/refile";
--- /dev/null
+/*
+ * Folders (directories) are created with this protection (mode)
+ */
+
+char *foldprot = "0751";
--- /dev/null
+/*
+ * For ARPANET mail, this is the local-site's Host name.
+ * (currently not used.)
+ */
+
+char *hostname = "Berkeley";
--- /dev/null
+/*
+ * When a user runs an MH program for the first time, this program
+ * is called to create his MH profile, and mail directory.
+ */
+
+char *installproc = "/usr/new/lib/mh/install-mh";
--- /dev/null
+char *listname = "select";
--- /dev/null
+/*
+ * Local network host name
+ */
+
+char *localname = "CSVAX";
--- /dev/null
+/*
+ * This is where the lock files are kept. It MUST be on the same
+ * file system as the "mailboxes" directory. It also must be read/
+ * write by the world. When a mailbox needs locking (while being
+ * read and cleared by inc, or written by deliver), a link to the
+ * mailbox is made in this directory, under the same name (i.e., the
+ * users name). Links are one of the few things even a privileged
+ * process (deliver) cannot over-ride. The deliver process waits
+ * for lockwait seconds for the lock to clear, then it over-rides
+ * the lock. This number should be set around 15-30 seconds in the
+ * case of a VERY loaded system.
+ */
+
+char *lockdir = "/usr/spool/mail/";
+int lockwait = 15; /* Seconds */
--- /dev/null
+/*
+ * This is standard ls, but "folder -all -short" calls it with
+ * a -x switch meaning "list only directories".
+ *
+ * Also, its nice to have columnated output rather than a simple
+ * list... (personal prejudice).
+ */
+
+char *lsproc = "/usr/ucb/ls";
--- /dev/null
+/*
+ * This is where the user mailboxes are kept. On our 11/70 they were
+ * kept in each users $HOME directory. This is where the VAX login
+ * program is looking for them, as well as the old BELL mail.
+ */
+
+char *mailboxes = "/usr/spool/mail/";
--- /dev/null
+/*
+ * This is the path for the Bell equivalent mail program... Used
+ * by "news -send" to send news items to the news user.
+ */
+
+char *mailproc = "/bin/mail";
--- /dev/null
+/*
+ * This is the name of the file used to store
+ * the user's MH profile
+ */
+
+char *mh_defs = "/.mh_profile";
--- /dev/null
+/*
+ * This is the delivery program called ONLY through send to
+ * actually deliver mail to users. It is fairly small, and
+ * must run SUID ROOT, to create new mailboxes.
+ */
+
+/* char *mh_deliver = "/usr/new/lib/mh/deliver"; */
--- /dev/null
+char *mh_prof = "/.mh_profile";
--- /dev/null
+/*
+ * This program is called to print out MH news IF NEWS is defined
+ * when the MH programs are compiled. This whole mechanism has not
+ * been tested under version 7!
+ */
+
+char *mhnews = "/usr/new/mh/news";
--- /dev/null
+/*
+ * Every NEW message will be created with this protection. When a
+ * message is filed it retains its protection, so this only applies
+ * to messages coming in through inc.
+ */
+
+char *msgprot = "0664";
--- /dev/null
+char *pfolder = "current-folder";
--- /dev/null
+/*
+ * This is the std BELL pr, which is invoked through show with the
+ * -pr switch.
+ */
+
+char *prproc = "/bin/pr";
--- /dev/null
+/*
+ * This program is usually called directly by users, but it is
+ * also invoked by "pick -scan".
+ */
+
+char *scanproc = "/usr/new/mh/scan";
--- /dev/null
+/*
+ * This program is usually called by one of the message composition
+ * programs: comp, repl, dist, and forw, but it may also be called
+ * directly to send a message previously composed.
+ */
+
+char *sendproc = "/usr/new/mh/send";
--- /dev/null
+/*
+ * This program is called to list messages. At Rand, the program
+ * c stops at the end of each page and waits for a <return> or
+ * <open> to continue. Eventually, this path should invoke a
+ * special program which displays messages much more intelligently--
+ * such as layed out nicely on the screen.
+ */
+
+char *showproc = "/usr/ucb/more"; /* 5/6/79 */
--- /dev/null
+/*
+ * This is the standard skeleton for message composition with both
+ * comp and forw.
+ */
+
+char *stdcomps = "/usr/new/lib/mh/components";
--- /dev/null
+/*
+ * This is the standard skeleton for message composition with dist.
+ */
+
+char *stddcomps = "/usr/new/lib/mh/distcomps";
--- /dev/null
+/*
+ * This file gives extern declarations to all the strings
+ * that we might ever reference.
+ *
+ * I don't know if this what strings.h is supposed to be,
+ * but this is as good a first guess as I can handle.
+ */
+
+extern char *anoyes[];
+extern char *components;
+extern char *current;
+extern char *defalt;
+extern char *distcomps;
+extern char *draft;
+extern char *fileproc;
+extern char *foldprot;
+extern char *hostname;
+extern char *installproc;
+extern char *listname;
+extern char *lockdir;
+extern int lockwait;
+extern char *lsproc;
+extern char *mailboxes;
+extern char *mailproc;
+extern char *mh_deliver;
+extern char *mh_prof;
+extern char *mhnews;
+extern char *msgprot;
+extern char *pfolder;
+extern char *prproc;
+extern char *scanproc;
+extern char *sendproc;
+extern char *showproc;
+extern char *stdcomps;
+extern char *stddcomps;
+extern char *sysed;
--- /dev/null
+/*
+ * This is the editor invoked by the various message composition
+ * programs. It SHOULD be a 2-D scope editor, such as Rand's Ned
+ * or Berkeley's ex, but any editor will work. If you don't have
+ * a scope editor, you might want to default to prompter, but it
+ * works very marginally with forw and dist.
+ */
+
+char *sysed = "/bin/e";
--- /dev/null
+/*
+ * This program is called to convert UNIX style
+ * mailboxes to MH style mail boxes, if we are trying
+ * to stay UNIX mailbox compatible.
+ */
+
+char *unixtomh = "/usr/new/lib/mh/unixtomh";
--- /dev/null
+subs.a: add.o \
+ ambigsw.o \
+ atooi.o \
+ brkstring.o \
+ cdate.o \
+ cndfree.o \
+ concat.o \
+ copy.o \
+ copyip.o \
+ cputc.o \
+ done.o \
+ fdcompare.o \
+ gans.o \
+ getans.o \
+ getcpy.o \
+ help.o \
+ invo_name.o \
+ locv.o \
+ m_convert.o \
+ m_delete.o \
+ m_edit.o \
+ m_find.o \
+ m_getdefs.o \
+ m_getfld.o \
+ m_getfolder.o \
+ m_gmprot.o \
+ m_gmsg.o \
+ m_maildir.o \
+ m_name.o \
+ m_replace.o \
+ m_send.o \
+ m_setcur.o \
+ m_update.o \
+ makedir.o \
+ makename.o \
+ peekc.o \
+ pr_array.o \
+ printsw.o \
+ putdate.o \
+ r1bindex.o \
+ showfile.o \
+ smatch.o \
+ ssequal.o \
+ trimcpy.o \
+ type.o \
+ uleq.o
+
+ ar cr subs.a `lorder *.o | tsort`
+
+.c.o:
+ cc -I../cmds -c -O $*.c
+ -@ld -x -r $@
+ @mv a.out $@
+
+clean:
+ rm -f *.o subs.a
--- /dev/null
+char *add(this, that)
+register char *this, *that;
+{
+ register char *r;
+
+ if(!this)
+ this = "";
+ if(!that)
+ that = "";
+ r = (char *) malloc(strlen(this)+strlen(that)+1);
+ sprintf(r, "%s%s", that, this);
+ if(*that)
+ cndfree(that);
+ return(r);
+}
--- /dev/null
+#include <stdio.h>
+
+ambigsw(arg, swp)
+char *arg;
+{
+ fprintf(stderr, "%s: ", invo_name());
+ fprintf(stderr, "-%s ambiguous. It matches \n", arg);
+ printsw(arg, swp, "-");
+}
+
--- /dev/null
+atooi(cp)
+register char *cp;
+{
+ register int i, base;
+
+/* base = 10; */
+ i = 0;
+/* if(*cp == '0') */
+ base = 8;
+ while(*cp >= '0' && *cp <= '9') {
+ i *= base;
+ i += *cp++ - '0';
+ }
+ return(i);
+}
--- /dev/null
+#define NSTR 25
+char **brkstring(strg,brksep,brkterm) /* returns pointer to static table of substring ptrs */
+char *strg;
+char *brksep, *brkterm;
+{
+
+ register char c, *bp, *sp;
+ static char *broken[NSTR+1]; /* static array of substring start addresses */
+ int bi;
+
+ sp = strg; /* scan string, replacing separators with zeroes */
+
+ for (bi=0; bi<NSTR; bi++) { /* and entering start addrs in "broken" */
+ while (brkany(c = *sp, brksep)) *sp++ = 0;
+ if (!c || brkany(c, brkterm)) {
+ *sp=0;
+ broken[bi] = 0;
+ return(broken); /* terminator found, finish up */
+ }
+
+ broken[bi] = sp; /* set next start addr */
+
+ while ((c = *++sp) && !brkany(c,brksep) && !brkany(c,brkterm));
+
+ }
+ broken[NSTR] = 0; /* reached limit of NSTR substrings */
+ return (broken);
+}
+
+brkany (chr,strg) /* returns 1 if chr in strg, 0 otherwise */
+char chr,*strg;
+{
+ register char *sp;
+
+ for (sp=strg; *sp; sp++)
+ if (chr == *sp) return (1);
+ return (0);
+}
--- /dev/null
+/* returns date in format dd-mon-yy@hh:mm:ss\0 */
+char *cdate(dataddr)
+long *dataddr;
+{
+ register char *cp;
+ char *ctime();
+
+ cp = ctime(dataddr);
+ cp[1] = cp[8];
+ cp[2] = cp[9];
+ cp[3] = '-';
+ cp[7] = '-';
+ cp[8] = cp[22];
+ cp[9] = cp[23];
+ cp[10] = '@';
+ cp[19] = 0;
+ return(cp+1);
+}
--- /dev/null
+/* Conditional free -- perform a free call if the address passed
+ * is in free storage; else NOP
+ */
+
+
+cndfree(addr)
+char *addr;
+{
+ extern char end;
+
+ if(addr >= &end) free(addr);
+}
--- /dev/null
+#include "mh.h"
+
+char *concat(args)
+char *args;
+{
+ register char **a;
+ register char *cp;
+ register int len;
+ register char *ret;
+
+ len = 1;
+ for(a = &args; *a; )
+ len += strlen(*a++);
+ ret = cp = (char *) malloc(len);
+ for(a = &args; *a; )
+ cp = copy(*a++, cp);
+ return(ret);
+}
--- /dev/null
+char *copy(from,to)
+register char *from, *to;
+{
+ while(*to++ = *from++);
+ return to-1;
+};
--- /dev/null
+int *copyip(ipf, ipt)
+register int *ipf, *ipt;
+{
+ while((*ipt = *ipf) && *ipf++ != -1)
+ ipt++;
+ *ipt = 0;
+ return(ipt);
+}
+
--- /dev/null
+#include <stdio.h>
+
+cputc(chr, ip)
+register FILE *ip;
+{
+ if(ip != NULL) {
+ putc(chr, ip);
+ if(ferror(ip)) {
+ perror("Write error");
+ done(-1);
+ }
+ }
+}
--- /dev/null
+#define NSTR 25
+
+/*
+ * Parse the given string into a number of sub strings separated
+ * by characters in brksep. Terminate on brkterm or 0.
+ */
+
+char **
+brkstring(strg, brksep, brkterm)
+ char *strg;
+ char *brksep, *brkterm;
+{
+ register int c;
+ register char *cp, **ap;
+ static char *broken[NSTR+1];
+
+ cp = strg;
+ ap = broken;
+ for (;;) {
+ if (ap-broken > NSTR) {
+ broken[NSTR] = 0;
+ return(broken);
+ }
+ while (brkany(*cp, brksep))
+ cp++;
+ if (*cp == 0 || *cp == brkterm) {
+done:
+ *ap = 0;
+ return(broken);
+ }
+ *ap++ = cp;
+ while (!brkany(*cp, brksep) && *cp && *cp != brkterm)
+ cp++;
+ if (*cp == 0 || *cp == brkterm) {
+ *cp = 0;
+ goto done;
+ }
+ *cp++ = 0;
+ }
+}
+
+brkany (chr,strg) /* returns 1 if chr in strg, 0 otherwise */
+char chr,*strg;
+{
+ register char *sp;
+
+ for (sp=strg; *sp; sp++)
+ if (chr == *sp) return (1);
+ return (0);
+}
--- /dev/null
+/* This routine is replaced by some modules if they need to do
+ * cleanup. All exits in the code call done rather than exit.
+ */
+
+done(status)
+{
+ exit(status);
+}
--- /dev/null
+fdcompare(fd1, fd2)
+{
+ int n1, n2, resp;
+ register int i;
+ register char *c1, *c2;
+ char b1[512], b2[512];
+
+ resp = 1;
+ while((n1 = read(fd1, b1, 512)) >= 0 &&
+ (n2 = read(fd2, b2, 512)) >= 0 &&
+ n1 == n2) {
+
+ c1 = b1; c2 = b2;
+ for(i = n1 < 512? n1 : 512; i--; )
+ if(*c1++ != *c2++) {
+ resp = 0;
+ goto leave;
+ }
+ if(n1 < 512)
+ goto leave;
+ }
+ resp = 0;
+leave:
+ lseek(fd1, 0l, 0);
+ lseek(fd2, 0l, 0);
+ return(resp);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+gans(prompt, ansp)
+struct swit *ansp;
+{
+ char ansbuf[32];
+ register char *cp;
+ register int i;
+ struct swit *ap;
+
+ for(;;) {
+ printf("%s", prompt);
+ fflush(stdout);
+ cp = ansbuf;
+ while((i = getchar()) != '\n') {
+ if(i == EOF)
+ return(0);
+ if(cp < &ansbuf[31]) {
+ if(i >= 'A' && i <= 'Z')
+ i += 'a'-'A';
+ *cp++ = i;
+ }
+ }
+ *cp = 0;
+ if(ansbuf[0] == '?' || cp == ansbuf) {
+ printf("Options are:\n");
+ for(ap = ansp; ap->sw; ap++)
+ printf(" %s\n", ap->sw);
+ continue;
+ }
+ if((i = smatch(ansbuf, ansp)) < 0) {
+ printf("%s: %s.\n", ansbuf, i == -1? "unknown":"ambiguous");
+ continue;
+ }
+ return(i);
+ }
+}
--- /dev/null
+#include "mh.h"
+#include <signal.h>
+#include <stdio.h>
+
+int g_sigint; /* sensed an interrupt */
+int g_sig();
+
+char **getans(prompt, ansp)
+struct swit *ansp;
+{
+ static char ansbuf[128];
+ register char *cp, **cpp;
+ register int i;
+ struct swit *ap;
+
+ signal(SIGINT, g_sig);
+ for(;;) {
+ printf("%s", prompt);
+ fflush(stdout);
+ cp = ansbuf;
+ while((i = getchar()) != '\n') {
+ if(i == EOF || g_sigint) {
+ g_sigint = 0;
+ return(0);
+ }
+ if(cp < &ansbuf[127])
+ *cp++ = i;
+ }
+ *cp = 0;
+ if(ansbuf[0] == '?' || cp == ansbuf) {
+ printf("Options are:\n");
+ printsw(ALL, ansp, "");
+ continue;
+ }
+ cpp = brkstring(ansbuf, " ", 0);
+ switch(smatch(*cpp, ansp)) {
+ case -2:ambigsw(*cpp, ansp); /* ambiguous */
+ continue;
+ case -1: /* unknown */
+ printf(" -%s unknown. Hit <CR> for help.\n", *cpp);
+ continue;
+ default:
+ return(cpp); /* list, edit, quit, send */
+ }
+ }
+}
+
+
+g_sig()
+{
+ signal(SIGINT, g_sig);
+ g_sigint = 1;
+ return;
+}
--- /dev/null
+char *getcpy(str)
+{
+ register char *cp;
+
+ cp = (char *) malloc(strlen(str) + 1);
+ strcpy(cp, str);
+ return(cp);
+}
--- /dev/null
+#include "mh.h"
+
+help(str, swp)
+char *str;
+{
+ printf("syntax: %s\n", str);
+ printf(" switches are:\n");
+ printsw(ALL, swp, "-");
+}
--- /dev/null
+/*
+ * This routine returns the address on the stack of the text of the
+ * first argument to the process. It only works on the VAX, and only
+ * if the process was not called with 4 empty args in a row.
+ */
+
+char *invo_name()
+{
+ register int *ip;
+
+ ip = (int *) 0x7ffffff8; /* Highest stack address -4 */
+
+ while(*--ip != 0) /* Look backwards for bumber */
+ ;
+ return (char *) &ip[1]; /* Next string is it. */
+}
--- /dev/null
+char *locv(longint)
+long longint;
+{
+ static char locvbuf[12];
+
+ sprintf(locvbuf, "%ld", longint);
+ return locvbuf;
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+int convdir;
+struct msgs *mp;
+char *delimp;
+
+m_convert(name)
+char *name;
+{
+ register char *cp;
+ register int first, last;
+ int found, group, range, err;
+ char *bp;
+
+ found = group = 0;
+ if(strcmp((cp = name), "all") == 0)
+ cp = "first-last";
+ if((err = first = m_conv(cp)) <= 0)
+ goto badbad;
+ if(*(cp = delimp) && *cp != '-' && *cp != ':') {
+ baddel: fprintf(stderr, "Illegal argument delimiter: \"%c\"\n", *delimp);
+ return(0);
+ }
+ if(*cp == '-') {
+ group++; cp++;
+ if((err = last = m_conv(cp)) <= 0) {
+ badbad: if(err == -1)
+ fprintf(stderr, "No %s message\n", cp);
+ else
+ badlist: fprintf(stderr, "Bad message list \"%s\".\n", name);
+ return(0);
+ }
+ if(last < first) goto badlist;
+ if(*delimp) goto baddel;
+ if(first > mp->hghmsg || last < mp->lowmsg) {
+ rangerr: fprintf(stderr, "No messages in range \"%s\".\n", name);
+ return(0);
+ }
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ } else if(*cp == ':') {
+ cp++;
+ if(*cp == '-') {
+ convdir = -1;
+ cp++;
+ } else if(*cp == '+') {
+ convdir = 1;
+ cp++;
+ }
+ if((range = atoi(bp = cp)) == 0)
+ goto badlist;
+ while(*bp >= '0' && *bp <= '9') bp++;
+ if(*bp)
+ goto baddel;
+ if((convdir > 0 && first > mp->hghmsg) ||
+ (convdir < 0 && first < mp->lowmsg))
+ goto rangerr;
+ if(first < mp->lowmsg)
+ first = mp->lowmsg;
+ if(first > mp->hghmsg)
+ first = mp->hghmsg;
+ for(last = first; last >= mp->lowmsg && last <= mp->hghmsg;
+ last += convdir)
+ if(mp->msgstats[last]&EXISTS)
+ if(--range <= 0)
+ break;
+ if(last < mp->lowmsg)
+ last = mp->lowmsg;
+ if(last > mp->hghmsg)
+ last = mp->hghmsg;
+ if(last < first) {
+ range = last; last = first; first = range;
+ }
+ } else {
+ if(first > mp->hghmsg || first < mp->lowmsg ||
+ !(mp->msgstats[first]&EXISTS)) {
+ fprintf(stderr, "Message %d doesn't exist.\n", first);
+ return(0);
+ }
+ last = first;
+ }
+ while(first <= last) {
+ if(mp->msgstats[first]&EXISTS) {
+ if(!(mp->msgstats[first]&SELECTED)) {
+ mp->numsel++;
+ mp->msgstats[first] |= SELECTED;
+ if(first < mp->lowsel)
+ mp->lowsel = first;
+ if(first > mp->hghsel)
+ mp->hghsel = first;
+ }
+ found++;
+ }
+ first++;
+ }
+ if(!found)
+ goto rangerr;
+ return(1);
+}
+
+m_conv(str)
+char *str;
+{
+ register char *cp, *bp;
+ register int i;
+ char buf[16];
+
+ convdir = 1;
+ cp = bp = str;
+ if(*cp >= '0' && *cp <= '9') {
+ while(*bp >= '0' && *bp <= '9') bp++;
+ delimp = bp;
+ return(atoi(cp));
+ }
+ bp = buf;
+ while((*cp >= 'a' && *cp <= 'z') || *cp == '.')
+ *bp++ = *cp++;
+ *bp++ = 0;
+ delimp = cp;
+ if(strcmp(buf, "first") == 0)
+ return(mp->lowmsg);
+ else if(strcmp(buf, "last") == 0) {
+ convdir = -1;
+ return(mp->hghmsg);
+ } else if(strcmp(buf, "cur") == 0 || strcmp(buf, ".") == 0)
+ return(mp->curmsg > 0 ? mp->curmsg : -1);
+ else if(strcmp(buf, "prev") == 0) {
+ convdir = -1;
+ for(i = (mp->curmsg<=mp->hghmsg)? mp->curmsg-1: mp->hghmsg;
+ i >= mp->lowmsg; i--) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1); /* non-existent message */
+ } else if(strcmp(buf, "next") == 0) {
+ for(i = (mp->curmsg>=mp->lowmsg)? mp->curmsg+1: mp->lowmsg;
+ i <= mp->hghmsg; i++) {
+ if(mp->msgstats[i]&EXISTS)
+ return(i);
+ }
+ return(-1);
+ } else
+ return(0); /* bad message list */
+}
--- /dev/null
+#include "mh.h"
+
+m_delete(key)
+char *key;
+{
+ register struct node *np, *npprev;
+
+ m_getdefs();
+ for(np = (struct node *) &m_defs; npprev = np; ) {
+ if((np = np->n_next) == 0)
+ break;
+ if(uleq(np->n_name, key)) {
+ npprev->n_next = np->n_next;
+ cndfree(np->n_name);
+ cndfree(np->n_field);
+ free(np);
+ def_flags |= DEFMOD;
+ return(0);
+ }
+ }
+ return(1);
+}
--- /dev/null
+#include "mh.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <stdio.h>
+#include "strings.h"
+
+struct msgs *mp;
+
+char *rindex();
+
+m_edit(ed, file, use, altmsg)
+char **ed, *file, *altmsg;
+int use;
+{
+ /* Exec editor. Normal exit returns 0.
+ * To abort, returns -1. To try again, returns -2
+ */
+
+ static char *edsave;
+ static int reedit;
+ struct stat stbuf;
+ int retstat;
+ register char *cp;
+ int pid, wpid;
+ int intr;
+ union { int statint;
+ struct {char lobyte, hibyte;} statby;
+ } status;
+
+ if(!reedit) { /* set initial editor */
+ if(!*ed && (*ed = m_find("editor")) == NULL)
+ *ed = sysed;
+ } else
+ if(!*ed) { /* no explicit editor */
+ *ed = edsave;
+ cp = rindex(*ed, '/');
+ if(cp == 0)
+ cp = *ed;
+ cp = concat(cp, "-next", 0);
+ if((cp = m_find(cp)) != NULL)
+ *ed = cp;
+ }
+ intr = (int) signal(SIGINT, SIG_IGN);
+ if((pid = fork()) == 0) {
+ if(altmsg) {
+ unlink("@");
+ link(altmsg, "@"); /* An easy handle on cur msg */
+ }
+ m_update();
+ fflush(stdout);
+ signal(SIGINT, (int (*)()) intr);
+ execlp(*ed, *ed, file, 0);
+ fprintf(stderr, "Can't exec the editor: ");
+ perror(*ed); done(-1);
+ } else if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ retstat = -1;
+ goto leave;
+ } else
+ while((wpid = wait(&status)) != -1 && wpid != pid) ;
+ signal(SIGINT, (int (*)()) intr);
+ if(status.statint) {
+ if((status.statby.hibyte == -1) || /* Can't exec editor */
+ (reedit && !status.statby.lobyte)) { /*2nd edit.Aborted by user*/
+ retstat = -2;
+ goto leave;
+ }
+ fprintf(stderr, "[%s aborted--%s ", invo_name(), file);
+ if(!use && status.statby.hibyte) { /* edit aborted by user */
+ unlink(file);
+ fprintf(stderr, "deleted]\n");
+ } else /* 'use' or system abort */
+ fprintf(stderr, "preserved]\n");
+ retstat = -2;
+ goto leave;
+ }
+ reedit++;
+ retstat = 0;
+ if(altmsg && !mp->msgflags&READONLY) {
+ stat("@", &stbuf);
+ if(stbuf.st_nlink == 1) /*@'s been edited by Ned*/
+ if(unlink(altmsg) == -1 || link("@", altmsg) == -1){
+ fprintf(stderr, "Can't update %s from @ file!\n",altmsg);
+ retstat = 0;
+ goto leave;
+ }
+ }
+ leave:
+ edsave = getcpy(*ed);
+ *ed = 0;
+ unlink("@"); /* Remove this extra link */
+ return(retstat);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+char *m_find(str)
+{
+ register struct node *n;
+
+ m_getdefs();
+ for(n = m_defs; n; n = n->n_next)
+ if(uleq(n->n_name, str))
+ return(n->n_field);
+ return(NULL);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+char defpath[128];
+
+struct procs {
+ char *procname;
+ char **procnaddr;
+} procs [] = {
+ { "lsproc", &lsproc },
+ { "mh_deliver", &mh_deliver },
+ { "prproc", &prproc },
+ { "scanproc", &scanproc },
+ { "showproc", &showproc },
+ { "sendproc", &sendproc },
+ { "fileproc", &fileproc },
+ { 0, 0 },
+};
+
+m_getdefs()
+{
+ register struct node *np;
+ register int state, wpid, pid;
+ register struct procs *ps;
+ int status;
+ FILE *ib;
+ char name[NAMESZ], field[128];
+
+ if(defpath[0])
+ return; /* We've already been called! */
+ if(!mypath)
+ if((mypath = getenv("HOME")) == NULL) {
+ fprintf(stderr, "HOME environment variable not set!\n");
+ done(1);
+ }
+ sprintf(defpath, "%s%s", mypath, mh_prof);
+/*** copy(mh_prof, copy(mypath, defpath)); ***/
+
+ if((ib = fopen(defpath, "r")) == NULL) {
+ if((pid = fork()) == 0) {
+ execl(installproc, "install-mh", "-auto", 0);
+ fprintf(stderr, "Can't exec ");perror(installproc);
+ done(1);
+ } else if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ done(1);
+ } else
+ while((wpid = wait(&status)) != -1 && wpid != pid)
+ ;
+ if(status || (ib = fopen(defpath, "r")) == NULL) {
+ fprintf(stderr, "[install-mh aborted]\n");
+ done(1);
+ }
+ }
+
+#ifdef NEWS /* NOT CONVERTED TO V7!!! */
+ fstat(fildes(ib), field);
+ deftime = (&field)->i_atime;
+#endif
+
+ np = (struct node *) &m_defs;
+ state = FLD;
+ for(;;)
+ switch(state = m_getfld(state,name,field,sizeof field,ib)) {
+ case FLD:
+ case FLDEOF:
+ np->n_next = (struct node *) malloc(sizeof *np);
+ np = np->n_next;
+ np->n_name = getcpy(name);
+ np->n_field = trimcpy(field);
+ np->n_next = 0;
+ for(ps = procs; ps->procname; ps++)
+ if(strcmp(np->n_name, ps->procname) == 0) {
+ *ps->procnaddr = np->n_field;
+ break;
+ }
+ if(state == FLDEOF) {
+ fclose(ib);
+ return(0);
+ }
+ continue;
+ case BODY:
+ case BODYEOF:
+ fprintf(stderr, ".mh_profile must not contain a body--it can't \
+end with a blank line!\n");
+ default:
+ fprintf(stderr, "Bad format: .mh_profile!\n");
+ done(1);
+ }
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+int m_fldsz;
+
+m_getfld(state, name, buf, bufsz, iob)
+int state, bufsz;
+char *name, *buf;
+FILE *iob;
+{
+ register char *cp;
+ register c;
+
+ top: while((c = getc(iob)) == '\001' && peekc(iob) == '\001')
+ while(getc(iob) != '\n');
+
+ if(c < 0)
+ return(FILEEOF);
+ m_fldsz = 0;
+
+ switch(state) {
+
+ case FLDEOF:
+ case BODYEOF:
+ case FLD:
+ if(c == '\n' || c == '-')
+ goto body;
+ cp = name;
+ for(;;) {
+ if(cp >= name+NAMESZ-1) {
+ *cp = 0;
+fprintf(stderr, "??Component Name Exceeds %d Chars:\n \"%s\"\n", NAMESZ-1, name);
+ return(LENERR);
+ }
+ if(c == ':')
+ break;
+ if(c == '\n' || c < 0) {
+ *cp = 0;
+fprintf(stderr, "??%s Encountered While Scanning for a colon:\n \"%s\"\n",
+ (c < 0)? "<eof>":"<end of line>", name);
+ return(FMTERR);
+ }
+ *cp++ = c;
+ *cp = 0;
+ c = getc(iob);
+ }
+
+ case FLDPLUS:
+ cp = buf;
+ for(;;) {
+ if((c = getc(iob)) < 0)
+ return(FLDEOF);
+ *cp++ = c;
+ *cp = 0;
+ m_fldsz++;
+ if(c == '\n')
+ if((c = peekc(iob)) != ' ' && c != '\t')
+ if(c == '\001' || c < 0)
+ return(FLDEOF);
+ else
+ return(FLD);
+ if(cp >= buf+bufsz-1)
+ return(peekc(iob) < 0? FLDEOF:FLDPLUS);
+ }
+
+ body: if(c == '-')
+ while(getc(iob) != '\n') ;
+ buf[0] = 0;
+ if((c = getc(iob)) == '\001' && peekc(iob) == '\001')
+ return(BODYEOF);
+
+ case BODY:
+ cp = buf; *cp = 0;
+ for(;;) {
+ if(c < 0 || (c == '\001' && peekc(iob) == '\001'))
+ return(BODYEOF);
+ *cp++ = c;
+ *cp = 0;
+ m_fldsz++;
+ if(cp >= buf+bufsz-1)
+ return(((c=peekc(iob))<0||c=='\001')?
+ BODYEOF: BODY);
+ c = getc(iob);
+ }
+
+ }
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+char *m_getfolder()
+{
+ register char *folder;
+
+ m_getdefs();
+ if((folder = m_find(pfolder)) == NULL || *folder == 0)
+ folder = defalt;
+ return(folder);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+m_gmprot()
+{
+ register char *cp;
+ register int prot;
+
+ if((cp = m_find("msg-protect")) != NULL)
+ prot = atooi(cp);
+ else
+ prot = atooi(msgprot);
+ return(prot);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/dir.h>
+
+struct msgs *mp;
+
+struct msgs *m_gmsg(name)
+char *name;
+{
+ register int i, j;
+ register char *cp;
+ register struct msgs *msgp;
+ register struct direct *dir;
+ DIR *dirp;
+ int curfil;
+ struct stat statb;
+ char buf[132];
+
+ struct {
+ int xhghmsg,
+ xnummsg,
+ xlowmsg,
+ xcurmsg;
+ char xselist,
+ xflags,
+ xfiller,
+ xothers;
+ char xmsgs[1000];
+ } msgbuf;
+
+ if ((dirp = opendir(".")) == 0)
+ return (0);
+ for(j = 0; j < 1000; j++)
+ msgbuf.xmsgs[j] = 0;
+ msgbuf.xcurmsg = 0;
+ msgbuf.xnummsg = 0;
+ msgbuf.xselist = 0;
+ msgbuf.xothers = 0;
+ msgbuf.xlowmsg = 5000;
+ msgbuf.xhghmsg = 0;
+ msgbuf.xflags = (access(".",2) == -1)? READONLY:0;
+
+ /*
+ * The following hack is that if the directory is writable
+ * and the cur file is not, we consider it to be read only
+ * folder.
+ */
+
+ if (stat("cur", &statb) >= 0 && access("cur", 2) < 0)
+ msgbuf.xflags |= READONLY;
+ curfil = 0;
+ while (dir = readdir(dirp)) {
+ cp = dir->d_name;
+ if (j = mu_atoi(cp)) {
+ if (j > msgbuf.xhghmsg)
+ msgbuf.xhghmsg = j;
+ msgbuf.xnummsg++;
+ if (j < msgbuf.xlowmsg)
+ msgbuf.xlowmsg = j;
+ msgbuf.xmsgs[j] = EXISTS;
+ } else if (*cp != ',' && *cp != '.' && *cp != '#')
+ if (strcmp(cp, current) == 0)
+ curfil++;
+ else if (strcmp(cp, listname) == 0)
+ msgbuf.xselist++;
+ else
+ msgbuf.xothers++;
+ }
+ if(!msgbuf.xhghmsg)
+ msgbuf.xlowmsg = 0;
+ closedir(dirp);
+ if(msgbuf.xflags&READONLY) {
+ sprintf(buf, "cur-%s", name);
+/*** copy(name, copy("cur-", buf)); ***/
+ if((cp = m_find(buf)) != NULL)
+ if(j = mu_atoi(cp))
+ msgbuf.xcurmsg = j;
+ } else if(curfil && (i = open(current, 0)) >= 0) {
+ if((j = read(i, buf, sizeof (buf))) >= 2) {
+ buf[j-1] = '\0'; /* Zap <lf> */
+ if (j = mu_atoi(buf))
+ msgbuf.xcurmsg = j;
+ }
+ close(i);
+ }
+ if( (int) (msgp = (struct msgs *) malloc(sizeof *mp + msgbuf.xhghmsg + 2)) == -1)
+ return(0);
+ msgp->hghmsg = msgbuf.xhghmsg;
+ msgp->nummsg = msgbuf.xnummsg;
+ msgp->lowmsg = msgbuf.xlowmsg;
+ msgp->curmsg = msgbuf.xcurmsg;
+ msgp->selist = msgbuf.xselist;
+ msgp->msgflags = msgbuf.xflags;
+ msgp->others = msgbuf.xothers;
+ msgp->foldpath = name;
+ msgp->lowsel = 5000;
+ msgp->hghsel = 0;
+ msgp->numsel = 0;
+ for(j = 0; j <= msgbuf.xhghmsg; j++)
+ msgp->msgstats[j] = msgbuf.xmsgs[j];
+ return(msgp);
+}
+
+
+mu_atoi(str)
+char *str;
+{
+ register char *cp;
+ register int i;
+
+ i = 0;
+ cp = str;
+ while(*cp) {
+ if(*cp < '0' || *cp > '9' || i > 99)
+ return(0);
+ i *= 10;
+ i += *cp++ - '0';
+ }
+ return(i);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+char *mypath;
+
+char *m_maildir(folder)
+char *folder;
+{
+ register char *fold, *path, *cp;
+ static char mailfold[128];
+
+ m_getdefs();
+ if(!(fold = folder))
+ fold = m_getfolder();
+ if(*fold == '/' || *fold == '.')
+ return(fold);
+ cp = mailfold;
+ if((path = m_find("path")) != NULL && *path) {
+ if(*path != '/') {
+ sprintf(cp, "%s/", mypath);
+ cp += strlen(cp);
+ }
+ cp = copy(path, cp);
+ if(cp[-1] != '/')
+ *cp++ = '/';
+ }
+ strcpy(cp, fold);
+ return(mailfold);
+}
--- /dev/null
+char *m_name(num)
+{
+ static char name[4];
+ register char *cp;
+ register int i;
+
+ name[0] = 0;
+ name[1] = 0;
+ name[2] = 0;
+ name[3] = 0;
+ i = num;
+ cp = &name[3];
+ if(i > 0 && i < 1000)
+ do {
+ *--cp = (i % 10) + '0';
+ i /= 10;
+ } while(i);
+ else
+ *--cp = '?';
+ return(cp);
+}
--- /dev/null
+#include "mh.h"
+
+
+m_replace(key,value)
+char *key, *value;
+
+{
+ register struct node *np;
+
+ m_getdefs();
+ for(np = m_defs; ; np = np->n_next) {
+ if(uleq(np->n_name, key)) {
+ if(strcmp(value, np->n_field) != 0) {
+ cndfree(np->n_field);
+ np->n_field = value;
+ def_flags |= DEFMOD;
+ }
+ return;
+ }
+ if(!np->n_next)
+ break;
+ }
+ np->n_next = (struct node *) malloc(sizeof *np);
+ np = np->n_next;
+ np->n_name = getcpy(key);
+ np->n_next = 0;
+ np->n_field = value;
+ def_flags |= DEFMOD;
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+m_send(arg, file)
+char *arg, *file;
+{
+ char *vec[10];
+ int ivec;
+
+ ivec = 0;
+ vec[ivec++] = "send";
+ vec[ivec++] = file;
+ if(*arg == 'v')
+ vec[ivec++] = "-verbose";
+ vec[ivec++] = 0;
+ m_update();
+ fflush(stdout);
+ execv(sendproc, vec);
+ fprintf(stderr, "Can't exec %s.\n", sendproc);
+ return(0);
+
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+struct msgs *mp;
+
+m_setcur(num)
+{
+ char buf[6];
+ register int i;
+ register char *cp1;
+
+ if(mp->msgflags&READONLY) {
+ m_replace(cp1 = concat("cur-",mp->foldpath,0), m_name(num));
+ free(cp1);
+ } else {
+ strcpy(buf, m_name(num));
+ cp1 = buf + strlen(buf);
+ *cp1++ = '\n';
+ if(strcmp(current, "cur"))
+ error("\"current\" got Clobbered!! Tell B. Borden");
+ if((i = creat(current, 0660)) >= 0) {
+ write(i, buf, cp1-buf);
+ close(i);
+ }
+ }
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+#include <signal.h>
+
+char defpath[];
+
+m_update()
+{
+ FILE *out;
+ register struct node *np;
+ int save;
+
+ if(def_flags & DEFMOD) {
+ save = (int) signal(SIGINT, SIG_IGN);
+ if((out = fopen(defpath, "w")) == NULL) {
+ fprintf(stderr, "Can't create %s!!\n", defpath);
+ done(1);
+ }
+ for(np = m_defs; np; np = np->n_next)
+ fprintf(out, "%s: %s\n", np->n_name, np->n_field);
+ fclose(out);
+ signal(SIGINT, (int (*)()) save);
+ def_flags &= ~DEFMOD;
+ }
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+makedir(dir)
+{
+ register int i, pid, wpid;
+ register char *c;
+ int status;
+
+ if((pid = fork()) == 0) {
+ execl("/bin/mkdir", "mkdir", dir, 0);
+ execl("/usr/bin/mkdir", "mkdir", dir, 0);
+ fprintf(stderr, "Can't exec mkdir!!?\n");
+ return(0);
+ }
+ if(pid == -1) {
+ fprintf(stderr, "Can't fork\n");
+ return(0);
+ }
+ while((wpid = wait(&status)) != pid && wpid != -1) ;
+ if(status) {
+ fprintf(stderr, "Bad exit status (%o) from mkdir.\n", status);
+ return(0);
+ }
+ chmod(dir, ((c = m_find("folder-protect")) != NULL)?
+ atooi(c) : atooi(foldprot));
+ return(1);
+}
--- /dev/null
+#include "mh.h"
+#include <stdio.h>
+
+char *makename(prefix,suffix)
+char *prefix, *suffix;
+{
+ static char tmpname[15];
+ register char *cp1, *cp2;
+ register int pid;
+
+ pid = getpid();
+ cp1 = tmpname;
+ for (cp2 = prefix; *cp1++ = *cp2++; );
+ cp1--;
+ do *cp1++ = pid%10 + '0'; while (pid /= 10);
+ for (cp2 = suffix; *cp1++ = *cp2++; );
+ if (cp1 >= &tmpname[15]) error("strs too long to makename");
+ return (tmpname);
+}
--- /dev/null
+#define ALL ""
+
+#define MAXARGS 1000 /* Max messages to exec */
+
+#define EXISTS 01 /* Flag bits in msgstats-- Deleted is */
+#define DELETED 02 /* undefined currently */
+#define SELECTED 04 /* Message selected by an arg */
+
+#define READONLY 01 /* No write access to folder */
+#define DEFMOD 01 /* In-core profile has been modified */
+
+/*#define NEWS 1 /* Define for news inclusion */
+
+struct swit {
+ char *sw;
+ int minchars;
+};
+
+/*
+ * m_gmsg() returns this structure. It contains the per folder
+ * information which is obtained from reading the folder directory.
+ */
+
+struct msgs {
+ int hghmsg; /* Highest msg in directory */
+ int nummsg; /* Actual Number of msgs */
+ int lowmsg; /* Lowest msg number */
+ int curmsg; /* Number of current msg if any */
+ int lowsel; /* Lowest selected msg number */
+ int hghsel; /* Highest selected msg number */
+ int numsel; /* Number of msgs selected */
+ char *foldpath; /* Pathname of folder */
+ char selist, /* Folder has a "select" file */
+ msgflags, /* Folder status bits */
+ filler,
+ others; /* Folder has other file(s) */
+ char msgstats[1]; /* Stat bytes for each msg */
+};
+
+ /* m_getfld definitions and return values */
+
+#define NAMESZ 64 /* Limit on component name size */
+#define LENERR -2 /* Name too long error from getfld */
+#define FMTERR -3 /* Message Format error */
+
+ /* m_getfld return codes */
+#define FLD 0 /* Field returned */
+#define FLDPLUS 1 /* Field " with more to come */
+#define FLDEOF 2 /* Field " ending at eom */
+#define BODY 3 /* Body " with more to come */
+#define BODYEOF 4 /* Body " ending at eom */
+#define FILEEOF 5 /* Reached end of input file */
+
+/*
+ * These standard strings are defined in strings.a. They are the
+ * only system-dependent parameters in MH, and thus by redefining
+ * their values and reloading the various modules, MH will run
+ * on any system.
+ */
+
+char
+ *components, /* Name of user's component file (in mh dir) */
+ *current, /* Name of current msg file in a folder */
+ *defalt, /* Name of the std folder (inbox) */
+ *distcomps, /* Name of `dist' components file */
+ *draft, /* Name of the normal draft file */
+ *fileproc, /* Path of file program */
+ *foldprot, /* Default folder protection */
+ *hostname, /* Local net host name */
+ *installproc, /* Name of auto-install program path */
+ *listname, /* Default selection list folder name */
+ *lockdir, /* Dir for lock files (Same fs as mailboxes)*/
+ *lsproc, /* Path of the Harvard ls program */
+ *mailboxes, /* Incoming mail directory */
+ *mh_prof, /* Name of users profile file */
+ *mh_deliver, /* Name of deliverer for mh */
+ *mhnews, /* Name of MH news file */
+ *msgprot, /* Default message protection (s.a. 0664) */
+ *pfolder, /* Name of current folder profile entry */
+ *prproc, /* Path of the pr program */
+ *scanproc, /* Path of the scan program */
+ *showproc, /* Path of the type (l) program */
+ *sendproc, /* Path of the send message program */
+ *stdcomps, /* Std comp file if missing user's own */
+ *stddcomps, /* Std dist file if missing user's own */
+ *sysed, /* Path of the std (ned) editor */
+/* Just about every program uses this also */
+ *mypath; /* User's log-on path */
+
+#ifdef UNIXCOMP
+char *unixtomh; /* Path of program to convert UNIX style
+ mailboxes to MH style mailboxes */
+char *Mailprog; /* Path of program to do actual mailing */
+char *localname; /* Name of local machine on local net */
+#endif
+
+/*
+ * node structure used to hold a linked list of the users profile
+ * information taken from logpath/.mh_prof.
+ */
+
+struct node {
+ struct node *n_next;
+ char *n_name,
+ *n_field;
+} *m_defs;
+
+char def_flags;
+
+
+/*
+ * The first char in the mhnews file indicates whether the program
+ * calling m_news() should continue running or halt.
+ */
+
+#define NEWSHALT '!' /* Halt after showing the news */
+#define NEWSCONT ' ' /* Continue (ditto) */
+#define NEWSPAUSE '\001' /* Pause during news output... */
+
+
+/*
+ * Miscellaneous Defines to speed things up
+ */
+
+#define error(str) { fprintf(stderr, "%s\n", str); exit(-1); }
+
+/*
+ * Routine type declarations -- needed by version 7 compiler
+ */
+
+char **brkstring();
+char *m_maildir();
+char *m_find();
+char *m_name();
+char *concat();
+char *getcpy();
+char *trimcpy();
+char *add();
+char *invo_name();
+char **copyip();
+char *getcpy();
+char *m_getfolder();
+struct msgs *m_gmsg();
+char *copy();
+char **getans();
+char *cdate();
+char *makename();
+char *r1bindex();
+
+/*
+ * Routine type declarations -- SHOULD BE GLOBAL
+ */
+char *getenv();
+
--- /dev/null
+#include <stdio.h>
+
+peekc(ib)
+FILE *ib;
+{
+ register c;
+
+ c = getc(ib);
+ ungetc(c,ib);
+ return(c);
+}
--- /dev/null
+pr_array(cp,ap)
+char *cp, **ap;
+{
+ register int i;
+
+ for(i=0; *ap; ap++,i++)
+ printf("%s[%d]=> %s\n", cp,i,*ap);
+}
+
--- /dev/null
+#include "mh.h"
+
+printsw(substr, swp, prefix)
+char *substr, *prefix;
+struct swit *swp;
+{
+ char buf[128];
+ register char *cp, *cp1;
+ register int i;
+ int len;
+
+ len = strlen(substr);
+ for(; swp->sw; swp++)
+ if(!*substr || /* null matches all strings */
+ (ssequal(substr, swp->sw) && len >= swp->minchars))
+ if(swp->minchars > 0) {
+ cp = buf;
+ *cp++ = '(';
+ for(cp1 = swp->sw, i = 0; i < swp->minchars; i++)
+ *cp++ = *cp1++;
+ *cp++ = ')';
+ while(*cp++ = *cp1++);
+ printf(" %s%s\n", prefix, buf);
+ } else if(swp->minchars == 0)
+ printf(" %s%s\n", prefix, swp->sw);
+}
--- /dev/null
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <sys/time.h>
+
+/*
+ * Output the date in right format gotten from
+ * the passed ctime(3) format date.
+ * If the passed date is NULL, output the current
+ * date and time.
+ */
+
+putdate(timestr, out)
+ char *timestr;
+ register FILE *out;
+{
+ register char *t, *p, *cp;
+ char *timezone();
+ struct tm *tmp;
+ struct tm *localtime();
+ struct timeb tb;
+ long now;
+ int isdst;
+ char *asctime();
+ static char *str = "SunMonTueWedThuFriSat";
+ static char *daytag[] = {
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday"
+ };
+
+ now = time((long *) 0);
+ tmp = localtime(&now);
+ isdst = tmp->tm_isdst;
+ if (timestr == 0)
+ timestr = asctime(tmp);
+ cp = str;
+ t = timestr;
+ while (*cp) {
+ if (strcmpn(cp, t, 3) == 0)
+ break;
+ cp += 3;
+ }
+ if (*cp)
+ cp = daytag[(cp - str) / 3];
+ else
+ cp = 0;
+ ftime(&tb);
+ /*
+ * This call to timezone() may be wrong:
+ * really need the tm_isdst whoever generated timestr.
+ */
+ p = timezone(tb.timezone, isdst);
+
+ if (cp == 0)
+ fprintf(out, "Date: %.2s %.3s %.4s %.2s%.2s-%.3s\n",
+ t+8, t+4, t+20, t+11, t+14, p);
+ else
+ fprintf(out, "Date: %.2s %.3s %.4s %.2s%.2s-%.3s (%s)\n",
+ t+8, t+4, t+20, t+11, t+14, p, cp);
+}
--- /dev/null
+/*
+ * r1bindex(str, chr) stands for Right plus 1 or Beginning index of
+ * chr in str. I.e. return ptr 1 past LAST occurance of chr in
+ * str, OR beginning of the string if str doesn't contain chr.
+ */
+
+char *
+r1bindex(str, chr)
+register char *str;
+register int chr;
+{
+ register char *cp;
+
+ for(cp = str; *cp; cp++) ;
+ --cp;
+ while(cp >= str && *cp != chr)
+ --cp;
+ return ++cp;
+}
--- /dev/null
+#include "mh.h"
+#include <signal.h>
+#include <stdio.h>
+
+showfile(file)
+char *file;
+{
+ int pid, wpid, intr, status;
+ char *vec[4];
+
+ intr = (int) signal(SIGINT, SIG_IGN);
+ m_update();
+ fflush(stdout);
+ if((pid = fork()) == 0) {
+ vec[0] = "mh-type";
+ vec[1] = file;
+ vec[2] = 0;
+ signal(SIGINT, (int (*)()) intr);
+ execv(showproc, vec);
+ perror("Can't exec showproc");
+ goto badleave;
+ } else if(pid == -1) {
+ fprintf(stderr, "No forks!\n");
+ goto badleave;
+ } else
+ while((wpid = wait(&status)) != -1 && wpid != pid) ;
+ signal(SIGINT, (int (*)()) intr);
+ if(status & 0377)
+ goto badleave;
+ return(0);
+
+ badleave:
+ fflush(stdout);
+ return(1);
+
+}
+
--- /dev/null
+#include "mh.h"
+
+/* switch match, or any unambiguous abbreviation */
+/* exact match always wins, even if shares same root */
+/* returns subscript in zero-terminated tbl[] of strings */
+/* returns -1 if no match, -2 if ambiguous */
+
+#define abs(i) (i < 0 ? -i : i)
+
+smatch(string, swp)
+char *string;
+struct swit *swp;
+{
+ register char *sp, *tcp;
+ struct swit *tp;
+ int firstone, stringlen;
+
+ firstone = -1;
+
+ for (stringlen = strlen(string), tp = swp; tcp = tp->sw; tp++) {
+ if(stringlen < abs(tp->minchars)) continue; /* no match */
+ for (sp = string; *sp == *tcp++; ) {
+ if (*sp++ == 0) return(tp-swp); /* exact match */
+ }
+ if (*sp != 0) {
+ if (*sp != ' ') continue; /* no match */
+ if (*--tcp == 0) return(tp-swp); /* exact match */
+ }
+ if (firstone == -1) firstone = tp-swp; /* possible match */
+ else firstone = -2; /* ambiguous */
+ }
+
+ return (firstone);
+}
--- /dev/null
+ssequal(substr, str)
+char *substr, *str;
+{
+ while(*substr)
+ if(*substr++ != *str++)
+ return(0);
+ return(1);
+}
--- /dev/null
+char *trimcpy(cp)
+register char *cp;
+{
+ register char *sp;
+
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+ sp = cp;
+ while(*sp)
+ if(*sp++ == '\n')
+ break;
+ *--sp = 0;
+ sp = (char *) malloc(sp - cp + 1);
+ strcpy(sp, cp);
+ return(sp);
+}
--- /dev/null
+type(ch, s)
+char *s;
+{
+ register char *p;
+
+ for (p = s; *p++; );
+ --p;
+ write(ch, s, p-s);
+ return(p-s);
+}
--- /dev/null
+uleq(c1, c2)
+register char *c1, *c2;
+{
+ register int c;
+
+ while(c = *c1++)
+ if((c|040) != (*c2|040))
+ return(0);
+ else
+ c2++;
+ return(*c2 == 0);
+}
--- /dev/null
+To:
+Cc:
+Subject:
+-------
--- /dev/null
+Distribution-to:
+Distribution-cc:
--- /dev/null
+/* Rewrite for VAX: BSB 9/9/79 */
+/* Compiled with V7 cc: BSB 6/2/79 */
+
+#include <stdio.h>
+#include <sgtty.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/types.h>
+#include <stat.h>
+
+#define CLEARPAGE write(2,"\014\000",2);
+#define PAUSE 0
+#define NOTIFY 1
+#define CLEAR 2
+#define NOTICLEAR 3
+
+int spage = 37;
+int page;
+short int width = 79;
+short int noclr = 0;
+short int first = 0;
+short int numop = 0;
+short int flagctl = 1;
+short int ontty = 1; /* assume we're outputting to a tty */
+short int delflg; /* a <DEL> was typed. */
+
+FILE *fin;
+jmp_buf envir;
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ register int i,k,n;
+ register char *c1, *c2;
+ int j, clrflag;
+ int int2(), getout();
+ struct sgttyb sg;
+ struct stat st;
+ extern char _sibuf[], _sobuf[];
+
+ if(gtty(1, &sg) == -1) {
+ ontty = 0;
+ flagctl = 0;
+ }
+ c1 = c2 = argv[0];
+ do
+ if(*c1++ == '/')
+ c2 = c1;
+ while(*c1);
+ if(*c2 == 'c')
+ noclr++;
+ k=0;
+ for( i=1; i<argc; i++ ) {/* look for - args */
+ if(argv[i][0] == '-' ) {
+ switch( argv[i][1] ) {
+ case 'c': noclr++; break;
+ case 'f': first=num(&argv[i][2]); /* set first line */
+ break;
+ case 'n': numop=1; /* set number option */
+ break;
+ case 'l':
+ case 'p': spage =num(&argv[i][2]); /* set page size */
+ break;
+ case 'w': width =num(&argv[i][2]);
+ break;
+ case 'x': flagctl = flagctl? 0 : 1;
+ break;
+ default: printf("Unknown switch: %s\n", argv[i]);
+ return;
+ }
+ } else
+ argv[k++] = argv[i];
+ }
+
+ if (spage<=0)
+ spage = 0x07fffffff; /* largest positive number! */
+ setbuf(stdout, _sobuf);
+ if(ontty)
+ signal(SIGINT,int2);
+ signal(SIGQUIT,getout);
+ page = spage;
+ if(k == 0) { /* filter */
+ if(!setjmp(envir)) {
+ fin = stdin;
+ setbuf(fin, _sibuf);
+ pfile(0);
+ }
+ getout();
+ }
+ j = 0;
+ setjmp(envir);
+ while((i=j++) < k) {
+ page = spage;
+ clrflag = 0;
+ if(fin != NULL) { fclose(fin); fin = NULL; }
+ if(stat(argv[i], &st) == 0 && (st.st_mode&S_IFMT) == S_IFDIR){
+ printf("%s: Is a directory!\n", argv[i]);
+ continue;
+ }
+ if((fin = fopen(argv[i],"r")) == NULL) {
+ printf("Cannot open \"%s\" for reading!\n", argv[i]);
+ continue;
+ }
+ if(st.st_size == 0) {
+ printf("File \"%s\" is empty.\n", argv[i]);
+ continue;
+ }
+ if(k>1) {
+ if(i && delflg <= 0)
+ printf("\n\n");
+ delflg = 0;
+ if(ontty) {
+ printf("Press <RETURN> to list \"%s\"\n", argv[i]);
+ clrflag = 1;
+ } else
+ printf(">>>>> File \"%s\"\n", argv[i]);
+ }
+
+ pfile(clrflag);
+ }
+ getout();
+}
+
+int linpos, line, ct;
+
+pfile(flg)
+{
+ register int c;
+
+ if(flg) nextpage(NOTICLEAR);
+ else if(!noclr && ontty)
+ CLEARPAGE;
+ delflg = -1;
+ line = 1;
+ ct = page;
+ while (line < first) /* Dcrocker: skip to first line */
+ if((c = getch()) == EOF)
+ return;
+ else if(c == '\n')
+ line++;
+ linpos = 0;
+
+ while ((c = getch()) != EOF)
+ putch(c);
+
+ fflush(stdout);
+}
+
+num(s) /* computes the internal form of a number */
+register char *s; /* bad chars are ignored */
+{
+ register int c, i, sign;
+
+ sign=1; i=0;
+ while(c = *s++) {
+ if(c=='-' && sign==1) sign = -1;
+ c -= '0';
+ if(c>=0 && c<=9) i=i*10+c;
+ }
+ return(i*sign);
+}
+
+nextpage (clearpage)
+{ char c;
+
+ if(!ontty)
+ return;
+ if (clearpage & NOTIFY)
+ putchar('\007');
+ fflush(stdout);
+ c = 0;
+ while(read(2, &c, 1) && c != '\n') ;
+ if (clearpage & CLEAR && c) {
+ CLEARPAGE;
+ page = spage;
+ } else {
+ page = (spage>>1) + (spage>>3);
+/*** page = spage * .6; ***/
+ }
+ return;
+}
+
+int2()
+{
+ signal(SIGINT,int2);
+ stdout->_cnt = BUFSIZ;
+ stdout->_ptr = stdout->_base;
+ if(delflg)
+ putchar('\n');
+ delflg++;
+ longjmp(envir, 1);
+}
+
+int peekc = -2;
+
+peekch()
+{
+ return(peekc = getch());
+}
+
+getch()
+{
+ register int c;
+ static word;
+
+ if(peekc != -2) {
+ c = peekc;
+ peekc = -2;
+ return(c);
+ };
+ c = getc(fin);
+ if(c != EOF)
+ c &= 0177;
+ return(c);
+}
+
+putch(c)
+register int c;
+{
+ if(linpos == 0 && numop) {
+ printf("%-5d | ");
+ linpos += 8;
+ }
+ if(c < 040 || c == 0177) switch(c) {
+ case '\n': line++;
+ linpos = -1;
+ break;
+ case 014: goto npage;
+ case 011: linpos += 8;
+ linpos &= ~07;
+ linpos--;
+ break;
+ default: if(flagctl) {
+ if(c == '\7')
+ putchar(c);
+ putch('^');
+ if(c != 0177)
+ c += '@';
+ else
+ c = 'd';
+ }
+ }
+ putchar(c);
+ linpos++;
+ if(width && linpos >= width && peekch() != '\n') {
+ putchar('\n'); linpos = 0;
+ }
+ if(linpos == 0 && --ct <= 0) {
+ npage: nextpage(NOTICLEAR);
+ ct = page;
+ }
+}
+
+
+getout()
+{
+ exit(0);
+}
--- /dev/null
+
\ No newline at end of file
--- /dev/null
+F=`grep '[Tt][Oo]:' $1 | sed 's/[Tt][Oo]:.*news\.//p'`
+if [ -d /usr/mhnews/$F ] ; then
+ cat /usr/mhnews/.1char >> /usr/mhnews/.$F
+ /usr/new/mh/file -link -file $1 +$F
+else
+ echo Unknown News Category: $F
+ exit 1
+fi