From: David Levine Date: Sun, 12 May 2019 15:03:14 +0000 (-0400) Subject: Added several historical source archives from the early days of MH. X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/0bc71c284a5004fb30f200b5069b9e8e1f14e497?hp=6a420d96a080e04da6c441f88cc52e60fe661089 Added several historical source archives from the early days of MH. SRI-NOSC, 2.9BSD, mh-jun-1982, and mh-nov-1983 predate those under RCS/CVS source code control. Thanks to M. Levinson, David Malone, Chad, Noel Chiappa, and Ralph for advising of their discoveries of the various archive locations. Removed docs/historical/mh-6.8.5/miscellany/mem/a.out because SPARC executables shouldn't be archived. --- diff --git a/docs/historical/2.9BSD/Makefile b/docs/historical/2.9BSD/Makefile new file mode 100644 index 00000000..4503c12a --- /dev/null +++ b/docs/historical/2.9BSD/Makefile @@ -0,0 +1,13 @@ +# %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 diff --git a/docs/historical/2.9BSD/README b/docs/historical/2.9BSD/README new file mode 100644 index 00000000..9d034eee --- /dev/null +++ b/docs/historical/2.9BSD/README @@ -0,0 +1,29 @@ +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. diff --git a/docs/historical/2.9BSD/cmds/Makefile b/docs/historical/2.9BSD/cmds/Makefile new file mode 100644 index 00000000..eaf82032 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/Makefile @@ -0,0 +1,221 @@ +# @(#)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 diff --git a/docs/historical/2.9BSD/cmds/aliascheck.c b/docs/historical/2.9BSD/cmds/aliascheck.c new file mode 100644 index 00000000..03d94f6c --- /dev/null +++ b/docs/historical/2.9BSD/cmds/aliascheck.c @@ -0,0 +1,209 @@ +#include +#include +#include +#include +#include + +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: "); + } +} diff --git a/docs/historical/2.9BSD/cmds/annotate.c b/docs/historical/2.9BSD/cmds/annotate.c new file mode 100644 index 00000000..fce8b747 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/annotate.c @@ -0,0 +1,110 @@ +#ifndef lint +static char sccsid[] = "@(#)annotate.c 4.1 2/23/83"; +#endif + +#include "mh.h" +#include +#include +#include + +/* 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); +} diff --git a/docs/historical/2.9BSD/cmds/comp.c b/docs/historical/2.9BSD/cmds/comp.c new file mode 100644 index 00000000..37a69aae --- /dev/null +++ b/docs/historical/2.9BSD/cmds/comp.c @@ -0,0 +1,163 @@ +#include "mh.h" +#include +#include +#include + +/* #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 []", 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); +} + diff --git a/docs/historical/2.9BSD/cmds/deliver.c b/docs/historical/2.9BSD/cmds/deliver.c new file mode 100644 index 00000000..4a4bc847 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/deliver.c @@ -0,0 +1,883 @@ +#ifndef lint +static char sccsid[] = "@(#)deliver.c 4.3 3/5/83"; +#endif + +#include "mh.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/*#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'); +} diff --git a/docs/historical/2.9BSD/cmds/dist.c b/docs/historical/2.9BSD/cmds/dist.c new file mode 100644 index 00000000..76ea4869 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/dist.c @@ -0,0 +1,295 @@ +#ifndef lint +static char sccsid[] = "@(#)dist.c 4.1 2/23/83"; +#endif + +#include "mh.h" +#include +#include +#include + +#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 []", 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); + + +} diff --git a/docs/historical/2.9BSD/cmds/emitl.c b/docs/historical/2.9BSD/cmds/emitl.c new file mode 100644 index 00000000..439b6180 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/emitl.c @@ -0,0 +1,55 @@ +/* + * 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 + +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); +} diff --git a/docs/historical/2.9BSD/cmds/folder.c b/docs/historical/2.9BSD/cmds/folder.c new file mode 100644 index 00000000..8d63c716 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/folder.c @@ -0,0 +1,316 @@ +#include "mh.h" +#include +#include +#include +#include +#include + +#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); +} diff --git a/docs/historical/2.9BSD/cmds/forw.c b/docs/historical/2.9BSD/cmds/forw.c new file mode 100644 index 00000000..636efe09 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/forw.c @@ -0,0 +1,316 @@ +#ifndef lint +static char sccsid[] = "@(#)forw.c 4.1 2/23/83"; +#endif + +#include "mh.h" +#include +#include +#include + +#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 []", 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); +} diff --git a/docs/historical/2.9BSD/cmds/grep.c b/docs/historical/2.9BSD/cmds/grep.c new file mode 100644 index 00000000..314d357b --- /dev/null +++ b/docs/historical/2.9BSD/cmds/grep.c @@ -0,0 +1,281 @@ +#include +#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); +} diff --git a/docs/historical/2.9BSD/cmds/inc.c b/docs/historical/2.9BSD/cmds/inc.c new file mode 100644 index 00000000..5b089071 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/inc.c @@ -0,0 +1,331 @@ +#include "mh.h" +#include +#include +#include +#include +#include +#include + +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("<> ", 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); +} diff --git a/docs/historical/2.9BSD/cmds/install-mh.c b/docs/historical/2.9BSD/cmds/install-mh.c new file mode 100644 index 00000000..828eff76 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/install-mh.c @@ -0,0 +1,109 @@ +#include "mh.h" +#include +#include +#include + +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); +} diff --git a/docs/historical/2.9BSD/cmds/mail.c b/docs/historical/2.9BSD/cmds/mail.c new file mode 100644 index 00000000..227265ff --- /dev/null +++ b/docs/historical/2.9BSD/cmds/mail.c @@ -0,0 +1,157 @@ +#include "mh.h" +#include +#include + +#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 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); +} diff --git a/docs/historical/2.9BSD/cmds/mh.h b/docs/historical/2.9BSD/cmds/mh.h new file mode 100644 index 00000000..fba207ff --- /dev/null +++ b/docs/historical/2.9BSD/cmds/mh.h @@ -0,0 +1,154 @@ +#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(); + diff --git a/docs/historical/2.9BSD/cmds/news.c b/docs/historical/2.9BSD/cmds/news.c new file mode 100644 index 00000000..b3bbbd43 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/news.c @@ -0,0 +1,301 @@ +#include "mh.h" +#include +#include +#include +#include +#include +#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 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 + struct timeb tb; + + ftime(&tb); + printf("%s.\n", nons[tb.millitm % NONS]); +} diff --git a/docs/historical/2.9BSD/cmds/next.c b/docs/historical/2.9BSD/cmds/next.c new file mode 100644 index 00000000..9fb34161 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/next.c @@ -0,0 +1,97 @@ +#include "mh.h" +#include +#include + +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); +} diff --git a/docs/historical/2.9BSD/cmds/nexthdr.c b/docs/historical/2.9BSD/cmds/nexthdr.c new file mode 100644 index 00000000..f7def4b9 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/nexthdr.c @@ -0,0 +1 @@ +int glbtype = 1; diff --git a/docs/historical/2.9BSD/cmds/pick.c b/docs/historical/2.9BSD/cmds/pick.c new file mode 100644 index 00000000..1384ac55 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/pick.c @@ -0,0 +1,490 @@ +#include "mh.h" +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/docs/historical/2.9BSD/cmds/prevhdr.c b/docs/historical/2.9BSD/cmds/prevhdr.c new file mode 100644 index 00000000..073abf28 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/prevhdr.c @@ -0,0 +1 @@ +int glbtype = -1; diff --git a/docs/historical/2.9BSD/cmds/prompter.c b/docs/historical/2.9BSD/cmds/prompter.c new file mode 100644 index 00000000..00a2a861 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/prompter.c @@ -0,0 +1,272 @@ +#include "mh.h" +#include +#include +#include +#include +#include + +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("", c + '@'); + else + printf("%c", c); +} diff --git a/docs/historical/2.9BSD/cmds/refile.c b/docs/historical/2.9BSD/cmds/refile.c new file mode 100644 index 00000000..02c16b87 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/refile.c @@ -0,0 +1,364 @@ +#ifndef lint +static char sccsid[] = "@(#)refile.c 1.1 5/26/83"; +#endif + +#include "mh.h" +#include +#include +#include +#include +#include + +#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= 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; +} diff --git a/docs/historical/2.9BSD/cmds/replsubs.c b/docs/historical/2.9BSD/cmds/replsubs.c new file mode 100644 index 00000000..77c57357 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/replsubs.c @@ -0,0 +1,232 @@ +#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[]@" + * "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); +} + diff --git a/docs/historical/2.9BSD/cmds/reply.c b/docs/historical/2.9BSD/cmds/reply.c new file mode 100644 index 00000000..3d59a39c --- /dev/null +++ b/docs/historical/2.9BSD/cmds/reply.c @@ -0,0 +1,321 @@ +#include "mh.h" +#include +#include +#include + +/*#define NEWS 1*/ + +#define NOUSE 0 + +/* #define TEST 1 */ + +char *anyl[] = { + "no", 0, + "yes", 0, + "list", 0, + 0 +}; + +char *aleqs[] = { + "list", 0, /* 0 */ + "edit []", 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; + } + } +} diff --git a/docs/historical/2.9BSD/cmds/rescue.c b/docs/historical/2.9BSD/cmds/rescue.c new file mode 100644 index 00000000..6c737140 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/rescue.c @@ -0,0 +1,404 @@ +/* + * 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 +#include +#include + +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); +} diff --git a/docs/historical/2.9BSD/cmds/rmf.c b/docs/historical/2.9BSD/cmds/rmf.c new file mode 100644 index 00000000..126fb1dc --- /dev/null +++ b/docs/historical/2.9BSD/cmds/rmf.c @@ -0,0 +1,191 @@ +#ifndef lint +static char sccsid[] = "@(#)rmf.c 1.4 7/7/83"; +#endif + +#include "mh.h" +#include +#include +#include +#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); +} diff --git a/docs/historical/2.9BSD/cmds/rmm.c b/docs/historical/2.9BSD/cmds/rmm.c new file mode 100644 index 00000000..da34094f --- /dev/null +++ b/docs/historical/2.9BSD/cmds/rmm.c @@ -0,0 +1,131 @@ +#ifndef lint +static char sccsid[] = "@(#)rmm.c 4.1 2/23/83"; +#endif + +#include "mh.h" +#include +#include + +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); +} diff --git a/docs/historical/2.9BSD/cmds/scan.c b/docs/historical/2.9BSD/cmds/scan.c new file mode 100644 index 00000000..72ef38ce --- /dev/null +++ b/docs/historical/2.9BSD/cmds/scan.c @@ -0,0 +1,128 @@ +#include "mh.h" +#include +#include + +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 [<curmsg); + fclose(in); + if(stdout->_cnt < 80) + fflush(stdout); + } + } + } + if(ff) + putchar('\014'); +leave: + m_update(); + done(0); +} + diff --git a/docs/historical/2.9BSD/cmds/scansub.c b/docs/historical/2.9BSD/cmds/scansub.c new file mode 100644 index 00000000..dc3d1dfc --- /dev/null +++ b/docs/historical/2.9BSD/cmds/scansub.c @@ -0,0 +1,407 @@ +#include "mh.h" +#include + +#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); +} diff --git a/docs/historical/2.9BSD/cmds/send.c b/docs/historical/2.9BSD/cmds/send.c new file mode 100644 index 00000000..95c3aec7 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/send.c @@ -0,0 +1,144 @@ +#ifndef lint +static char sccsid[] = "@(#)send.c 4.2 2/23/83"; +#endif + +#include "mh.h" +#include +#include +#include +#include +#include + +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); + } +} diff --git a/docs/historical/2.9BSD/cmds/show.c b/docs/historical/2.9BSD/cmds/show.c new file mode 100644 index 00000000..5c8bf961 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/show.c @@ -0,0 +1,132 @@ +#include "mh.h" +#include +#include + +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); +} + + diff --git a/docs/historical/2.9BSD/cmds/strings.h b/docs/historical/2.9BSD/cmds/strings.h new file mode 100644 index 00000000..70c67e58 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/strings.h @@ -0,0 +1,42 @@ +/* + * 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 diff --git a/docs/historical/2.9BSD/cmds/unixtomh.c b/docs/historical/2.9BSD/cmds/unixtomh.c new file mode 100644 index 00000000..26a33de0 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/unixtomh.c @@ -0,0 +1,602 @@ +# + +/* + * 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 +#include +#include +#include + + +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); +} diff --git a/docs/historical/2.9BSD/cmds/vars.c b/docs/historical/2.9BSD/cmds/vars.c new file mode 100644 index 00000000..cac97e07 --- /dev/null +++ b/docs/historical/2.9BSD/cmds/vars.c @@ -0,0 +1,10 @@ + 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]; diff --git a/docs/historical/2.9BSD/doc/Alias.Design b/docs/historical/2.9BSD/doc/Alias.Design new file mode 100644 index 00000000..ed2490aa --- /dev/null +++ b/docs/historical/2.9BSD/doc/Alias.Design @@ -0,0 +1,67 @@ +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." will +be mapped to "news". This is used for the MH news facility. + +Bruce Borden October 1979 diff --git a/docs/historical/2.9BSD/doc/MH_VGRIND b/docs/historical/2.9BSD/doc/MH_VGRIND new file mode 100755 index 00000000..346e7f68 --- /dev/null +++ b/docs/historical/2.9BSD/doc/MH_VGRIND @@ -0,0 +1,27 @@ +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 diff --git a/docs/historical/2.9BSD/doc/MHgenerate b/docs/historical/2.9BSD/doc/MHgenerate new file mode 100644 index 00000000..2ef96695 --- /dev/null +++ b/docs/historical/2.9BSD/doc/MHgenerate @@ -0,0 +1,122 @@ + 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 diff --git a/docs/historical/2.9BSD/doc/MHnotes b/docs/historical/2.9BSD/doc/MHnotes new file mode 100644 index 00000000..93167eb1 --- /dev/null +++ b/docs/historical/2.9BSD/doc/MHnotes @@ -0,0 +1,178 @@ +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-: highest-seen". + + Rather than read through the news folders to determine + the number of entries, a file with name . (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 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 diff --git a/docs/historical/2.9BSD/doc/Makefile b/docs/historical/2.9BSD/doc/Makefile new file mode 100644 index 00000000..49f2d78f --- /dev/null +++ b/docs/historical/2.9BSD/doc/Makefile @@ -0,0 +1,2 @@ +manual: + itroff -me titlepage mh.me diff --git a/docs/historical/2.9BSD/doc/mh.me b/docs/historical/2.9BSD/doc/mh.me new file mode 100644 index 00000000..630fa1a0 --- /dev/null +++ b/docs/historical/2.9BSD/doc/mh.me @@ -0,0 +1,2510 @@ +.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 \*(<\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//Mail/draft (where /usr/ 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 +( 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\*(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\-next:\0\*(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 +^:\0default switches~^All +^cur\-:\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 . +(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 \fR, to invoke + 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\-next: \*(rq names an alternative editor. + +.Fi +^/etc/mh/components~^The message skeleton +^or /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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\*(<> + 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 /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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 +.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/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: \*(<> + 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 /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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 +\*(<> date +.ti 1.5i + +.ti 1.5i + +.ti 2.5i + +.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 +^/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 \*(< will cause the whole component to be left out. +A \*(lq\\\*(rq +preceding a 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 (or ). +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 during message-body typing is equivalent to + for compatibility with NED. +A 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: or +cc: , +Subject: Re: +In-reply-to: Your message of +.ti +\w'In-reply-to: 'u + +.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: \*(<>. + +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 +^/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\ \ \ \ \[\*(</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 + 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 +or . +If a is entered, \fIl\fR will clear the +screen before listing the next page, whereas 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 /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 + 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~^| +^^^^^ + +^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~^| +^^^^^\*(lq\--\*(rq~^| +^^^^ +.re \" Reset Tabs +.fi +.sp +.pp +Where 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 of messages, beginning +with \*(lqmsg\*(rq (in the case of first, cur, next, or ), +or ending with \*(lqmsg\*(rq (in the case of prev or last). ++ forces \*(lqstarting with msg\*(rq, and \- 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 diff --git a/docs/historical/2.9BSD/doc/titlepage b/docs/historical/2.9BSD/doc/titlepage new file mode 100644 index 00000000..427f1563 --- /dev/null +++ b/docs/historical/2.9BSD/doc/titlepage @@ -0,0 +1,23 @@ +.(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 diff --git a/docs/historical/2.9BSD/man/Makefile b/docs/historical/2.9BSD/man/Makefile new file mode 100644 index 00000000..237443e9 --- /dev/null +++ b/docs/historical/2.9BSD/man/Makefile @@ -0,0 +1,37 @@ +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:; diff --git a/docs/historical/2.9BSD/man/comp.1 b/docs/historical/2.9BSD/man/comp.1 new file mode 100644 index 00000000..87c392e8 --- /dev/null +++ b/docs/historical/2.9BSD/man/comp.1 @@ -0,0 +1,82 @@ +.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 \fR, to invoke + 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\-next: \*(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 /components 'u +/etc/mh/components The message skeleton +or /components Rather than the standard skeleton +$HOME/\*.mh_profile The user profile +/draft The default message file +/usr/new/send To send the composed message +.fi +.SH "PROFILE COMPONENTS" +.nf +.ta \w'\-next: 'u +Path: To determine the user's MH directory +Editor: To override the use of /bin/ned as the default editor +\-next: editor to be used after exit from +.SH DEFAULTS +.nf +`file' defaults to draft +`\-editor' defaults to /bin/ned +`\-nouse' +.fi diff --git a/docs/historical/2.9BSD/man/dist.1 b/docs/historical/2.9BSD/man/dist.1 new file mode 100644 index 00000000..2b0abf4d --- /dev/null +++ b/docs/historical/2.9BSD/man/dist.1 @@ -0,0 +1,83 @@ +.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\*(<> + 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 /components 'u +/etc/mh/components The message skeleton +or /components Rather than the standard skeleton +$HOME/\*.mh\(ruprofile The user profile +/draft The default message file +/usr/bin/send To send the composed message +.fi +.SH "PROFILE COMPONENTS" +.nf +.ta \w'\-next: 'u +Path: To determine the user's MH directory +Editor: To override the use of /bin/ned as the default editor +\-next: editor to be used after exit from +.fi +.SH DEFAULTS +.nf +`+folder' defaults to the current folder +`msg' defaults to cur +`\-editor' defaults to /bin/ned +`\-noannotate' +`\-noinplace' +.fi diff --git a/docs/historical/2.9BSD/man/file.1 b/docs/historical/2.9BSD/man/file.1 new file mode 100644 index 00000000..74c74416 --- /dev/null +++ b/docs/historical/2.9BSD/man/file.1 @@ -0,0 +1,91 @@ +.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. diff --git a/docs/historical/2.9BSD/man/folder.1 b/docs/historical/2.9BSD/man/folder.1 new file mode 100644 index 00000000..063faf9f --- /dev/null +++ b/docs/historical/2.9BSD/man/folder.1 @@ -0,0 +1,105 @@ +.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 +.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/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. diff --git a/docs/historical/2.9BSD/man/forw.1 b/docs/historical/2.9BSD/man/forw.1 new file mode 100644 index 00000000..ed873271 --- /dev/null +++ b/docs/historical/2.9BSD/man/forw.1 @@ -0,0 +1,68 @@ +.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: \*(<> + 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 /components 'u +/etc/mh/components The message skeleton +or /components Rather than the standard skeleton +$HOME/\*.mh\(ruprofile The user profile +/draft The default message file +/usr/bin/send To send the composed message +.fi +.SH "PROFILE COMPONENTS" +.nf +.ta \w'\-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 +\-next: editor to be used after exit from +.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. diff --git a/docs/historical/2.9BSD/man/inc.1 b/docs/historical/2.9BSD/man/inc.1 new file mode 100644 index 00000000..48238b43 --- /dev/null +++ b/docs/historical/2.9BSD/man/inc.1 @@ -0,0 +1,84 @@ +.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 +\*(<> date +.ti 1.5i + +.ti 1.5i + +.ti 2.5i + + +.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'/audit-file 'u +$HOME/\*.mh\(ruprofile The user profile +$HOME/\*.mail The user's mail drop +/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. diff --git a/docs/historical/2.9BSD/man/next.1 b/docs/historical/2.9BSD/man/next.1 new file mode 100644 index 00000000..9531180f --- /dev/null +++ b/docs/historical/2.9BSD/man/next.1 @@ -0,0 +1,29 @@ +.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. diff --git a/docs/historical/2.9BSD/man/pick.1 b/docs/historical/2.9BSD/man/pick.1 new file mode 100644 index 00000000..bdd15e10 --- /dev/null +++ b/docs/historical/2.9BSD/man/pick.1 @@ -0,0 +1,185 @@ +.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 \*(< will cause the whole component to be left out. +A \*(lq\\\*(rq +preceding a 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 (or ). +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 during message-body typing is equivalent to + for compatibility with NED. +A 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 diff --git a/docs/historical/2.9BSD/man/repl.1 b/docs/historical/2.9BSD/man/repl.1 new file mode 100644 index 00000000..50f98c3d --- /dev/null +++ b/docs/historical/2.9BSD/man/repl.1 @@ -0,0 +1,81 @@ +.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: or +cc: , +Subject: Re: +In-reply-to: Your message of +.ti +\w'In-reply-to: 'u + +.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: \*(<>. + +.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 +/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. diff --git a/docs/historical/2.9BSD/man/rmf.1 b/docs/historical/2.9BSD/man/rmf.1 new file mode 100644 index 00000000..9dfeeccd --- /dev/null +++ b/docs/historical/2.9BSD/man/rmf.1 @@ -0,0 +1,62 @@ +.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 /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. diff --git a/docs/historical/2.9BSD/man/rmm.1 b/docs/historical/2.9BSD/man/rmm.1 new file mode 100644 index 00000000..35c07c1d --- /dev/null +++ b/docs/historical/2.9BSD/man/rmm.1 @@ -0,0 +1,32 @@ +.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. diff --git a/docs/historical/2.9BSD/man/scan.1 b/docs/historical/2.9BSD/man/scan.1 new file mode 100644 index 00000000..4216108c --- /dev/null +++ b/docs/historical/2.9BSD/man/scan.1 @@ -0,0 +1,64 @@ +.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\ \ \ \ \[\*(</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. diff --git a/docs/historical/2.9BSD/man/show.1 b/docs/historical/2.9BSD/man/show.1 new file mode 100644 index 00000000..abbea1aa --- /dev/null +++ b/docs/historical/2.9BSD/man/show.1 @@ -0,0 +1,64 @@ +.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 + 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 +or . +If a is entered, \fIl\fR will clear the +screen before listing the next page, whereas 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 /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. diff --git a/docs/historical/2.9BSD/strings/Mailprog.c b/docs/historical/2.9BSD/strings/Mailprog.c new file mode 100644 index 00000000..fe8edb32 --- /dev/null +++ b/docs/historical/2.9BSD/strings/Mailprog.c @@ -0,0 +1,7 @@ +/* + * 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"; diff --git a/docs/historical/2.9BSD/strings/Makefile b/docs/historical/2.9BSD/strings/Makefile new file mode 100644 index 00000000..eef5784b --- /dev/null +++ b/docs/historical/2.9BSD/strings/Makefile @@ -0,0 +1,38 @@ +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 diff --git a/docs/historical/2.9BSD/strings/anoyes.c b/docs/historical/2.9BSD/strings/anoyes.c new file mode 100644 index 00000000..eb842c93 --- /dev/null +++ b/docs/historical/2.9BSD/strings/anoyes.c @@ -0,0 +1,5 @@ +char *anoyes[] = { + "no", 0, + "yes", 0, + 0, +}; diff --git a/docs/historical/2.9BSD/strings/components.c b/docs/historical/2.9BSD/strings/components.c new file mode 100644 index 00000000..ffd97cb1 --- /dev/null +++ b/docs/historical/2.9BSD/strings/components.c @@ -0,0 +1 @@ +char *components = "components"; diff --git a/docs/historical/2.9BSD/strings/current.c b/docs/historical/2.9BSD/strings/current.c new file mode 100644 index 00000000..86ea3685 --- /dev/null +++ b/docs/historical/2.9BSD/strings/current.c @@ -0,0 +1 @@ +char *current = "cur"; diff --git a/docs/historical/2.9BSD/strings/defalt.c b/docs/historical/2.9BSD/strings/defalt.c new file mode 100644 index 00000000..ab3a0125 --- /dev/null +++ b/docs/historical/2.9BSD/strings/defalt.c @@ -0,0 +1 @@ +char *defalt = "inbox"; diff --git a/docs/historical/2.9BSD/strings/distcomps.c b/docs/historical/2.9BSD/strings/distcomps.c new file mode 100644 index 00000000..acd7eb7f --- /dev/null +++ b/docs/historical/2.9BSD/strings/distcomps.c @@ -0,0 +1 @@ +char *distcomps = "distcomps"; diff --git a/docs/historical/2.9BSD/strings/draft.c b/docs/historical/2.9BSD/strings/draft.c new file mode 100644 index 00000000..0e25051a --- /dev/null +++ b/docs/historical/2.9BSD/strings/draft.c @@ -0,0 +1 @@ +char *draft = "draft"; diff --git a/docs/historical/2.9BSD/strings/fileproc.c b/docs/historical/2.9BSD/strings/fileproc.c new file mode 100644 index 00000000..56626c78 --- /dev/null +++ b/docs/historical/2.9BSD/strings/fileproc.c @@ -0,0 +1,6 @@ +/* + * 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"; diff --git a/docs/historical/2.9BSD/strings/foldprot.c b/docs/historical/2.9BSD/strings/foldprot.c new file mode 100644 index 00000000..8769a274 --- /dev/null +++ b/docs/historical/2.9BSD/strings/foldprot.c @@ -0,0 +1,5 @@ +/* + * Folders (directories) are created with this protection (mode) + */ + +char *foldprot = "0751"; diff --git a/docs/historical/2.9BSD/strings/hostname.c b/docs/historical/2.9BSD/strings/hostname.c new file mode 100644 index 00000000..64278d6e --- /dev/null +++ b/docs/historical/2.9BSD/strings/hostname.c @@ -0,0 +1,6 @@ +/* + * For ARPANET mail, this is the local-site's Host name. + * (currently not used.) + */ + +char *hostname = "Berkeley"; diff --git a/docs/historical/2.9BSD/strings/installproc.c b/docs/historical/2.9BSD/strings/installproc.c new file mode 100644 index 00000000..38814e74 --- /dev/null +++ b/docs/historical/2.9BSD/strings/installproc.c @@ -0,0 +1,6 @@ +/* + * 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"; diff --git a/docs/historical/2.9BSD/strings/listname.c b/docs/historical/2.9BSD/strings/listname.c new file mode 100644 index 00000000..af8a8827 --- /dev/null +++ b/docs/historical/2.9BSD/strings/listname.c @@ -0,0 +1 @@ +char *listname = "select"; diff --git a/docs/historical/2.9BSD/strings/localname.c b/docs/historical/2.9BSD/strings/localname.c new file mode 100644 index 00000000..8d22edfa --- /dev/null +++ b/docs/historical/2.9BSD/strings/localname.c @@ -0,0 +1,5 @@ +/* + * Local network host name + */ + +char *localname = "unknown"; diff --git a/docs/historical/2.9BSD/strings/lockdir.c b/docs/historical/2.9BSD/strings/lockdir.c new file mode 100644 index 00000000..e349552c --- /dev/null +++ b/docs/historical/2.9BSD/strings/lockdir.c @@ -0,0 +1,15 @@ +/* + * 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 */ diff --git a/docs/historical/2.9BSD/strings/lsproc.c b/docs/historical/2.9BSD/strings/lsproc.c new file mode 100644 index 00000000..c926d79e --- /dev/null +++ b/docs/historical/2.9BSD/strings/lsproc.c @@ -0,0 +1,9 @@ +/* + * 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"; diff --git a/docs/historical/2.9BSD/strings/mailboxes.c b/docs/historical/2.9BSD/strings/mailboxes.c new file mode 100644 index 00000000..b9c56b90 --- /dev/null +++ b/docs/historical/2.9BSD/strings/mailboxes.c @@ -0,0 +1,7 @@ +/* + * 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/"; diff --git a/docs/historical/2.9BSD/strings/mailproc.c b/docs/historical/2.9BSD/strings/mailproc.c new file mode 100644 index 00000000..b7020766 --- /dev/null +++ b/docs/historical/2.9BSD/strings/mailproc.c @@ -0,0 +1,6 @@ +/* + * 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"; diff --git a/docs/historical/2.9BSD/strings/mh_defs.c b/docs/historical/2.9BSD/strings/mh_defs.c new file mode 100644 index 00000000..fa86e657 --- /dev/null +++ b/docs/historical/2.9BSD/strings/mh_defs.c @@ -0,0 +1,6 @@ +/* + * This is the name of the file used to store + * the user's MH profile + */ + +char *mh_defs = "/.mh_profile"; diff --git a/docs/historical/2.9BSD/strings/mh_deliver.c b/docs/historical/2.9BSD/strings/mh_deliver.c new file mode 100644 index 00000000..601d6146 --- /dev/null +++ b/docs/historical/2.9BSD/strings/mh_deliver.c @@ -0,0 +1,7 @@ +/* + * 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"; diff --git a/docs/historical/2.9BSD/strings/mh_prof.c b/docs/historical/2.9BSD/strings/mh_prof.c new file mode 100644 index 00000000..db3cc3ad --- /dev/null +++ b/docs/historical/2.9BSD/strings/mh_prof.c @@ -0,0 +1 @@ +char *mh_prof = "/.mh_profile"; diff --git a/docs/historical/2.9BSD/strings/mhnews.c b/docs/historical/2.9BSD/strings/mhnews.c new file mode 100644 index 00000000..098e8f43 --- /dev/null +++ b/docs/historical/2.9BSD/strings/mhnews.c @@ -0,0 +1,7 @@ +/* + * 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"; diff --git a/docs/historical/2.9BSD/strings/msgprot.c b/docs/historical/2.9BSD/strings/msgprot.c new file mode 100644 index 00000000..65f1ff03 --- /dev/null +++ b/docs/historical/2.9BSD/strings/msgprot.c @@ -0,0 +1,7 @@ +/* + * 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"; diff --git a/docs/historical/2.9BSD/strings/pfolder.c b/docs/historical/2.9BSD/strings/pfolder.c new file mode 100644 index 00000000..209c7ee8 --- /dev/null +++ b/docs/historical/2.9BSD/strings/pfolder.c @@ -0,0 +1 @@ +char *pfolder = "current-folder"; diff --git a/docs/historical/2.9BSD/strings/prproc.c b/docs/historical/2.9BSD/strings/prproc.c new file mode 100644 index 00000000..4417a454 --- /dev/null +++ b/docs/historical/2.9BSD/strings/prproc.c @@ -0,0 +1,6 @@ +/* + * This is the std BELL pr, which is invoked through show with the + * -pr switch. + */ + +char *prproc = "/bin/pr"; diff --git a/docs/historical/2.9BSD/strings/scanproc.c b/docs/historical/2.9BSD/strings/scanproc.c new file mode 100644 index 00000000..0bb22ea8 --- /dev/null +++ b/docs/historical/2.9BSD/strings/scanproc.c @@ -0,0 +1,6 @@ +/* + * This program is usually called directly by users, but it is + * also invoked by "pick -scan". + */ + +char *scanproc = "/usr/new/mh/scan"; diff --git a/docs/historical/2.9BSD/strings/sendproc.c b/docs/historical/2.9BSD/strings/sendproc.c new file mode 100644 index 00000000..82baf792 --- /dev/null +++ b/docs/historical/2.9BSD/strings/sendproc.c @@ -0,0 +1,7 @@ +/* + * 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"; diff --git a/docs/historical/2.9BSD/strings/showproc.c b/docs/historical/2.9BSD/strings/showproc.c new file mode 100644 index 00000000..4bd7c6d8 --- /dev/null +++ b/docs/historical/2.9BSD/strings/showproc.c @@ -0,0 +1,9 @@ +/* + * This program is called to list messages. At Rand, the program + * c stops at the end of each page and waits for a or + * 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 */ diff --git a/docs/historical/2.9BSD/strings/stdcomps.c b/docs/historical/2.9BSD/strings/stdcomps.c new file mode 100644 index 00000000..5329fbe1 --- /dev/null +++ b/docs/historical/2.9BSD/strings/stdcomps.c @@ -0,0 +1,6 @@ +/* + * This is the standard skeleton for message composition with both + * comp and forw. + */ + +char *stdcomps = "/usr/new/lib/mh/components"; diff --git a/docs/historical/2.9BSD/strings/stddcomps.c b/docs/historical/2.9BSD/strings/stddcomps.c new file mode 100644 index 00000000..0e3fa764 --- /dev/null +++ b/docs/historical/2.9BSD/strings/stddcomps.c @@ -0,0 +1,5 @@ +/* + * This is the standard skeleton for message composition with dist. + */ + +char *stddcomps = "/usr/new/lib/mh/distcomps"; diff --git a/docs/historical/2.9BSD/strings/strings.h b/docs/historical/2.9BSD/strings/strings.h new file mode 100644 index 00000000..3ab459cf --- /dev/null +++ b/docs/historical/2.9BSD/strings/strings.h @@ -0,0 +1,36 @@ +/* + * 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; diff --git a/docs/historical/2.9BSD/strings/sysed.c b/docs/historical/2.9BSD/strings/sysed.c new file mode 100644 index 00000000..fe69d617 --- /dev/null +++ b/docs/historical/2.9BSD/strings/sysed.c @@ -0,0 +1,9 @@ +/* + * 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"; diff --git a/docs/historical/2.9BSD/strings/unixtomh.c b/docs/historical/2.9BSD/strings/unixtomh.c new file mode 100644 index 00000000..0d3ce085 --- /dev/null +++ b/docs/historical/2.9BSD/strings/unixtomh.c @@ -0,0 +1,7 @@ +/* + * 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"; diff --git a/docs/historical/2.9BSD/subs/16158symdef b/docs/historical/2.9BSD/subs/16158symdef new file mode 100644 index 00000000..d3bd053a --- /dev/null +++ b/docs/historical/2.9BSD/subs/16158symdef @@ -0,0 +1,51 @@ +_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 diff --git a/docs/historical/2.9BSD/subs/16158symref b/docs/historical/2.9BSD/subs/16158symref new file mode 100644 index 00000000..c0c1d2d6 --- /dev/null +++ b/docs/historical/2.9BSD/subs/16158symref @@ -0,0 +1,925 @@ +_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 diff --git a/docs/historical/2.9BSD/subs/Makefile b/docs/historical/2.9BSD/subs/Makefile new file mode 100644 index 00000000..e6814aca --- /dev/null +++ b/docs/historical/2.9BSD/subs/Makefile @@ -0,0 +1,56 @@ +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 diff --git a/docs/historical/2.9BSD/subs/add.c b/docs/historical/2.9BSD/subs/add.c new file mode 100644 index 00000000..aad38155 --- /dev/null +++ b/docs/historical/2.9BSD/subs/add.c @@ -0,0 +1,15 @@ +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); +} diff --git a/docs/historical/2.9BSD/subs/ambigsw.c b/docs/historical/2.9BSD/subs/ambigsw.c new file mode 100644 index 00000000..505b2d4c --- /dev/null +++ b/docs/historical/2.9BSD/subs/ambigsw.c @@ -0,0 +1,10 @@ +#include + +ambigsw(arg, swp) +char *arg; +{ + fprintf(stderr, "%s: ", invo_name()); + fprintf(stderr, "-%s ambiguous. It matches \n", arg); + printsw(arg, swp, "-"); +} + diff --git a/docs/historical/2.9BSD/subs/atooi.c b/docs/historical/2.9BSD/subs/atooi.c new file mode 100644 index 00000000..79991d3e --- /dev/null +++ b/docs/historical/2.9BSD/subs/atooi.c @@ -0,0 +1,15 @@ +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); +} diff --git a/docs/historical/2.9BSD/subs/brkstring.c b/docs/historical/2.9BSD/subs/brkstring.c new file mode 100644 index 00000000..9933ff13 --- /dev/null +++ b/docs/historical/2.9BSD/subs/brkstring.c @@ -0,0 +1,38 @@ +#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= &end) free(addr); +} diff --git a/docs/historical/2.9BSD/subs/concat.c b/docs/historical/2.9BSD/subs/concat.c new file mode 100644 index 00000000..ba19272b --- /dev/null +++ b/docs/historical/2.9BSD/subs/concat.c @@ -0,0 +1,18 @@ +#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); +} diff --git a/docs/historical/2.9BSD/subs/copy.c b/docs/historical/2.9BSD/subs/copy.c new file mode 100644 index 00000000..3284c123 --- /dev/null +++ b/docs/historical/2.9BSD/subs/copy.c @@ -0,0 +1,6 @@ +char *copy(from,to) +register char *from, *to; +{ + while(*to++ = *from++); + return to-1; +}; diff --git a/docs/historical/2.9BSD/subs/copyip.c b/docs/historical/2.9BSD/subs/copyip.c new file mode 100644 index 00000000..a1454811 --- /dev/null +++ b/docs/historical/2.9BSD/subs/copyip.c @@ -0,0 +1,9 @@ +int *copyip(ipf, ipt) +register int *ipf, *ipt; +{ + while((*ipt = *ipf) && *ipf++ != -1) + ipt++; + *ipt = 0; + return(ipt); +} + diff --git a/docs/historical/2.9BSD/subs/cputc.c b/docs/historical/2.9BSD/subs/cputc.c new file mode 100644 index 00000000..f3715fb6 --- /dev/null +++ b/docs/historical/2.9BSD/subs/cputc.c @@ -0,0 +1,13 @@ +#include + +cputc(chr, ip) +register FILE *ip; +{ + if(ip != NULL) { + putc(chr, ip); + if(ferror(ip)) { + perror("Write error"); + done(-1); + } + } +} diff --git a/docs/historical/2.9BSD/subs/crpbrkstring.c b/docs/historical/2.9BSD/subs/crpbrkstring.c new file mode 100644 index 00000000..bea75147 --- /dev/null +++ b/docs/historical/2.9BSD/subs/crpbrkstring.c @@ -0,0 +1,50 @@ +#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); +} diff --git a/docs/historical/2.9BSD/subs/done.c b/docs/historical/2.9BSD/subs/done.c new file mode 100644 index 00000000..5808ba31 --- /dev/null +++ b/docs/historical/2.9BSD/subs/done.c @@ -0,0 +1,8 @@ +/* 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); +} diff --git a/docs/historical/2.9BSD/subs/fdcompare.c b/docs/historical/2.9BSD/subs/fdcompare.c new file mode 100644 index 00000000..94a54b2f --- /dev/null +++ b/docs/historical/2.9BSD/subs/fdcompare.c @@ -0,0 +1,27 @@ +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); +} diff --git a/docs/historical/2.9BSD/subs/gans.c b/docs/historical/2.9BSD/subs/gans.c new file mode 100644 index 00000000..c85c1e00 --- /dev/null +++ b/docs/historical/2.9BSD/subs/gans.c @@ -0,0 +1,38 @@ +#include "mh.h" +#include + +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); + } +} diff --git a/docs/historical/2.9BSD/subs/getans.c b/docs/historical/2.9BSD/subs/getans.c new file mode 100644 index 00000000..11abb450 --- /dev/null +++ b/docs/historical/2.9BSD/subs/getans.c @@ -0,0 +1,54 @@ +#include "mh.h" +#include +#include + +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 for help.\n", *cpp); + continue; + default: + return(cpp); /* list, edit, quit, send */ + } + } +} + + +g_sig() +{ + signal(SIGINT, g_sig); + g_sigint = 1; + return; +} diff --git a/docs/historical/2.9BSD/subs/getcpy.c b/docs/historical/2.9BSD/subs/getcpy.c new file mode 100644 index 00000000..ab94cd1b --- /dev/null +++ b/docs/historical/2.9BSD/subs/getcpy.c @@ -0,0 +1,8 @@ +char *getcpy(str) +{ + register char *cp; + + cp = (char *) malloc(strlen(str) + 1); + strcpy(cp, str); + return(cp); +} diff --git a/docs/historical/2.9BSD/subs/help.c b/docs/historical/2.9BSD/subs/help.c new file mode 100644 index 00000000..9f6dc12c --- /dev/null +++ b/docs/historical/2.9BSD/subs/help.c @@ -0,0 +1,9 @@ +#include "mh.h" + +help(str, swp) +char *str; +{ + printf("syntax: %s\n", str); + printf(" switches are:\n"); + printsw(ALL, swp, "-"); +} diff --git a/docs/historical/2.9BSD/subs/invo_name.c b/docs/historical/2.9BSD/subs/invo_name.c new file mode 100644 index 00000000..25b86a4e --- /dev/null +++ b/docs/historical/2.9BSD/subs/invo_name.c @@ -0,0 +1,16 @@ +/* + * 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. */ +} diff --git a/docs/historical/2.9BSD/subs/locv.c b/docs/historical/2.9BSD/subs/locv.c new file mode 100644 index 00000000..b530686e --- /dev/null +++ b/docs/historical/2.9BSD/subs/locv.c @@ -0,0 +1,8 @@ +char *locv(longint) +long longint; +{ + static char locvbuf[12]; + + sprintf(locvbuf, "%ld", longint); + return locvbuf; +} diff --git a/docs/historical/2.9BSD/subs/m_convert.c b/docs/historical/2.9BSD/subs/m_convert.c new file mode 100644 index 00000000..43220b40 --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_convert.c @@ -0,0 +1,147 @@ +#include "mh.h" +#include + +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 */ +} diff --git a/docs/historical/2.9BSD/subs/m_delete.c b/docs/historical/2.9BSD/subs/m_delete.c new file mode 100644 index 00000000..b1732bfa --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_delete.c @@ -0,0 +1,22 @@ +#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); +} diff --git a/docs/historical/2.9BSD/subs/m_edit.c b/docs/historical/2.9BSD/subs/m_edit.c new file mode 100644 index 00000000..13b470a0 --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_edit.c @@ -0,0 +1,94 @@ +#include "mh.h" +#include +#include +#include +#include +#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); +} diff --git a/docs/historical/2.9BSD/subs/m_find.c b/docs/historical/2.9BSD/subs/m_find.c new file mode 100644 index 00000000..26743a0f --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_find.c @@ -0,0 +1,13 @@ +#include "mh.h" +#include + +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); +} diff --git a/docs/historical/2.9BSD/subs/m_getdefs.c b/docs/historical/2.9BSD/subs/m_getdefs.c new file mode 100644 index 00000000..35eb0857 --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_getdefs.c @@ -0,0 +1,90 @@ +#include "mh.h" +#include + +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); + } +} diff --git a/docs/historical/2.9BSD/subs/m_getfld.c b/docs/historical/2.9BSD/subs/m_getfld.c new file mode 100644 index 00000000..27c33006 --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_getfld.c @@ -0,0 +1,87 @@ +#include "mh.h" +#include + +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)? "":"", 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); + } + + } +} diff --git a/docs/historical/2.9BSD/subs/m_getfolder.c b/docs/historical/2.9BSD/subs/m_getfolder.c new file mode 100644 index 00000000..9f86bf6a --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_getfolder.c @@ -0,0 +1,12 @@ +#include "mh.h" +#include + +char *m_getfolder() +{ + register char *folder; + + m_getdefs(); + if((folder = m_find(pfolder)) == NULL || *folder == 0) + folder = defalt; + return(folder); +} diff --git a/docs/historical/2.9BSD/subs/m_gmprot.c b/docs/historical/2.9BSD/subs/m_gmprot.c new file mode 100644 index 00000000..34302593 --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_gmprot.c @@ -0,0 +1,14 @@ +#include "mh.h" +#include + +m_gmprot() +{ + register char *cp; + register int prot; + + if((cp = m_find("msg-protect")) != NULL) + prot = atooi(cp); + else + prot = atooi(msgprot); + return(prot); +} diff --git a/docs/historical/2.9BSD/subs/m_gmsg.c b/docs/historical/2.9BSD/subs/m_gmsg.c new file mode 100644 index 00000000..7962a6bc --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_gmsg.c @@ -0,0 +1,122 @@ +#include "mh.h" +#include +#include +#include +#include + +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 */ + 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); +} diff --git a/docs/historical/2.9BSD/subs/m_maildir.c b/docs/historical/2.9BSD/subs/m_maildir.c new file mode 100644 index 00000000..a64ef75f --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_maildir.c @@ -0,0 +1,29 @@ +#include "mh.h" +#include + +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); +} diff --git a/docs/historical/2.9BSD/subs/m_name.c b/docs/historical/2.9BSD/subs/m_name.c new file mode 100644 index 00000000..c8880af5 --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_name.c @@ -0,0 +1,21 @@ +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); +} diff --git a/docs/historical/2.9BSD/subs/m_replace.c b/docs/historical/2.9BSD/subs/m_replace.c new file mode 100644 index 00000000..4d6496dd --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_replace.c @@ -0,0 +1,29 @@ +#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; +} diff --git a/docs/historical/2.9BSD/subs/m_send.c b/docs/historical/2.9BSD/subs/m_send.c new file mode 100644 index 00000000..22ca0a7d --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_send.c @@ -0,0 +1,22 @@ +#include "mh.h" +#include + +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); + +} diff --git a/docs/historical/2.9BSD/subs/m_setcur.c b/docs/historical/2.9BSD/subs/m_setcur.c new file mode 100644 index 00000000..e6251497 --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_setcur.c @@ -0,0 +1,26 @@ +#include "mh.h" +#include + +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); + } + } +} diff --git a/docs/historical/2.9BSD/subs/m_update.c b/docs/historical/2.9BSD/subs/m_update.c new file mode 100644 index 00000000..c2ea0495 --- /dev/null +++ b/docs/historical/2.9BSD/subs/m_update.c @@ -0,0 +1,25 @@ +#include "mh.h" +#include +#include + +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; + } +} diff --git a/docs/historical/2.9BSD/subs/makedir.c b/docs/historical/2.9BSD/subs/makedir.c new file mode 100644 index 00000000..7f9c9279 --- /dev/null +++ b/docs/historical/2.9BSD/subs/makedir.c @@ -0,0 +1,28 @@ +#include "mh.h" +#include + +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); +} diff --git a/docs/historical/2.9BSD/subs/makename.c b/docs/historical/2.9BSD/subs/makename.c new file mode 100644 index 00000000..027c4d8e --- /dev/null +++ b/docs/historical/2.9BSD/subs/makename.c @@ -0,0 +1,19 @@ +#include "mh.h" +#include + +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); +} diff --git a/docs/historical/2.9BSD/subs/peekc.c b/docs/historical/2.9BSD/subs/peekc.c new file mode 100644 index 00000000..0f5cea05 --- /dev/null +++ b/docs/historical/2.9BSD/subs/peekc.c @@ -0,0 +1,11 @@ +#include + +peekc(ib) +FILE *ib; +{ + register c; + + c = getc(ib); + ungetc(c,ib); + return(c); +} diff --git a/docs/historical/2.9BSD/subs/pr_array.c b/docs/historical/2.9BSD/subs/pr_array.c new file mode 100644 index 00000000..00fddabd --- /dev/null +++ b/docs/historical/2.9BSD/subs/pr_array.c @@ -0,0 +1,9 @@ +pr_array(cp,ap) +char *cp, **ap; +{ + register int i; + + for(i=0; *ap; ap++,i++) + printf("%s[%d]=> %s\n", cp,i,*ap); +} + diff --git a/docs/historical/2.9BSD/subs/printsw.c b/docs/historical/2.9BSD/subs/printsw.c new file mode 100644 index 00000000..0b516e8e --- /dev/null +++ b/docs/historical/2.9BSD/subs/printsw.c @@ -0,0 +1,26 @@ +#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); +} diff --git a/docs/historical/2.9BSD/subs/putdate.c b/docs/historical/2.9BSD/subs/putdate.c new file mode 100644 index 00000000..ad0b8559 --- /dev/null +++ b/docs/historical/2.9BSD/subs/putdate.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include + +/* + * 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); +} diff --git a/docs/historical/2.9BSD/subs/r1bindex.c b/docs/historical/2.9BSD/subs/r1bindex.c new file mode 100644 index 00000000..2aa54479 --- /dev/null +++ b/docs/historical/2.9BSD/subs/r1bindex.c @@ -0,0 +1,19 @@ +/* + * 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; +} diff --git a/docs/historical/2.9BSD/subs/showfile.c b/docs/historical/2.9BSD/subs/showfile.c new file mode 100644 index 00000000..c75c138d --- /dev/null +++ b/docs/historical/2.9BSD/subs/showfile.c @@ -0,0 +1,37 @@ +#include "mh.h" +#include +#include + +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); + +} + diff --git a/docs/historical/2.9BSD/subs/smatch.c b/docs/historical/2.9BSD/subs/smatch.c new file mode 100644 index 00000000..aa4a2d39 --- /dev/null +++ b/docs/historical/2.9BSD/subs/smatch.c @@ -0,0 +1,34 @@ +#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); +} diff --git a/docs/historical/2.9BSD/subs/ssequal.c b/docs/historical/2.9BSD/subs/ssequal.c new file mode 100644 index 00000000..124581c2 --- /dev/null +++ b/docs/historical/2.9BSD/subs/ssequal.c @@ -0,0 +1,8 @@ +ssequal(substr, str) +char *substr, *str; +{ + while(*substr) + if(*substr++ != *str++) + return(0); + return(1); +} diff --git a/docs/historical/2.9BSD/subs/trimcpy.c b/docs/historical/2.9BSD/subs/trimcpy.c new file mode 100644 index 00000000..eb7d5fe9 --- /dev/null +++ b/docs/historical/2.9BSD/subs/trimcpy.c @@ -0,0 +1,16 @@ +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); +} diff --git a/docs/historical/2.9BSD/subs/type.c b/docs/historical/2.9BSD/subs/type.c new file mode 100644 index 00000000..31c800b2 --- /dev/null +++ b/docs/historical/2.9BSD/subs/type.c @@ -0,0 +1,10 @@ +type(ch, s) +char *s; +{ + register char *p; + + for (p = s; *p++; ); + --p; + write(ch, s, p-s); + return(p-s); +} diff --git a/docs/historical/2.9BSD/subs/uleq.c b/docs/historical/2.9BSD/subs/uleq.c new file mode 100644 index 00000000..663adcd5 --- /dev/null +++ b/docs/historical/2.9BSD/subs/uleq.c @@ -0,0 +1,12 @@ +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); +} diff --git a/docs/historical/2.9BSD/support/components b/docs/historical/2.9BSD/support/components new file mode 100644 index 00000000..657e5ddf --- /dev/null +++ b/docs/historical/2.9BSD/support/components @@ -0,0 +1,4 @@ +To: +Cc: +Subject: +------- diff --git a/docs/historical/2.9BSD/support/distcomps b/docs/historical/2.9BSD/support/distcomps new file mode 100644 index 00000000..b3415f92 --- /dev/null +++ b/docs/historical/2.9BSD/support/distcomps @@ -0,0 +1,2 @@ +Distribution-to: +Distribution-cc: diff --git a/docs/historical/2.9BSD/support/l.c b/docs/historical/2.9BSD/support/l.c new file mode 100644 index 00000000..2f7b8d26 --- /dev/null +++ b/docs/historical/2.9BSD/support/l.c @@ -0,0 +1,259 @@ +/* Rewrite for VAX: BSB 9/9/79 */ +/* Compiled with V7 cc: BSB 6/2/79 */ + +#include +#include +#include +#include +#include +#include + +#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 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; i1) { + if(i && delflg <= 0) + printf("\n\n"); + delflg = 0; + if(ontty) { + printf("Press 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); +} diff --git a/docs/historical/2.9BSD/support/news-1char b/docs/historical/2.9BSD/support/news-1char new file mode 100755 index 00000000..0519ecba --- /dev/null +++ b/docs/historical/2.9BSD/support/news-1char @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/historical/2.9BSD/support/news-mh_receiv b/docs/historical/2.9BSD/support/news-mh_receiv new file mode 100755 index 00000000..8f7d4368 --- /dev/null +++ b/docs/historical/2.9BSD/support/news-mh_receiv @@ -0,0 +1,8 @@ +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 diff --git a/docs/historical/README b/docs/historical/README index 6828e317..ba59a732 100644 --- a/docs/historical/README +++ b/docs/historical/README @@ -1,3 +1,5 @@ +This directory +-------------- The most recent versions of the documents in this directory were downloaded from ftp://ftp.vim.org/pub/mail/mh/doc/ @@ -14,16 +16,52 @@ were downloaded from ftp://munnari.oz.au/pub/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 @@ -31,8 +69,8 @@ the postscript (.ps) files have been converted to pdf using ps2pdf. D. Levine 28 Feb 2012 ------------------------------------------------------------------------- ------------------------------------------------------------------------- +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- mh/doc/README @@ -52,7 +90,7 @@ Postscript versions are also available: 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: @@ -81,7 +119,7 @@ intosh, and printing them on a Laserwriter. If you are able to generate 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: diff --git a/docs/historical/SRI-NOSC/annotate.c b/docs/historical/SRI-NOSC/annotate.c new file mode 100644 index 00000000..238068fa --- /dev/null +++ b/docs/historical/SRI-NOSC/annotate.c @@ -0,0 +1,107 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/delete.c b/docs/historical/SRI-NOSC/delete.c new file mode 100644 index 00000000..879ed934 --- /dev/null +++ b/docs/historical/SRI-NOSC/delete.c @@ -0,0 +1,123 @@ +/* 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(); +} diff --git a/docs/historical/SRI-NOSC/delete.run b/docs/historical/SRI-NOSC/delete.run new file mode 100644 index 00000000..1426cd76 --- /dev/null +++ b/docs/historical/SRI-NOSC/delete.run @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/SRI-NOSC/errlst b/docs/historical/SRI-NOSC/errlst new file mode 100644 index 00000000..fa8407c6 --- /dev/null +++ b/docs/historical/SRI-NOSC/errlst @@ -0,0 +1 @@ +cc -n send.o subs.a strings-ec.a libg.a libh.a mailib.a mailib.a diff --git a/docs/historical/SRI-NOSC/errors.h b/docs/historical/SRI-NOSC/errors.h new file mode 100644 index 00000000..68f69334 --- /dev/null +++ b/docs/historical/SRI-NOSC/errors.h @@ -0,0 +1,41 @@ +# +/* 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 */ diff --git a/docs/historical/SRI-NOSC/file.c b/docs/historical/SRI-NOSC/file.c new file mode 100644 index 00000000..f0429e35 --- /dev/null +++ b/docs/historical/SRI-NOSC/file.c @@ -0,0 +1,275 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/file.run b/docs/historical/SRI-NOSC/file.run new file mode 100644 index 00000000..f5c87343 --- /dev/null +++ b/docs/historical/SRI-NOSC/file.run @@ -0,0 +1,3 @@ +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 diff --git a/docs/historical/SRI-NOSC/forward.c b/docs/historical/SRI-NOSC/forward.c new file mode 100644 index 00000000..b27a68bb --- /dev/null +++ b/docs/historical/SRI-NOSC/forward.c @@ -0,0 +1,314 @@ +/* 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); +} diff --git a/docs/historical/SRI-NOSC/forward.run b/docs/historical/SRI-NOSC/forward.run new file mode 100644 index 00000000..33b221f8 --- /dev/null +++ b/docs/historical/SRI-NOSC/forward.run @@ -0,0 +1,6 @@ +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 + diff --git a/docs/historical/SRI-NOSC/install-defs.c b/docs/historical/SRI-NOSC/install-defs.c new file mode 100644 index 00000000..b01a12cd --- /dev/null +++ b/docs/historical/SRI-NOSC/install-defs.c @@ -0,0 +1,110 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/install-defs.r b/docs/historical/SRI-NOSC/install-defs.r new file mode 100644 index 00000000..5d81be10 --- /dev/null +++ b/docs/historical/SRI-NOSC/install-defs.r @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/SRI-NOSC/iobuf.h b/docs/historical/SRI-NOSC/iobuf.h new file mode 100644 index 00000000..553a7632 --- /dev/null +++ b/docs/historical/SRI-NOSC/iobuf.h @@ -0,0 +1,7 @@ +/* file used for getc/putc */ +struct iobuf { + int b_fildes; + int b_nleft; + char *b_nextp; + char b_buff[512]; +}; diff --git a/docs/historical/SRI-NOSC/mh.h b/docs/historical/SRI-NOSC/mh.h new file mode 100644 index 00000000..4ae84513 --- /dev/null +++ b/docs/historical/SRI-NOSC/mh.h @@ -0,0 +1,108 @@ +#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... */ diff --git a/docs/historical/SRI-NOSC/nosc.txt b/docs/historical/SRI-NOSC/nosc.txt new file mode 100644 index 00000000..31409975 --- /dev/null +++ b/docs/historical/SRI-NOSC/nosc.txt @@ -0,0 +1,33 @@ +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 ARPANET; + it used the NCP 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 + diff --git a/docs/historical/SRI-NOSC/nullproc.c b/docs/historical/SRI-NOSC/nullproc.c new file mode 100644 index 00000000..a93dd9a9 --- /dev/null +++ b/docs/historical/SRI-NOSC/nullproc.c @@ -0,0 +1,3 @@ +main(argc,argv) char *argv[]; +{ int i;printf("NULL PROCESS\n"); + for (i=0; in_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); +} diff --git a/docs/historical/SRI-NOSC/open.run b/docs/historical/SRI-NOSC/open.run new file mode 100644 index 00000000..deab5a2f --- /dev/null +++ b/docs/historical/SRI-NOSC/open.run @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/SRI-NOSC/pickup.c b/docs/historical/SRI-NOSC/pickup.c new file mode 100644 index 00000000..37b6aee0 --- /dev/null +++ b/docs/historical/SRI-NOSC/pickup.c @@ -0,0 +1,201 @@ +#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("<> ", 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(); +} + + + + diff --git a/docs/historical/SRI-NOSC/pickup.run b/docs/historical/SRI-NOSC/pickup.run new file mode 100644 index 00000000..321fdc3f --- /dev/null +++ b/docs/historical/SRI-NOSC/pickup.run @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/SRI-NOSC/pr.c b/docs/historical/SRI-NOSC/pr.c new file mode 100644 index 00000000..ddfac043 --- /dev/null +++ b/docs/historical/SRI-NOSC/pr.c @@ -0,0 +1,1050 @@ +# +/* + * 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; +} diff --git a/docs/historical/SRI-NOSC/pr.run b/docs/historical/SRI-NOSC/pr.run new file mode 100644 index 00000000..d2a5c60d --- /dev/null +++ b/docs/historical/SRI-NOSC/pr.run @@ -0,0 +1,2 @@ +cc -n pr.c +if -r a.out mv a.out pr diff --git a/docs/historical/SRI-NOSC/prompter.c b/docs/historical/SRI-NOSC/prompter.c new file mode 100644 index 00000000..4ac66812 --- /dev/null +++ b/docs/historical/SRI-NOSC/prompter.c @@ -0,0 +1,323 @@ +#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 /* @ => */ +#define CERASE 001 /* # => */ + +/*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 */ + if(field[0] == 0) { + printf("Options are:\n no\n yes\n show\n \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("", c + '@'); + else + printf("%c", c); +} diff --git a/docs/historical/SRI-NOSC/prompter.run b/docs/historical/SRI-NOSC/prompter.run new file mode 100644 index 00000000..60c23119 --- /dev/null +++ b/docs/historical/SRI-NOSC/prompter.run @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/SRI-NOSC/purge.c b/docs/historical/SRI-NOSC/purge.c new file mode 100644 index 00000000..5e4a66aa --- /dev/null +++ b/docs/historical/SRI-NOSC/purge.c @@ -0,0 +1,144 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/purge.run b/docs/historical/SRI-NOSC/purge.run new file mode 100644 index 00000000..b73af250 --- /dev/null +++ b/docs/historical/SRI-NOSC/purge.run @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/SRI-NOSC/putc.s b/docs/historical/SRI-NOSC/putc.s new file mode 100644 index 00000000..e6474dd0 --- /dev/null +++ b/docs/historical/SRI-NOSC/putc.s @@ -0,0 +1,93 @@ +/ 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 diff --git a/docs/historical/SRI-NOSC/reply.c b/docs/historical/SRI-NOSC/reply.c new file mode 100644 index 00000000..ac9f42f5 --- /dev/null +++ b/docs/historical/SRI-NOSC/reply.c @@ -0,0 +1,333 @@ +#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 */ +} + diff --git a/docs/historical/SRI-NOSC/reply.run b/docs/historical/SRI-NOSC/reply.run new file mode 100644 index 00000000..f541fab1 --- /dev/null +++ b/docs/historical/SRI-NOSC/reply.run @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/SRI-NOSC/rmf.c b/docs/historical/SRI-NOSC/rmf.c new file mode 100644 index 00000000..0ef88159 --- /dev/null +++ b/docs/historical/SRI-NOSC/rmf.c @@ -0,0 +1,178 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/rmf.run b/docs/historical/SRI-NOSC/rmf.run new file mode 100644 index 00000000..3f8a79c7 --- /dev/null +++ b/docs/historical/SRI-NOSC/rmf.run @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/SRI-NOSC/scan.c b/docs/historical/SRI-NOSC/scan.c new file mode 100644 index 00000000..dc4333c6 --- /dev/null +++ b/docs/historical/SRI-NOSC/scan.c @@ -0,0 +1,126 @@ +#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 [<curmsg); + close(in.b_fildes); + if(fout.b_nextp + 80 >= (&fout) + 1) + /* if(msgnum & 1) */ + flush(); + } + } + } + if(ff) + putchar('\014'); +leave: + m_update(); + flush(); +} + diff --git a/docs/historical/SRI-NOSC/scan.run b/docs/historical/SRI-NOSC/scan.run new file mode 100644 index 00000000..4ed0c93c --- /dev/null +++ b/docs/historical/SRI-NOSC/scan.run @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/SRI-NOSC/scansub.c b/docs/historical/SRI-NOSC/scansub.c new file mode 100644 index 00000000..b8c1411d --- /dev/null +++ b/docs/historical/SRI-NOSC/scansub.c @@ -0,0 +1,361 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/send-ec.run b/docs/historical/SRI-NOSC/send-ec.run new file mode 100755 index 00000000..16093cf1 --- /dev/null +++ b/docs/historical/SRI-NOSC/send-ec.run @@ -0,0 +1,7 @@ +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 diff --git a/docs/historical/SRI-NOSC/send.c b/docs/historical/SRI-NOSC/send.c new file mode 100644 index 00000000..0a6250b9 --- /dev/null +++ b/docs/historical/SRI-NOSC/send.c @@ -0,0 +1,933 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/send.run b/docs/historical/SRI-NOSC/send.run new file mode 100755 index 00000000..07ee0d82 --- /dev/null +++ b/docs/historical/SRI-NOSC/send.run @@ -0,0 +1,7 @@ +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 diff --git a/docs/historical/SRI-NOSC/sgtty.h b/docs/historical/SRI-NOSC/sgtty.h new file mode 100644 index 00000000..c8c8aaff --- /dev/null +++ b/docs/historical/SRI-NOSC/sgtty.h @@ -0,0 +1,38 @@ +/* + * 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 */ diff --git a/docs/historical/SRI-NOSC/show.c b/docs/historical/SRI-NOSC/show.c new file mode 100644 index 00000000..b6ed3f8c --- /dev/null +++ b/docs/historical/SRI-NOSC/show.c @@ -0,0 +1,147 @@ +#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(); +} diff --git a/docs/historical/SRI-NOSC/show.run b/docs/historical/SRI-NOSC/show.run new file mode 100644 index 00000000..00ea5d6d --- /dev/null +++ b/docs/historical/SRI-NOSC/show.run @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/SRI-NOSC/signals.h b/docs/historical/SRI-NOSC/signals.h new file mode 100644 index 00000000..69e424f0 --- /dev/null +++ b/docs/historical/SRI-NOSC/signals.h @@ -0,0 +1,20 @@ +#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) */ diff --git a/docs/historical/SRI-NOSC/stat.h b/docs/historical/SRI-NOSC/stat.h new file mode 100644 index 00000000..0fa8dc54 --- /dev/null +++ b/docs/historical/SRI-NOSC/stat.h @@ -0,0 +1,36 @@ +# +/* + * 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; }; diff --git a/docs/historical/SRI-NOSC/strings-ec.c b/docs/historical/SRI-NOSC/strings-ec.c new file mode 100644 index 00000000..89bb65d2 --- /dev/null +++ b/docs/historical/SRI-NOSC/strings-ec.c @@ -0,0 +1,42 @@ +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 */ diff --git a/docs/historical/SRI-NOSC/strings.c b/docs/historical/SRI-NOSC/strings.c new file mode 100644 index 00000000..a4a6a721 --- /dev/null +++ b/docs/historical/SRI-NOSC/strings.c @@ -0,0 +1,42 @@ +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 */ diff --git a/docs/historical/SRI-NOSC/strings.run b/docs/historical/SRI-NOSC/strings.run new file mode 100644 index 00000000..7bd013c4 --- /dev/null +++ b/docs/historical/SRI-NOSC/strings.run @@ -0,0 +1,2 @@ +cc -c strings.c +if -r strings.o mv strings.o strings.a diff --git a/docs/historical/SRI-NOSC/subs.dir/ambigsw.c b/docs/historical/SRI-NOSC/subs.dir/ambigsw.c new file mode 100644 index 00000000..2aa265c0 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/ambigsw.c @@ -0,0 +1,8 @@ +ambigsw(arg, swp) +char *arg; +{ + printf("%s: ", invo_name()); + printf("-%s ambiguous. It matches \n", arg); + printsw(arg, swp); +} + diff --git a/docs/historical/SRI-NOSC/subs.dir/atoi.c b/docs/historical/SRI-NOSC/subs.dir/atoi.c new file mode 100644 index 00000000..d33254cb --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/atoi.c @@ -0,0 +1,13 @@ +atoi(str) +{ + register char *cp; + register int i; + + i = 0; + cp = str; + while(*cp >= '0' && *cp <= '9') { + i =* 10; + i =+ *cp++ - '0'; + } + return(i); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/atooi.c b/docs/historical/SRI-NOSC/subs.dir/atooi.c new file mode 100644 index 00000000..11fab041 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/atooi.c @@ -0,0 +1,16 @@ +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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/cfree.c b/docs/historical/SRI-NOSC/subs.dir/cfree.c new file mode 100644 index 00000000..2b7abece --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/cfree.c @@ -0,0 +1,12 @@ +/* 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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/concat.c b/docs/historical/SRI-NOSC/subs.dir/concat.c new file mode 100644 index 00000000..a86cb2b4 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/concat.c @@ -0,0 +1,15 @@ +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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/copyip.c b/docs/historical/SRI-NOSC/subs.dir/copyip.c new file mode 100644 index 00000000..47c30b42 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/copyip.c @@ -0,0 +1,12 @@ +copyip(ipfrom, ipto) +int *ipfrom, *ipto; +{ + register int *ipf, *ipt; + + ipf=ipfrom; ipt=ipto; + while((*ipt = *ipf) && *ipf++ != -1) + ipt++; + *ipt = 0; + return(ipt); +} + diff --git a/docs/historical/SRI-NOSC/subs.dir/cputc.c b/docs/historical/SRI-NOSC/subs.dir/cputc.c new file mode 100644 index 00000000..ba7c9073 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/cputc.c @@ -0,0 +1,15 @@ +#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); } + } +} diff --git a/docs/historical/SRI-NOSC/subs.dir/gans.c b/docs/historical/SRI-NOSC/subs.dir/gans.c new file mode 100644 index 00000000..52b0b26a --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/gans.c @@ -0,0 +1,37 @@ +#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); + } +} diff --git a/docs/historical/SRI-NOSC/subs.dir/getchar.c b/docs/historical/SRI-NOSC/subs.dir/getchar.c new file mode 100644 index 00000000..a2b84547 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/getchar.c @@ -0,0 +1,9 @@ +getchar() +{ + int c; + + c = 0; + if(read(0, &c, 1) != 1) + return(0); + return(c); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/getcpy.c b/docs/historical/SRI-NOSC/subs.dir/getcpy.c new file mode 100644 index 00000000..08a47333 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/getcpy.c @@ -0,0 +1,8 @@ +getcpy(str) +{ + register char *cp; + + cp = alloc(length(str) + 1); + copy(str, cp); + return(cp); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/help.c b/docs/historical/SRI-NOSC/subs.dir/help.c new file mode 100644 index 00000000..d1758280 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/help.c @@ -0,0 +1,9 @@ +#include "mh.h" + +help(str, swp) +char *str; +{ + printf("syntax: %s\n", str); + printf(" switches are:\n"); + printsw(ALL, swp); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/invo_name.c b/docs/historical/SRI-NOSC/subs.dir/invo_name.c new file mode 100644 index 00000000..bf6a8551 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/invo_name.c @@ -0,0 +1,12 @@ +invo_name() +{ + register int *ip; + + ip = 0; + + while(*--ip != -1) + ; + while(*--ip < 0) + ; + return(ip[2]); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_convert.c b/docs/historical/SRI-NOSC/subs.dir/m_convert.c new file mode 100644 index 00000000..84becba8 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_convert.c @@ -0,0 +1,156 @@ +#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 */ +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_convert.c.te b/docs/historical/SRI-NOSC/subs.dir/m_convert.c.te new file mode 100644 index 00000000..7ddd0158 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_convert.c.te @@ -0,0 +1,142 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_convert.c.tm b/docs/historical/SRI-NOSC/subs.dir/m_convert.c.tm new file mode 100644 index 00000000..60559b56 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_convert.c.tm @@ -0,0 +1,139 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_convert.old b/docs/historical/SRI-NOSC/subs.dir/m_convert.old new file mode 100644 index 00000000..494d97af --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_convert.old @@ -0,0 +1,165 @@ +#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 */ +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_delete.c b/docs/historical/SRI-NOSC/subs.dir/m_delete.c new file mode 100644 index 00000000..ab81a0ea --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_delete.c @@ -0,0 +1,21 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_find.c b/docs/historical/SRI-NOSC/subs.dir/m_find.c new file mode 100644 index 00000000..e8968c2c --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_find.c @@ -0,0 +1,12 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_getdefs.c b/docs/historical/SRI-NOSC/subs.dir/m_getdefs.c new file mode 100644 index 00000000..53f7bb4e --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_getdefs.c @@ -0,0 +1,69 @@ +#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); + } +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_getfld.c b/docs/historical/SRI-NOSC/subs.dir/m_getfld.c new file mode 100644 index 00000000..8add2c3b --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_getfld.c @@ -0,0 +1,86 @@ +#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)? "":"", 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); + } + + } +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_getfolder.c b/docs/historical/SRI-NOSC/subs.dir/m_getfolder.c new file mode 100644 index 00000000..0a04b90f --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_getfolder.c @@ -0,0 +1,11 @@ +char defalt[]; + +m_getfolder() +{ + register char *folder; + + m_getdefs(); + if((folder = m_find("folder")) == -1 || *folder == 0) + folder = defalt; + return(folder); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_gmprot.c b/docs/historical/SRI-NOSC/subs.dir/m_gmprot.c new file mode 100644 index 00000000..46b54356 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_gmprot.c @@ -0,0 +1,12 @@ +char msgprot[]; + +m_gmprot() +{ + register int prot; + + if((prot = m_find("msg-protect")) != -1) + prot = atooi(prot); + else + prot = atooi(msgprot); + return(prot); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_gmsg.c b/docs/historical/SRI-NOSC/subs.dir/m_gmsg.c new file mode 100644 index 00000000..d0989460 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_gmsg.c @@ -0,0 +1,125 @@ +#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 */ + 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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_maildir.c b/docs/historical/SRI-NOSC/subs.dir/m_maildir.c new file mode 100644 index 00000000..b8c88675 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_maildir.c @@ -0,0 +1,23 @@ +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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_name.c b/docs/historical/SRI-NOSC/subs.dir/m_name.c new file mode 100644 index 00000000..d1db6c21 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_name.c @@ -0,0 +1,25 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_news.cc b/docs/historical/SRI-NOSC/subs.dir/m_news.cc new file mode 100644 index 00000000..24e8f661 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_news.cc @@ -0,0 +1,25 @@ +#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); + } +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_replace.c b/docs/historical/SRI-NOSC/subs.dir/m_replace.c new file mode 100644 index 00000000..96a96f52 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_replace.c @@ -0,0 +1,29 @@ +#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; +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_setcur.c b/docs/historical/SRI-NOSC/subs.dir/m_setcur.c new file mode 100644 index 00000000..e35edb0b --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_setcur.c @@ -0,0 +1,27 @@ +#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); + } + } +} diff --git a/docs/historical/SRI-NOSC/subs.dir/m_update.c b/docs/historical/SRI-NOSC/subs.dir/m_update.c new file mode 100644 index 00000000..24a6619d --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/m_update.c @@ -0,0 +1,30 @@ +#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; + } +} diff --git a/docs/historical/SRI-NOSC/subs.dir/makedir.c b/docs/historical/SRI-NOSC/subs.dir/makedir.c new file mode 100644 index 00000000..28c3a715 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/makedir.c @@ -0,0 +1,28 @@ +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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/peekc.c b/docs/historical/SRI-NOSC/subs.dir/peekc.c new file mode 100644 index 00000000..34a14f70 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/peekc.c @@ -0,0 +1,15 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/pr_array.c b/docs/historical/SRI-NOSC/subs.dir/pr_array.c new file mode 100644 index 00000000..00fddabd --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/pr_array.c @@ -0,0 +1,9 @@ +pr_array(cp,ap) +char *cp, **ap; +{ + register int i; + + for(i=0; *ap; ap++,i++) + printf("%s[%d]=> %s\n", cp,i,*ap); +} + diff --git a/docs/historical/SRI-NOSC/subs.dir/printsw.c b/docs/historical/SRI-NOSC/subs.dir/printsw.c new file mode 100644 index 00000000..a69f1e10 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/printsw.c @@ -0,0 +1,26 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/puts.c b/docs/historical/SRI-NOSC/subs.dir/puts.c new file mode 100644 index 00000000..b4d16162 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/puts.c @@ -0,0 +1,18 @@ +#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); } + } +} diff --git a/docs/historical/SRI-NOSC/subs.dir/showfile.c b/docs/historical/SRI-NOSC/subs.dir/showfile.c new file mode 100644 index 00000000..b6ce76a3 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/showfile.c @@ -0,0 +1,18 @@ +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; +} diff --git a/docs/historical/SRI-NOSC/subs.dir/smatch.c b/docs/historical/SRI-NOSC/subs.dir/smatch.c new file mode 100644 index 00000000..0da9c7eb --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/smatch.c @@ -0,0 +1,37 @@ +#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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/ssequal.c b/docs/historical/SRI-NOSC/subs.dir/ssequal.c new file mode 100644 index 00000000..124581c2 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/ssequal.c @@ -0,0 +1,8 @@ +ssequal(substr, str) +char *substr, *str; +{ + while(*substr) + if(*substr++ != *str++) + return(0); + return(1); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/subs.run b/docs/historical/SRI-NOSC/subs.dir/subs.run new file mode 100755 index 00000000..d5542d47 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/subs.run @@ -0,0 +1,20 @@ +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 diff --git a/docs/historical/SRI-NOSC/subs.dir/trimcpy.c b/docs/historical/SRI-NOSC/subs.dir/trimcpy.c new file mode 100644 index 00000000..d14ab6c2 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/trimcpy.c @@ -0,0 +1,16 @@ +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); +} diff --git a/docs/historical/SRI-NOSC/subs.dir/uleq.c b/docs/historical/SRI-NOSC/subs.dir/uleq.c new file mode 100644 index 00000000..da58a0c6 --- /dev/null +++ b/docs/historical/SRI-NOSC/subs.dir/uleq.c @@ -0,0 +1,13 @@ +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); +} diff --git a/docs/historical/SRI-NOSC/undelete.c b/docs/historical/SRI-NOSC/undelete.c new file mode 100644 index 00000000..2cfead63 --- /dev/null +++ b/docs/historical/SRI-NOSC/undelete.c @@ -0,0 +1,103 @@ +#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(); +} diff --git a/docs/historical/SRI-NOSC/undelete.run b/docs/historical/SRI-NOSC/undelete.run new file mode 100644 index 00000000..a8771618 --- /dev/null +++ b/docs/historical/SRI-NOSC/undelete.run @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/SRI-NOSC/wait.s b/docs/historical/SRI-NOSC/wait.s new file mode 100644 index 00000000..76599b89 --- /dev/null +++ b/docs/historical/SRI-NOSC/wait.s @@ -0,0 +1,21 @@ +/ 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 diff --git a/docs/historical/SRI-NOSC/write.c b/docs/historical/SRI-NOSC/write.c new file mode 100644 index 00000000..eb6fb10e --- /dev/null +++ b/docs/historical/SRI-NOSC/write.c @@ -0,0 +1,190 @@ +#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(); +} + + + + + diff --git a/docs/historical/SRI-NOSC/write.run b/docs/historical/SRI-NOSC/write.run new file mode 100644 index 00000000..19c7532a --- /dev/null +++ b/docs/historical/SRI-NOSC/write.run @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/mh-6.8.5/miscellany/mem/a.out b/docs/historical/mh-6.8.5/miscellany/mem/a.out deleted file mode 100755 index 90eeea62..00000000 Binary files a/docs/historical/mh-6.8.5/miscellany/mem/a.out and /dev/null differ diff --git a/docs/historical/mh-jun-1982/4bsd.changes b/docs/historical/mh-jun-1982/4bsd.changes new file mode 100644 index 00000000..d4374623 --- /dev/null +++ b/docs/historical/mh-jun-1982/4bsd.changes @@ -0,0 +1,7 @@ + + +11/15/80 + + _sobuf is defined. Previously it was in stdio.h + + errno is defined. Previously it was in errno.h diff --git a/docs/historical/mh-jun-1982/ANOMALIES b/docs/historical/mh-jun-1982/ANOMALIES new file mode 100644 index 00000000..7198dc93 --- /dev/null +++ b/docs/historical/mh-jun-1982/ANOMALIES @@ -0,0 +1,12 @@ +"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. diff --git a/docs/historical/mh-jun-1982/Alias.Design b/docs/historical/mh-jun-1982/Alias.Design new file mode 100644 index 00000000..ed2490aa --- /dev/null +++ b/docs/historical/mh-jun-1982/Alias.Design @@ -0,0 +1,67 @@ +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." will +be mapped to "news". This is used for the MH news facility. + +Bruce Borden October 1979 diff --git a/docs/historical/mh-jun-1982/Bugs b/docs/historical/mh-jun-1982/Bugs new file mode 100644 index 00000000..320ebf70 --- /dev/null +++ b/docs/historical/mh-jun-1982/Bugs @@ -0,0 +1,213 @@ +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 diff --git a/docs/historical/mh-jun-1982/DOC/README b/docs/historical/mh-jun-1982/DOC/README new file mode 100644 index 00000000..2d2dc74d --- /dev/null +++ b/docs/historical/mh-jun-1982/DOC/README @@ -0,0 +1 @@ +More recent information is to be found in the man pages in ../man diff --git a/docs/historical/mh-jun-1982/DOC/brief b/docs/historical/mh-jun-1982/DOC/brief new file mode 100644 index 00000000..b09d6661 --- /dev/null +++ b/docs/historical/mh-jun-1982/DOC/brief @@ -0,0 +1,41 @@ + + + + + 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. diff --git a/docs/historical/mh-jun-1982/DOC/mh.me b/docs/historical/mh-jun-1982/DOC/mh.me new file mode 100644 index 00000000..f46b2fa4 --- /dev/null +++ b/docs/historical/mh-jun-1982/DOC/mh.me @@ -0,0 +1,2508 @@ +.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 \*(<\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//Mail/draft (where /usr/ 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 +( 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\*(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\-next:\0\*(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 +^:\0default switches~^All +^cur\-:\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 . +(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 \fR, to invoke + 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\-next: \*(rq names an alternative editor. + +.Fi +^/etc/mh/components~^The message skeleton +^or /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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\*(<> + 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 /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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 +.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/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: \*(<> + 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 /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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 +\*(<> date +.ti 1.5i + +.ti 1.5i + +.ti 2.5i + +.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 +^/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 \*(< will cause the whole component to be left out. +A \*(lq\\\*(rq +preceding a 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 (or ). +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 during message-body typing is equivalent to + for compatibility with NED. +A 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: or +cc: , +Subject: Re: +In-reply-to: Your message of +.ti +\w'In-reply-to: 'u + +.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: \*(<>. + +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 +^/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\ \ \ \ \[\*(</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 + 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 +or . +If a is entered, \fIl\fR will clear the +screen before listing the next page, whereas 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 /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 + 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~^| +^^^^^ + +^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~^| +^^^^^\*(lq\--\*(rq~^| +^^^^ +.re \" Reset Tabs +.fi +.sp +.pp +Where 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 of messages, beginning +with \*(lqmsg\*(rq (in the case of first, cur, next, or ), +or ending with \*(lqmsg\*(rq (in the case of prev or last). ++ forces \*(lqstarting with msg\*(rq, and \- 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 diff --git a/docs/historical/mh-jun-1982/DOC/mh.me.5 b/docs/historical/mh-jun-1982/DOC/mh.me.5 new file mode 100644 index 00000000..de016ee7 --- /dev/null +++ b/docs/historical/mh-jun-1982/DOC/mh.me.5 @@ -0,0 +1,2507 @@ +.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 \*(<\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//Mail/draft (where /usr/ 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 +( 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\*(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\-next:\0\*(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 +^:\0default switches~^All +^cur\-:\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 . +(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 \fR, to invoke + 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\-next: \*(rq names an alternative editor. + +.Fi +^/etc/mh/components~^The message skeleton +^or /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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\*(<> + 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 /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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 +.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/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: \*(<> + 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 /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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 +\*(<> date +.ti 1.5i + +.ti 1.5i + +.ti 2.5i + +.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 +^/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 \*(< will cause the whole component to be left out. +A \*(lq\\\*(rq +preceding a 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 (or ). +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 during message-body typing is equivalent to + for compatibility with NED. +A 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: or +cc: , +Subject: Re: +In-reply-to: Your message of +.ti +\w'In-reply-to: 'u + +.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: \*(<>. + +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 +^/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\ \ \ \ \[\*(</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 + 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 +or . +If a is entered, \fIl\fR will clear the +screen before listing the next page, whereas 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 /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 + 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~^| +^^^^^ + +^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~^| +^^^^^\*(lq\--\*(rq~^| +^^^^ +.re \" Reset Tabs +.fi +.sp +.pp +Where 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 of messages, beginning +with \*(lqmsg\*(rq (in the case of first, cur, next, or ), +or ending with \*(lqmsg\*(rq (in the case of prev or last). ++ forces \*(lqstarting with msg\*(rq, and \- 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 diff --git a/docs/historical/mh-jun-1982/DOC/mh1.nr b/docs/historical/mh-jun-1982/DOC/mh1.nr new file mode 100644 index 00000000..a6139810 --- /dev/null +++ b/docs/historical/mh-jun-1982/DOC/mh1.nr @@ -0,0 +1,2482 @@ +.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 \*(<\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//Mail/draft (where /usr/ 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 +( 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\*(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\-next:\0\*(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 +^:\0default switches~^All +^cur\-:\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 . +(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 \fR, to invoke + 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\-next: \*(rq names an alternative editor. + +.Fi +^/etc/mh/components~^The message skeleton +^or /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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\*(<> + 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 /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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 +.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/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: \*(<> + 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 /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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 +\*(<> date +.ti 1.5i + +.ti 1.5i + +.ti 2.5i + +.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 +^/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 \*(< will cause the whole component to be left out. +A \*(lq\\\*(rq +preceding a 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 (or ). +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 ( 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 , 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 during message-body typing is equivalent to + for compatibility with NED. +A 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: or +cc: , +Subject: Re: +In-reply-to: Your message of +.ti +\w'In-reply-to: 'u + +.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: \*(<> + +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 +^/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\ \ \ \ \[\*(</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 + 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 +or . +If a is entered, \fIl\fR will clear the +screen before listing the next page, whereas 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 /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 + 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~^| +^^^^^ + +^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~^| +^^^^^\*(lq\--\*(rq~^| +^^^^ +.re \" Reset Tabs +.fi +.sp +.pp +Where 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 of messages, beginning +with \*(lqmsg\*(rq (in the case of first, cur, next, or ), +or ending with \*(lqmsg\*(rq (in the case of prev or last). ++ forces \*(lqstarting with msg\*(rq, and \- 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 diff --git a/docs/historical/mh-jun-1982/DOC/mhcov.t b/docs/historical/mh-jun-1982/DOC/mhcov.t new file mode 100644 index 00000000..38aaee7d --- /dev/null +++ b/docs/historical/mh-jun-1982/DOC/mhcov.t @@ -0,0 +1,29 @@ +.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 diff --git a/docs/historical/mh-jun-1982/DOC/rand.t b/docs/historical/mh-jun-1982/DOC/rand.t new file mode 100644 index 00000000..e28549bb --- /dev/null +++ b/docs/historical/mh-jun-1982/DOC/rand.t @@ -0,0 +1,10 @@ +.de RA +.mk v +\kh\c +.ft B +.ps \\$1 +.vs \\$1+2 +RAND\kH +.br +.ps \\$1/4 +SANTA MONICA, CA. 90406 diff --git a/docs/historical/mh-jun-1982/Extras/anno.bld b/docs/historical/mh-jun-1982/Extras/anno.bld new file mode 100644 index 00000000..56e135ed --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/anno.bld @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/mh-jun-1982/Extras/anno.cc b/docs/historical/mh-jun-1982/Extras/anno.cc new file mode 100644 index 00000000..397bfa00 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/anno.cc @@ -0,0 +1,162 @@ +#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: <> + * 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; diff --git a/docs/historical/mh-jun-1982/Extras/getenv.c b/docs/historical/mh-jun-1982/Extras/getenv.c new file mode 100644 index 00000000..eeaa939b --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/getenv.c @@ -0,0 +1,25 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include +#include + +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; +} diff --git a/docs/historical/mh-jun-1982/Extras/imp.h b/docs/historical/mh-jun-1982/Extras/imp.h new file mode 100644 index 00000000..de51d376 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/imp.h @@ -0,0 +1,83 @@ +#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 diff --git a/docs/historical/mh-jun-1982/Extras/lasthdr.c b/docs/historical/mh-jun-1982/Extras/lasthdr.c new file mode 100644 index 00000000..d6bf0aef --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/lasthdr.c @@ -0,0 +1,8 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +int glbtype 0; diff --git a/docs/historical/mh-jun-1982/Extras/libg/getpw.c b/docs/historical/mh-jun-1982/Extras/libg/getpw.c new file mode 100644 index 00000000..fa8a40f0 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/getpw.c @@ -0,0 +1,68 @@ +#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++); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/getwho.c b/docs/historical/mh-jun-1982/Extras/libg/getwho.c new file mode 100644 index 00000000..2430c2ea --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/getwho.c @@ -0,0 +1,19 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/gtfstn.c b/docs/historical/mh-jun-1982/Extras/libg/gtfstn.c new file mode 100644 index 00000000..f8ba9cac --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/gtfstn.c @@ -0,0 +1,12 @@ +#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"); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/gtldat.c b/docs/historical/mh-jun-1982/Extras/libg/gtldat.c new file mode 100644 index 00000000..5dea14b4 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/gtldat.c @@ -0,0 +1,14 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/gtlogn.c b/docs/historical/mh-jun-1982/Extras/libg/gtlogn.c new file mode 100644 index 00000000..205cdeaa --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/gtlogn.c @@ -0,0 +1,21 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/gtlstn.c b/docs/historical/mh-jun-1982/Extras/libg/gtlstn.c new file mode 100644 index 00000000..6896bcbf --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/gtlstn.c @@ -0,0 +1,12 @@ +#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"); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/gtluid.c b/docs/historical/mh-jun-1982/Extras/libg/gtluid.c new file mode 100644 index 00000000..88daa1a9 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/gtluid.c @@ -0,0 +1,23 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/gtmnem.c b/docs/historical/mh-jun-1982/Extras/libg/gtmnem.c new file mode 100644 index 00000000..ecd3acac --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/gtmnem.c @@ -0,0 +1,12 @@ +#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"); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/gtpath.c b/docs/historical/mh-jun-1982/Extras/libg/gtpath.c new file mode 100644 index 00000000..12ad8fba --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/gtpath.c @@ -0,0 +1,21 @@ +#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 diff --git a/docs/historical/mh-jun-1982/Extras/libg/gtpriv.c b/docs/historical/mh-jun-1982/Extras/libg/gtpriv.c new file mode 100644 index 00000000..6fb2735c --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/gtpriv.c @@ -0,0 +1,12 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/gtpswd.c b/docs/historical/mh-jun-1982/Extras/libg/gtpswd.c new file mode 100644 index 00000000..d2286e88 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/gtpswd.c @@ -0,0 +1,23 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/gtruid.c b/docs/historical/mh-jun-1982/Extras/libg/gtruid.c new file mode 100644 index 00000000..2d0afd15 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/gtruid.c @@ -0,0 +1,26 @@ +#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)); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/gttype.c b/docs/historical/mh-jun-1982/Extras/libg/gttype.c new file mode 100644 index 00000000..624efa3d --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/gttype.c @@ -0,0 +1,13 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/gtubuf.c b/docs/historical/mh-jun-1982/Extras/libg/gtubuf.c new file mode 100644 index 00000000..6193944b --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/gtubuf.c @@ -0,0 +1,16 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/gtunum.c b/docs/historical/mh-jun-1982/Extras/libg/gtunum.c new file mode 100644 index 00000000..38d1eff6 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/gtunum.c @@ -0,0 +1,51 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/ttynam.c b/docs/historical/mh-jun-1982/Extras/libg/ttynam.c new file mode 100644 index 00000000..b4e8dcbe --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/ttynam.c @@ -0,0 +1,34 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libg/ttynum.c b/docs/historical/mh-jun-1982/Extras/libg/ttynum.c new file mode 100644 index 00000000..dbf646fc --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libg/ttynum.c @@ -0,0 +1,40 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/any.c b/docs/historical/mh-jun-1982/Extras/libh/any.c new file mode 100644 index 00000000..d7bdf87b --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/any.c @@ -0,0 +1,17 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/brkstg.c b/docs/historical/mh-jun-1982/Extras/libh/brkstg.c new file mode 100644 index 00000000..e28f5196 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/brkstg.c @@ -0,0 +1,45 @@ +#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; bi12) + 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= 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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/echo.c b/docs/historical/mh-jun-1982/Extras/libh/echo.c new file mode 100644 index 00000000..9e499f19 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/echo.c @@ -0,0 +1,23 @@ +#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 diff --git a/docs/historical/mh-jun-1982/Extras/libh/equal.c b/docs/historical/mh-jun-1982/Extras/libh/equal.c new file mode 100644 index 00000000..6170dcc6 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/equal.c @@ -0,0 +1,16 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/error.c b/docs/historical/mh-jun-1982/Extras/libh/error.c new file mode 100644 index 00000000..c9686561 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/error.c @@ -0,0 +1,20 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/errtyp.c b/docs/historical/mh-jun-1982/Extras/libh/errtyp.c new file mode 100644 index 00000000..77c2312b --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/errtyp.c @@ -0,0 +1,24 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/excsrh.c b/docs/historical/mh-jun-1982/Extras/libh/excsrh.c new file mode 100644 index 00000000..95b4580d --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/excsrh.c @@ -0,0 +1,61 @@ +#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)); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/execsh.c b/docs/historical/mh-jun-1982/Extras/libh/execsh.c new file mode 100644 index 00000000..d584d70c --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/execsh.c @@ -0,0 +1,45 @@ +#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)); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/fmt.c b/docs/historical/mh-jun-1982/Extras/libh/fmt.c new file mode 100644 index 00000000..4d9b5715 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/fmt.c @@ -0,0 +1,38 @@ +#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]); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/fopen2.c b/docs/historical/mh-jun-1982/Extras/libh/fopen2.c new file mode 100644 index 00000000..5c40bb3b --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/fopen2.c @@ -0,0 +1,26 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/fseek.c b/docs/historical/mh-jun-1982/Extras/libh/fseek.c new file mode 100644 index 00000000..356864e4 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/fseek.c @@ -0,0 +1,89 @@ +#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 diff --git a/docs/historical/mh-jun-1982/Extras/libh/gdate.c b/docs/historical/mh-jun-1982/Extras/libh/gdate.c new file mode 100644 index 00000000..fedface4 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/gdate.c @@ -0,0 +1,144 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/getcopy.c b/docs/historical/mh-jun-1982/Extras/libh/getcopy.c new file mode 100644 index 00000000..bd6db764 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/getcopy.c @@ -0,0 +1,34 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/getl.c b/docs/historical/mh-jun-1982/Extras/libh/getl.c new file mode 100644 index 00000000..cfacb31c --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/getl.c @@ -0,0 +1,28 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/getline.c b/docs/historical/mh-jun-1982/Extras/libh/getline.c new file mode 100644 index 00000000..bfe014b2 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/getline.c @@ -0,0 +1,25 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/glbmtc.c b/docs/historical/mh-jun-1982/Extras/libh/glbmtc.c new file mode 100644 index 00000000..d85beae9 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/glbmtc.c @@ -0,0 +1,58 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/gwd.c b/docs/historical/mh-jun-1982/Extras/libh/gwd.c new file mode 100644 index 00000000..d8a8319c --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/gwd.c @@ -0,0 +1,123 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/inputf.c b/docs/historical/mh-jun-1982/Extras/libh/inputf.c new file mode 100644 index 00000000..78ba0ea6 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/inputf.c @@ -0,0 +1,184 @@ +#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 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 diff --git a/docs/historical/mh-jun-1982/Extras/libh/length.c b/docs/historical/mh-jun-1982/Extras/libh/length.c new file mode 100644 index 00000000..2b650721 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/length.c @@ -0,0 +1,16 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/makename.c b/docs/historical/mh-jun-1982/Extras/libh/makename.c new file mode 100644 index 00000000..0e0fcc00 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/makename.c @@ -0,0 +1,23 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/prndec.c b/docs/historical/mh-jun-1982/Extras/libh/prndec.c new file mode 100644 index 00000000..a5100801 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/prndec.c @@ -0,0 +1,33 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/subshell.c b/docs/historical/mh-jun-1982/Extras/libh/subshell.c new file mode 100644 index 00000000..eb8a88e5 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/subshell.c @@ -0,0 +1,44 @@ +#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]); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/swmtch.c b/docs/historical/mh-jun-1982/Extras/libh/swmtch.c new file mode 100644 index 00000000..1f9e4902 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/swmtch.c @@ -0,0 +1,35 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/t.c b/docs/historical/mh-jun-1982/Extras/libh/t.c new file mode 100644 index 00000000..c911f5c3 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/t.c @@ -0,0 +1,15 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/libh/type.c b/docs/historical/mh-jun-1982/Extras/libh/type.c new file mode 100644 index 00000000..1b3efcc8 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/libh/type.c @@ -0,0 +1,17 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/Extras/mailsys.h b/docs/historical/mh-jun-1982/Extras/mailsys.h new file mode 100644 index 00000000..3b56dc18 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/mailsys.h @@ -0,0 +1,19 @@ +#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 */ diff --git a/docs/historical/mh-jun-1982/Extras/resp.bld b/docs/historical/mh-jun-1982/Extras/resp.bld new file mode 100644 index 00000000..a770af06 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/resp.bld @@ -0,0 +1,5 @@ +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 + diff --git a/docs/historical/mh-jun-1982/Extras/resp.c b/docs/historical/mh-jun-1982/Extras/resp.c new file mode 100644 index 00000000..ec7bd531 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/resp.c @@ -0,0 +1,329 @@ +#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 []", 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; + } diff --git a/docs/historical/mh-jun-1982/Extras/sndmsg.bld b/docs/historical/mh-jun-1982/Extras/sndmsg.bld new file mode 100644 index 00000000..83286c25 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/sndmsg.bld @@ -0,0 +1,10 @@ +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 + diff --git a/docs/historical/mh-jun-1982/Extras/sndmsg.c b/docs/historical/mh-jun-1982/Extras/sndmsg.c new file mode 100644 index 00000000..481f4385 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/sndmsg.c @@ -0,0 +1,550 @@ +#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 diff --git a/docs/historical/mh-jun-1982/Extras/strings.h b/docs/historical/mh-jun-1982/Extras/strings.h new file mode 100644 index 00000000..46769601 --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/strings.h @@ -0,0 +1,12 @@ +/* + * Type definitions for the strings(3) subroutines. + */ + +char *strcat(); +char *strncat(); +char *strcpy(); +char *strncpy(); +int strcmp(); +int strncmp(); +char *index(); +char *rindex(); diff --git a/docs/historical/mh-jun-1982/Extras/whoami.h b/docs/historical/mh-jun-1982/Extras/whoami.h new file mode 100644 index 00000000..fdd5c3be --- /dev/null +++ b/docs/historical/mh-jun-1982/Extras/whoami.h @@ -0,0 +1,13 @@ +/* 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. */ diff --git a/docs/historical/mh-jun-1982/Log b/docs/historical/mh-jun-1982/Log new file mode 100644 index 00000000..ce631939 --- /dev/null +++ b/docs/historical/mh-jun-1982/Log @@ -0,0 +1,300 @@ +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 ) + +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 , + 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 *, 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 diff --git a/docs/historical/mh-jun-1982/MHL.Design b/docs/historical/mh-jun-1982/MHL.Design new file mode 100644 index 00000000..0546b960 --- /dev/null +++ b/docs/historical/mh-jun-1982/MHL.Design @@ -0,0 +1,148 @@ + 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 or will begin the output, with +clearing the screen (if appropriate), and suppressing the screen +clear. An will abort the current message ouput, prompting +for the next message (if there is one), and a 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 diff --git a/docs/historical/mh-jun-1982/MHgenerate b/docs/historical/mh-jun-1982/MHgenerate new file mode 100644 index 00000000..3570300b --- /dev/null +++ b/docs/historical/mh-jun-1982/MHgenerate @@ -0,0 +1,178 @@ + 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 diff --git a/docs/historical/mh-jun-1982/MHnotes b/docs/historical/mh-jun-1982/MHnotes new file mode 100644 index 00000000..a62da1fd --- /dev/null +++ b/docs/historical/mh-jun-1982/MHnotes @@ -0,0 +1,186 @@ +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-: highest-seen". + + Rather than read through the news folders to determine + the number of entries, a file with name . (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 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 diff --git a/docs/historical/mh-jun-1982/Makefile b/docs/historical/mh-jun-1982/Makefile new file mode 100644 index 00000000..dc27821d --- /dev/null +++ b/docs/historical/mh-jun-1982/Makefile @@ -0,0 +1,100 @@ +# +# 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 diff --git a/docs/historical/mh-jun-1982/README b/docs/historical/mh-jun-1982/README new file mode 100644 index 00000000..3ba4b78b --- /dev/null +++ b/docs/historical/mh-jun-1982/README @@ -0,0 +1,7 @@ +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. diff --git a/docs/historical/mh-jun-1982/Wishlist b/docs/historical/mh-jun-1982/Wishlist new file mode 100644 index 00000000..4f4cd1f0 --- /dev/null +++ b/docs/historical/mh-jun-1982/Wishlist @@ -0,0 +1,509 @@ +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 " -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: " 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 + #include + + 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 option, + where 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 + + Environment Variable + is your actual login name USER + is your login directory HOME + 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 ") + (Done by having a file with one line for each user, of the format: +
: + is the local user name + says whether or not to forward +
is the forwarding address + 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 + -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: + +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 diff --git a/docs/historical/mh-jun-1982/adrparse.h b/docs/historical/mh-jun-1982/adrparse.h new file mode 100644 index 00000000..6d49ae47 --- /dev/null +++ b/docs/historical/mh-jun-1982/adrparse.h @@ -0,0 +1,35 @@ +#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 */ diff --git a/docs/historical/mh-jun-1982/dytest/Makefile b/docs/historical/mh-jun-1982/dytest/Makefile new file mode 100644 index 00000000..d2dfb297 --- /dev/null +++ b/docs/historical/mh-jun-1982/dytest/Makefile @@ -0,0 +1,414 @@ +# +# 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 diff --git a/docs/historical/mh-jun-1982/dytest/README b/docs/historical/mh-jun-1982/dytest/README new file mode 100644 index 00000000..10d9c017 --- /dev/null +++ b/docs/historical/mh-jun-1982/dytest/README @@ -0,0 +1,2 @@ +This directory contains Dave Yost's test versions +of some mh commands. diff --git a/docs/historical/mh-jun-1982/dytest/mhl.c b/docs/historical/mh-jun-1982/dytest/mhl.c new file mode 100644 index 00000000..1441e3c1 --- /dev/null +++ b/docs/historical/mh-jun-1982/dytest/mhl.c @@ -0,0 +1,762 @@ +#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 +#include +#include +#include +#ifndef INCLUDED_BY_SHOW +#include +#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 */ + +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 */ + + 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 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 diff --git a/docs/historical/mh-jun-1982/dytest/show.c b/docs/historical/mh-jun-1982/dytest/show.c new file mode 100644 index 00000000..83dede24 --- /dev/null +++ b/docs/historical/mh-jun-1982/dytest/show.c @@ -0,0 +1,177 @@ +#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 +#include + +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" diff --git a/docs/historical/mh-jun-1982/folder.h b/docs/historical/mh-jun-1982/folder.h new file mode 100644 index 00000000..2818cfa7 --- /dev/null +++ b/docs/historical/mh-jun-1982/folder.h @@ -0,0 +1,13 @@ +#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; +}; diff --git a/docs/historical/mh-jun-1982/man/Makefile b/docs/historical/mh-jun-1982/man/Makefile new file mode 100644 index 00000000..989fd9e7 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/Makefile @@ -0,0 +1,54 @@ +# +# 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) diff --git a/docs/historical/mh-jun-1982/man/ali.1 b/docs/historical/mh-jun-1982/man/ali.1 new file mode 100644 index 00000000..2721bb3f --- /dev/null +++ b/docs/historical/mh-jun-1982/man/ali.1 @@ -0,0 +1,35 @@ +.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) diff --git a/docs/historical/mh-jun-1982/man/comp.1 b/docs/historical/mh-jun-1982/man/comp.1 new file mode 100644 index 00000000..1be70dd7 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/comp.1 @@ -0,0 +1,99 @@ +.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 \fR, to invoke + for further editing; and \fBedit\fR, to re-edit using the +same editor that was used on the preceding round unless a profile +entry ``\-next: '' 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 /components Rather than the standard +.br +$HOME/\*.mh\(ruprofile The user profile +.br +/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 +\-next: To name an editor to be used + after exit from +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 diff --git a/docs/historical/mh-jun-1982/man/conflict.8 b/docs/historical/mh-jun-1982/man/conflict.8 new file mode 100644 index 00000000..0de74185 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/conflict.8 @@ -0,0 +1,52 @@ +.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) diff --git a/docs/historical/mh-jun-1982/man/deliver.8 b/docs/historical/mh-jun-1982/man/deliver.8 new file mode 100644 index 00000000..875963f5 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/deliver.8 @@ -0,0 +1,161 @@ +.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. diff --git a/docs/historical/mh-jun-1982/man/dist.1 b/docs/historical/mh-jun-1982/man/dist.1 new file mode 100644 index 00000000..8f75984a --- /dev/null +++ b/docs/historical/mh-jun-1982/man/dist.1 @@ -0,0 +1,96 @@ +.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:\ <> + 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 /components Rather than the standard skeleton +.br +$HOME/.mh\(ruprofile The user profile +.br +/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 +\-next: To name an editor to be used + after exit from +.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 diff --git a/docs/historical/mh-jun-1982/man/file.1 b/docs/historical/mh-jun-1982/man/file.1 new file mode 100644 index 00000000..048eca91 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/file.1 @@ -0,0 +1,87 @@ +.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. diff --git a/docs/historical/mh-jun-1982/man/folder.1 b/docs/historical/mh-jun-1982/man/folder.1 new file mode 100644 index 00000000..12d0f528 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/folder.1 @@ -0,0 +1,104 @@ +.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 ``/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. diff --git a/docs/historical/mh-jun-1982/man/folders.1 b/docs/historical/mh-jun-1982/man/folders.1 new file mode 100644 index 00000000..4c13cc9e --- /dev/null +++ b/docs/historical/mh-jun-1982/man/folders.1 @@ -0,0 +1 @@ +.so /usr/man/man1/folder.1 diff --git a/docs/historical/mh-jun-1982/man/forw.1 b/docs/historical/mh-jun-1982/man/forw.1 new file mode 100644 index 00000000..c228fc0f --- /dev/null +++ b/docs/historical/mh-jun-1982/man/forw.1 @@ -0,0 +1,77 @@ +.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: \*(<> + 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 /components Rather than the standard skeleton +.br +$HOME/\*.mh\(ruprofile The user profile +.br +/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 +\-next: To name an editor to be used + after exit from +.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 diff --git a/docs/historical/mh-jun-1982/man/inc.1 b/docs/historical/mh-jun-1982/man/inc.1 new file mode 100644 index 00000000..435a6276 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/inc.1 @@ -0,0 +1,100 @@ +.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 +\*(<> date +.ti 1.5i + +.ti 1.5i + +.ti 2.5i + +.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 +/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 diff --git a/docs/historical/mh-jun-1982/man/mail.1 b/docs/historical/mh-jun-1982/man/mail.1 new file mode 100644 index 00000000..cb224aa6 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/mail.1 @@ -0,0 +1,48 @@ + +.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) diff --git a/docs/historical/mh-jun-1982/man/mailer.8 b/docs/historical/mh-jun-1982/man/mailer.8 new file mode 100644 index 00000000..f06d617e --- /dev/null +++ b/docs/historical/mh-jun-1982/man/mailer.8 @@ -0,0 +1,69 @@ +.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) diff --git a/docs/historical/mh-jun-1982/man/mh-alias.5 b/docs/historical/mh-jun-1982/man/mh-alias.5 new file mode 100644 index 00000000..d1e257b0 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/mh-alias.5 @@ -0,0 +1,89 @@ +.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." 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 diff --git a/docs/historical/mh-jun-1982/man/mh-mail.5 b/docs/historical/mh-jun-1982/man/mh-mail.5 new file mode 100644 index 00000000..a3ec0705 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/mh-mail.5 @@ -0,0 +1,193 @@ +.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. diff --git a/docs/historical/mh-jun-1982/man/mh-profile.5 b/docs/historical/mh-jun-1982/man/mh-profile.5 new file mode 100644 index 00000000..49a7b54e --- /dev/null +++ b/docs/historical/mh-jun-1982/man/mh-profile.5 @@ -0,0 +1,113 @@ +.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 diff --git a/docs/historical/mh-jun-1982/man/mh.1 b/docs/historical/mh-jun-1982/man/mh.1 new file mode 100644 index 00000000..24fcfa41 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/mh.1 @@ -0,0 +1,54 @@ +.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 diff --git a/docs/historical/mh-jun-1982/man/mhl.1 b/docs/historical/mh-jun-1982/man/mhl.1 new file mode 100644 index 00000000..0da2459b --- /dev/null +++ b/docs/historical/mh-jun-1982/man/mhl.1 @@ -0,0 +1,184 @@ +.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 or will begin the output, with +clearing the screen (if appropriate), and suppressing the screen +clear. An will abort the current message ouput, prompting +for the next message (if there is one), and a 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 diff --git a/docs/historical/mh-jun-1982/man/mhpath.1 b/docs/historical/mh-jun-1982/man/mhpath.1 new file mode 100644 index 00000000..741c3965 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/mhpath.1 @@ -0,0 +1,116 @@ +.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": +\ 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. diff --git a/docs/historical/mh-jun-1982/man/netmail.5 b/docs/historical/mh-jun-1982/man/netmail.5 new file mode 100644 index 00000000..96d4f411 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/netmail.5 @@ -0,0 +1,39 @@ +.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) diff --git a/docs/historical/mh-jun-1982/man/news.1 b/docs/historical/mh-jun-1982/man/news.1 new file mode 100644 index 00000000..51951768 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/news.1 @@ -0,0 +1,101 @@ +.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/ The news folders +.br +~news/. The number of items in +.SH PROFILE COMPONENTS +News-topics: Topics the user is interested in. +.br +News-: 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. diff --git a/docs/historical/mh-jun-1982/man/next.1 b/docs/historical/mh-jun-1982/man/next.1 new file mode 100644 index 00000000..24a91d08 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/next.1 @@ -0,0 +1,29 @@ +.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. diff --git a/docs/historical/mh-jun-1982/man/pick.1 b/docs/historical/mh-jun-1982/man/pick.1 new file mode 100644 index 00000000..5417d323 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/pick.1 @@ -0,0 +1,188 @@ +.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 \*(< will cause the whole component to be left out. +A ``\\'' +preceding a 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 (or ). +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 during message-body typing is equivalent to + for compatibility with NED. +A 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 diff --git a/docs/historical/mh-jun-1982/man/repl.1 b/docs/historical/mh-jun-1982/man/repl.1 new file mode 100644 index 00000000..a3835801 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/repl.1 @@ -0,0 +1,94 @@ +.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: or +cc: , +Subject: Re: +In-reply-to: Your message of +.ti +\w'In-reply-to: 'u + +.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: \*(<>. + +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 +/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 diff --git a/docs/historical/mh-jun-1982/man/rmail.1 b/docs/historical/mh-jun-1982/man/rmail.1 new file mode 100644 index 00000000..f2ae09fd --- /dev/null +++ b/docs/historical/mh-jun-1982/man/rmail.1 @@ -0,0 +1,44 @@ + +.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) diff --git a/docs/historical/mh-jun-1982/man/rmf.1 b/docs/historical/mh-jun-1982/man/rmf.1 new file mode 100644 index 00000000..3c7e7d85 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/rmf.1 @@ -0,0 +1,59 @@ +.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. diff --git a/docs/historical/mh-jun-1982/man/rmm.1 b/docs/historical/mh-jun-1982/man/rmm.1 new file mode 100644 index 00000000..88b5ac9a --- /dev/null +++ b/docs/historical/mh-jun-1982/man/rmm.1 @@ -0,0 +1,52 @@ +.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. diff --git a/docs/historical/mh-jun-1982/man/scan.1 b/docs/historical/mh-jun-1982/man/scan.1 new file mode 100644 index 00000000..49a4b21d --- /dev/null +++ b/docs/historical/mh-jun-1982/man/scan.1 @@ -0,0 +1,90 @@ +.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\ \ \ \ \[\*(<> +.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 </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 diff --git a/docs/historical/mh-jun-1982/man/show.1 b/docs/historical/mh-jun-1982/man/show.1 new file mode 100644 index 00000000..8c369cb6 --- /dev/null +++ b/docs/historical/mh-jun-1982/man/show.1 @@ -0,0 +1,74 @@ +.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 + 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 +or . +If a is entered, \fIc\fR will clear the +screen before listing the next page, whereas 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 /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. diff --git a/docs/historical/mh-jun-1982/mh.diff b/docs/historical/mh-jun-1982/mh.diff new file mode 100644 index 00000000..746d9218 --- /dev/null +++ b/docs/historical/mh-jun-1982/mh.diff @@ -0,0 +1,693 @@ +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 +< +< Cc: csd-mgrs +< 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= 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 diff --git a/docs/historical/mh-jun-1982/mh.h b/docs/historical/mh-jun-1982/mh.h new file mode 100644 index 00000000..792f71c8 --- /dev/null +++ b/docs/historical/mh-jun-1982/mh.h @@ -0,0 +1,202 @@ +#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 diff --git a/docs/historical/mh-jun-1982/misc/depend.sh b/docs/historical/mh-jun-1982/misc/depend.sh new file mode 100755 index 00000000..8abadf18 --- /dev/null +++ b/docs/historical/mh-jun-1982/misc/depend.sh @@ -0,0 +1,10 @@ +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 diff --git a/docs/historical/mh-jun-1982/progs/Makefile b/docs/historical/mh-jun-1982/progs/Makefile new file mode 100644 index 00000000..daa147a7 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/Makefile @@ -0,0 +1,416 @@ +# +# 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 diff --git a/docs/historical/mh-jun-1982/progs/Makefile.bak b/docs/historical/mh-jun-1982/progs/Makefile.bak new file mode 100644 index 00000000..99d5da74 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/Makefile.bak @@ -0,0 +1,415 @@ +# +# 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 diff --git a/docs/historical/mh-jun-1982/progs/UUCP.MEMO b/docs/historical/mh-jun-1982/progs/UUCP.MEMO new file mode 100644 index 00000000..94518cb6 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/UUCP.MEMO @@ -0,0 +1,133 @@ + 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 remote from ". + 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 ". 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 " + 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 diff --git a/docs/historical/mh-jun-1982/progs/adrformat.c b/docs/historical/mh-jun-1982/progs/adrformat.c new file mode 100644 index 00000000..f4740274 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/adrformat.c @@ -0,0 +1,68 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include +#include "../mh.h" +#include "../adrparse.h" +#include + +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; +} diff --git a/docs/historical/mh-jun-1982/progs/adrparse.c b/docs/historical/mh-jun-1982/progs/adrparse.c new file mode 100644 index 00000000..e64284ea --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/adrparse.c @@ -0,0 +1,291 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include +#include +#include "../mh.h" +#include "../adrparse.h" + +extern char *strcpy(), *strncpy(); + +#ifndef ARPANET +#define HOSTTBL "/dev/null" +#else +#include +#endif +#include + +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 diff --git a/docs/historical/mh-jun-1982/progs/ali.c b/docs/historical/mh-jun-1982/progs/ali.c new file mode 100644 index 00000000..3c26c1cc --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/ali.c @@ -0,0 +1,323 @@ +#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 +#include +#include +#include + +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 diff --git a/docs/historical/mh-jun-1982/progs/annotate.c b/docs/historical/mh-jun-1982/progs/annotate.c new file mode 100644 index 00000000..79835978 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/annotate.c @@ -0,0 +1,117 @@ +#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 +#include +#include +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 diff --git a/docs/historical/mh-jun-1982/progs/comp.c b/docs/historical/mh-jun-1982/progs/comp.c new file mode 100644 index 00000000..9989e2c7 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/comp.c @@ -0,0 +1,178 @@ +#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 +#include +#include + +/* #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 []", 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); +} + diff --git a/docs/historical/mh-jun-1982/progs/conflict.c b/docs/historical/mh-jun-1982/progs/conflict.c new file mode 100644 index 00000000..1937efcf --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/conflict.c @@ -0,0 +1,221 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include +#include +#include +#include +#include +#include +#include "../mh.h" +#include + +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 diff --git a/docs/historical/mh-jun-1982/progs/deliver.c b/docs/historical/mh-jun-1982/progs/deliver.c new file mode 100644 index 00000000..47e73599 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/deliver.c @@ -0,0 +1,1154 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include +#include "../mh.h" +#include "../adrparse.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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.* 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 diff --git a/docs/historical/mh-jun-1982/progs/dist.c b/docs/historical/mh-jun-1982/progs/dist.c new file mode 100644 index 00000000..67a0c114 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/dist.c @@ -0,0 +1,295 @@ +#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 +#include +#include +#include +#include + +#define NOUSE 0 + +/* #define TEST 1 */ + +struct swit anyl[] = { + "no", 0, + "yes", 0, + "list", 0, + 0, +}; + +struct swit aleqs[] = { + "list", 0, /* 0 */ + "edit []", 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); +} diff --git a/docs/historical/mh-jun-1982/progs/file.c b/docs/historical/mh-jun-1982/progs/file.c new file mode 100644 index 00000000..3421ef88 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/file.c @@ -0,0 +1,257 @@ +#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 + +#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 diff --git a/docs/historical/mh-jun-1982/progs/folder.c b/docs/historical/mh-jun-1982/progs/folder.c new file mode 100644 index 00000000..2a046b74 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/folder.c @@ -0,0 +1,322 @@ +#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 +#include +#include +#include + +#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 diff --git a/docs/historical/mh-jun-1982/progs/forw.c b/docs/historical/mh-jun-1982/progs/forw.c new file mode 100644 index 00000000..30961268 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/forw.c @@ -0,0 +1,318 @@ +#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 +#include +#include +#include +#include + +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 []", 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 diff --git a/docs/historical/mh-jun-1982/progs/grep.c b/docs/historical/mh-jun-1982/progs/grep.c new file mode 100644 index 00000000..df270c67 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/grep.c @@ -0,0 +1,287 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include +#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); +} diff --git a/docs/historical/mh-jun-1982/progs/inc.c b/docs/historical/mh-jun-1982/progs/inc.c new file mode 100644 index 00000000..cbfe8d87 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/inc.c @@ -0,0 +1,279 @@ +#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 +#include +#include +#include +#include +#include +#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("<> ", 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 diff --git a/docs/historical/mh-jun-1982/progs/install-mh.c b/docs/historical/mh-jun-1982/progs/install-mh.c new file mode 100644 index 00000000..21d2ffdc --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/install-mh.c @@ -0,0 +1,120 @@ +#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 +#include +#include + +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*/ +} diff --git a/docs/historical/mh-jun-1982/progs/mail.c b/docs/historical/mh-jun-1982/progs/mail.c new file mode 100644 index 00000000..9b61f18b --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/mail.c @@ -0,0 +1,166 @@ +#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 +#include + +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 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); +} diff --git a/docs/historical/mh-jun-1982/progs/mhl.c b/docs/historical/mh-jun-1982/progs/mhl.c new file mode 100644 index 00000000..1441e3c1 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/mhl.c @@ -0,0 +1,762 @@ +#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 +#include +#include +#include +#ifndef INCLUDED_BY_SHOW +#include +#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 */ + +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 */ + + 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 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 diff --git a/docs/historical/mh-jun-1982/progs/mhpath.c b/docs/historical/mh-jun-1982/progs/mhpath.c new file mode 100644 index 00000000..64829ab3 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/mhpath.c @@ -0,0 +1,323 @@ +#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 +#include + + +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 + +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->hghmsghghmsg+ 1 : \ No newline at end of file diff --git a/docs/historical/mh-jun-1982/progs/news.c b/docs/historical/mh-jun-1982/progs/news.c new file mode 100644 index 00000000..2a96f994 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/news.c @@ -0,0 +1,404 @@ +#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 +#include +#include +#include +#include + +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 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 + 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); +} diff --git a/docs/historical/mh-jun-1982/progs/next.c b/docs/historical/mh-jun-1982/progs/next.c new file mode 100644 index 00000000..2469fdaa --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/next.c @@ -0,0 +1,114 @@ +#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 +#include + +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); +} diff --git a/docs/historical/mh-jun-1982/progs/nexthdr.c b/docs/historical/mh-jun-1982/progs/nexthdr.c new file mode 100644 index 00000000..863656b3 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/nexthdr.c @@ -0,0 +1,8 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +int glbtype = 1; diff --git a/docs/historical/mh-jun-1982/progs/pick.c b/docs/historical/mh-jun-1982/progs/pick.c new file mode 100644 index 00000000..0cda291a --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/pick.c @@ -0,0 +1,427 @@ +#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 +#include +#include +#include +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 diff --git a/docs/historical/mh-jun-1982/progs/prevhdr.c b/docs/historical/mh-jun-1982/progs/prevhdr.c new file mode 100644 index 00000000..d9d0ee48 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/prevhdr.c @@ -0,0 +1,8 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +int glbtype = -1; diff --git a/docs/historical/mh-jun-1982/progs/prompter.c b/docs/historical/mh-jun-1982/progs/prompter.c new file mode 100644 index 00000000..0de368a7 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/prompter.c @@ -0,0 +1,287 @@ +#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 +#include +#include +#include +#include + +#define CKILL 006 /* @ => */ +#define CERASE 001 /* # => */ + +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("", c + '@'); + else + printf("%c" \ No newline at end of file diff --git a/docs/historical/mh-jun-1982/progs/ptt.c b/docs/historical/mh-jun-1982/progs/ptt.c new file mode 100644 index 00000000..1057c8b1 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/ptt.c @@ -0,0 +1,42 @@ +#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")); +} diff --git a/docs/historical/mh-jun-1982/progs/repl.c b/docs/historical/mh-jun-1982/progs/repl.c new file mode 100644 index 00000000..c99d1df6 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/repl.c @@ -0,0 +1,494 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include +#include "../mh.h" +#include +#include +#include +#include +#include +#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 []", 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 diff --git a/docs/historical/mh-jun-1982/progs/replsubs.c b/docs/historical/mh-jun-1982/progs/replsubs.c new file mode 100644 index 00000000..5e6e7726 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/replsubs.c @@ -0,0 +1,236 @@ +#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[]@" + * "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 diff --git a/docs/historical/mh-jun-1982/progs/rmail.c b/docs/historical/mh-jun-1982/progs/rmail.c new file mode 100644 index 00000000..d18bbd62 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/rmail.c @@ -0,0 +1,391 @@ +#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 +#include + +#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 +#include +#include + +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= 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("???"); +} diff --git a/docs/historical/mh-jun-1982/progs/rmail.c.nodate b/docs/historical/mh-jun-1982/progs/rmail.c.nodate new file mode 100644 index 00000000..fab61c4c --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/rmail.c.nodate @@ -0,0 +1,301 @@ +#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 +#include + +#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 +#include +#include + +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 diff --git a/docs/historical/mh-jun-1982/progs/rmf.c b/docs/historical/mh-jun-1982/progs/rmf.c new file mode 100644 index 00000000..1b1d2336 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/rmf.c @@ -0,0 +1,181 @@ +#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 +#include + +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 diff --git a/docs/historical/mh-jun-1982/progs/rmm.c b/docs/historical/mh-jun-1982/progs/rmm.c new file mode 100644 index 00000000..5deac2ff --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/rmm.c @@ -0,0 +1,155 @@ +#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 +#include +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); +} diff --git a/docs/historical/mh-jun-1982/progs/scan.c b/docs/historical/mh-jun-1982/progs/scan.c new file mode 100644 index 00000000..6d4c70bf --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/scan.c @@ -0,0 +1,150 @@ +#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 +#include +#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 diff --git a/docs/historical/mh-jun-1982/progs/scansub.c b/docs/historical/mh-jun-1982/progs/scansub.c new file mode 100644 index 00000000..5cb419b7 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/scansub.c @@ -0,0 +1,673 @@ +#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 +#include +#include +#include +#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 [< '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; diff --git a/docs/historical/mh-jun-1982/progs/scansub.h b/docs/historical/mh-jun-1982/progs/scansub.h new file mode 100644 index 00000000..0703ef58 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/scansub.h @@ -0,0 +1,5 @@ + +#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 */ diff --git a/docs/historical/mh-jun-1982/progs/send.c b/docs/historical/mh-jun-1982/progs/send.c new file mode 100644 index 00000000..015c7154 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/send.c @@ -0,0 +1,145 @@ +#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 +#include +#include +#include +#include + +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); + } +} diff --git a/docs/historical/mh-jun-1982/progs/show.c b/docs/historical/mh-jun-1982/progs/show.c new file mode 100644 index 00000000..1caa14b3 --- /dev/null +++ b/docs/historical/mh-jun-1982/progs/show.c @@ -0,0 +1,178 @@ +#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 +#include + +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 diff --git a/docs/historical/mh-jun-1982/strings/Makefile b/docs/historical/mh-jun-1982/strings/Makefile new file mode 100644 index 00000000..2c119e26 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/Makefile @@ -0,0 +1,94 @@ +# +# 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 diff --git a/docs/historical/mh-jun-1982/strings/anoyes.c b/docs/historical/mh-jun-1982/strings/anoyes.c new file mode 100644 index 00000000..fdcf6a40 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/anoyes.c @@ -0,0 +1,14 @@ +#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, +}; diff --git a/docs/historical/mh-jun-1982/strings/components.c b/docs/historical/mh-jun-1982/strings/components.c new file mode 100644 index 00000000..019790a6 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/components.c @@ -0,0 +1,8 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +char *components = "components"; diff --git a/docs/historical/mh-jun-1982/strings/current.c b/docs/historical/mh-jun-1982/strings/current.c new file mode 100644 index 00000000..6c45f32d --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/current.c @@ -0,0 +1,8 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +char *current = "cur"; diff --git a/docs/historical/mh-jun-1982/strings/defalt.c b/docs/historical/mh-jun-1982/strings/defalt.c new file mode 100644 index 00000000..48d26a1c --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/defalt.c @@ -0,0 +1,8 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +char *defalt = "inbox"; diff --git a/docs/historical/mh-jun-1982/strings/distcomps.c b/docs/historical/mh-jun-1982/strings/distcomps.c new file mode 100644 index 00000000..381bcd20 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/distcomps.c @@ -0,0 +1,8 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +char *distcomps = "distcomps"; diff --git a/docs/historical/mh-jun-1982/strings/draft.c b/docs/historical/mh-jun-1982/strings/draft.c new file mode 100644 index 00000000..a947bbca --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/draft.c @@ -0,0 +1,8 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +char *draft = "draft"; diff --git a/docs/historical/mh-jun-1982/strings/fileproc.c b/docs/historical/mh-jun-1982/strings/fileproc.c new file mode 100644 index 00000000..1570f97c --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/fileproc.c @@ -0,0 +1,13 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/foldprot.c b/docs/historical/mh-jun-1982/strings/foldprot.c new file mode 100644 index 00000000..99b6c0f0 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/foldprot.c @@ -0,0 +1,12 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/installproc.c b/docs/historical/mh-jun-1982/strings/installproc.c new file mode 100644 index 00000000..1af8f3f0 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/installproc.c @@ -0,0 +1,13 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/listname.c b/docs/historical/mh-jun-1982/strings/listname.c new file mode 100644 index 00000000..066e3e3b --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/listname.c @@ -0,0 +1,8 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +char *listname = "select"; diff --git a/docs/historical/mh-jun-1982/strings/lockdir.c b/docs/historical/mh-jun-1982/strings/lockdir.c new file mode 100644 index 00000000..9242dff6 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/lockdir.c @@ -0,0 +1,24 @@ +#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 + +char *lockdir = MAILLOCKDIR; +short lockwait = 15; /* Sec \ No newline at end of file diff --git a/docs/historical/mh-jun-1982/strings/lproc.c b/docs/historical/mh-jun-1982/strings/lproc.c new file mode 100644 index 00000000..1b05f91e --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/lproc.c @@ -0,0 +1,14 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/lsproc.c b/docs/historical/mh-jun-1982/strings/lsproc.c new file mode 100644 index 00000000..44e9d40f --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/lsproc.c @@ -0,0 +1,16 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/mailboxes.c b/docs/historical/mh-jun-1982/strings/mailboxes.c new file mode 100644 index 00000000..cecec665 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/mailboxes.c @@ -0,0 +1,16 @@ +#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 + +char *mailboxes = MAILDROP; diff --git a/docs/historical/mh-jun-1982/strings/mailproc.c b/docs/historical/mh-jun-1982/strings/mailproc.c new file mode 100644 index 00000000..ede94cbf --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/mailproc.c @@ -0,0 +1,13 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/mh_deliver.c b/docs/historical/mh-jun-1982/strings/mh_deliver.c new file mode 100644 index 00000000..1328aed7 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/mh_deliver.c @@ -0,0 +1,14 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/mh_prof.c b/docs/historical/mh-jun-1982/strings/mh_prof.c new file mode 100644 index 00000000..959d5db4 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/mh_prof.c @@ -0,0 +1,8 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/mhlformat.c b/docs/historical/mh-jun-1982/strings/mhlformat.c new file mode 100644 index 00000000..23238ca4 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/mhlformat.c @@ -0,0 +1,8 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/mhlstdfmt.c b/docs/historical/mh-jun-1982/strings/mhlstdfmt.c new file mode 100644 index 00000000..da501be0 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/mhlstdfmt.c @@ -0,0 +1,8 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/mhnews.c b/docs/historical/mh-jun-1982/strings/mhnews.c new file mode 100644 index 00000000..ba789177 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/mhnews.c @@ -0,0 +1,14 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/msgprot.c b/docs/historical/mh-jun-1982/strings/msgprot.c new file mode 100644 index 00000000..44cc6970 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/msgprot.c @@ -0,0 +1,14 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/pfolder.c b/docs/historical/mh-jun-1982/strings/pfolder.c new file mode 100644 index 00000000..b273f233 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/pfolder.c @@ -0,0 +1,8 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/prproc.c b/docs/historical/mh-jun-1982/strings/prproc.c new file mode 100644 index 00000000..2e0a75eb --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/prproc.c @@ -0,0 +1,13 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/rhosts.c b/docs/historical/mh-jun-1982/strings/rhosts.c new file mode 100644 index 00000000..666c3ebf --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/rhosts.c @@ -0,0 +1,25 @@ +#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 + diff --git a/docs/historical/mh-jun-1982/strings/scanproc.c b/docs/historical/mh-jun-1982/strings/scanproc.c new file mode 100644 index 00000000..c80cd989 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/scanproc.c @@ -0,0 +1,13 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/sendproc.c b/docs/historical/mh-jun-1982/strings/sendproc.c new file mode 100644 index 00000000..b071d026 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/sendproc.c @@ -0,0 +1,14 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/showproc.c b/docs/historical/mh-jun-1982/strings/showproc.c new file mode 100644 index 00000000..fd8f7734 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/showproc.c @@ -0,0 +1,16 @@ +#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 or + * 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 */ diff --git a/docs/historical/mh-jun-1982/strings/stdcomps.c b/docs/historical/mh-jun-1982/strings/stdcomps.c new file mode 100644 index 00000000..d9e29915 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/stdcomps.c @@ -0,0 +1,13 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/stddcomps.c b/docs/historical/mh-jun-1982/strings/stddcomps.c new file mode 100644 index 00000000..ce108372 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/stddcomps.c @@ -0,0 +1,12 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/sysed.c b/docs/historical/mh-jun-1982/strings/sysed.c new file mode 100644 index 00000000..f034e201 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/sysed.c @@ -0,0 +1,16 @@ +#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"; diff --git a/docs/historical/mh-jun-1982/strings/sysname.c b/docs/historical/mh-jun-1982/strings/sysname.c new file mode 100644 index 00000000..7761e883 --- /dev/null +++ b/docs/historical/mh-jun-1982/strings/sysname.c @@ -0,0 +1,5 @@ +#include + +#ifndef sysname +char sysname[] = SYSNAME; +#endif diff --git a/docs/historical/mh-jun-1982/subs/Makefile b/docs/historical/mh-jun-1982/subs/Makefile new file mode 100644 index 00000000..ca75fb91 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/Makefile @@ -0,0 +1,209 @@ +# +# 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 diff --git a/docs/historical/mh-jun-1982/subs/Makefile.bak b/docs/historical/mh-jun-1982/subs/Makefile.bak new file mode 100644 index 00000000..34bd5ede --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/Makefile.bak @@ -0,0 +1,209 @@ +# +# 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 diff --git a/docs/historical/mh-jun-1982/subs/add.c b/docs/historical/mh-jun-1982/subs/add.c new file mode 100644 index 00000000..7126135d --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/add.c @@ -0,0 +1,28 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include +#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); +} diff --git a/docs/historical/mh-jun-1982/subs/ambigsw.c b/docs/historical/mh-jun-1982/subs/ambigsw.c new file mode 100644 index 00000000..0afcd7b8 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/ambigsw.c @@ -0,0 +1,19 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include +#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, "-"); +} + diff --git a/docs/historical/mh-jun-1982/subs/atooi.c b/docs/historical/mh-jun-1982/subs/atooi.c new file mode 100644 index 00000000..a72af550 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/atooi.c @@ -0,0 +1,22 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/subs/brkstring.c b/docs/historical/mh-jun-1982/subs/brkstring.c new file mode 100644 index 00000000..b61ff2e9 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/brkstring.c @@ -0,0 +1,49 @@ +#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= &end) free(addr); +} diff --git a/docs/historical/mh-jun-1982/subs/concat.c b/docs/historical/mh-jun-1982/subs/concat.c new file mode 100644 index 00000000..73c11341 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/concat.c @@ -0,0 +1,27 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/subs/copy.c b/docs/historical/mh-jun-1982/subs/copy.c new file mode 100644 index 00000000..950752a7 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/copy.c @@ -0,0 +1,13 @@ +#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; +}; diff --git a/docs/historical/mh-jun-1982/subs/copyip.c b/docs/historical/mh-jun-1982/subs/copyip.c new file mode 100644 index 00000000..150db915 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/copyip.c @@ -0,0 +1,22 @@ +#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; +} + diff --git a/docs/historical/mh-jun-1982/subs/cputc.c b/docs/historical/mh-jun-1982/subs/cputc.c new file mode 100644 index 00000000..531e0825 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/cputc.c @@ -0,0 +1,20 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include + +cputc(chr, ip) +register FILE *ip; +{ + if(ip != NULL) { + putc(chr, ip); + if(ferror(ip)) { + perror("Write error"); + done(-1); + } + } +} diff --git a/docs/historical/mh-jun-1982/subs/depend.sh b/docs/historical/mh-jun-1982/subs/depend.sh new file mode 100755 index 00000000..8abadf18 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/depend.sh @@ -0,0 +1,10 @@ +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 diff --git a/docs/historical/mh-jun-1982/subs/done.c b/docs/historical/mh-jun-1982/subs/done.c new file mode 100644 index 00000000..1a299128 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/done.c @@ -0,0 +1,15 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/subs/fdcompare.c b/docs/historical/mh-jun-1982/subs/fdcompare.c new file mode 100644 index 00000000..66451269 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/fdcompare.c @@ -0,0 +1,37 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/subs/gans.c b/docs/historical/mh-jun-1982/subs/gans.c new file mode 100644 index 00000000..a8f1e688 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/gans.c @@ -0,0 +1,46 @@ +#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 + +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); + } +} diff --git a/docs/historical/mh-jun-1982/subs/getans.c b/docs/historical/mh-jun-1982/subs/getans.c new file mode 100644 index 00000000..2c40e9f8 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/getans.c @@ -0,0 +1,62 @@ +#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 +#include + +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 for help.\n", *cpp); + continue; + default: + return(cpp); /* list, edit, quit, send */ + } + } +} + + +g_sig() +{ + VOID signal(SIGINT, g_sig); + g_sigint = 1; + return; +} diff --git a/docs/historical/mh-jun-1982/subs/getcpy.c b/docs/historical/mh-jun-1982/subs/getcpy.c new file mode 100644 index 00000000..b81d8d32 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/getcpy.c @@ -0,0 +1,22 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/subs/help.c b/docs/historical/mh-jun-1982/subs/help.c new file mode 100644 index 00000000..130a481a --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/help.c @@ -0,0 +1,17 @@ +#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, "-"); +} diff --git a/docs/historical/mh-jun-1982/subs/invo_name.c b/docs/historical/mh-jun-1982/subs/invo_name.c new file mode 100644 index 00000000..b684288a --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/invo_name.c @@ -0,0 +1,26 @@ +#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 diff --git a/docs/historical/mh-jun-1982/subs/locv.c b/docs/historical/mh-jun-1982/subs/locv.c new file mode 100644 index 00000000..5e585295 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/locv.c @@ -0,0 +1,19 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include + +extern char *sprintf (); + +char * +locv(longint) + long longint; +{ + static char locvbuf[12]; + + return sprintf(locvbuf, "%ld", longint); +} diff --git a/docs/historical/mh-jun-1982/subs/m_convert.c b/docs/historical/mh-jun-1982/subs/m_convert.c new file mode 100644 index 00000000..3f56b52a --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_convert.c @@ -0,0 +1,156 @@ +#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 +#include + +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 */ +} diff --git a/docs/historical/mh-jun-1982/subs/m_delete.c b/docs/historical/mh-jun-1982/subs/m_delete.c new file mode 100644 index 00000000..f2dedf71 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_delete.c @@ -0,0 +1,29 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/subs/m_edit.c b/docs/historical/mh-jun-1982/subs/m_edit.c new file mode 100644 index 00000000..b87381a4 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_edit.c @@ -0,0 +1,98 @@ +#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 +#include +#include +#include +#include + +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); +} diff --git a/docs/historical/mh-jun-1982/subs/m_file.c b/docs/historical/mh-jun-1982/subs/m_file.c new file mode 100644 index 00000000..550d7d4a --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_file.c @@ -0,0 +1,95 @@ +#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 +#include +#include +#include + +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 diff --git a/docs/historical/mh-jun-1982/subs/m_find.c b/docs/historical/mh-jun-1982/subs/m_find.c new file mode 100644 index 00000000..71576a32 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_find.c @@ -0,0 +1,21 @@ +#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 + +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); +} diff --git a/docs/historical/mh-jun-1982/subs/m_getcur.c b/docs/historical/mh-jun-1982/subs/m_getcur.c new file mode 100644 index 00000000..57d244d5 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_getcur.c @@ -0,0 +1,34 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include +#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 */ + curfil = mu_atoi(buf); + } + VOID close(i); + } + return curfil; +} diff --git a/docs/historical/mh-jun-1982/subs/m_getdefs.c b/docs/historical/mh-jun-1982/subs/m_getdefs.c new file mode 100644 index 00000000..a7070603 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_getdefs.c @@ -0,0 +1,99 @@ +#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 + +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 diff --git a/docs/historical/mh-jun-1982/subs/m_getfld.c b/docs/historical/mh-jun-1982/subs/m_getfld.c new file mode 100644 index 00000000..4b66a69f --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_getfld.c @@ -0,0 +1,95 @@ +#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 + +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)? "":"", 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*/ +} diff --git a/docs/historical/mh-jun-1982/subs/m_getfolder.c b/docs/historical/mh-jun-1982/subs/m_getfolder.c new file mode 100644 index 00000000..d8e0048a --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_getfolder.c @@ -0,0 +1,19 @@ +#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 + +char *m_getfolder() +{ + register char *folder; + + m_getdefs(); + if((folder = m_find(pfolder)) == NULL || *folder == 0) + folder = defalt; + return(folder); +} diff --git a/docs/historical/mh-jun-1982/subs/m_gmprot.c b/docs/historical/mh-jun-1982/subs/m_gmprot.c new file mode 100644 index 00000000..b920342f --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_gmprot.c @@ -0,0 +1,21 @@ +#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 + +m_gmprot() +{ + register char *cp; + register int prot; + + if((cp = m_find("msg-protect")) != NULL) + prot = atooi(cp); + else + prot = atooi(msgprot); + return(prot); +} diff --git a/docs/historical/mh-jun-1982/subs/m_gmsg.c b/docs/historical/mh-jun-1982/subs/m_gmsg.c new file mode 100644 index 00000000..65eace0b --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_gmsg.c @@ -0,0 +1,124 @@ +#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 + +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 */ + 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); + } +} diff --git a/docs/historical/mh-jun-1982/subs/m_maildir.c b/docs/historical/mh-jun-1982/subs/m_maildir.c new file mode 100644 index 00000000..694f19ca --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_maildir.c @@ -0,0 +1,39 @@ +#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 + +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 diff --git a/docs/historical/mh-jun-1982/subs/m_name.c b/docs/historical/mh-jun-1982/subs/m_name.c new file mode 100644 index 00000000..042268e5 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_name.c @@ -0,0 +1,30 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/subs/m_news.cc b/docs/historical/mh-jun-1982/subs/m_news.cc new file mode 100644 index 00000000..50ef9b48 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_news.cc @@ -0,0 +1,53 @@ +#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); +} + diff --git a/docs/historical/mh-jun-1982/subs/m_replace.c b/docs/historical/mh-jun-1982/subs/m_replace.c new file mode 100644 index 00000000..45b65487 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_replace.c @@ -0,0 +1,36 @@ +#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; +} diff --git a/docs/historical/mh-jun-1982/subs/m_send.c b/docs/historical/mh-jun-1982/subs/m_send.c new file mode 100644 index 00000000..8b640ae8 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_send.c @@ -0,0 +1,34 @@ +#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 + +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); + +} diff --git a/docs/historical/mh-jun-1982/subs/m_setcur.c b/docs/historical/mh-jun-1982/subs/m_setcur.c new file mode 100644 index 00000000..5c715130 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_setcur.c @@ -0,0 +1,39 @@ +#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 + +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); + } + } +} diff --git a/docs/historical/mh-jun-1982/subs/m_update.c b/docs/historical/mh-jun-1982/subs/m_update.c new file mode 100644 index 00000000..3fef7738 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/m_update.c @@ -0,0 +1,32 @@ +#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 +#include + +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; + } +} diff --git a/docs/historical/mh-jun-1982/subs/makedir.c b/docs/historical/mh-jun-1982/subs/makedir.c new file mode 100644 index 00000000..2a912b31 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/makedir.c @@ -0,0 +1,37 @@ +#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 + +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); +} diff --git a/docs/historical/mh-jun-1982/subs/makename.c b/docs/historical/mh-jun-1982/subs/makename.c new file mode 100644 index 00000000..2ce9c5d5 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/makename.c @@ -0,0 +1,25 @@ +#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 + +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 diff --git a/docs/historical/mh-jun-1982/subs/mu_atoi.c b/docs/historical/mh-jun-1982/subs/mu_atoi.c new file mode 100644 index 00000000..978f5b8f --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/mu_atoi.c @@ -0,0 +1,27 @@ +#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; +} diff --git a/docs/historical/mh-jun-1982/subs/path.c b/docs/historical/mh-jun-1982/subs/path.c new file mode 100644 index 00000000..e5bcc709 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/path.c @@ -0,0 +1,23 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/subs/peekc.c b/docs/historical/mh-jun-1982/subs/peekc.c new file mode 100644 index 00000000..ac4889a7 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/peekc.c @@ -0,0 +1,19 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include +#include "../mh.h" + +peekc(ib) +FILE *ib; +{ + register c; + + c = getc(ib); + VOID ungetc(c,ib); + return(c); +} diff --git a/docs/historical/mh-jun-1982/subs/pr_array.c b/docs/historical/mh-jun-1982/subs/pr_array.c new file mode 100644 index 00000000..f7da7857 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/pr_array.c @@ -0,0 +1,16 @@ +#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); +} + diff --git a/docs/historical/mh-jun-1982/subs/printsw.c b/docs/historical/mh-jun-1982/subs/printsw.c new file mode 100644 index 00000000..b1bf63d2 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/printsw.c @@ -0,0 +1,33 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/subs/putenv.c b/docs/historical/mh-jun-1982/subs/putenv.c new file mode 100644 index 00000000..1f3e64e2 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/putenv.c @@ -0,0 +1,66 @@ +#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 + +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); +} diff --git a/docs/historical/mh-jun-1982/subs/pwd.c b/docs/historical/mh-jun-1982/subs/pwd.c new file mode 100644 index 00000000..4a1c0bcb --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/pwd.c @@ -0,0 +1,27 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include +#include + +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; +} diff --git a/docs/historical/mh-jun-1982/subs/r1bindex.c b/docs/historical/mh-jun-1982/subs/r1bindex.c new file mode 100644 index 00000000..b567feb0 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/r1bindex.c @@ -0,0 +1,27 @@ +#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; +} diff --git a/docs/historical/mh-jun-1982/subs/showfile.c b/docs/historical/mh-jun-1982/subs/showfile.c new file mode 100644 index 00000000..552abe32 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/showfile.c @@ -0,0 +1,45 @@ +#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 +#include + +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); + +} + diff --git a/docs/historical/mh-jun-1982/subs/smatch.c b/docs/historical/mh-jun-1982/subs/smatch.c new file mode 100644 index 00000000..786f398d --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/smatch.c @@ -0,0 +1,40 @@ +#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 diff --git a/docs/historical/mh-jun-1982/subs/ssequal.c b/docs/historical/mh-jun-1982/subs/ssequal.c new file mode 100644 index 00000000..27958c22 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/ssequal.c @@ -0,0 +1,15 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/subs/subs-lc b/docs/historical/mh-jun-1982/subs/subs-lc new file mode 100644 index 00000000..99cd49c7 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/subs-lc @@ -0,0 +1,63 @@ +/*LINTLIBRARY*/ +#include "../mh.h" +#include "../folder.h" +#include +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; } diff --git a/docs/historical/mh-jun-1982/subs/trimcpy.c b/docs/historical/mh-jun-1982/subs/trimcpy.c new file mode 100644 index 00000000..078bea83 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/trimcpy.c @@ -0,0 +1,30 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/subs/type.c b/docs/historical/mh-jun-1982/subs/type.c new file mode 100644 index 00000000..008fe8b1 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/type.c @@ -0,0 +1,23 @@ +#ifdef COMMENT + Proprietary Rand Corporation, 1981. + Further distribution of this software + subject to the terms of the Rand + license agreement. +#endif + +#include + +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); +} diff --git a/docs/historical/mh-jun-1982/subs/uleq.c b/docs/historical/mh-jun-1982/subs/uleq.c new file mode 100644 index 00000000..016a0901 --- /dev/null +++ b/docs/historical/mh-jun-1982/subs/uleq.c @@ -0,0 +1,19 @@ +#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); +} diff --git a/docs/historical/mh-jun-1982/support/MailAliases b/docs/historical/mh-jun-1982/support/MailAliases new file mode 100644 index 00000000..df56c538 --- /dev/null +++ b/docs/historical/mh-jun-1982/support/MailAliases @@ -0,0 +1,13 @@ +; 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 (incl null) + diff --git a/docs/historical/mh-jun-1982/support/Makefile b/docs/historical/mh-jun-1982/support/Makefile new file mode 100644 index 00000000..22b0ab0c --- /dev/null +++ b/docs/historical/mh-jun-1982/support/Makefile @@ -0,0 +1,38 @@ +# +# 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) diff --git a/docs/historical/mh-jun-1982/support/aliascheck.c b/docs/historical/mh-jun-1982/support/aliascheck.c new file mode 100644 index 00000000..d1bd2808 --- /dev/null +++ b/docs/historical/mh-jun-1982/support/aliascheck.c @@ -0,0 +1,77 @@ +#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 +#include +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 == '*'; +} diff --git a/docs/historical/mh-jun-1982/support/components b/docs/historical/mh-jun-1982/support/components new file mode 100644 index 00000000..6d4da32f --- /dev/null +++ b/docs/historical/mh-jun-1982/support/components @@ -0,0 +1,4 @@ +To: +Cc: +Subject: +------- diff --git a/docs/historical/mh-jun-1982/support/distcomps b/docs/historical/mh-jun-1982/support/distcomps new file mode 100644 index 00000000..b3415f92 --- /dev/null +++ b/docs/historical/mh-jun-1982/support/distcomps @@ -0,0 +1,2 @@ +Distribution-to: +Distribution-cc: diff --git a/docs/historical/mh-jun-1982/support/l.c b/docs/historical/mh-jun-1982/support/l.c new file mode 100644 index 00000000..c156e54c --- /dev/null +++ b/docs/historical/mh-jun-1982/support/l.c @@ -0,0 +1,323 @@ +#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 +#include +#include +#include +#include +#include + +#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 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; i1) { + if(i && delflg <= 0) + printf("\n\n"); + delflg = 0; + if(ontty) { + printf("Press 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 diff --git a/docs/historical/mh-jun-1982/support/mailsys.h b/docs/historical/mh-jun-1982/support/mailsys.h new file mode 100644 index 00000000..3b56dc18 --- /dev/null +++ b/docs/historical/mh-jun-1982/support/mailsys.h @@ -0,0 +1,19 @@ +#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 */ diff --git a/docs/historical/mh-jun-1982/support/mhl.format b/docs/historical/mh-jun-1982/support/mhl.format new file mode 100644 index 00000000..ceb4fc77 --- /dev/null +++ b/docs/historical/mh-jun-1982/support/mhl.format @@ -0,0 +1,29 @@ +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 diff --git a/docs/historical/mh-jun-1982/support/news/1char b/docs/historical/mh-jun-1982/support/news/1char new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/docs/historical/mh-jun-1982/support/news/1char @@ -0,0 +1 @@ + diff --git a/docs/historical/mh-jun-1982/support/news/Makefile b/docs/historical/mh-jun-1982/support/news/Makefile new file mode 100644 index 00000000..18d4d954 --- /dev/null +++ b/docs/historical/mh-jun-1982/support/news/Makefile @@ -0,0 +1,17 @@ +# +# 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 diff --git a/docs/historical/mh-jun-1982/support/news/mh_profile b/docs/historical/mh-jun-1982/support/news/mh_profile new file mode 100644 index 00000000..01ecf19d --- /dev/null +++ b/docs/historical/mh-jun-1982/support/news/mh_profile @@ -0,0 +1 @@ +Path: /usr/news diff --git a/docs/historical/mh-jun-1982/support/news/mh_receive b/docs/historical/mh-jun-1982/support/news/mh_receive new file mode 100755 index 00000000..8987b7b9 --- /dev/null +++ b/docs/historical/mh-jun-1982/support/news/mh_receive @@ -0,0 +1,17 @@ +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. diff --git a/docs/historical/mh-jun-1982/support/putenv.c b/docs/historical/mh-jun-1982/support/putenv.c new file mode 100644 index 00000000..1f3e64e2 --- /dev/null +++ b/docs/historical/mh-jun-1982/support/putenv.c @@ -0,0 +1,66 @@ +#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 + +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); +} diff --git a/docs/historical/mh-jun-1982/support/strings.h b/docs/historical/mh-jun-1982/support/strings.h new file mode 100644 index 00000000..46769601 --- /dev/null +++ b/docs/historical/mh-jun-1982/support/strings.h @@ -0,0 +1,12 @@ +/* + * Type definitions for the strings(3) subroutines. + */ + +char *strcat(); +char *strncat(); +char *strcpy(); +char *strncpy(); +int strcmp(); +int strncmp(); +char *index(); +char *rindex(); diff --git a/docs/historical/mh-nov-1983/Makefile b/docs/historical/mh-nov-1983/Makefile new file mode 100644 index 00000000..7855432f --- /dev/null +++ b/docs/historical/mh-nov-1983/Makefile @@ -0,0 +1,13 @@ +# %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 diff --git a/docs/historical/mh-nov-1983/README b/docs/historical/mh-nov-1983/README new file mode 100644 index 00000000..9d034eee --- /dev/null +++ b/docs/historical/mh-nov-1983/README @@ -0,0 +1,29 @@ +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. diff --git a/docs/historical/mh-nov-1983/cmds/Makefile b/docs/historical/mh-nov-1983/cmds/Makefile new file mode 100644 index 00000000..7dbbb51c --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/Makefile @@ -0,0 +1,214 @@ +# @(#)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 diff --git a/docs/historical/mh-nov-1983/cmds/aliascheck.c b/docs/historical/mh-nov-1983/cmds/aliascheck.c new file mode 100644 index 00000000..03d94f6c --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/aliascheck.c @@ -0,0 +1,209 @@ +#include +#include +#include +#include +#include + +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: "); + } +} diff --git a/docs/historical/mh-nov-1983/cmds/annotate.c b/docs/historical/mh-nov-1983/cmds/annotate.c new file mode 100644 index 00000000..fce8b747 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/annotate.c @@ -0,0 +1,110 @@ +#ifndef lint +static char sccsid[] = "@(#)annotate.c 4.1 2/23/83"; +#endif + +#include "mh.h" +#include +#include +#include + +/* 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); +} diff --git a/docs/historical/mh-nov-1983/cmds/comp.c b/docs/historical/mh-nov-1983/cmds/comp.c new file mode 100644 index 00000000..37a69aae --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/comp.c @@ -0,0 +1,163 @@ +#include "mh.h" +#include +#include +#include + +/* #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 []", 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); +} + diff --git a/docs/historical/mh-nov-1983/cmds/deliver.c b/docs/historical/mh-nov-1983/cmds/deliver.c new file mode 100644 index 00000000..87d58b42 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/deliver.c @@ -0,0 +1,883 @@ +#ifndef lint +static char sccsid[] = "@(#)deliver.c 4.4 9/25/83"; +#endif + +#include "mh.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#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'); +} diff --git a/docs/historical/mh-nov-1983/cmds/dist.c b/docs/historical/mh-nov-1983/cmds/dist.c new file mode 100644 index 00000000..76ea4869 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/dist.c @@ -0,0 +1,295 @@ +#ifndef lint +static char sccsid[] = "@(#)dist.c 4.1 2/23/83"; +#endif + +#include "mh.h" +#include +#include +#include + +#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 []", 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); + + +} diff --git a/docs/historical/mh-nov-1983/cmds/emitl.c b/docs/historical/mh-nov-1983/cmds/emitl.c new file mode 100644 index 00000000..439b6180 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/emitl.c @@ -0,0 +1,55 @@ +/* + * 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 + +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); +} diff --git a/docs/historical/mh-nov-1983/cmds/folder.c b/docs/historical/mh-nov-1983/cmds/folder.c new file mode 100644 index 00000000..a5b9e46f --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/folder.c @@ -0,0 +1,316 @@ +#include "mh.h" +#include +#include +#include +#include +#include + +#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); +} diff --git a/docs/historical/mh-nov-1983/cmds/forw.c b/docs/historical/mh-nov-1983/cmds/forw.c new file mode 100644 index 00000000..636efe09 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/forw.c @@ -0,0 +1,316 @@ +#ifndef lint +static char sccsid[] = "@(#)forw.c 4.1 2/23/83"; +#endif + +#include "mh.h" +#include +#include +#include + +#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 []", 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); +} diff --git a/docs/historical/mh-nov-1983/cmds/grep.c b/docs/historical/mh-nov-1983/cmds/grep.c new file mode 100644 index 00000000..314d357b --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/grep.c @@ -0,0 +1,281 @@ +#include +#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); +} diff --git a/docs/historical/mh-nov-1983/cmds/inc.c b/docs/historical/mh-nov-1983/cmds/inc.c new file mode 100644 index 00000000..3b433b6c --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/inc.c @@ -0,0 +1,335 @@ +#ifndef lint +static char sccsid[] = "@(#)inc.c 1.2 9/25/83"; +#endif + +#include "mh.h" +#include +#include +#include +#include +#include +#include + +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("<> ", 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); +} diff --git a/docs/historical/mh-nov-1983/cmds/install-mh.c b/docs/historical/mh-nov-1983/cmds/install-mh.c new file mode 100644 index 00000000..0e536e6f --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/install-mh.c @@ -0,0 +1,109 @@ +#include "mh.h" +#include +#include +#include + +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); +} diff --git a/docs/historical/mh-nov-1983/cmds/mail.c b/docs/historical/mh-nov-1983/cmds/mail.c new file mode 100644 index 00000000..227265ff --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/mail.c @@ -0,0 +1,157 @@ +#include "mh.h" +#include +#include + +#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 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); +} diff --git a/docs/historical/mh-nov-1983/cmds/mh.h b/docs/historical/mh-nov-1983/cmds/mh.h new file mode 100644 index 00000000..9ba122a5 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/mh.h @@ -0,0 +1,154 @@ +#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(); + diff --git a/docs/historical/mh-nov-1983/cmds/news.c b/docs/historical/mh-nov-1983/cmds/news.c new file mode 100644 index 00000000..42f0ed46 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/news.c @@ -0,0 +1,300 @@ +#include "mh.h" +#include +#include +#include +#include +#include +#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 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 + struct timeb tb; + + ftime(&tb); + printf("%s.\n", nons[tb.millitm % NONS]); +} diff --git a/docs/historical/mh-nov-1983/cmds/next.c b/docs/historical/mh-nov-1983/cmds/next.c new file mode 100644 index 00000000..9fb34161 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/next.c @@ -0,0 +1,97 @@ +#include "mh.h" +#include +#include + +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); +} diff --git a/docs/historical/mh-nov-1983/cmds/nexthdr.c b/docs/historical/mh-nov-1983/cmds/nexthdr.c new file mode 100644 index 00000000..f7def4b9 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/nexthdr.c @@ -0,0 +1 @@ +int glbtype = 1; diff --git a/docs/historical/mh-nov-1983/cmds/pick.c b/docs/historical/mh-nov-1983/cmds/pick.c new file mode 100644 index 00000000..1384ac55 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/pick.c @@ -0,0 +1,490 @@ +#include "mh.h" +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/docs/historical/mh-nov-1983/cmds/prevhdr.c b/docs/historical/mh-nov-1983/cmds/prevhdr.c new file mode 100644 index 00000000..073abf28 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/prevhdr.c @@ -0,0 +1 @@ +int glbtype = -1; diff --git a/docs/historical/mh-nov-1983/cmds/prompter.c b/docs/historical/mh-nov-1983/cmds/prompter.c new file mode 100644 index 00000000..1a9a0bb6 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/prompter.c @@ -0,0 +1,271 @@ +#include "mh.h" +#include +#include +#include +#include +#include + +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("", c + '@'); + else + printf("%c", c); +} diff --git a/docs/historical/mh-nov-1983/cmds/refile.c b/docs/historical/mh-nov-1983/cmds/refile.c new file mode 100644 index 00000000..02c16b87 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/refile.c @@ -0,0 +1,364 @@ +#ifndef lint +static char sccsid[] = "@(#)refile.c 1.1 5/26/83"; +#endif + +#include "mh.h" +#include +#include +#include +#include +#include + +#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= 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; +} diff --git a/docs/historical/mh-nov-1983/cmds/replsubs.c b/docs/historical/mh-nov-1983/cmds/replsubs.c new file mode 100644 index 00000000..77c57357 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/replsubs.c @@ -0,0 +1,232 @@ +#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[]@" + * "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); +} + diff --git a/docs/historical/mh-nov-1983/cmds/reply.c b/docs/historical/mh-nov-1983/cmds/reply.c new file mode 100644 index 00000000..3d59a39c --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/reply.c @@ -0,0 +1,321 @@ +#include "mh.h" +#include +#include +#include + +/*#define NEWS 1*/ + +#define NOUSE 0 + +/* #define TEST 1 */ + +char *anyl[] = { + "no", 0, + "yes", 0, + "list", 0, + 0 +}; + +char *aleqs[] = { + "list", 0, /* 0 */ + "edit []", 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; + } + } +} diff --git a/docs/historical/mh-nov-1983/cmds/rescue.c b/docs/historical/mh-nov-1983/cmds/rescue.c new file mode 100644 index 00000000..57b8b1ff --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/rescue.c @@ -0,0 +1,415 @@ +/* + * 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 +#include +#include + +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); +} diff --git a/docs/historical/mh-nov-1983/cmds/rmf.c b/docs/historical/mh-nov-1983/cmds/rmf.c new file mode 100644 index 00000000..3522bce2 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/rmf.c @@ -0,0 +1,166 @@ +#ifndef lint +static char sccsid[] = "@(#)rmf.c 1.4 7/7/83"; +#endif + +#include "mh.h" +#include +#include +#include +#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"); +} diff --git a/docs/historical/mh-nov-1983/cmds/rmm.c b/docs/historical/mh-nov-1983/cmds/rmm.c new file mode 100644 index 00000000..da34094f --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/rmm.c @@ -0,0 +1,131 @@ +#ifndef lint +static char sccsid[] = "@(#)rmm.c 4.1 2/23/83"; +#endif + +#include "mh.h" +#include +#include + +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); +} diff --git a/docs/historical/mh-nov-1983/cmds/scan.c b/docs/historical/mh-nov-1983/cmds/scan.c new file mode 100644 index 00000000..72ef38ce --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/scan.c @@ -0,0 +1,128 @@ +#include "mh.h" +#include +#include + +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 [<curmsg); + fclose(in); + if(stdout->_cnt < 80) + fflush(stdout); + } + } + } + if(ff) + putchar('\014'); +leave: + m_update(); + done(0); +} + diff --git a/docs/historical/mh-nov-1983/cmds/scansub.c b/docs/historical/mh-nov-1983/cmds/scansub.c new file mode 100644 index 00000000..dc3d1dfc --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/scansub.c @@ -0,0 +1,407 @@ +#include "mh.h" +#include + +#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); +} diff --git a/docs/historical/mh-nov-1983/cmds/send.c b/docs/historical/mh-nov-1983/cmds/send.c new file mode 100644 index 00000000..6660f131 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/send.c @@ -0,0 +1,325 @@ +#ifndef lint +static char sccsid[] = "@(#)send.c 4.6 7/7/83"; +#endif + +#include "mh.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); + } +} diff --git a/docs/historical/mh-nov-1983/cmds/show.c b/docs/historical/mh-nov-1983/cmds/show.c new file mode 100644 index 00000000..5c8bf961 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/show.c @@ -0,0 +1,132 @@ +#include "mh.h" +#include +#include + +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); +} + + diff --git a/docs/historical/mh-nov-1983/cmds/strings.h b/docs/historical/mh-nov-1983/cmds/strings.h new file mode 100644 index 00000000..70c67e58 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/strings.h @@ -0,0 +1,42 @@ +/* + * 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 diff --git a/docs/historical/mh-nov-1983/cmds/unixtomh.c b/docs/historical/mh-nov-1983/cmds/unixtomh.c new file mode 100644 index 00000000..2190c625 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/unixtomh.c @@ -0,0 +1,603 @@ +# + +/* + * 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 +#include +#include +#include + +#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); +} diff --git a/docs/historical/mh-nov-1983/cmds/vars.c b/docs/historical/mh-nov-1983/cmds/vars.c new file mode 100644 index 00000000..cac97e07 --- /dev/null +++ b/docs/historical/mh-nov-1983/cmds/vars.c @@ -0,0 +1,10 @@ + 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]; diff --git a/docs/historical/mh-nov-1983/doc/Alias.Design b/docs/historical/mh-nov-1983/doc/Alias.Design new file mode 100644 index 00000000..ed2490aa --- /dev/null +++ b/docs/historical/mh-nov-1983/doc/Alias.Design @@ -0,0 +1,67 @@ +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." will +be mapped to "news". This is used for the MH news facility. + +Bruce Borden October 1979 diff --git a/docs/historical/mh-nov-1983/doc/MH_VGRIND b/docs/historical/mh-nov-1983/doc/MH_VGRIND new file mode 100644 index 00000000..346e7f68 --- /dev/null +++ b/docs/historical/mh-nov-1983/doc/MH_VGRIND @@ -0,0 +1,27 @@ +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 diff --git a/docs/historical/mh-nov-1983/doc/MHgenerate b/docs/historical/mh-nov-1983/doc/MHgenerate new file mode 100644 index 00000000..2ef96695 --- /dev/null +++ b/docs/historical/mh-nov-1983/doc/MHgenerate @@ -0,0 +1,122 @@ + 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 diff --git a/docs/historical/mh-nov-1983/doc/MHnotes b/docs/historical/mh-nov-1983/doc/MHnotes new file mode 100644 index 00000000..93167eb1 --- /dev/null +++ b/docs/historical/mh-nov-1983/doc/MHnotes @@ -0,0 +1,178 @@ +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-: highest-seen". + + Rather than read through the news folders to determine + the number of entries, a file with name . (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 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 diff --git a/docs/historical/mh-nov-1983/doc/Makefile b/docs/historical/mh-nov-1983/doc/Makefile new file mode 100644 index 00000000..49f2d78f --- /dev/null +++ b/docs/historical/mh-nov-1983/doc/Makefile @@ -0,0 +1,2 @@ +manual: + itroff -me titlepage mh.me diff --git a/docs/historical/mh-nov-1983/doc/mh.me b/docs/historical/mh-nov-1983/doc/mh.me new file mode 100644 index 00000000..630fa1a0 --- /dev/null +++ b/docs/historical/mh-nov-1983/doc/mh.me @@ -0,0 +1,2510 @@ +.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 \*(<\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//Mail/draft (where /usr/ 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 +( 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\*(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\-next:\0\*(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 +^:\0default switches~^All +^cur\-:\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 . +(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 \fR, to invoke + 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\-next: \*(rq names an alternative editor. + +.Fi +^/etc/mh/components~^The message skeleton +^or /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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\*(<> + 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 /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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 +.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/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: \*(<> + 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 /components~^Rather than the standard skeleton +^$HOME/\*.mh\(ruprofile~^The user profile +^/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 +^\-next:~^To name an editor to be used after exit from +.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 +\*(<> date +.ti 1.5i + +.ti 1.5i + +.ti 2.5i + +.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 +^/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 \*(< will cause the whole component to be left out. +A \*(lq\\\*(rq +preceding a 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 (or ). +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 during message-body typing is equivalent to + for compatibility with NED. +A 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: or +cc: , +Subject: Re: +In-reply-to: Your message of +.ti +\w'In-reply-to: 'u + +.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: \*(<>. + +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 +^/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\ \ \ \ \[\*(</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 + 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 +or . +If a is entered, \fIl\fR will clear the +screen before listing the next page, whereas 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 /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 + 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~^| +^^^^^ + +^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~^| +^^^^^\*(lq\--\*(rq~^| +^^^^ +.re \" Reset Tabs +.fi +.sp +.pp +Where 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 of messages, beginning +with \*(lqmsg\*(rq (in the case of first, cur, next, or ), +or ending with \*(lqmsg\*(rq (in the case of prev or last). ++ forces \*(lqstarting with msg\*(rq, and \- 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 diff --git a/docs/historical/mh-nov-1983/doc/titlepage b/docs/historical/mh-nov-1983/doc/titlepage new file mode 100644 index 00000000..427f1563 --- /dev/null +++ b/docs/historical/mh-nov-1983/doc/titlepage @@ -0,0 +1,23 @@ +.(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 diff --git a/docs/historical/mh-nov-1983/man/Makefile b/docs/historical/mh-nov-1983/man/Makefile new file mode 100644 index 00000000..b95bc899 --- /dev/null +++ b/docs/historical/mh-nov-1983/man/Makefile @@ -0,0 +1,39 @@ +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:; diff --git a/docs/historical/mh-nov-1983/man/comp.1 b/docs/historical/mh-nov-1983/man/comp.1 new file mode 100644 index 00000000..87c392e8 --- /dev/null +++ b/docs/historical/mh-nov-1983/man/comp.1 @@ -0,0 +1,82 @@ +.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 \fR, to invoke + 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\-next: \*(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 /components 'u +/etc/mh/components The message skeleton +or /components Rather than the standard skeleton +$HOME/\*.mh_profile The user profile +/draft The default message file +/usr/new/send To send the composed message +.fi +.SH "PROFILE COMPONENTS" +.nf +.ta \w'\-next: 'u +Path: To determine the user's MH directory +Editor: To override the use of /bin/ned as the default editor +\-next: editor to be used after exit from +.SH DEFAULTS +.nf +`file' defaults to draft +`\-editor' defaults to /bin/ned +`\-nouse' +.fi diff --git a/docs/historical/mh-nov-1983/man/dist.1 b/docs/historical/mh-nov-1983/man/dist.1 new file mode 100644 index 00000000..2b0abf4d --- /dev/null +++ b/docs/historical/mh-nov-1983/man/dist.1 @@ -0,0 +1,83 @@ +.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\*(<> + 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 /components 'u +/etc/mh/components The message skeleton +or /components Rather than the standard skeleton +$HOME/\*.mh\(ruprofile The user profile +/draft The default message file +/usr/bin/send To send the composed message +.fi +.SH "PROFILE COMPONENTS" +.nf +.ta \w'\-next: 'u +Path: To determine the user's MH directory +Editor: To override the use of /bin/ned as the default editor +\-next: editor to be used after exit from +.fi +.SH DEFAULTS +.nf +`+folder' defaults to the current folder +`msg' defaults to cur +`\-editor' defaults to /bin/ned +`\-noannotate' +`\-noinplace' +.fi diff --git a/docs/historical/mh-nov-1983/man/file.1 b/docs/historical/mh-nov-1983/man/file.1 new file mode 100644 index 00000000..74c74416 --- /dev/null +++ b/docs/historical/mh-nov-1983/man/file.1 @@ -0,0 +1,91 @@ +.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. diff --git a/docs/historical/mh-nov-1983/man/folder.1 b/docs/historical/mh-nov-1983/man/folder.1 new file mode 100644 index 00000000..063faf9f --- /dev/null +++ b/docs/historical/mh-nov-1983/man/folder.1 @@ -0,0 +1,105 @@ +.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 +.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/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. diff --git a/docs/historical/mh-nov-1983/man/forw.1 b/docs/historical/mh-nov-1983/man/forw.1 new file mode 100644 index 00000000..ed873271 --- /dev/null +++ b/docs/historical/mh-nov-1983/man/forw.1 @@ -0,0 +1,68 @@ +.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: \*(<> + 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 /components 'u +/etc/mh/components The message skeleton +or /components Rather than the standard skeleton +$HOME/\*.mh\(ruprofile The user profile +/draft The default message file +/usr/bin/send To send the composed message +.fi +.SH "PROFILE COMPONENTS" +.nf +.ta \w'\-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 +\-next: editor to be used after exit from +.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. diff --git a/docs/historical/mh-nov-1983/man/inc.1 b/docs/historical/mh-nov-1983/man/inc.1 new file mode 100644 index 00000000..48238b43 --- /dev/null +++ b/docs/historical/mh-nov-1983/man/inc.1 @@ -0,0 +1,84 @@ +.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 +\*(<> date +.ti 1.5i + +.ti 1.5i + +.ti 2.5i + + +.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'/audit-file 'u +$HOME/\*.mh\(ruprofile The user profile +$HOME/\*.mail The user's mail drop +/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. diff --git a/docs/historical/mh-nov-1983/man/next.1 b/docs/historical/mh-nov-1983/man/next.1 new file mode 100644 index 00000000..9531180f --- /dev/null +++ b/docs/historical/mh-nov-1983/man/next.1 @@ -0,0 +1,29 @@ +.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. diff --git a/docs/historical/mh-nov-1983/man/pick.1 b/docs/historical/mh-nov-1983/man/pick.1 new file mode 100644 index 00000000..bdd15e10 --- /dev/null +++ b/docs/historical/mh-nov-1983/man/pick.1 @@ -0,0 +1,185 @@ +.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 \*(< will cause the whole component to be left out. +A \*(lq\\\*(rq +preceding a 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 (or ). +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 during message-body typing is equivalent to + for compatibility with NED. +A 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 diff --git a/docs/historical/mh-nov-1983/man/repl.1 b/docs/historical/mh-nov-1983/man/repl.1 new file mode 100644 index 00000000..50f98c3d --- /dev/null +++ b/docs/historical/mh-nov-1983/man/repl.1 @@ -0,0 +1,81 @@ +.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: or +cc: , +Subject: Re: +In-reply-to: Your message of +.ti +\w'In-reply-to: 'u + +.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: \*(<>. + +.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 +/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. diff --git a/docs/historical/mh-nov-1983/man/rmf.1 b/docs/historical/mh-nov-1983/man/rmf.1 new file mode 100644 index 00000000..9dfeeccd --- /dev/null +++ b/docs/historical/mh-nov-1983/man/rmf.1 @@ -0,0 +1,62 @@ +.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 /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. diff --git a/docs/historical/mh-nov-1983/man/rmm.1 b/docs/historical/mh-nov-1983/man/rmm.1 new file mode 100644 index 00000000..35c07c1d --- /dev/null +++ b/docs/historical/mh-nov-1983/man/rmm.1 @@ -0,0 +1,32 @@ +.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. diff --git a/docs/historical/mh-nov-1983/man/scan.1 b/docs/historical/mh-nov-1983/man/scan.1 new file mode 100644 index 00000000..4216108c --- /dev/null +++ b/docs/historical/mh-nov-1983/man/scan.1 @@ -0,0 +1,64 @@ +.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\ \ \ \ \[\*(</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. diff --git a/docs/historical/mh-nov-1983/man/show.1 b/docs/historical/mh-nov-1983/man/show.1 new file mode 100644 index 00000000..abbea1aa --- /dev/null +++ b/docs/historical/mh-nov-1983/man/show.1 @@ -0,0 +1,64 @@ +.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 + 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 +or . +If a is entered, \fIl\fR will clear the +screen before listing the next page, whereas 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 /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. diff --git a/docs/historical/mh-nov-1983/strings/Mailprog.c b/docs/historical/mh-nov-1983/strings/Mailprog.c new file mode 100644 index 00000000..fe8edb32 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/Mailprog.c @@ -0,0 +1,7 @@ +/* + * 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"; diff --git a/docs/historical/mh-nov-1983/strings/Makefile b/docs/historical/mh-nov-1983/strings/Makefile new file mode 100644 index 00000000..966fc434 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/Makefile @@ -0,0 +1,37 @@ +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 diff --git a/docs/historical/mh-nov-1983/strings/anoyes.c b/docs/historical/mh-nov-1983/strings/anoyes.c new file mode 100644 index 00000000..eb842c93 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/anoyes.c @@ -0,0 +1,5 @@ +char *anoyes[] = { + "no", 0, + "yes", 0, + 0, +}; diff --git a/docs/historical/mh-nov-1983/strings/components.c b/docs/historical/mh-nov-1983/strings/components.c new file mode 100644 index 00000000..ffd97cb1 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/components.c @@ -0,0 +1 @@ +char *components = "components"; diff --git a/docs/historical/mh-nov-1983/strings/current.c b/docs/historical/mh-nov-1983/strings/current.c new file mode 100644 index 00000000..86ea3685 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/current.c @@ -0,0 +1 @@ +char *current = "cur"; diff --git a/docs/historical/mh-nov-1983/strings/defalt.c b/docs/historical/mh-nov-1983/strings/defalt.c new file mode 100644 index 00000000..ab3a0125 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/defalt.c @@ -0,0 +1 @@ +char *defalt = "inbox"; diff --git a/docs/historical/mh-nov-1983/strings/distcomps.c b/docs/historical/mh-nov-1983/strings/distcomps.c new file mode 100644 index 00000000..acd7eb7f --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/distcomps.c @@ -0,0 +1 @@ +char *distcomps = "distcomps"; diff --git a/docs/historical/mh-nov-1983/strings/draft.c b/docs/historical/mh-nov-1983/strings/draft.c new file mode 100644 index 00000000..0e25051a --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/draft.c @@ -0,0 +1 @@ +char *draft = "draft"; diff --git a/docs/historical/mh-nov-1983/strings/fileproc.c b/docs/historical/mh-nov-1983/strings/fileproc.c new file mode 100644 index 00000000..56626c78 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/fileproc.c @@ -0,0 +1,6 @@ +/* + * 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"; diff --git a/docs/historical/mh-nov-1983/strings/foldprot.c b/docs/historical/mh-nov-1983/strings/foldprot.c new file mode 100644 index 00000000..8769a274 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/foldprot.c @@ -0,0 +1,5 @@ +/* + * Folders (directories) are created with this protection (mode) + */ + +char *foldprot = "0751"; diff --git a/docs/historical/mh-nov-1983/strings/hostname.c b/docs/historical/mh-nov-1983/strings/hostname.c new file mode 100644 index 00000000..64278d6e --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/hostname.c @@ -0,0 +1,6 @@ +/* + * For ARPANET mail, this is the local-site's Host name. + * (currently not used.) + */ + +char *hostname = "Berkeley"; diff --git a/docs/historical/mh-nov-1983/strings/installproc.c b/docs/historical/mh-nov-1983/strings/installproc.c new file mode 100644 index 00000000..38814e74 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/installproc.c @@ -0,0 +1,6 @@ +/* + * 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"; diff --git a/docs/historical/mh-nov-1983/strings/listname.c b/docs/historical/mh-nov-1983/strings/listname.c new file mode 100644 index 00000000..af8a8827 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/listname.c @@ -0,0 +1 @@ +char *listname = "select"; diff --git a/docs/historical/mh-nov-1983/strings/localname.c b/docs/historical/mh-nov-1983/strings/localname.c new file mode 100644 index 00000000..b11b7da9 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/localname.c @@ -0,0 +1,5 @@ +/* + * Local network host name + */ + +char *localname = "CSVAX"; diff --git a/docs/historical/mh-nov-1983/strings/lockdir.c b/docs/historical/mh-nov-1983/strings/lockdir.c new file mode 100644 index 00000000..1496570a --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/lockdir.c @@ -0,0 +1,15 @@ +/* + * 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 */ diff --git a/docs/historical/mh-nov-1983/strings/lsproc.c b/docs/historical/mh-nov-1983/strings/lsproc.c new file mode 100644 index 00000000..50ca14c9 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/lsproc.c @@ -0,0 +1,9 @@ +/* + * 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"; diff --git a/docs/historical/mh-nov-1983/strings/mailboxes.c b/docs/historical/mh-nov-1983/strings/mailboxes.c new file mode 100644 index 00000000..b9c56b90 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/mailboxes.c @@ -0,0 +1,7 @@ +/* + * 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/"; diff --git a/docs/historical/mh-nov-1983/strings/mailproc.c b/docs/historical/mh-nov-1983/strings/mailproc.c new file mode 100644 index 00000000..b7020766 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/mailproc.c @@ -0,0 +1,6 @@ +/* + * 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"; diff --git a/docs/historical/mh-nov-1983/strings/mh_defs.c b/docs/historical/mh-nov-1983/strings/mh_defs.c new file mode 100644 index 00000000..fa86e657 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/mh_defs.c @@ -0,0 +1,6 @@ +/* + * This is the name of the file used to store + * the user's MH profile + */ + +char *mh_defs = "/.mh_profile"; diff --git a/docs/historical/mh-nov-1983/strings/mh_deliver.c b/docs/historical/mh-nov-1983/strings/mh_deliver.c new file mode 100644 index 00000000..62f4928c --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/mh_deliver.c @@ -0,0 +1,7 @@ +/* + * 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"; */ diff --git a/docs/historical/mh-nov-1983/strings/mh_prof.c b/docs/historical/mh-nov-1983/strings/mh_prof.c new file mode 100644 index 00000000..db3cc3ad --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/mh_prof.c @@ -0,0 +1 @@ +char *mh_prof = "/.mh_profile"; diff --git a/docs/historical/mh-nov-1983/strings/mhnews.c b/docs/historical/mh-nov-1983/strings/mhnews.c new file mode 100644 index 00000000..098e8f43 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/mhnews.c @@ -0,0 +1,7 @@ +/* + * 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"; diff --git a/docs/historical/mh-nov-1983/strings/msgprot.c b/docs/historical/mh-nov-1983/strings/msgprot.c new file mode 100644 index 00000000..65f1ff03 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/msgprot.c @@ -0,0 +1,7 @@ +/* + * 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"; diff --git a/docs/historical/mh-nov-1983/strings/pfolder.c b/docs/historical/mh-nov-1983/strings/pfolder.c new file mode 100644 index 00000000..209c7ee8 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/pfolder.c @@ -0,0 +1 @@ +char *pfolder = "current-folder"; diff --git a/docs/historical/mh-nov-1983/strings/prproc.c b/docs/historical/mh-nov-1983/strings/prproc.c new file mode 100644 index 00000000..4417a454 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/prproc.c @@ -0,0 +1,6 @@ +/* + * This is the std BELL pr, which is invoked through show with the + * -pr switch. + */ + +char *prproc = "/bin/pr"; diff --git a/docs/historical/mh-nov-1983/strings/scanproc.c b/docs/historical/mh-nov-1983/strings/scanproc.c new file mode 100644 index 00000000..0bb22ea8 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/scanproc.c @@ -0,0 +1,6 @@ +/* + * This program is usually called directly by users, but it is + * also invoked by "pick -scan". + */ + +char *scanproc = "/usr/new/mh/scan"; diff --git a/docs/historical/mh-nov-1983/strings/sendproc.c b/docs/historical/mh-nov-1983/strings/sendproc.c new file mode 100644 index 00000000..82baf792 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/sendproc.c @@ -0,0 +1,7 @@ +/* + * 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"; diff --git a/docs/historical/mh-nov-1983/strings/showproc.c b/docs/historical/mh-nov-1983/strings/showproc.c new file mode 100644 index 00000000..4bd7c6d8 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/showproc.c @@ -0,0 +1,9 @@ +/* + * This program is called to list messages. At Rand, the program + * c stops at the end of each page and waits for a or + * 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 */ diff --git a/docs/historical/mh-nov-1983/strings/stdcomps.c b/docs/historical/mh-nov-1983/strings/stdcomps.c new file mode 100644 index 00000000..5329fbe1 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/stdcomps.c @@ -0,0 +1,6 @@ +/* + * This is the standard skeleton for message composition with both + * comp and forw. + */ + +char *stdcomps = "/usr/new/lib/mh/components"; diff --git a/docs/historical/mh-nov-1983/strings/stddcomps.c b/docs/historical/mh-nov-1983/strings/stddcomps.c new file mode 100644 index 00000000..0e3fa764 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/stddcomps.c @@ -0,0 +1,5 @@ +/* + * This is the standard skeleton for message composition with dist. + */ + +char *stddcomps = "/usr/new/lib/mh/distcomps"; diff --git a/docs/historical/mh-nov-1983/strings/strings.h b/docs/historical/mh-nov-1983/strings/strings.h new file mode 100644 index 00000000..e9af6d0c --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/strings.h @@ -0,0 +1,36 @@ +/* + * 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; diff --git a/docs/historical/mh-nov-1983/strings/sysed.c b/docs/historical/mh-nov-1983/strings/sysed.c new file mode 100644 index 00000000..25bb0e57 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/sysed.c @@ -0,0 +1,9 @@ +/* + * 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"; diff --git a/docs/historical/mh-nov-1983/strings/unixtomh.c b/docs/historical/mh-nov-1983/strings/unixtomh.c new file mode 100644 index 00000000..0d3ce085 --- /dev/null +++ b/docs/historical/mh-nov-1983/strings/unixtomh.c @@ -0,0 +1,7 @@ +/* + * 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"; diff --git a/docs/historical/mh-nov-1983/subs/Makefile b/docs/historical/mh-nov-1983/subs/Makefile new file mode 100644 index 00000000..62c74495 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/Makefile @@ -0,0 +1,56 @@ +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 diff --git a/docs/historical/mh-nov-1983/subs/add.c b/docs/historical/mh-nov-1983/subs/add.c new file mode 100644 index 00000000..aad38155 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/add.c @@ -0,0 +1,15 @@ +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); +} diff --git a/docs/historical/mh-nov-1983/subs/ambigsw.c b/docs/historical/mh-nov-1983/subs/ambigsw.c new file mode 100644 index 00000000..505b2d4c --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/ambigsw.c @@ -0,0 +1,10 @@ +#include + +ambigsw(arg, swp) +char *arg; +{ + fprintf(stderr, "%s: ", invo_name()); + fprintf(stderr, "-%s ambiguous. It matches \n", arg); + printsw(arg, swp, "-"); +} + diff --git a/docs/historical/mh-nov-1983/subs/atooi.c b/docs/historical/mh-nov-1983/subs/atooi.c new file mode 100644 index 00000000..79991d3e --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/atooi.c @@ -0,0 +1,15 @@ +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); +} diff --git a/docs/historical/mh-nov-1983/subs/brkstring.c b/docs/historical/mh-nov-1983/subs/brkstring.c new file mode 100644 index 00000000..9933ff13 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/brkstring.c @@ -0,0 +1,38 @@ +#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= &end) free(addr); +} diff --git a/docs/historical/mh-nov-1983/subs/concat.c b/docs/historical/mh-nov-1983/subs/concat.c new file mode 100644 index 00000000..ba19272b --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/concat.c @@ -0,0 +1,18 @@ +#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); +} diff --git a/docs/historical/mh-nov-1983/subs/copy.c b/docs/historical/mh-nov-1983/subs/copy.c new file mode 100644 index 00000000..3284c123 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/copy.c @@ -0,0 +1,6 @@ +char *copy(from,to) +register char *from, *to; +{ + while(*to++ = *from++); + return to-1; +}; diff --git a/docs/historical/mh-nov-1983/subs/copyip.c b/docs/historical/mh-nov-1983/subs/copyip.c new file mode 100644 index 00000000..a1454811 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/copyip.c @@ -0,0 +1,9 @@ +int *copyip(ipf, ipt) +register int *ipf, *ipt; +{ + while((*ipt = *ipf) && *ipf++ != -1) + ipt++; + *ipt = 0; + return(ipt); +} + diff --git a/docs/historical/mh-nov-1983/subs/cputc.c b/docs/historical/mh-nov-1983/subs/cputc.c new file mode 100644 index 00000000..f3715fb6 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/cputc.c @@ -0,0 +1,13 @@ +#include + +cputc(chr, ip) +register FILE *ip; +{ + if(ip != NULL) { + putc(chr, ip); + if(ferror(ip)) { + perror("Write error"); + done(-1); + } + } +} diff --git a/docs/historical/mh-nov-1983/subs/crpbrkstring.c b/docs/historical/mh-nov-1983/subs/crpbrkstring.c new file mode 100644 index 00000000..bea75147 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/crpbrkstring.c @@ -0,0 +1,50 @@ +#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); +} diff --git a/docs/historical/mh-nov-1983/subs/done.c b/docs/historical/mh-nov-1983/subs/done.c new file mode 100644 index 00000000..5808ba31 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/done.c @@ -0,0 +1,8 @@ +/* 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); +} diff --git a/docs/historical/mh-nov-1983/subs/fdcompare.c b/docs/historical/mh-nov-1983/subs/fdcompare.c new file mode 100644 index 00000000..94a54b2f --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/fdcompare.c @@ -0,0 +1,27 @@ +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); +} diff --git a/docs/historical/mh-nov-1983/subs/gans.c b/docs/historical/mh-nov-1983/subs/gans.c new file mode 100644 index 00000000..c85c1e00 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/gans.c @@ -0,0 +1,38 @@ +#include "mh.h" +#include + +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); + } +} diff --git a/docs/historical/mh-nov-1983/subs/getans.c b/docs/historical/mh-nov-1983/subs/getans.c new file mode 100644 index 00000000..11abb450 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/getans.c @@ -0,0 +1,54 @@ +#include "mh.h" +#include +#include + +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 for help.\n", *cpp); + continue; + default: + return(cpp); /* list, edit, quit, send */ + } + } +} + + +g_sig() +{ + signal(SIGINT, g_sig); + g_sigint = 1; + return; +} diff --git a/docs/historical/mh-nov-1983/subs/getcpy.c b/docs/historical/mh-nov-1983/subs/getcpy.c new file mode 100644 index 00000000..ab94cd1b --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/getcpy.c @@ -0,0 +1,8 @@ +char *getcpy(str) +{ + register char *cp; + + cp = (char *) malloc(strlen(str) + 1); + strcpy(cp, str); + return(cp); +} diff --git a/docs/historical/mh-nov-1983/subs/help.c b/docs/historical/mh-nov-1983/subs/help.c new file mode 100644 index 00000000..9f6dc12c --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/help.c @@ -0,0 +1,9 @@ +#include "mh.h" + +help(str, swp) +char *str; +{ + printf("syntax: %s\n", str); + printf(" switches are:\n"); + printsw(ALL, swp, "-"); +} diff --git a/docs/historical/mh-nov-1983/subs/invo_name.c b/docs/historical/mh-nov-1983/subs/invo_name.c new file mode 100644 index 00000000..25b86a4e --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/invo_name.c @@ -0,0 +1,16 @@ +/* + * 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. */ +} diff --git a/docs/historical/mh-nov-1983/subs/locv.c b/docs/historical/mh-nov-1983/subs/locv.c new file mode 100644 index 00000000..b530686e --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/locv.c @@ -0,0 +1,8 @@ +char *locv(longint) +long longint; +{ + static char locvbuf[12]; + + sprintf(locvbuf, "%ld", longint); + return locvbuf; +} diff --git a/docs/historical/mh-nov-1983/subs/m_convert.c b/docs/historical/mh-nov-1983/subs/m_convert.c new file mode 100644 index 00000000..43220b40 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_convert.c @@ -0,0 +1,147 @@ +#include "mh.h" +#include + +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 */ +} diff --git a/docs/historical/mh-nov-1983/subs/m_delete.c b/docs/historical/mh-nov-1983/subs/m_delete.c new file mode 100644 index 00000000..b1732bfa --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_delete.c @@ -0,0 +1,22 @@ +#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); +} diff --git a/docs/historical/mh-nov-1983/subs/m_edit.c b/docs/historical/mh-nov-1983/subs/m_edit.c new file mode 100644 index 00000000..13b470a0 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_edit.c @@ -0,0 +1,94 @@ +#include "mh.h" +#include +#include +#include +#include +#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); +} diff --git a/docs/historical/mh-nov-1983/subs/m_find.c b/docs/historical/mh-nov-1983/subs/m_find.c new file mode 100644 index 00000000..26743a0f --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_find.c @@ -0,0 +1,13 @@ +#include "mh.h" +#include + +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); +} diff --git a/docs/historical/mh-nov-1983/subs/m_getdefs.c b/docs/historical/mh-nov-1983/subs/m_getdefs.c new file mode 100644 index 00000000..35eb0857 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_getdefs.c @@ -0,0 +1,90 @@ +#include "mh.h" +#include + +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); + } +} diff --git a/docs/historical/mh-nov-1983/subs/m_getfld.c b/docs/historical/mh-nov-1983/subs/m_getfld.c new file mode 100644 index 00000000..27c33006 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_getfld.c @@ -0,0 +1,87 @@ +#include "mh.h" +#include + +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)? "":"", 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); + } + + } +} diff --git a/docs/historical/mh-nov-1983/subs/m_getfolder.c b/docs/historical/mh-nov-1983/subs/m_getfolder.c new file mode 100644 index 00000000..9f86bf6a --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_getfolder.c @@ -0,0 +1,12 @@ +#include "mh.h" +#include + +char *m_getfolder() +{ + register char *folder; + + m_getdefs(); + if((folder = m_find(pfolder)) == NULL || *folder == 0) + folder = defalt; + return(folder); +} diff --git a/docs/historical/mh-nov-1983/subs/m_gmprot.c b/docs/historical/mh-nov-1983/subs/m_gmprot.c new file mode 100644 index 00000000..34302593 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_gmprot.c @@ -0,0 +1,14 @@ +#include "mh.h" +#include + +m_gmprot() +{ + register char *cp; + register int prot; + + if((cp = m_find("msg-protect")) != NULL) + prot = atooi(cp); + else + prot = atooi(msgprot); + return(prot); +} diff --git a/docs/historical/mh-nov-1983/subs/m_gmsg.c b/docs/historical/mh-nov-1983/subs/m_gmsg.c new file mode 100644 index 00000000..20f220ac --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_gmsg.c @@ -0,0 +1,122 @@ +#include "mh.h" +#include +#include +#include +#include + +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 */ + 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); +} diff --git a/docs/historical/mh-nov-1983/subs/m_maildir.c b/docs/historical/mh-nov-1983/subs/m_maildir.c new file mode 100644 index 00000000..a64ef75f --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_maildir.c @@ -0,0 +1,29 @@ +#include "mh.h" +#include + +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); +} diff --git a/docs/historical/mh-nov-1983/subs/m_name.c b/docs/historical/mh-nov-1983/subs/m_name.c new file mode 100644 index 00000000..c8880af5 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_name.c @@ -0,0 +1,21 @@ +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); +} diff --git a/docs/historical/mh-nov-1983/subs/m_replace.c b/docs/historical/mh-nov-1983/subs/m_replace.c new file mode 100644 index 00000000..4d6496dd --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_replace.c @@ -0,0 +1,29 @@ +#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; +} diff --git a/docs/historical/mh-nov-1983/subs/m_send.c b/docs/historical/mh-nov-1983/subs/m_send.c new file mode 100644 index 00000000..22ca0a7d --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_send.c @@ -0,0 +1,22 @@ +#include "mh.h" +#include + +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); + +} diff --git a/docs/historical/mh-nov-1983/subs/m_setcur.c b/docs/historical/mh-nov-1983/subs/m_setcur.c new file mode 100644 index 00000000..e6251497 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_setcur.c @@ -0,0 +1,26 @@ +#include "mh.h" +#include + +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); + } + } +} diff --git a/docs/historical/mh-nov-1983/subs/m_update.c b/docs/historical/mh-nov-1983/subs/m_update.c new file mode 100644 index 00000000..c2ea0495 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/m_update.c @@ -0,0 +1,25 @@ +#include "mh.h" +#include +#include + +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; + } +} diff --git a/docs/historical/mh-nov-1983/subs/makedir.c b/docs/historical/mh-nov-1983/subs/makedir.c new file mode 100644 index 00000000..7f9c9279 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/makedir.c @@ -0,0 +1,28 @@ +#include "mh.h" +#include + +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); +} diff --git a/docs/historical/mh-nov-1983/subs/makename.c b/docs/historical/mh-nov-1983/subs/makename.c new file mode 100644 index 00000000..027c4d8e --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/makename.c @@ -0,0 +1,19 @@ +#include "mh.h" +#include + +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); +} diff --git a/docs/historical/mh-nov-1983/subs/mh.h b/docs/historical/mh-nov-1983/subs/mh.h new file mode 100644 index 00000000..9ba122a5 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/mh.h @@ -0,0 +1,154 @@ +#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(); + diff --git a/docs/historical/mh-nov-1983/subs/peekc.c b/docs/historical/mh-nov-1983/subs/peekc.c new file mode 100644 index 00000000..0f5cea05 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/peekc.c @@ -0,0 +1,11 @@ +#include + +peekc(ib) +FILE *ib; +{ + register c; + + c = getc(ib); + ungetc(c,ib); + return(c); +} diff --git a/docs/historical/mh-nov-1983/subs/pr_array.c b/docs/historical/mh-nov-1983/subs/pr_array.c new file mode 100644 index 00000000..00fddabd --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/pr_array.c @@ -0,0 +1,9 @@ +pr_array(cp,ap) +char *cp, **ap; +{ + register int i; + + for(i=0; *ap; ap++,i++) + printf("%s[%d]=> %s\n", cp,i,*ap); +} + diff --git a/docs/historical/mh-nov-1983/subs/printsw.c b/docs/historical/mh-nov-1983/subs/printsw.c new file mode 100644 index 00000000..0b516e8e --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/printsw.c @@ -0,0 +1,26 @@ +#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); +} diff --git a/docs/historical/mh-nov-1983/subs/putdate.c b/docs/historical/mh-nov-1983/subs/putdate.c new file mode 100644 index 00000000..7a8fb3d5 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/putdate.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include + +/* + * 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); +} diff --git a/docs/historical/mh-nov-1983/subs/r1bindex.c b/docs/historical/mh-nov-1983/subs/r1bindex.c new file mode 100644 index 00000000..2aa54479 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/r1bindex.c @@ -0,0 +1,19 @@ +/* + * 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; +} diff --git a/docs/historical/mh-nov-1983/subs/showfile.c b/docs/historical/mh-nov-1983/subs/showfile.c new file mode 100644 index 00000000..c75c138d --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/showfile.c @@ -0,0 +1,37 @@ +#include "mh.h" +#include +#include + +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); + +} + diff --git a/docs/historical/mh-nov-1983/subs/smatch.c b/docs/historical/mh-nov-1983/subs/smatch.c new file mode 100644 index 00000000..aa4a2d39 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/smatch.c @@ -0,0 +1,34 @@ +#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); +} diff --git a/docs/historical/mh-nov-1983/subs/ssequal.c b/docs/historical/mh-nov-1983/subs/ssequal.c new file mode 100644 index 00000000..124581c2 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/ssequal.c @@ -0,0 +1,8 @@ +ssequal(substr, str) +char *substr, *str; +{ + while(*substr) + if(*substr++ != *str++) + return(0); + return(1); +} diff --git a/docs/historical/mh-nov-1983/subs/trimcpy.c b/docs/historical/mh-nov-1983/subs/trimcpy.c new file mode 100644 index 00000000..eb7d5fe9 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/trimcpy.c @@ -0,0 +1,16 @@ +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); +} diff --git a/docs/historical/mh-nov-1983/subs/type.c b/docs/historical/mh-nov-1983/subs/type.c new file mode 100644 index 00000000..31c800b2 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/type.c @@ -0,0 +1,10 @@ +type(ch, s) +char *s; +{ + register char *p; + + for (p = s; *p++; ); + --p; + write(ch, s, p-s); + return(p-s); +} diff --git a/docs/historical/mh-nov-1983/subs/uleq.c b/docs/historical/mh-nov-1983/subs/uleq.c new file mode 100644 index 00000000..663adcd5 --- /dev/null +++ b/docs/historical/mh-nov-1983/subs/uleq.c @@ -0,0 +1,12 @@ +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); +} diff --git a/docs/historical/mh-nov-1983/support/components b/docs/historical/mh-nov-1983/support/components new file mode 100644 index 00000000..657e5ddf --- /dev/null +++ b/docs/historical/mh-nov-1983/support/components @@ -0,0 +1,4 @@ +To: +Cc: +Subject: +------- diff --git a/docs/historical/mh-nov-1983/support/distcomps b/docs/historical/mh-nov-1983/support/distcomps new file mode 100644 index 00000000..b3415f92 --- /dev/null +++ b/docs/historical/mh-nov-1983/support/distcomps @@ -0,0 +1,2 @@ +Distribution-to: +Distribution-cc: diff --git a/docs/historical/mh-nov-1983/support/l.c b/docs/historical/mh-nov-1983/support/l.c new file mode 100644 index 00000000..2f7b8d26 --- /dev/null +++ b/docs/historical/mh-nov-1983/support/l.c @@ -0,0 +1,259 @@ +/* Rewrite for VAX: BSB 9/9/79 */ +/* Compiled with V7 cc: BSB 6/2/79 */ + +#include +#include +#include +#include +#include +#include + +#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 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; i1) { + if(i && delflg <= 0) + printf("\n\n"); + delflg = 0; + if(ontty) { + printf("Press 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); +} diff --git a/docs/historical/mh-nov-1983/support/news-1char b/docs/historical/mh-nov-1983/support/news-1char new file mode 100644 index 00000000..0519ecba --- /dev/null +++ b/docs/historical/mh-nov-1983/support/news-1char @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/historical/mh-nov-1983/support/news-mh_receiv b/docs/historical/mh-nov-1983/support/news-mh_receiv new file mode 100644 index 00000000..8f7d4368 --- /dev/null +++ b/docs/historical/mh-nov-1983/support/news-mh_receiv @@ -0,0 +1,8 @@ +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