BSD 2 development
authorKurt A. Shoens <kurt@ucbvax.Berkeley.EDU>
Wed, 9 May 1979 07:32:38 +0000 (23:32 -0800)
committerKurt A. Shoens <kurt@ucbvax.Berkeley.EDU>
Wed, 9 May 1979 07:32:38 +0000 (23:32 -0800)
Work on file src/Mail/list.c
Work on file src/Mail/local.h
Work on file src/Mail/lock.c
Work on file src/Mail/main.c
Work on file src/Mail/names.c
Work on file src/Mail/quit.c
Work on file src/Mail/rcv.h
Work on file src/Mail/send.c
Work on file src/Mail/strings.c
Work on file src/Mail/temp.c
Work on file src/Mail/tty.c
Work on file src/Mail/v6.local.c
Work on file src/Mail/v7.local.c
Work on file src/Mail/vars.c
Work on file src/Mail/version.c

Synthesized-from: 2bsd

15 files changed:
src/Mail/list.c [new file with mode: 0644]
src/Mail/local.h [new file with mode: 0644]
src/Mail/lock.c [new file with mode: 0644]
src/Mail/main.c [new file with mode: 0644]
src/Mail/names.c [new file with mode: 0644]
src/Mail/quit.c [new file with mode: 0644]
src/Mail/rcv.h [new file with mode: 0644]
src/Mail/send.c [new file with mode: 0644]
src/Mail/strings.c [new file with mode: 0644]
src/Mail/temp.c [new file with mode: 0644]
src/Mail/tty.c [new file with mode: 0644]
src/Mail/v6.local.c [new file with mode: 0644]
src/Mail/v7.local.c [new file with mode: 0644]
src/Mail/vars.c [new file with mode: 0644]
src/Mail/version.c [new file with mode: 0644]

diff --git a/src/Mail/list.c b/src/Mail/list.c
new file mode 100644 (file)
index 0000000..35b2d39
--- /dev/null
@@ -0,0 +1,498 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+
+#include "rcv.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Message list handling.
+ */
+
+/*
+ * Convert the user string of message numbers and
+ * store the numbers into vector.
+ *
+ * Returns the count of messages picked up or -1 on error.
+ */
+
+getmsglist(buf, vector, flags)
+       char *buf;
+       int *vector;
+{
+       register int *ip;
+       register struct message *mp;
+
+       if (markall(buf, flags) < 0)
+               return(-1);
+       ip = vector;
+       for (mp = &message[0]; mp < &message[msgCount]; mp++)
+               if (mp->m_flag & MMARK)
+                       *ip++ = mp - &message[0] + 1;
+       *ip = NULL;
+       return(ip - vector);
+}
+
+/*
+ * Mark all messages that the user wanted from the command
+ * line in the message structure.  Return 0 on success, -1
+ * on error.
+ */
+
+markall(buf, f)
+       char buf[];
+{
+       register char **np;
+       register int i;
+       char *namelist[NMLSIZE], *bufp;
+       int tok, beg, mc, star, other;
+
+       for (i = 1; i <= msgCount; i++)
+               unmark(i);
+       bufp = buf;
+       mc = 0;
+       np = &namelist[0];
+       scaninit();
+       tok = scan(&bufp);
+       star = 0;
+       other = 0;
+       beg = 0;
+       while (tok != TEOL) {
+               switch (tok) {
+               case TNUMBER:
+number:
+                       if (star) {
+                               printf("No numbers mixed with *\n");
+                               return(-1);
+                       }
+                       mc++;
+                       other++;
+                       if (beg != 0) {
+                               if (check(lexnumber, f))
+                                       return(-1);
+                               for (i = beg; i <= lexnumber; i++)
+                                       mark(i);
+                               beg = 0;
+                               break;
+                       }
+                       beg = lexnumber;
+                       if (check(beg, f))
+                               return(-1);
+                       tok = scan(&bufp);
+                       regret(tok);
+                       if (tok != TDASH) {
+                               mark(beg);
+                               beg = 0;
+                       }
+                       break;
+
+               case TDASH:
+                       if (beg == 0) {
+                               printf("Unexpected leading dash\n");
+                               return(-1);
+                       }
+                       break;
+
+               case TSTRING:
+                       if (beg != 0) {
+                               printf("Non-numeric second argument\n");
+                               return(-1);
+                       }
+                       other++;
+                       *np++ = savestr(lexstring);
+                       break;
+
+               case TDOLLAR:
+               case TUP:
+               case TDOT:
+                       lexnumber = metamess(lexstring[0], f);
+                       if (lexnumber == -1)
+                               return(-1);
+                       goto number;
+
+               case TSTAR:
+                       if (other) {
+                               printf("Can't mix \"*\" with anything\n");
+                               return(-1);
+                       }
+                       star++;
+                       break;
+               }
+               tok = scan(&bufp);
+       }
+       *np = NOSTR;
+       mc = 0;
+       if (star) {
+               for (i = 0; i < msgCount; i++)
+                       if ((message[i].m_flag & MDELETED) == f) {
+                               mark(i+1);
+                               mc++;
+                       }
+               if (mc == 0) {
+                       printf("No applicable messages.\n");
+                       return(-1);
+               }
+               return(0);
+       }
+
+       /*
+        * If no numbers were given, mark all of the messages,
+        * so that we can unmark any whose sender was not selected
+        * if any user names were given.
+        */
+
+       if (np > namelist && mc == 0)
+               for (i = 1; i <= msgCount; i++)
+                       if ((message[i-1].m_flag & (MSAVED|MDELETED)) == f)
+                               mark(i);
+
+       /*
+        * If any names were given, go through and eliminate any
+        * messages whose senders were not requested.
+        */
+
+       if (np > namelist) {
+               for (i = 1; i <= msgCount; i++) {
+                       for (mc = 0, np = &namelist[0]; *np != NOSTR; np++)
+                               if (sender(*np, i)) {
+                                       mc++;
+                                       break;
+                               }
+                       if (mc == 0)
+                               unmark(i);
+               }
+
+               /*
+                * Make sure we got some decent messages.
+                */
+
+               mc = 0;
+               for (i = 1; i <= msgCount; i++)
+                       if (message[i-1].m_flag & MMARK) {
+                               mc++;
+                               break;
+                       }
+               if (mc == 0) {
+                       printf("No applicable messages from {%s",
+                               namelist[0]);
+                       for (np = &namelist[1]; *np != NOSTR; np++)
+                               printf(", %s", *np);
+                       printf("}\n");
+                       return(-1);
+               }
+       }
+       return(0);
+}
+
+/*
+ * Check the passed message number for legality and proper flags.
+ */
+
+check(mesg, f)
+{
+       register struct message *mp;
+
+       if (mesg < 1 || mesg > msgCount) {
+               printf("%d: Invalid message number\n", mesg);
+               return(-1);
+       }
+       mp = &message[mesg-1];
+       if ((mp->m_flag & MDELETED) != f) {
+               printf("%d: Inappropriate message\n", mesg);
+               return(-1);
+       }
+       return(0);
+}
+
+/*
+ * Scan out the list of string arguments, shell style
+ * for a RAWLIST.
+ */
+
+getrawlist(line, argv)
+       char line[];
+       char **argv;
+{
+       register char **ap, *cp, *cp2;
+       char linebuf[BUFSIZ], quotec;
+
+       ap = argv;
+       cp = line;
+       while (*cp != '\0') {
+               while (any(*cp, " \t"))
+                       cp++;
+               cp2 = linebuf;
+               quotec = 0;
+               if (any(*cp, "'\""))
+                       quotec = *cp++;
+               if (quotec == 0)
+                       while (*cp != '\0' && !any(*cp, " \t"))
+                               *cp2++ = *cp++;
+               else {
+                       while (*cp != '\0' && *cp != quotec)
+                               *cp2++ = *cp++;
+                       if (*cp != '\0')
+                               cp++;
+               }
+               *cp2 = '\0';
+               if (cp2 == linebuf)
+                       break;
+               *ap++ = savestr(linebuf);
+       }
+       *ap = NOSTR;
+       return(ap-argv);
+}
+
+/*
+ * scan out a single lexical item and return its token number,
+ * updating the string pointer passed **p.  Also, store the value
+ * of the number or string scanned in lexnumber or lexstring as
+ * appropriate.  In any event, store the scanned `thing' in lexstring.
+ */
+
+struct lex {
+       char    l_char;
+       char    l_token;
+} singles[] = {
+       '$',    TDOLLAR,
+       '.',    TDOT,
+       '^',    TUP,
+       '*',    TSTAR,
+       '-',    TDASH,
+       '(',    TOPEN,
+       ')',    TCLOSE,
+       0,      0
+};
+
+scan(sp)
+       char **sp;
+{
+       register char *cp, *cp2;
+       register int c;
+       register struct lex *lp;
+       int quotec;
+
+       if (regretp >= 0) {
+               copy(stringstack[regretp], lexstring);
+               lexnumber = numberstack[regretp];
+               return(regretstack[regretp--]);
+       }
+       cp = *sp;
+       cp2 = lexstring;
+       c = *cp++;
+
+       /*
+        * strip away leading white space.
+        */
+
+       while (any(c, " \t"))
+               c = *cp++;
+
+       /*
+        * If no characters remain, we are at end of line,
+        * so report that.
+        */
+
+       if (c == '\0') {
+               *sp = --cp;
+               return(TEOL);
+       }
+
+       /*
+        * If the leading character is a digit, scan
+        * the number and convert it on the fly.
+        * Return TNUMBER when done.
+        */
+
+       if (isdigit(c)) {
+               lexnumber = 0;
+               while (isdigit(c)) {
+                       lexnumber = lexnumber*10 + c - '0';
+                       *cp2++ = c;
+                       c = *cp++;
+               }
+               *cp2 = '\0';
+               *sp = --cp;
+               return(TNUMBER);
+       }
+
+       /*
+        * Check for single character tokens; return such
+        * if found.
+        */
+
+       for (lp = &singles[0]; lp->l_char != 0; lp++)
+               if (c == lp->l_char) {
+                       lexstring[0] = c;
+                       lexstring[1] = '\0';
+                       *sp = cp;
+                       return(lp->l_token);
+               }
+
+       /*
+        * We've got a string!  Copy all the characters
+        * of the string into lexstring, until we see
+        * a null, space, or tab.
+        * If the lead character is a " or ', save it
+        * and scan until you get another.
+        */
+
+       quotec = 0;
+       if (any(c, "'\"")) {
+               quotec = c;
+               c = *cp++;
+       }
+       while (c != '\0') {
+               if (c == quotec)
+                       break;
+               if (quotec == 0 && any(c, " \t"))
+                       break;
+               if (cp2 - lexstring < STRINGLEN-1)
+                       *cp2++ = c;
+               c = *cp++;
+       }
+       if (quotec && c == 0)
+               fprintf(stderr, "Missing %c\n", quotec);
+       *sp = --cp;
+       *cp2 = '\0';
+       return(TSTRING);
+}
+
+/*
+ * Unscan the named token by pushing it onto the regret stack.
+ */
+
+regret(token)
+{
+       if (++regretp >= REGDEP)
+               panic("Too many regrets");
+       regretstack[regretp] = token;
+       lexstring[STRINGLEN-1] = '\0';
+       stringstack[regretp] = savestr(lexstring);
+       numberstack[regretp] = lexnumber;
+}
+
+/*
+ * Reset all the scanner global variables.
+ */
+
+scaninit()
+{
+       regretp = -1;
+}
+
+/*
+ * Find the first message whose flags & m == f  and return
+ * its message number.
+ */
+
+first(f, m)
+{
+       register int mesg;
+       register struct message *mp;
+
+       mesg = dot - &message[0];
+       mesg++;
+       for (mp = dot; mp < &message[msgCount]; mp++) {
+               if ((mp->m_flag & m) == f)
+                       return(mesg);
+               mesg++;
+       }
+       mesg = dot - &message[0];
+       for (mp = dot-1; mp >= &message[0]; mp--) {
+               if ((mp->m_flag & m) == f)
+                       return(mesg);
+               mesg--;
+       }
+       return(NULL);
+}
+
+/*
+ * See if the passed name sent the passed message number.  Return true
+ * if so.
+ */
+
+sender(str, mesg)
+       char *str;
+{
+       register struct message *mp;
+
+       mp = &message[mesg-1];
+       return(!strcmp(nameof(mp), str));
+}
+
+/*
+ * Mark the named message by setting its mark bit.
+ */
+
+mark(mesg)
+{
+       register int i;
+
+       i = mesg;
+       if (i < 1 || i > msgCount)
+               panic("Bad message number to mark");
+       message[i-1].m_flag |= MMARK;
+}
+
+/*
+ * Unmark the named message.
+ */
+
+unmark(mesg)
+{
+       register int i;
+
+       i = mesg;
+       if (i < 1 || i > msgCount)
+               panic("Bad message number to unmark");
+       message[i-1].m_flag &= ~MMARK;
+}
+
+/*
+ * Return the message number corresponding to the passed meta character.
+ */
+
+metamess(meta, f)
+{
+       register int c, m;
+       register struct message *mp;
+
+       c = meta;
+       switch (c) {
+       case '^':
+               /*
+                * First 'good' message left.
+                */
+               for (mp = &message[0]; mp < &message[msgCount]; mp++)
+                       if ((mp->m_flag & MDELETED) == f)
+                               return(mp - &message[0] + 1);
+               printf("No applicable messages\n");
+               return(-1);
+
+       case '$':
+               /*
+                * Last 'good message left.
+                */
+               for (mp = &message[msgCount-1]; mp >= &message[0]; mp--)
+                       if ((mp->m_flag & MDELETED) == f)
+                               return(mp - &message[0] + 1);
+               printf("No applicable messages\n");
+               return(-1);
+
+       case '.':
+               /* 
+                * Current message.
+                */
+               m = dot - &message[0] + 1;
+               if ((dot->m_flag & MDELETED) != f) {
+                       printf("%d: Inappropriate message\n", m);
+                       return(-1);
+               }
+               return(m);
+
+       default:
+               printf("Unknown metachar (%c)\n", c);
+               return(-1);
+       }
+}
diff --git a/src/Mail/local.h b/src/Mail/local.h
new file mode 100644 (file)
index 0000000..cdf4238
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright (c) 1979 Regents of the University of California */
+/*
+ * Declarations and constants specific to an installation.
+ * Version 7.
+ */
+#define        MAIL            "/bin/mail"     /* Name of mail sender */
+#define        EDITOR          "/usr/ucb/ex"   /* Name of text editor */
+#define        VISUAL          "/usr/ucb/vi"   /* Name of display editor */
+#define        HELPFILE        "/usr/lib/Mail.help"
+                                       /* Name of casual help file */
+#define        THELPFILE       "/usr/lib/Mail.help.~"
+                                       /* Name of casual tilde help */
+#define        UIDMASK         0177777         /* Significant uid bits */
+#define        MASTER          "/usr/lib/Mail.rc"
+#define        APPENDS                         /* New mail goes to end of mailbox */
+
+/*
+ * Machine dependent type declarations.
+ */
+
+typedef        short   flag_t;                 /* flag arguments everywhere */
diff --git a/src/Mail/lock.c b/src/Mail/lock.c
new file mode 100644 (file)
index 0000000..2d187f6
--- /dev/null
@@ -0,0 +1,79 @@
+/* Copyright (c) 1979 Regents of the University of California */
+char   maillock[]      = ".lock";              /* Lock suffix for mailname */
+char   locktmp[]       = "/usr/spool/mail/tmXXXXXX";
+char   curlock[50];                            /* Last used name of lock */
+static int             locked;                 /* To note that we locked it */
+
+/*
+ * Lock the specified mail file by setting the file mailfile.lock.
+ * We must, of course, be careful to remove the lock file by a call
+ * to unlock before we stop.  The algorithm used here is to see if
+ * the lock exists, and if it does, to check its modify time.  If it
+ * is older than 200 seconds, we assume error and set our own file.
+ * Otherwise, we wait for 5 seconds and try again.
+ */
+
+lock(file)
+char *file;
+{
+       register int f;
+       struct stat sbuf;
+       long curtime;
+
+       if (locked)
+               return(0);
+       strcpy(curlock, mailname);
+       strcat(curlock, maillock);
+       mktemp(locktmp);
+       unlink(locktmp);
+       for (;;) {
+               f = lock1(locktmp, curlock);
+               if (f == 0) {
+                       locked = 1;
+                       return(0);
+               }
+               stat(curlock, &sbuf);
+               time(&curtime);
+               if (curtime < sbuf.st_ctime + 200) {
+                       sleep(5);
+                       continue;
+               }
+               unlink(curlock);
+               cnt++;
+       }
+       return(-1);
+}
+
+/*
+ * Remove the mail lock, and note that we no longer
+ * have it locked.
+ */
+
+unlock()
+{
+
+       unlink(curlock);
+       locked = 0;
+}
+
+/*
+ * Attempt to set the lock by creating the temporary file,
+ * then doing a link/unlink.  If it fails, return -1 else 0
+ */
+
+lock1(tempfile, name)
+       char tempfile[], name[];
+{
+       register int fd;
+
+       fd = creat(tempfile, 0);
+       if (fd < 0)
+               return(-1);
+       if (link(tempfile, name) < 0) {
+               unlink(tempfile);
+               return(-1);
+       }
+       unlink(tempfile);
+       close(fd);
+       return(0);
+}
diff --git a/src/Mail/main.c b/src/Mail/main.c
new file mode 100644 (file)
index 0000000..864be5f
--- /dev/null
@@ -0,0 +1,111 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+
+#include "rcv.h"
+#include <sys/stat.h>
+
+/*
+ * Mail -- a mail program
+ *
+ * Startup -- interface with user.
+ */
+
+/*
+ * Find out who the user is, copy his mail file (if exists) into
+ * /tmp/Rxxxxx and set up the message pointers.  Then, print out the
+ * message headers and read user commands.
+ */
+
+main(argc, argv)
+       char **argv;
+{
+       register char *ef;
+       register int i;
+       FILE *ibuf;
+       extern char tempMesg[], _sobuf[];
+
+       argv[argc] = (char *) -1;
+       mypid = getpid();
+       intty = isatty(0);
+       outtty = isatty(1);
+       setbuf(stdout, _sobuf);
+       tinit();
+       ef = NOSTR;
+       for (i = 1; i < argc; i++) {
+               if (equal(argv[i], "-f")) {
+                       ef = argv[i+1];
+                       break;
+               }
+               if (equal(argv[i], "-n")) {
+                       demail();
+                       exit(0);
+               }
+       }
+       if (ef == NOSTR && argc > 1) {
+               commands();
+               i = 1;
+               if (equal(argv[1], "-i")) {
+                       assign("ignore", "");
+                       i++;
+               }
+               mail(&argv[i]);
+
+               /*
+                * why wait?
+                */
+
+               exit(0);
+       }
+       rcvmode++;
+       if (ef != NOSTR) {
+               edit++;
+               if (ef == (char *) -1)
+                       ef = mbox;
+               editfile = mailname = ef;
+               if ((ibuf = fopen(mailname, "r")) == NULL) {
+                       perror(mailname);
+                       exit(1);
+               }
+               if ((i = open(mailname, 1)) < 0)
+                       printf("Warning: \"%s\" not writable.\n", mailname);
+               else
+                       close(i);
+       }
+       else {
+               if ((ibuf = fopen(mailname, "r")) == NULL) {
+                       printf("No mail.\n");
+                       exit(0);
+               }
+       }
+
+       /*
+        * Copy the mudder into /tmp
+        * and set pointers.
+        * Announce the presence of this funny file.
+        */
+
+       mailsize = fsize(ibuf);
+       if ((otf = fopen(tempMesg, "w")) == NULL) {
+               perror(tempMesg);
+               exit(1);
+       }
+       if ((itf = fopen(tempMesg, "r")) == NULL) {
+               perror(tempMesg);
+               exit(1);
+       }
+       unlink(tempMesg);
+       setptr(ibuf);
+       fclose(ibuf);
+
+       /*
+        * print headings and accept user commands. */
+
+       if (msgCount == 0) {
+               printf("No messages.\n");
+               exit(1);
+       }
+       commands();
+       if (!edit)
+               quit();
+       exit(0);
+}
diff --git a/src/Mail/names.c b/src/Mail/names.c
new file mode 100644 (file)
index 0000000..3f6e7a5
--- /dev/null
@@ -0,0 +1,483 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+
+/*
+ * Mail -- a mail program
+ *
+ * Handle name lists.
+ */
+
+#include "rcv.h"
+
+/*
+ * Allocate a single element of a name list,
+ * initialize its name field to the passed
+ * name and return it.
+ */
+
+struct name *
+nalloc(str)
+       char str[];
+{
+       register struct name *np;
+
+       np = (struct name *) salloc(sizeof *np);
+       np->n_flink = NIL;
+       np->n_blink = NIL;
+       np->n_name = savestr(str);
+       return(np);
+}
+
+/*
+ * Find the tail of a list and return it.
+ */
+
+struct name *
+tailof(name)
+       struct name *name;
+{
+       register struct name *np;
+
+       np = name;
+       if (np == NIL)
+               return(NIL);
+       while (np->n_flink != NIL)
+               np = np->n_flink;
+       return(np);
+}
+
+/*
+ * Extract a list of names from a line,
+ * and make a list of names from it.
+ * Return the list or NIL if none found.
+ */
+
+struct name *
+extract(line)
+       char line[];
+{
+       register char *cp;
+       register struct name *top, *np, *t;
+       char nbuf[BUFSIZ];
+
+       if (line == NOSTR)
+               return(NIL);
+       top = NIL;
+       np = NIL;
+       cp = line;
+       while ((cp = yankword(cp, nbuf)) != NOSTR) {
+               t = nalloc(nbuf);
+               if (top == NIL)
+                       top = t;
+               else
+                       np->n_flink = t;
+               t->n_blink = np;
+               np = t;
+       }
+       return(top);
+}
+
+/*
+ * Grab a single word (liberal word)
+ * Throw away things between ()'s.
+ */
+
+char *
+yankword(ap, wbuf)
+       char *ap, wbuf[];
+{
+       register char *cp, *cp2;
+
+       do {
+               for (cp = ap; *cp && any(*cp, " \t"); cp++)
+                       ;
+               if (*cp == '(') {
+                       while (*cp && *cp != ')')
+                               cp++;
+                       if (*cp)
+                               cp++;
+               }
+               if (*cp == '\0')
+                       return(NOSTR);
+       } while (any(*cp, " \t("));
+       for (cp2 = wbuf; *cp && !any(*cp, " \t("); *cp2++ = *cp++)
+               ;
+       *cp2 = '\0';
+       return(cp);
+}
+
+/*
+ * Verify that all the users in the list of names are
+ * legitimate.  Bitch about and delink those who aren't.
+ */
+
+struct name *
+verify(names)
+       struct name *names;
+{
+       register struct name *np, *top, *t, *x;
+
+       top = names;
+       np = names;
+       while (np != NIL) {
+               if (any(':', np->n_name) || getuserid(np->n_name) != -1
+                   || strcmp(np->n_name, "msgs") == 0) {
+                       np = np->n_flink;
+                       continue;
+               }
+               fprintf(stderr, "Can't send to %s\n", np->n_name);
+               senderr++;
+               if (np == top) {
+                       top = np->n_flink;
+                       if (top != NIL)
+                               top->n_blink = NIL;
+                       np = top;
+                       continue;
+               }
+               x = np->n_blink;
+               t = np->n_flink;
+               x->n_flink = t;
+               if (t != NIL)
+                       t->n_blink = x;
+               np = t;
+       }
+       return(top);
+}
+
+/*
+ * For each recipient in the passed name list with a /
+ * in the name, append the message to the end of the named file
+ * and remove him from the recipient list.
+ */
+
+struct name *
+outof(names, fo, hp)
+       struct name *names;
+       FILE *fo;
+       struct header *hp;
+{
+       register int c;
+       register struct name *np, *top, *t, *x;
+       long now;
+       char *date, *ctime();
+       FILE *fout;
+
+       top = names;
+       np = names;
+       time(&now);
+       date = ctime(&now);
+       while (np != NIL) {
+               if (!any('/', np->n_name)) {
+                       np = np->n_flink;
+                       continue;
+               }
+               if ((fout = fopen(np->n_name, "a")) == NULL) {
+                       perror(np->n_name);
+                       senderr++;
+               }
+               else {
+                       rewind(fo);
+                       fprintf(fout, "From %s %s", myname, date);
+                       puthead(hp, fout);
+                       while ((c = getc(fo)) != EOF)
+                               putc(c, fout);
+                       fflush(fout);
+                       if (ferror(fout))
+                               perror(np->n_name);
+                       fclose(fout);
+               }
+               if (np == top) {
+                       top = np->n_flink;
+                       if (top != NIL)
+                               top->n_blink = NIL;
+                       np = top;
+                       continue;
+               }
+               x = np->n_blink;
+               t = np->n_flink;
+               x->n_flink = t;
+               if (t != NIL)
+                       t->n_blink = x;
+               np = t;
+       }
+       return(top);
+}
+
+/*
+ * Map all of the aliased users in the invoker's sendrc
+ * file and insert them into the list.
+ */
+
+struct name *
+usermap(names)
+       struct name *names;
+{
+       register struct name *new, *np, *cp;
+       struct grouphead *gh;
+       struct group *gp;
+       register int metoo;
+
+       new = NIL;
+       np = names;
+       metoo = (value("metoo") != NOSTR);
+       while (np != NIL) {
+               if (np->n_name[0] == '\\') {
+                       while (*np->n_name == '\\')
+                               (np->n_name)++;
+                       cp = np->n_flink;
+                       new = put(new, np);
+                       np = cp;
+                       continue;
+               }
+               if ((gh = findgroup(np->n_name)) != NOGRP) {
+                       for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) {
+                               if (!metoo && equal(gp->ge_name, myname))
+                                       continue;
+                               cp = nalloc(gp->ge_name);
+                               new = put(new, cp);
+                       }
+                       np = np->n_flink;
+                       continue;
+               }
+               else {
+                       cp = np->n_flink;
+                       new = put(new, np);
+                       np = cp;
+               }
+       }
+       return(new);
+}
+
+/*
+ * Compute the length of the passed name list and
+ * return it.
+ */
+
+lengthof(name)
+       struct name *name;
+{
+       register struct name *np;
+       register int c;
+
+       for (c = 0, np = name; np != NIL; c++, np = np->n_flink)
+               ;
+       return(c);
+}
+
+/*
+ * Concatenate the two passed name lists, return the result.
+ */
+
+struct name *
+cat(n1, n2)
+       struct name *n1, *n2;
+{
+       register struct name *tail;
+
+       if (n1 == NIL)
+               return(n2);
+       if (n2 == NIL)
+               return(n1);
+       tail = tailof(n1);
+       tail->n_flink = n2;
+       n2->n_blink = tail;
+       return(n1);
+}
+
+/*
+ * Unpack the name list onto a vector of strings.
+ * Return an error if the name list won't fit.
+ */
+
+char **
+unpack(np)
+       struct name *np;
+{
+       register char **ap, **top;
+       register struct name *n;
+       char *cp;
+       int t;
+
+       n = np;
+       if ((t = lengthof(n)) == 0)
+               panic("No names to unpack");
+       top = (char **) salloc((t+2) * sizeof cp);
+       ap = top;
+       *ap++ = "mail";
+       while (n != NIL) {
+               *ap++ = n->n_name;
+               n = n->n_flink;
+       }
+       *ap = NOSTR;
+       return(top);
+}
+
+/*
+ * See if the user named himself as a destination
+ * for outgoing mail.  If so, set the global flag
+ * selfsent so that we avoid removing his mailbox.
+ */
+
+mechk(names)
+       struct name *names;
+{
+       register struct name *np;
+       char myname[9];
+
+       if (getname(uid, myname) < 0)
+               return;
+       for (np = names; np != NIL; np = np->n_flink)
+               if (equal(myname, np->n_name)) {
+                       selfsent++;
+                       return;
+               }
+}
+
+/*
+ * Remove all of the duplicates from the passed name list by
+ * insertion sorting them, then checking for dups.
+ * Return the head of the new list.
+ */
+
+struct name *
+elide(names)
+       struct name *names;
+{
+       register struct name *np, *t, *new;
+       struct name *x;
+
+       new = names;
+       np = names;
+       np = np->n_flink;
+       if (np != NIL)
+               np->n_blink = NIL;
+       new->n_flink = NIL;
+       while (np != NIL) {
+               t = new;
+               while (strcmp(t->n_name, np->n_name) > 0) {
+                       if (t->n_flink == NIL)
+                               break;
+                       t = t->n_flink;
+               }
+
+               /*
+                * If we ran out of t's, put the new entry after
+                * the current value of t.
+                */
+
+               if (strcmp(t->n_name, np->n_name) > 0) {
+                       t->n_flink = np;
+                       np->n_blink = t;
+                       t = np;
+                       np = np->n_flink;
+                       t->n_flink = NIL;
+                       continue;
+               }
+
+               /*
+                * Otherwise, put the new entry in front of the
+                * current t.  If at the front of the list,
+                * the new guy becomes the new head of the list.
+                */
+
+               if (t == new) {
+                       t = np;
+                       np = np->n_flink;
+                       t->n_flink = new;
+                       new->n_blink = t;
+                       t->n_blink = NIL;
+                       new = t;
+                       continue;
+               }
+
+               /*
+                * The normal case -- we are inserting into the
+                * middle of the list.
+                */
+
+               x = np;
+               np = np->n_flink;
+               x->n_flink = t;
+               x->n_blink = t->n_blink;
+               t->n_blink->n_flink = x;
+               t->n_blink = x;
+       }
+
+       /*
+        * Now the list headed up by new is sorted.
+        * Go through it and remove duplicates.
+        */
+
+       np = new;
+       while (np != NIL) {
+               t = np;
+               while (t->n_flink!=NIL && equal(np->n_name,t->n_flink->n_name))
+                       t = t->n_flink;
+               if (t == np || t == NIL) {
+                       np = np->n_flink;
+                       continue;
+               }
+               
+               /*
+                * Now t points to the last entry with the same name
+                * as np.  Make np point beyond t.
+                */
+
+               np->n_flink = t->n_flink;
+               if (t->n_flink != NIL)
+                       t->n_flink->n_blink = np;
+               np = np->n_flink;
+       }
+       return(new);
+}
+
+/*
+ * Put another node onto a list of names and return
+ * the list.
+ */
+
+struct name *
+put(list, node)
+       struct name *list, *node;
+{
+       node->n_flink = list;
+       node->n_blink = NIL;
+       if (list != NIL)
+               list->n_blink = node;
+       return(node);
+}
+
+/*
+ * Determine the number of elements in
+ * a name list and return it.
+ */
+
+count(np)
+       register struct name *np;
+{
+       register int c = 0;
+
+       while (np != NIL) {
+               c++;
+               np = np->n_flink;
+       }
+       return(c);
+}
+
+/*
+ * Pretty print a name list
+ * Uncomment it if you need it.
+ *
+ * prettyprint(name)
+ *     struct name *name;
+ * {
+ *     register struct name *np;
+ * 
+ *     np = name;
+ *     while (np != NIL) {
+ *             fprintf(stderr, "%s ", np->n_name);
+ *             np = np->n_flink;
+ *     }
+ *     fprintf(stderr, "\n");
+ * }
+ */
diff --git a/src/Mail/quit.c b/src/Mail/quit.c
new file mode 100644 (file)
index 0000000..c5b4f7c
--- /dev/null
@@ -0,0 +1,281 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+
+#include "rcv.h"
+#include <sys/stat.h>
+
+/*
+ * Rcv -- receive mail rationally.
+ *
+ * Termination processing.
+ */
+
+/*
+ * Save all of the undetermined messages at the top of "mbox"
+ * Save all untouched messages back in the system mailbox.
+ * Remove the system mailbox, if none saved there.
+ */
+
+quit()
+{
+       int mcount, p, modify;
+       FILE *ibuf, *obuf, *fbuf, *rbuf;
+       register struct message *mp;
+       register int c;
+       extern char tempQuit[], tempResid[];
+       struct stat minfo;
+
+       /*
+        * See if there any messages to save in mbox.  If no, we
+        * can save copying mbox to /tmp and back.
+        *
+        * Check also to see if any files need to be preserved.
+        * Delete all untouched messages to keep them out of mbox.
+        * If all the messages are to be preserved, just exit with
+        * a message.
+        *
+        * If the luser has sent mail to himself, refuse to do
+        * anything with the mailbox.
+        */
+
+       if (selfsent) {
+newmail:
+               printf("You have new mail.\n");
+               unlock();
+               return;
+       }
+       rbuf = NULL;
+       lock(mailname);
+       if (stat(mailname, &minfo) >= 0 && minfo.st_size > mailsize) {
+               printf("New mail has arrived.\n");
+               rbuf = fopen(tempResid, "w");
+               fbuf = fopen(mailname, "r");
+               if (rbuf == NULL || fbuf == NULL)
+                       goto newmail;
+#ifdef APPENDS
+               fseek(fbuf, mailsize, 0);
+               while ((c = getc(fbuf)) != EOF)
+                       putc(c, rbuf);
+#else
+               p = minfo.st_size - mailsize;
+               while (p-- > 0) {
+                       c = getc(fbuf);
+                       if (c == EOF)
+                               goto newmail;
+                       putc(c, rbuf);
+               }
+#endif
+               fclose(fbuf);
+               fclose(rbuf);
+               if ((rbuf = fopen(tempResid, "r")) == NULL)
+                       goto newmail;
+               unlink(tempResid);
+       }
+       for (mp = &message[0]; mp < &message[msgCount]; mp++) {
+               if (mp->m_flag & MDELETED)
+                       mp->m_flag = MDELETED|MTOUCH;
+               if ((mp->m_flag & MTOUCH) == 0)
+                       mp->m_flag |= MDELETED;
+       }
+       modify = 0;
+       for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
+               if ((mp->m_flag & (MSAVED|MDELETED|MPRESERVE)) == 0)
+                       c++;
+               if ((mp->m_flag & MPRESERVE) || (mp->m_flag & MTOUCH) == 0)
+                       p++;
+               if (mp->m_flag & MODIFY)
+                       modify++;
+       }
+       if (p == msgCount && !modify && rbuf == NULL) {
+               if (p == 1)
+                       printf("Held 1 message in %s\n", mailname);
+               else
+                       printf("Held %2d messages in %s\n", p, mailname);
+               unlock();
+               return;
+       }
+       if (c == 0) {
+               if (p != 0) {
+                       writeback(rbuf);
+                       unlock();
+                       return;
+               }
+               goto remove;
+       }
+
+       /*
+        * Create another temporary file and copy user's mbox file
+        * darin.  If there is no mbox, copy nothing.
+        * If he has specified "append" don't copy his mailbox,
+        * just copy saveable entries at the end.
+        */
+
+       mcount = c;
+       if (value("append") == NOSTR) {
+               if ((obuf = fopen(tempQuit, "w")) == NULL) {
+                       perror(tempQuit);
+                       unlock();
+                       return;
+               }
+               if ((ibuf = fopen(tempQuit, "r")) == NULL) {
+                       perror(tempQuit);
+                       unlink(tempQuit);
+                       fclose(obuf);
+                       unlock();
+                       return;
+               }
+               unlink(tempQuit);
+               if ((fbuf = fopen(mbox, "r")) != NULL) {
+                       while ((c = getc(fbuf)) != EOF)
+                               putc(c, obuf);
+                       fclose(fbuf);
+               }
+               if (ferror(obuf)) {
+                       perror(tempQuit);
+                       fclose(ibuf);
+                       fclose(obuf);
+                       unlock();
+                       return;
+               }
+               fclose(obuf);
+               close(creat(mbox, 0600));
+               if ((obuf = fopen(mbox, "w")) == NULL) {
+                       perror(mbox);
+                       fclose(ibuf);
+                       unlock();
+                       return;
+               }
+       }
+       if (value("append") != NOSTR)
+               if ((obuf = fopen(mbox, "a")) == NULL) {
+                       perror(mbox);
+                       unlock();
+                       return;
+               }
+       for (mp = &message[0]; mp < &message[msgCount]; mp++)
+               if ((mp->m_flag & (MDELETED|MSAVED|MPRESERVE)) == 0)
+                       if (send(mp, obuf) < 0) {
+                               perror(mbox);
+                               fclose(ibuf);
+                               fclose(obuf);
+                               unlock();
+                               return;
+                       }
+
+       /*
+        * Copy the user's old mbox contents back
+        * to the end of the stuff we just saved.
+        * If we are appending, this is unnecessary.
+        */
+
+       if (value("append") == NOSTR) {
+               rewind(ibuf);
+               c = getc(ibuf);
+               while (c != EOF) {
+                       putc(c, obuf);
+                       if (ferror(obuf))
+                               break;
+                       c = getc(ibuf);
+               }
+               fclose(ibuf);
+               fflush(obuf);
+       }
+       if (ferror(obuf)) {
+               perror(mbox);
+               fclose(obuf);
+               unlock();
+               return;
+       }
+       fclose(obuf);
+       if (mcount == 1)
+               printf("Saved 1 message in mbox\n");
+       else
+               printf("Saved %d messages in mbox\n", mcount);
+
+       /*
+        * Now we are ready to copy back preserved files to
+        * the system mailbox, if any were requested.
+        */
+
+       if (p != 0) {
+               writeback(rbuf);
+               unlock();
+               return;
+       }
+
+       /*
+        * Finally, remove his /usr/mail file.
+        * If new mail has arrived, copy it back.
+        */
+
+remove:
+       if (rbuf != NULL) {
+               fbuf = fopen(mailname, "w");
+               if (fbuf == NULL)
+                       goto newmail;
+               while ((c = getc(rbuf)) != EOF)
+                       putc(c, fbuf);
+               fclose(rbuf);
+               fclose(fbuf);
+               alter(mailname);
+               unlock();
+               return;
+       }
+       demail();
+       unlock();
+}
+
+/*
+ * Preserve all the appropriate messages back in the system
+ * mailbox, and print a nice message indicated how many were
+ * saved.  On any error, just return -1.  Else return 0.
+ * Incorporate the any new mail that we found.
+ */
+
+writeback(res)
+       register FILE *res;
+{
+       register struct message *mp;
+       register int p, c;
+       FILE *obuf;
+
+       p = 0;
+       if ((obuf = fopen(mailname, "w")) == NULL) {
+               perror(mailname);
+               return(-1);
+       }
+#ifndef APPEND
+       if (res != NULL)
+               while ((c = getc(res)) != EOF)
+                       putc(c, obuf);
+#endif
+       for (mp = &message[0]; mp < &message[msgCount]; mp++)
+               if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
+                       p++;
+                       if (send(mp, obuf) < 0) {
+                               perror(mailname);
+                               fclose(obuf);
+                               return(-1);
+                       }
+               }
+#ifdef APPEND
+       if (res != NULL)
+               while ((c = getc(res)) != EOF)
+                       putc(c, obuf);
+#endif
+       fflush(obuf);
+       if (ferror(obuf)) {
+               perror(mailname);
+               fclose(obuf);
+               return(-1);
+       }
+       if (res != NULL)
+               fclose(res);
+       fclose(obuf);
+       alter(mailname);
+       if (p == 1)
+               printf("Held 1 message in %s\n", mailname);
+       else
+               printf("Held %d messages in %s\n", p, mailname);
+       return(0);
+}
diff --git a/src/Mail/rcv.h b/src/Mail/rcv.h
new file mode 100644 (file)
index 0000000..82cd8ce
--- /dev/null
@@ -0,0 +1,12 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+
+/*
+ * Mail -- a mail program
+ *
+ * This file is included by normal files which want both
+ * globals and declarations.
+ */
+
+#include "def.h"
+#include "glob.h"
diff --git a/src/Mail/send.c b/src/Mail/send.c
new file mode 100644 (file)
index 0000000..2831db5
--- /dev/null
@@ -0,0 +1,302 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+
+#include "rcv.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Mail to others.
+ */
+
+/*
+ * Send message described by the passed pointer to the
+ * passed output buffer.  Return -1 on error, but normally
+ * the number of lines written.
+ */
+
+send(mailp, obuf)
+       struct message *mailp;
+       FILE *obuf;
+{
+       register struct message *mp;
+       register int t;
+       unsigned int c;
+       FILE *ibuf;
+       int lc;
+
+       mp = mailp;
+       ibuf = setinput(mp);
+       c = msize(mp);
+       lc = 0;
+       while (c-- > 0) {
+               putc(t = getc(ibuf), obuf);
+               if (t == '\n')
+                       lc++;
+               if (ferror(obuf))
+                       return(-1);
+       }
+       return(lc);
+}
+
+/*
+ * Interface between the argument list and the mail1 routine
+ * which does all the dirty work.
+ */
+
+mail(people)
+       char **people;
+{
+       register char *cp2;
+       register int s;
+       char *buf, **ap;
+       struct header head;
+
+       for (s = 0, ap = people; *ap != (char *) -1; ap++)
+               s += strlen(*ap) + 1;
+       buf = salloc(s+1);
+       cp2 = buf;
+       for (ap = people; *ap != (char *) -1; ap++) {
+               cp2 = copy(*ap, cp2);
+               *cp2++ = ' ';
+       }
+       if (cp2 != buf)
+               cp2--;
+       *cp2 = '\0';
+       head.h_to = buf;
+       head.h_subj = NOSTR;
+       head.h_cc = NOSTR;
+       head.h_seq = 0;
+       mail1(&head);
+       return(0);
+}
+
+
+/*
+ * Send mail to a bunch of user names.  The interface is through
+ * the mail routine below.
+ */
+
+sendmail(str)
+       char *str;
+{
+       register char **ap;
+       char *bufp;
+       register int t;
+       struct header head;
+
+       if (blankline(str))
+               head.h_to = NOSTR;
+       else
+               head.h_to = str;
+       head.h_subj = NOSTR;
+       head.h_cc = NOSTR;
+       head.h_seq = 0;
+       mail1(&head);
+       return(0);
+}
+
+/*
+ * Mail a message on standard input to the people indicated
+ * in the passed header.  (Internal interface).
+ */
+
+mail1(hp)
+       struct header *hp;
+{
+       register char *cp;
+       int pid, i, s;
+       char **namelist;
+       struct name *to;
+       FILE *mtf;
+
+       /*
+        * Collect user's mail from standard input.
+        * Get the result as mtf.
+        */
+
+       pid = -1;
+       if (hp->h_subj == NOSTR)
+               hp->h_seq = 0;
+       else
+               hp->h_seq = 1;
+       if ((mtf = collect(hp)) == NULL)
+               return(-1);
+       if (fsize(mtf) == 0 && hp->h_subj == NOSTR) {
+               printf("No message !?!\n");
+               goto out;
+       }
+       if (intty && value("askcc") != NOSTR)
+               grabh(hp, GCC);
+       else if (intty) {
+               printf("EOT\n");
+               flush();
+       }
+
+       /*
+        * Now, take the user names from the combined
+        * to and cc lists and do all the alias
+        * processing.
+        */
+
+       senderr = 0;
+       to = usermap(cat(extract(hp->h_to), extract(hp->h_cc)));
+       if (to == NIL) {
+               printf("No recipients specified\n");
+               goto topdog;
+       }
+
+       /*
+        * Look through the recipient list for names with /'s
+        * in them which we write to as files directly.
+        */
+
+       to = outof(to, mtf, hp);
+       to = verify(to);
+       if (senderr) {
+topdog:
+               unlink(deadletter);
+               exwrite(deadletter, mtf, 1);
+       }
+       if (to == NIL)
+               goto out;
+       to = elide(to);
+       mechk(to);
+       if (count(to) > 1)
+               hp->h_seq++;
+       if (hp->h_seq > 0)
+               if ((mtf = infix(hp, mtf)) == NULL) {
+                       fprintf(stderr, ". . . message lost, sorry.\n");
+                       return(-1);
+               }
+       namelist = unpack(to);
+       if (value("record") != NOSTR)
+               savemail(value("record"), hp, mtf, namelist);
+
+       /*
+        * Wait, to absorb a potential zombie, then
+        * fork, set up the temporary mail file as standard
+        * input for "mail" and exec with the user list we generated
+        * far above. Return the process id to caller in case he
+        * wants to await the completion of mail.
+        */
+
+       wait(&s);
+       rewind(mtf);
+       pid = fork();
+       if (pid == -1) {
+               perror("fork");
+               goto out;
+       }
+       if (pid == 0) {
+               for (i = 1; i  < 17; i++)
+                       signal(i, SIG_IGN);
+               s = fileno(mtf);
+               for (i = 3; i < 15; i++)
+                       if (i != s)
+                               close(i);
+               close(0);
+               dup(s);
+               close(s);
+               execv(MAIL, namelist);
+               perror(MAIL);
+               exit(1);
+       }
+
+out:
+       fclose(mtf);
+       return(pid);
+}
+
+/*
+ * Prepend a header in front of the collected stuff
+ * and return the new file.
+ */
+
+FILE *
+infix(hp, fi)
+       struct header *hp;
+       FILE *fi;
+{
+       extern char tempMail[];
+       register FILE *nfo, *nfi;
+       register int c;
+
+       if ((nfo = fopen(tempMail, "w")) == NULL) {
+               perror(tempMail);
+               return(fi);
+       }
+       if ((nfi = fopen(tempMail, "r")) == NULL) {
+               perror(tempMail);
+               fclose(nfo);
+               return(fi);
+       }
+       unlink(tempMail);
+       puthead(hp, nfo);
+       c = getc(fi);
+       while (c != EOF) {
+               putc(c, nfo);
+               c = getc(fi);
+       }
+       fflush(nfo);
+       if (ferror(nfo)) {
+               perror(tempMail);
+               fclose(nfo);
+               fclose(nfi);
+               return(fi);
+       }
+       fclose(nfo);
+       fclose(fi);
+       rewind(nfi);
+       return(nfi);
+}
+
+/*
+ * Dump the to, subj, cc header on the
+ * passed file buffer.
+ */
+
+puthead(hp, fo)
+       struct header *hp;
+       FILE *fo;
+{
+       if (hp->h_to != NOSTR)
+               fprintf(fo, "To: %s\n", hp->h_to);
+       if (hp->h_subj != NOSTR)
+               fprintf(fo, "Subj: %s\n", hp->h_subj);
+       if (hp->h_cc != NOSTR)
+               fprintf(fo, "Cc: %s\n", hp->h_cc);
+       if (hp->h_to != NOSTR || hp->h_subj != NOSTR || hp->h_cc != NOSTR)
+               putc('\n', fo);
+       return(0);
+}
+
+/*
+ * Save the outgoing mail on the passed file.
+ */
+
+savemail(name, hp, fi, tolist)
+       char name[], **tolist;
+       struct header *hp;
+       FILE *fi;
+{
+       register FILE *fo;
+       register int c;
+       long now;
+
+       if ((fo = fopen(name, "a")) == NULL) {
+               perror(name);
+               return(-1);
+       }
+       time(&now);
+       fprintf(fo, "From %s %s", *(tolist+1), ctime(&now));
+       rewind(fi);
+       for (c = getc(fi); c != EOF; c = getc(fi))
+               putc(c, fo);
+       fprintf(fo, "\n");
+       fflush(fo);
+       if (ferror(fo))
+               perror(name);
+       fclose(fo);
+       return(0);
+}
diff --git a/src/Mail/strings.c b/src/Mail/strings.c
new file mode 100644 (file)
index 0000000..531678e
--- /dev/null
@@ -0,0 +1,75 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+
+/*
+ * Mail -- a mail program
+ *
+ * String allocation routines.
+ * Strings handed out here are reclaimed at the top of the command
+ * loop each time, so they need not be freed.
+ */
+
+#include "rcv.h"
+
+/*
+ * Allocate size more bytes of space and return the address of the
+ * first byte to the caller.  An even number of bytes are always
+ * allocated so that the space will always be on a word boundary.
+ * The string spaces are of exponentially increasing size, to satisfy
+ * the occasional user with enormous string size requests.
+ */
+
+char *
+salloc(size)
+{
+       register char *t;
+       register int s;
+       register struct strings *sp;
+       int index;
+
+       s = size;
+       s++;
+       s &= ~01;
+       index = 0;
+       for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++) {
+               if (sp->s_topFree == NOSTR && (STRINGSIZE << index) >= s)
+                       break;
+               if (sp->s_nleft >= s)
+                       break;
+               index++;
+       }
+       if (sp >= &stringdope[NSPACE])
+               panic("Ran out of memory!");
+       if (sp->s_topFree == NOSTR) {
+               index = sp - &stringdope[0];
+               sp->s_topFree = (char *) calloc(STRINGSIZE << index,
+                   (unsigned) 1);
+               sp->s_nextFree = sp->s_topFree;
+               sp->s_nleft = STRINGSIZE << index;
+       }
+       sp->s_nleft -= s;
+       t = sp->s_nextFree;
+       sp->s_nextFree += s;
+       return(t);
+}
+
+/*
+ * Reset the string area to be empty.
+ * Called to free all strings allocated
+ * since last reset.
+ */
+
+sreset()
+{
+       register struct strings *sp;
+       register int index;
+
+       index = 0;
+       for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++) {
+               if (sp->s_topFree == NOSTR)
+                       continue;
+               sp->s_nextFree = sp->s_topFree;
+               sp->s_nleft = STRINGSIZE << index;
+               index++;
+       }
+}
diff --git a/src/Mail/temp.c b/src/Mail/temp.c
new file mode 100644 (file)
index 0000000..e271d51
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+
+#include "rcv.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Give names to all the temporary files that we will need.
+ */
+
+char   tempMail[14];
+char   tempQuit[14];
+char   tempEdit[14];
+char   tempSet[14];
+char   tempResid[14];
+char   tempMesg[14];
+
+tinit()
+{
+       register char *cp, *cp2;
+       char uname[9];
+
+       copy("/tmp/RsXXXXX", tempMail);
+       copy("/tmp/RqXXXXX", tempResid);
+       copy("/tmp/RmXXXXX", tempQuit);
+       copy("/tmp/ReXXXXX", tempEdit);
+       copy("/tmp/RxXXXXX", tempSet);
+       copy("/tmp/RxXXXXX", tempMesg);
+       mktemp(tempMail);
+       mktemp(tempResid);
+       mktemp(tempQuit);
+       mktemp(tempEdit);
+       mktemp(tempSet);
+       mktemp(tempMesg);
+
+       uid = getuid() & UIDMASK;
+       if (getname(uid, uname) < 0) {
+               printf("Who are you!?\n");
+               exit(1);
+       }
+       copy(uname, myname);
+       mailname = mailspace;
+       cp = value("HOME");
+       if (cp == NOSTR)
+               cp = ".";
+       copy(cp, homedir);
+       findmail();
+       cp = copy(homedir, mbox);
+       copy("/mbox", cp);
+       cp = copy(homedir, mailrc);
+       copy("/.mailrc", cp);
+       cp = copy(homedir, deadletter);
+       copy("/dead.letter", cp);
+}
diff --git a/src/Mail/tty.c b/src/Mail/tty.c
new file mode 100644 (file)
index 0000000..6ab1096
--- /dev/null
@@ -0,0 +1,126 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+
+/*
+ * Mail -- a mail program
+ *
+ * Generally useful tty stuff.
+ */
+
+#include "rcv.h"
+#include <sgtty.h>
+
+static int     c_erase;                /* Current erase char */
+static int     c_kill;                 /* Current kill char */
+
+/*
+ * Read all relevant header fields.
+ */
+
+grabh(hp, gflags)
+       struct header *hp;
+{
+       struct sgttyb ttybuf;
+       register int s;
+       int (*savesigs[2])(), errs, set;
+
+       errs = 0;
+       set = 0;
+       if (gtty(fileno(stdin), &ttybuf) < 0) {
+               perror("gtty");
+               return(-1);
+       }
+       c_erase = ttybuf.sg_erase;
+       c_kill = ttybuf.sg_kill;
+       ttybuf.sg_erase = 0;
+       ttybuf.sg_kill = 0;
+       for (s = SIGINT; s <= SIGQUIT; s++)
+               if ((savesigs[s-SIGINT] = signal(s, SIG_IGN)) == SIG_DFL)
+                       signal(s, SIG_DFL);
+       if (gflags & GTO) {
+               if (!set && hp->h_to != NOSTR)
+                       set++, stty(fileno(stdin), &ttybuf);
+               hp->h_to = readtty("To: ", hp->h_to);
+               if (hp->h_to != NOSTR)
+                       hp->h_seq++;
+       }
+       if (gflags & GSUBJ) {
+               if (!set && hp->h_subj != NOSTR)
+                       set++, stty(fileno(stdin), &ttybuf);
+               hp->h_subj = readtty("Subj: ", hp->h_subj);
+               if (hp->h_subj != NOSTR)
+                       hp->h_seq++;
+       }
+       if (gflags & GCC) {
+               if (!set && hp->h_cc != NOSTR)
+                       set++, stty(fileno(stdin), &ttybuf);
+               hp->h_cc = readtty("Cc: ", hp->h_cc);
+               if (hp->h_cc != NOSTR)
+                       hp->h_seq++;
+       }
+       ttybuf.sg_erase = c_erase;
+       ttybuf.sg_kill = c_kill;
+       if (set)
+               stty(fileno(stdin), &ttybuf);
+
+out:
+       for (s = SIGINT; s <= SIGQUIT; s++)
+               signal(s, savesigs[s-SIGINT]);
+       return(errs);
+}
+
+/*
+ * Read up a header from standard input.
+ * The source string has the preliminary contents to
+ * be read.
+ *
+ */
+
+char *
+readtty(pr, src)
+       char pr[], src[];
+{
+       char canonb[BUFSIZ];
+       register int c;
+       register char *cp, *cp2;
+
+       fputs(pr, stdout);
+       if (src != NOSTR)
+               cp = copy(src, canonb);
+       else
+               cp = copy("", canonb);
+       fputs(canonb, stdout);
+       fflush(stdout);
+       if ((cp2 = gets(cp)) == NOSTR || *cp2 == '\0')
+               return(src);
+       cp = canonb;
+       cp2 = cp;
+       while (*cp != '\0') {
+               c = *cp++;
+               if (c == c_erase) {
+                       if (cp2 == canonb)
+                               continue;
+                       if (cp2[-1] == '\\') {
+                               cp2[-1] = c;
+                               continue;
+                       }
+                       cp2--;
+                       continue;
+               }
+               if (c == c_kill) {
+                       if (cp2 == canonb)
+                               continue;
+                       if (cp2[-1] == '\\') {
+                               cp2[-1] = c;
+                               continue;
+                       }
+                       cp2 = canonb;
+                       continue;
+               }
+               *cp2++ = c;
+       }
+       *cp2 = '\0';
+       if (equal("", canonb))
+               return(NOSTR);
+       return(savestr(canonb));
+}
diff --git a/src/Mail/v6.local.c b/src/Mail/v6.local.c
new file mode 100644 (file)
index 0000000..68399d9
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+
+/*
+ * Mail -- a mail program
+ *
+ * Unix version 6.0
+ */
+
+#include "rcv.h"
+
+/*
+ * Locate the user's mailbox file (ie, the place where new, unread
+ * mail is queued).  In Version 6, it is in ~/.mail
+ */
+
+findmail()
+{
+       register char *cp;
+
+       cp = copy(homedir, mailname);
+       copy("/.mail", cp);
+}
+
+/*
+ * Get rid of the queued mail.
+ */
+
+demail()
+{
+       close(creat(mailname, 0666));
+       alter(mailname);
+}
+
+/*
+ * Get an environment variable.  At present, we only support
+ * "SHELL" and "HOME".  This routine makes use of the getpw
+ * routine in the neighboring getname.c stuff.
+ */
+
+char *
+getenv(name)
+       char name[];
+{
+       char pwline[LINESIZE];
+       static char val[30];
+       register char *cp, *dp;
+       register int cc;
+
+       if (equal(name, "SHELL"))
+               cc = 6;
+       else if (equal(name, "HOME"))
+               cc = 5;
+       else
+               return(NOSTR);
+       if (getpw(uid, pwline) < 0)
+               return(NOSTR);
+       for (cp = pwline; *cp && cc > 0;)
+               if (*cp++ == ':')
+                       cc--;
+       dp = cp;
+       while (*cp != ':' && *cp != '\0')
+               cp++;
+       *cp = '\0';
+       if (*dp == '\0')
+               return(NOSTR);
+       copy(dp, val);
+       return(val);
+}
+
+/*
+ * Lock and unlock retrofits which are only
+ * significant in version 7.
+ */
+
+lock(name)
+       char *name;
+{
+
+       return(0);
+}
+
+unlock()
+{
+
+       return(0);
+}
diff --git a/src/Mail/v7.local.c b/src/Mail/v7.local.c
new file mode 100644 (file)
index 0000000..6aed607
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+
+/*
+ * Mail -- a mail program
+ *
+ * Version 7
+ *
+ * Local routines that are installation dependent.
+ * All fiddlers please note:  if you make careful note of
+ * what you change here, I will incorporate your changes and
+ * you won't have to remake them each release.
+ */
+
+#include "rcv.h"
+
+/*
+ * Locate the user's mailbox file (ie, the place where new, unread
+ * mail is queued).  In Version 7, it is in /usr/spool/mail/name.
+ */
+
+findmail()
+{
+       register char *cp;
+
+       cp = copy("/usr/spool/mail/", mailname);
+       copy(myname, cp);
+}
+
+/*
+ * Get rid of the queued mail.
+ */
+
+demail()
+{
+       unlink(mailname);
+}
+
+/*
+ * A stub for the mailfile locking stuff.
+ */
+
+lock(name)
+       char name[];
+{
+
+       return(0);
+}
+
+unlock()
+{
+
+       return(0);
+}
diff --git a/src/Mail/vars.c b/src/Mail/vars.c
new file mode 100644 (file)
index 0000000..9f91c36
--- /dev/null
@@ -0,0 +1,157 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+
+#include "rcv.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Variable handling stuff.
+ */
+
+/*
+ * Assign a value to a variable.
+ */
+
+assign(name, value)
+       char name[], value[];
+{
+       register struct var *vp;
+       register int h;
+
+       h = hash(name);
+       vp = lookup(name);
+       if (vp == NOVAR) {
+               vp = (struct var *) calloc(sizeof *vp, 1);
+               vp->v_name = vcopy(name);
+               vp->v_link = variables[h];
+               variables[h] = vp;
+       }
+       else
+               vfree(vp->v_value);
+       vp->v_value = vcopy(value);
+}
+
+/*
+ * Free up a variable string.  We do not bother to allocate
+ * strings whose value is "" since they are expected to be frequent.
+ * Thus, we cannot free same!
+ */
+
+vfree(cp)
+       register char *cp;
+{
+       if (!equal(cp, ""))
+               cfree(cp);
+}
+
+/*
+ * Copy a variable value into permanent (ie, not collected after each
+ * command) space.  Do not bother to alloc space for ""
+ */
+
+char *
+vcopy(str)
+       char str[];
+{
+       register char *top, *cp, *cp2;
+
+       if (equal(str, ""))
+               return("");
+       top = calloc(strlen(str)+1, 1);
+       cp = top;
+       cp2 = str;
+       while (*cp++ = *cp2++)
+               ;
+       return(top);
+}
+
+/*
+ * Get the value of a variable and return it.
+ * Look in the environment if its not available locally.
+ */
+
+char *
+value(name)
+       char name[];
+{
+       register struct var *vp;
+
+       if ((vp = lookup(name)) == NOVAR)
+               return(getenv(name));
+       return(vp->v_value);
+}
+
+/*
+ * Locate a variable and return its variable
+ * node.
+ */
+
+struct var *
+lookup(name)
+       char name[];
+{
+       register struct var *vp;
+       register int h;
+
+       h = hash(name);
+       for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
+               if (equal(vp->v_name, name))
+                       return(vp);
+       return(NOVAR);
+}
+
+/*
+ * Locate a group name and return it.
+ */
+
+struct grouphead *
+findgroup(name)
+       char name[];
+{
+       register struct grouphead *gh;
+       register int h;
+
+       h = hash(name);
+       for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
+               if (equal(gh->g_name, name))
+                       return(gh);
+       return(NOGRP);
+}
+
+/*
+ * Print a group out on stdout
+ */
+
+printgroup(name)
+       char name[];
+{
+       register struct grouphead *gh;
+       register struct group *gp;
+
+       if ((gh = findgroup(name)) == NOGRP) {
+               printf("\"%s\": not a group\n", name);
+               return;
+       }
+       printf("%s\t", gh->g_name);
+       for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link)
+               printf(" %s", gp->ge_name);
+       printf("\n");
+}
+
+/*
+ * Hash the passed string and return an index into
+ * the variable or group hash table.
+ */
+
+hash(name)
+       char name[];
+{
+       register int h;
+       register char *cp;
+
+       for (cp = name, h = 0; *cp; h = (h << 2) + *cp++)
+               ;
+       h &= ~0100000;
+       return(h % HSHSIZE);
+}
diff --git a/src/Mail/version.c b/src/Mail/version.c
new file mode 100644 (file)
index 0000000..02e4ac5
--- /dev/null
@@ -0,0 +1,2 @@
+/* Copyright (c) 1979 Regents of the University of California */
+char   *version = "April 2, 1979";