BSD 4 development
authorBill Joy <wnj@ucbvax.Berkeley.EDU>
Fri, 31 Oct 1980 14:39:59 +0000 (06:39 -0800)
committerBill Joy <wnj@ucbvax.Berkeley.EDU>
Fri, 31 Oct 1980 14:39:59 +0000 (06:39 -0800)
Work on file usr/src/cmd/delivermail/TO_BE_DONE
Work on file usr/src/cmd/delivermail/alias.c.save
Work on file usr/src/cmd/delivermail/aliases.5
Work on file usr/src/cmd/delivermail/arpa-mailer.8
Work on file usr/src/cmd/delivermail/delivermail.8
Work on file usr/src/cmd/delivermail/mail-dm.c
Work on file usr/src/cmd/delivermail/userinfo.5
Work on file usr/src/cmd/delivermail/v6-mail.c

Synthesized-from: CSRG//cd1/4.0

usr/src/cmd/delivermail/TO_BE_DONE [new file with mode: 0644]
usr/src/cmd/delivermail/alias.c.save [new file with mode: 0644]
usr/src/cmd/delivermail/aliases.5 [new file with mode: 0644]
usr/src/cmd/delivermail/arpa-mailer.8 [new file with mode: 0644]
usr/src/cmd/delivermail/delivermail.8 [new file with mode: 0644]
usr/src/cmd/delivermail/mail-dm.c [new file with mode: 0644]
usr/src/cmd/delivermail/userinfo.5 [new file with mode: 0644]
usr/src/cmd/delivermail/v6-mail.c [new file with mode: 0644]

diff --git a/usr/src/cmd/delivermail/TO_BE_DONE b/usr/src/cmd/delivermail/TO_BE_DONE
new file mode 100644 (file)
index 0000000..aa04f22
--- /dev/null
@@ -0,0 +1,22 @@
+     ** (Someday) collect all names that are local in advance, and send
+       them all off to /bin/mail at once -- fork before sending so
+       that we can return status quickly.
+
+    *** Handle :Include: specifications.
+
+      * (Somehow) have "From" person modified so that if an alias exists
+       for the person, it will appear post-aliased rather than pre-aliased,
+       especially (perhaps only?) in ARPANET mail.  For example, if there
+       exists an alias "fabry->cory:fabry", then if mail comes in from
+       "cory:fabry", make it appear as though it were from "fabry".
+
+      * Do aliasing on mail being returned also (?).
+
+   **** Allow "<user>" "at" "<host>" as three separate parameters.
+
+    *** Put host aliasing into the users file, e.g.,
+       vax135!:research!vax135!
+
+  ***** Change sendto & aliasdbm to know about quoted commas.
+       Currently, quoted commas delimit aliases when they should be
+       ignored.
diff --git a/usr/src/cmd/delivermail/alias.c.save b/usr/src/cmd/delivermail/alias.c.save
new file mode 100644 (file)
index 0000000..b9d6cda
--- /dev/null
@@ -0,0 +1,279 @@
+# include <stdio.h>
+# include <ctype.h>
+# include <pwd.h>
+# include "delivermail.h"
+
+/*
+**  ALIAS -- Compute aliases.
+**
+**     Scans the file /usr/lib/mailaliases for a set of aliases.
+**     If found, it arranges to deliver to them by inserting the
+**     new names onto the SendQ queue.
+**
+**     Parameters:
+**             none
+**
+**     Returns:
+**             none
+**
+**     Side Effects:
+**             Aliases found on SendQ are removed and put onto
+**             AliasQ; replacements are added to SendQ.  This is
+**             done until no such replacement occurs.
+**
+**     Defined Constants:
+**             MAXRCRSN -- the maximum recursion depth.
+**             ALIASFILE -- the pathname of the alias file.
+**
+**     Requires:
+**             fopen (stdio)
+**             fgets (stdio)
+**             rewind (stdio)
+**             isspace (sys)
+**             printf (sys)
+**             deliver
+**
+**     Called By:
+**             deliver
+**
+**     Files:
+**             /usr/lib/mailaliases -- the mail aliases.
+**
+**     Notes:
+**             If NoAlias (the "-n" flag) is set, no aliasing is
+**                     done.
+**
+**     Deficiencies:
+**             It should complain about names that are aliased to
+**                     nothing.
+**             It is unsophisticated about line overflows.
+**             It should probably take either the ARPANET sndmsg
+**                     format for aliases, or read Mail files and
+**                     pick out 'alias' commands.
+**
+**     History:
+**             12/27/79 -- written.
+*/
+
+
+# define ALIASFILE     "/usr/lib/mailaliases"
+# define MAXRCRSN      10
+
+
+alias()
+{
+       register addrq *q;
+       FILE *af;
+       char line[MAXLINE+1];
+       register char *p;
+       register char *u;
+       extern int errno;
+       int didalias;
+       int gotmatch;
+
+       if (NoAlias)
+               return (0);
+       if (Debug)
+               printf("--- alias ---\n");
+
+       /* open alias file if not already open */
+       if (Debug && (af = fopen("mailaliases", "r")) != NULL)
+               printf(" [using local alias file]\n");
+       else if ((af = fopen(ALIASFILE, "r")) == NULL)
+       {
+               if (Debug)
+                       printf("Can't open %s\n", ALIASFILE);
+               errno = 0;
+               return;
+       }
+
+       /*
+       **  Scan alias file.
+       **      If we find any user that any line matches any user, we
+       **      will send to the line rather than to the user.
+       */
+
+       didalias = TRUE;
+       while (didalias)
+       {
+               didalias = FALSE;
+               gotmatch = FALSE;
+               rewind(af);
+               while (fgets(line, sizeof line, af) != NULL)
+               {
+                       /* check for continuation lines */
+                       if (isspace(line[0]))
+                       {
+                               if (gotmatch)
+                               {
+                                       if (Debug)
+                                               printf("   ... also aliased to %s", line);
+                                       sendto(line);
+                               }
+                               continue;
+                       }
+                       gotmatch = FALSE;
+                       /* comments begin with `#' */
+                       if (line[0] == '#')
+                               continue;
+                       p = NULL;
+                       for (q = &SendQ; (q = nxtinq(q)) != NULL; )
+                       {
+                               if ((p = matchalias(valueq(q), line)) != NULL)
+                                       break;
+                       }
+
+                       if (p != NULL)
+                       {
+                               /*
+                               **  Match on Alias.
+                               **      Deliver to the target list.
+                               **      Remove the alias from the send queue
+                               **        and put it on the Alias queue.
+                               */
+
+                               if (Debug)
+                                       printf("%s aliased to %s", valueq(q), p);
+                               tkoffq(q, &SendQ);
+                               putonq(q, &AliasQ);
+                               didalias++;
+                               gotmatch++;
+                               sendto(p);
+                       }
+               }
+       }
+       fclose(af);
+}
+\f/*
+**  MATCHALIAS -- Match name against alias.
+**
+**     The alias is a full alias line, in the format:
+**             pseudonym:name1,name2,name3,...
+**     This routine just matches against the pseudonym.
+**
+**     Parameters:
+**             user -- the user to match against.
+**             line -- the alias line.
+**
+**     Returns:
+**             A pointer to the first character after the colon on
+**                     a match.
+**             NULL otherwise.
+**
+**     Side Effects:
+**             none
+**
+**     Requires:
+**             none
+**
+**     Called By:
+**             alias
+**
+**     History:
+**             1/11/80 -- broken from alias
+*/
+
+matchalias(user, line)
+       register char *user;
+       register char *line;
+{
+       for (; *user != '\0' && *line == *user; line++, user++)
+               continue;
+       while (isspace(*line))
+               line++;
+       if (*user == '\0' && *line == ':')
+               return (++line);
+       return (NULL);
+}
+\f/*
+**  FORWARD -- Try to forward mail
+**
+**     This is similar but not identical to aliasing.  Local
+**     users may put a file ".userinfo" in their home directory
+**     saying what account(s) they would like their mail
+**     forwarded to.  This file looks a lot like ARPANET
+**     mail headers, i.e., each line is
+**             field-name: value
+**     This routine is looking for the field "forward-to".
+**
+**     Parameters:
+**             user -- the name of the user who's mail we
+**                     would like to forward to.
+**
+**     Returns:
+**             NULL -- we arranged to forward this somewhere,
+**                     so don't send it yourself.
+**             else -- send it to whoever this returns.
+**
+**     Side Effects:
+**             New names are added to SendQ.
+**
+**     Requires:
+**             setpwent (sys)
+**             getpwname (sys)
+**             strcpy (sys)
+**             strcat (sys)
+**             fopen (sys)
+**             fgets (sys)
+**             matchhdr
+**             sendto
+**             fclose (sys)
+**
+**     Called By:
+**             recipient
+**
+**     History:
+**             1/23/80 -- written.
+*/
+
+char *
+forward(user)
+       char *user;
+{
+       register struct passwd *pw;
+       char buf[MAXLINE];
+       register char *p;
+       register FILE *uf;
+       extern struct passwd *getpwnam();
+       extern char *matchhdr();
+
+       /*
+       **  Find and open the user's .userinfo file.
+       */
+
+       setpwent();
+       if ((pw = getpwnam(user)) == NULL)
+               return (user);
+       strcpy(buf, pw->pw_dir);
+       strcat(buf, "/.userinfo");
+       if ((uf = fopen(buf, "r")) == NULL)
+               return (user);
+       
+       /*
+       **  Look for forward-to: field.
+       */
+
+       while (fgets(buf, sizeof buf, uf) != NULL)
+       {
+               if ((p = matchhdr(buf, "forward-to")) == NULL)
+                       continue;
+               
+               /*
+               **  We have a foward entry.
+               **      Send to the list
+               */
+
+               fclose(uf);
+               if (Debug)
+                       printf("--%s", buf);
+               sendto(p);
+               return (NULL);
+       }
+
+       /*
+       **  No match -- send to the original user.
+       */
+
+       fclose(uf);
+       return (user);
+}
diff --git a/usr/src/cmd/delivermail/aliases.5 b/usr/src/cmd/delivermail/aliases.5
new file mode 100644 (file)
index 0000000..f1bc0d6
--- /dev/null
@@ -0,0 +1,33 @@
+.TH ALIASES 5 12/31/79
+.SH NAME
+aliases \- aliases file for delivermail
+.SH SYNOPSIS
+/usr/lib/aliases
+.SH DESCRIPTION
+This file describes user id aliases
+that will be used
+by
+.I /etc/delivermail.
+It is formatted as a series of lines
+of the form
+.in +0.5i
+name:addr1,addr2,...addrn
+.in
+The
+.I name
+is the name to alias,
+and the
+.I addri
+are the addresses to send the message to.
+Lines beginning with white space
+are continuation lines.
+Lines beginning with `\|#\|'
+are comments.
+.PP
+Aliasing occurs only on local names.
+Loops can not occur,
+since no message will be sent to any person
+more than once.
+.SH SEE\ ALSO
+delivermail(8)
+.SH BUGS
diff --git a/usr/src/cmd/delivermail/arpa-mailer.8 b/usr/src/cmd/delivermail/arpa-mailer.8
new file mode 100644 (file)
index 0000000..92270f3
--- /dev/null
@@ -0,0 +1,38 @@
+.TH ARPA-MAILER 8 12/31/79
+.SH NAME
+arpa-mailer \- deliver mail to the
+.SM ARPANET
+.SH SYNOPSIS
+/usr/lib/mailers/arpa
+.I from-address
+.I to-host
+.I to-user
+.SH DESCRIPTION
+.I Arpa-mailer
+queues the letter found on its standard input
+for delivery to the host and user specified.
+The actual delivery will be performed by the
+.SM ARPANET
+mailer daemon.
+.PP
+If the letter does not appear to have a full
+.SM ARPANET
+header,
+.I arpa-mailer
+will insert ``Date:'' and ``From:''
+fields in the proper format.
+The ``From:'' person
+is determined by the from-address argument,
+with colons translated to periods
+and ``@Berkeley'' appended.
+The from-address argument
+is also used by the
+mailer daemon
+to return the mail to you
+if there is a problem at the receiving host.
+.SH FILES
+.RI /dev/net/ to-host
+.br
+/usr/spool/netmail/*
+.SH SEE\ ALSO
+delivermail(8), mailer(ARPA)
diff --git a/usr/src/cmd/delivermail/delivermail.8 b/usr/src/cmd/delivermail/delivermail.8
new file mode 100644 (file)
index 0000000..dc90015
--- /dev/null
@@ -0,0 +1,251 @@
+.TH DELIVERMAIL 8
+.SH NAME
+delivermail \- deliver mail to arbitrary people
+.SH SYNOPSIS
+.B /etc/delivermail
+[
+.BR \- [ fr ]
+.I address
+] [
+.B \-a
+] [
+.BR \-e [ empqw ]
+] [
+.B \-n
+] [
+.B \-m
+] [
+.B \-s
+] [
+.B \-i
+] [
+.B \-h
+.I N
+] address ...
+.SH DESCRIPTION
+.I Delivermail
+delivers a letter to one or more people,
+routing the letter over whatever networks
+are necessary.
+.I Delivermail
+will do inter-net forwarding as necessary
+to deliver the mail to the correct place.
+.PP
+.I Delivermail
+is not intended as a user interface routine;
+it is expected that other programs will provide user-friendly
+front ends,
+and
+.I delivermail
+will be used only to deliver pre-formatted messages.
+.PP
+.I Delivermail
+reads its standard input
+up to a control-D
+or a single dot
+and sends a copy of the letter found there
+to all of the addresses listed.
+If the
+.B \-i
+flag is given,
+single dots are ignored.
+It determines the network to use
+based on the syntax of the addresses.
+Addresses containing the character `@'
+or the word ``at''
+are sent to the
+.SM ARPANET;
+addresses containing `!'
+are sent to the
+.SM UUCP
+net,
+and addresses containing `:' or `.'
+are sent to the Berkeley network.
+Other addresses are assumed to be local.
+.PP
+Local addresses are looked up in the file
+.I /usr/lib/mailaliases
+and aliased appropriately.
+Aliasing can be prevented by preceeding the address
+with a backslash or using the
+.B \-n
+flag.
+Normally the sender is not included in any alias
+expansions, e.g.,
+if `john' sends to `group',
+and `group' includes `john' in the expansion,
+then the letter will not be delivered to `john'.
+The
+.B \-m
+flag disables this suppression.
+.PP
+.I Delivermail
+computes the person sending the mail
+by looking at your login name.
+The ``from'' person
+can be explicitly specified by using the
+.B \-f
+flag;
+or, if the
+.B \-a
+flag is given,
+delivermail looks in the body of the message
+for a ``From:'' or ``Sender:''
+field in
+.SM ARPANET
+format.
+The
+.B \-f
+and
+.B \-a
+flags can be used
+only by the special users
+.I root
+and
+.I network,
+or if the person you are trying to become
+is the same as the person you are.
+The
+.B \-r
+flag is entirely equivalent to the
+.B \-f
+flag; it is provided for ease of interface only.
+.PP
+The
+.BI \-e x
+flag controls the disposition of error output,
+as follows:
+.TP 3n
+.B e
+Print errors on the standard output,
+and echo a copy of the message when done.
+It is assumed that a network server will
+return the message back to the user.
+.TP
+.B m
+Mail errors back to the user.
+.TP
+.B p
+Print errors on the standard output.
+.TP
+.B q
+Throw errors away;
+only exit status is returned.
+.TP
+.B w
+Write errors back to the user's terminal,
+but only if the user is still logged in
+and write permission is enabled;
+otherwise errors are mailed back.
+.LP
+If the error is not mailed back,
+and if the mail originated on the machine where the error occurred,
+the letter is appended to the file
+.I dead.letter
+in the sender's home directory.
+.PP
+If the first character of the user name
+is a vertical bar,
+the rest of the user name is used as the name of a program
+to pipe the mail to.
+It may be necessary to quote the name of the user
+to keep
+.I delivermail
+from supressing the blanks from between arguments.
+.PP
+The message is normally editted to eliminate ``From''
+lines that might confuse other mailers.
+In particular,
+``From'' lines in the header are deleted,
+and ``From'' lines in the body are prepended by `>'.
+The
+.B \-s
+flag saves ``From'' lines in the header.
+.PP
+The
+.B \-h
+flag gives a ``hop-count'', i.e.,
+a measure of how many times this message
+has been processed by
+.I delivermail
+(presumably on different machines).
+Each time
+.I delivermail
+processes a message,
+it increases the hop-count by one;
+if it exceeds 30
+.I delivermail
+assumes that an alias loop has occured
+and it aborts the message.
+The hop-count defaults to zero.
+.PP
+.I Delivermail
+returns an exit status
+describing what it did.
+The codes are defined in
+.IR mailexits.h :
+.ta 3n +\w'EX_UNAVAILABLE'u+3n
+.de XX
+.ti \n(.iu
+..
+.in +\w'EX_UNAVAILABLE'u+6n
+.XX
+0      EX_OK   Succesful completion on all addresses.
+.XX
+2      EX_NOUSER       User name not recognized.
+.XX
+3      EX_UNAVAILABLE  Catchall meaning necessary resources
+were not available.
+.XX
+4      EX_SYNTAX       Syntax error in address.
+.XX
+5      EX_SOFTWARE     Internal software error,
+including bad arguments.
+.XX
+6      EX_OSERR        Temporary operating system error,
+such as ``cannot fork''.
+.XX
+7      EX_NOHOST       Host name not recognized.
+.DT
+.PP
+.SH FILES
+.in +10
+.ti -10
+/usr/lib/mailaliases \- to alias names
+.ti -10
+/bin/mail \- to deliver local mail
+.ti -10
+/usr/net/bin/sendmail \- to deliver Berkeley mail
+.ti -10
+/usr/lib/mailers/arpa \- to deliver
+.SM ARPANET
+mail
+.ti -10
+/usr/lib/mailers/uucp \- to deliver
+.SM UUCP
+mail
+.ti -10
+/tmp/mail* \- temp file
+.ti -10
+/tmp/xscript* \- saved transcript
+.ti -10
+/dev/log \- to log status (optional)
+.in -10
+.SH SEE\ ALSO
+mail(1), Mail(UCB), arpa-mailer(8), uucp-mailer(8),
+mailaliases(5), userinfo(5)
+.SH BUGS
+.I Delivermail
+sends one copy of the letter
+to each user;
+it should send one copy
+of the letter to each host
+and distribute to multiple users there
+whenever possible.
+.PP
+.I Delivermail
+assumes the addresses can be represented as one word.
+This is incorrect according to the
+.SM ARPANET
+mail protocol RFC 733 (NIC 41952),
+but is consistant with the real world.
diff --git a/usr/src/cmd/delivermail/mail-dm.c b/usr/src/cmd/delivermail/mail-dm.c
new file mode 100644 (file)
index 0000000..b112b48
--- /dev/null
@@ -0,0 +1,445 @@
+#include <arpa/netopen.h>
+#include "srvrftp.h"
+#include <statbuf.h>
+#include <arpa/hostnames.h>
+#include <io_buf.h>
+#include <arpa/mail.h>
+#include <ident.h>
+#include <signal.h>
+#include <log.h>
+extern int fout;
+\f/*
+Name:
+       mail
+
+Function:
+       handle the MAIL <user> command over the command connection
+
+Algorithm:
+       see if we have a known user
+
+       if mailbox file can't be gotten
+               return
+       tell him it is ok to go ahead with mail
+
+       while he doesn't type a period
+               read and write data
+       say completed
+
+Parameters:
+       username in arg
+
+Returns:
+       nothing
+
+Globals:
+       arg
+       username=
+
+Calls:
+       strmove
+       getuser
+       loguser
+       openmail
+       closemail
+       getline
+       chown (sys)
+       time (sys)
+       printf (sys)
+       getch   (util)
+       putch   (util)
+
+Called by:
+       main thru command array
+
+History:
+       initial coding          Mark Kampe UCLA-ATS
+       modified 4/13/76 by S. F. Holmgren for Illinois version
+       modified 6/30/76 by S. F. Holmgren to call getmbox
+       modified 10/18/76 by J. S. Kravitz to improve net mail header
+       chown removed by R. Balocca @ CAC, Sunday 1977 February 20
+       getline removed and limit on line length removed by using
+       getch and putch added by R. Balocca @ CAC, 1977 March 8 Tuesday
+       Fixed oversight in above (forgot to translate <crlf> to <lf>)
+               1977 March 10 Thursday by Rick Balocca @ CAC
+       Added openmail & closemail, added logging, and fixed several
+               bugs on or about 12/21/79 by Eric Allman, UCB/INGRES.
+       Changed to always accept mail -- bad mail will be sent back --
+               1/9/80 by Eric Allman, UCB/INGRES.
+*/\f
+#define gt (c = getch())
+mail()
+{
+       register char *p;       /* general use */
+       register int c;
+       int i;
+
+       /* extern struct io_buf obuf; */
+
+       /* get to open mailbox file descriptor */
+       fflush(&fout);
+       if( (fout = openmail(arg)) < 0 )
+               return;
+
+       /* obuf.unused = 0;     obuf.addr = 0;  /* fake a fcreat */
+
+       /* say its ok to continue */
+       netreply( "350 Enter mail, end with a line containing only `.'\r\n" );
+
+       for(;;)                         /* while no error or <crlf>.<crlf> */
+       {
+               /* we are at beginning of line */
+
+               if(gt=='.')                     /*"."*/
+               {
+                       if(gt=='\r')                    /*".\r"*/
+                       {
+                               if(gt=='\n')                    /*".\r\n"*/
+                               {
+                                       /* end of message */
+                                       break;
+                               }
+                               else
+                               {                               /*".\r"c*/
+                                       putch('.');
+                                       putch('\r');
+                               }
+                       }
+                       else                            /*"."c"*/
+                               putch('.');
+               }
+                                                               /*"-"*/
+                                       /* c */
+               for(;;)
+               {
+                       for(; c != '\r'; gt)
+                       {
+                               if( c < 0 )
+                               {
+                                       /* fflush(&obuf); */
+                                       /* write(obuf.fid, "\n***** Sender aborted connection *****\n", 39); */
+                                       fflush(&fout);
+                                       write(fout, "\n***** Sender aborted connection *****\n", 39);
+                                       goto out;
+                               }
+                               else
+                                       putch(c);
+                       }
+       
+                                               /*"\r"*/
+                       if( gt == '\n' )
+                       {                       /*"\r\n"*/
+crlf:
+                               putch('\n');
+                               break;
+                       }
+                       else
+                       {                       /*"\r"c*/
+crc:
+                               putch('\r');
+                               if(c=='\0')
+                                       gt;     /* "\r\0" */
+                                               /* is arpa escape for "\r" */
+                       }
+               }
+       }
+
+out:
+       fflush(&fout);
+       if (closemail(fout) >= 0)
+               netreply("256 Mail accepted\r\n");
+}
+
+\f/*
+Name:
+       datamail
+
+Function:
+       handle the MLFL command
+
+Algorithm:
+       fork
+               make sure we have a valid user
+                       say bad user and exit
+               send sock command
+               open data connection
+               get open mailbox file descriptor
+               call rcvdata to receive mail
+
+Parameters:
+       username in arg
+
+Returns:
+       nothing
+
+Globals:
+       arg
+
+Calls:
+       fork (sys)
+       strmove
+       netreply
+       sendsock
+       dataconnection
+       getmbox
+       rcvdata
+       printf (sys)
+       time (sys)
+
+Called by:
+       main thru command array 
+
+History:
+       initial coding 4/13/76 by S. F. Holmgren
+       modified 10/18/76 by J. S. Kravitz to put net mail header
+       chown removed by R. Balocca @ CAC, Sunday 1977 February 20
+*/\f
+datamail()
+{
+       register netdata;
+       /* register mboxfid; */
+       register int i;
+
+       i = fork();
+       if (i < 0)
+       {
+               netreply("455 Mail server temporarily unavailable\r\n");
+               return;
+       }
+       else if (i == 0)
+       {
+               fflush(&fout);
+               if ((fout = openmail(arg)) < 0)
+                       exit(3);
+
+               /* send sock command */
+               sendsock( U4 );
+
+               /* open data connection */
+               netdata = dataconnection( U4 );
+
+               /* say its ok to proceed */
+               numreply( NUM250 );
+
+               /* get data from net connection and copy to mail file */
+               /* rcvdata( netdata,mboxfid ); */
+               if (rcvdata(netdata, fout) < 0)
+                       exit(1);
+
+               /* close the mail, see if ok; if so say ok */
+               fflush(&fout);
+               if (closemail(fout) >= 0)
+                       numreply( NUM252 );
+
+               exit( 0 );
+       }
+}
+\f/*
+**  OPENMAIL -- Open a channel to the mail server
+**
+**     Gets the mail server started up ready to handle our
+**     mail.
+**
+**     Algorithm:
+**             See if the user is specified.
+**                     If not, send to user "root".
+**             See if the user exists.
+**                     If not, signal error 450 and return.
+**             Fork.
+**             Create a pipe
+**                     Signal "unavailable" and exit on failure.
+**             Fork.
+**                     Signal "unavailable" and exit on failure
+**                     In child:
+**                             Call mailer: /etc/delivermail is preferred.
+**                     In parent:
+**                             Avoid pipe signals in case delivermail dies.
+**                             Save the childs pid.
+**                             Return file descriptor.
+**
+**     Notes:
+**             The check to see if the user actually exists should
+**             go away so that we can do real mail forwarding.
+**
+**     Parameters:
+**             who -- the user to send the mail to.
+**
+**     Returns:
+**             File descriptor to send mail to.
+**             -1 on failure.
+**
+**     Side Effects:
+**             Forks /etc/delivermail or /bin/mail or /usr/bin/mail.
+**             Becomes "network" in the child.
+**
+**     Requires:
+**             strmove
+**             getuser
+**             netreply
+**             pipe (sys)
+**             fork (sys)
+**             close (sys)
+**             dup (sys)
+**             execl (sys)
+**             signal (sys)
+**             exit (sys)
+**
+**     Called By:
+**             mail
+**             datamail
+**
+**     History:
+**             1/9/80 -- Added 050 & 455 reply messages if execl's
+**                     fail.  Eric Allman UCB/INGRES.
+**             11/26/79 -- Modified to map upper case to lower
+**                     case.  Eric Allman UCB/INGRES.
+**             11/10/79 -- Written by Eric Allman UCB/INGRES
+**             3/6/80 -- Dropped case mapping; delivermail does
+**                     that now.  EPA UCB/INGRES.
+*/
+
+int Mail_pid;
+char *Mail_user;
+
+openmail(who)
+       char *who;
+{
+       register char *w;
+       register int i;
+       int pvect[2];
+       register char *p;
+
+       w = who;
+       if (w == 0)
+               w = "root";
+/*
+       else
+       {
+               for (p = w; *p != '\0'; p++)
+               {
+                       if (*p >= 'A' && *p <= 'Z')
+                               *p =- 'A' - 'a';
+               }
+       }
+*/
+       Mail_user = w;
+
+       /* see if the user exists */
+       strmove(w, username);
+/*
+       if (getuser(0) == 0)
+       {
+               netreply("450 User unknown\r\n");
+               return (-1);
+       }
+*/
+
+       /* try to get a pipe to the mailer */
+       if (pipe(pvect) < 0)
+       {
+         unavailable:
+               netreply("455 Mail server temporarily unavailable\r\n");
+               return (-1);
+       }
+
+       /* fork */
+       i = fork();
+       if (i < 0)
+       {
+               /* failure */
+               close(pvect[0]);
+               close(pvect[1]);
+               goto unavailable;
+       }
+       else if (i == 0)
+       {
+               /* child */
+               close(pvect[1]);
+               close(0);
+               dup(pvect[0]);
+               close(pvect[0]);
+               setuid(NETUID);
+
+               /* try to call something to deliver the mail */
+               execl("/etc/delivermail", "delivermail", "-em", "-a", w, 0);
+               netreply("050 Not using normal mail server, beware!\r\n");
+               execl("/bin/mail", "mail", w, 0);
+               execl("/usr/bin/mail", "mail", w, 0);
+
+               /* doesn't seem to be anything around */
+               netreply("455 Mail server unavailable\r\n");
+               exit(3);
+       }
+
+       /* else parent */
+       signal(SIGPIPE, SIG_IGN);
+       Mail_pid = i;
+       close(pvect[0]);
+       return (pvect[1]);
+}
+\f/*
+**  CLOSEMAIL -- Close the mail file and get actual status
+**
+**     The mail file is closed.
+**
+**     Algorithm:
+**             Wait for the mailer to die.
+**                     If it wasn't there, be non-comittal.
+**             If it died a violent death, give error.
+**
+**     Parameters:
+**             fd -- the file descriptor of the mail file.
+**
+**     Returns:
+**             none.
+**
+**     Side Effects:
+**             mailer is soaked up.
+**
+**     Requires:
+**             close (sys)
+**             wait (sys)
+**
+**     Called By:
+**             mail
+**             datamail
+**
+**     History:
+**             1/9/80 -- Changed to not check for errors in mailing,
+**                     since these will be mailed back.
+**             11/10/79 -- Written by Eric Allman UCB/INGRES.
+*/
+
+closemail(fd)
+       int fd;
+{
+       auto int st;
+       register int i;
+
+       /* close the pipe -- mail should go away */
+       close(fd);
+
+       /* wait for its body */
+       while ((i = wait(&st)) != Mail_pid)
+       {
+               if (i < 0)
+               {
+                       /* how did this happen? */
+                       logmsg(LOG_ERR, "mail from host %d to %s: no child",
+                           openparams.o_frnhost & 0377, Mail_user);
+                       goto unavailable;
+               }
+       }
+
+       /* 'st' is now the status of the mailer */
+       if ((st & 0377) != 0)
+       {
+               logmsg(LOG_ERR, "mail from host %d to %s: status %o",
+                   openparams.o_frnhost & 0377, Mail_user, st);
+unavailable:
+               netreply("455 Mail not delivered -- local system error\r\n");
+               return (-1);
+       }
+
+       return (0);
+}
diff --git a/usr/src/cmd/delivermail/userinfo.5 b/usr/src/cmd/delivermail/userinfo.5
new file mode 100644 (file)
index 0000000..8a4edc7
--- /dev/null
@@ -0,0 +1,55 @@
+.TH USERINFO 5 1/22/80
+.SH NAME
+userinfo \- per-user database of personal information
+.SH SYNOPSIS
+~/.userinfo
+.SH DESCRIPTION
+The
+.I \&.userinfo
+database contains a set of miscellaneous information
+about each user.
+It is formatted as a sequence of lines
+of the form ``field-name: value''.
+.I Field-name
+must begin in the first column,
+but there may be spaces before or after the colon.
+Spaces in the value field may be significant or not,
+depending on the semantics of the particular field.
+Fields may be in any order.
+Case in field names is ignored.
+.PP
+The following fields are defined:
+.IP name \w'office-address'u+3n
+The user's full name.
+.IP office-address
+The user's office address.
+.IP office-phone
+The user's office phone number.
+.IP home-address
+The home address;
+lines of the address are separated with semicolons.
+.IP home-phone
+The home phone number.
+.IP forward-to
+The address to forward any incoming mail to.
+.IP project
+The project that this user is associated with.
+.IP advisor
+This user's advisor or supervisor.
+.IP affiliation
+A business or technical affiliation
+(for outside users).
+.PP
+Other fields may be defined as needed.
+.SH EXAMPLE
+.nf
+NAME: Eric Allman
+Forward-To: ingres:eric
+home-phone: (415) 843-9461
+office-address: 380 Cory
+office-phone: 2-7520
+Project: INGRES
+Advisor: Mike Stonebraker
+.fi
+.SH SEE\ ALSO
+finger(1), delivermail(8)
diff --git a/usr/src/cmd/delivermail/v6-mail.c b/usr/src/cmd/delivermail/v6-mail.c
new file mode 100644 (file)
index 0000000..5e71bcd
--- /dev/null
@@ -0,0 +1,544 @@
+#
+
+/*
+ * mail command usage
+ *     mail [-yn]
+ *             prints your mail
+ *     mail people
+ *             sends standard input to people
+ *
+ *     mail -r machine user people
+ *             sends mail from the network
+ *
+ * if NOTROOT is defined, don't run as root.
+ */
+
+#define        SIGINT          2
+#define DIRECT         040000
+#define RMAILCMD       "/usr/net/bin/sendmail"
+#define GETUID()       (getuid() & 0377)
+#define        SPOOLDIR        "/usr/spool/mail/"
+#define NOTROOT                $
+
+struct inode {
+       char minor;
+       char major;
+       int inumber;
+       int flags;
+       char nlinks;
+       char uid;
+       char gid;
+       char size0;
+       int size1;
+       int addr[8];
+       int actime[2];
+       int modtime[2];
+} inode;
+
+char   lettmp[] "/tmp/maXXXXX";
+char   preptmp[] "/tmp/mbXXXXX";
+int    pwfil;
+int    chew;
+int    errs;
+char   *strcat(), *strcpy();
+
+main(argc, argv)
+char **argv;
+{
+       register int me;
+       extern int fout;
+       int uf, delexit();
+       char namebuf[20];
+
+       mktemp(lettmp);
+       mktemp(preptmp);
+       unlink(lettmp);
+       unlink(preptmp);
+       me = GETUID();
+       if (getname(me, namebuf) < 0) {
+               printf("Who are you?\n");
+               delexit(1);
+       }
+       if (argc < 2)
+               goto hitit;
+       for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++)
+       switch(argv[0][1]) {
+               register char *cp, *np;
+
+               case 'y':
+               case 'n':
+                       argc++, argv--;
+hitit:
+                       printmail(argc, argv, namebuf);
+                       delexit(0);
+
+               case 'r':
+                       if (argc < 2)
+                               continue;
+               case 'f':
+                       if (argc < 1)
+                               continue;
+                       if (!equal("network", namebuf) && me != 0) {
+                               printf("Nice try!\n");
+                               delexit(1);
+                       }
+                       chew++;
+                       np = namebuf;
+                       for (cp = argv[1]; *cp; cp++)
+                               *np++ = *cp;
+                       if (argv[0][1] == 'r')
+                       {
+                               argc--, argv++;
+                               *np++ = ':';
+                               for (cp = argv[1]; *cp; cp++)
+                                       *np++ = *cp;
+                       }
+                       *np++ = 0;
+                       argc--, argv++;
+                       continue;
+       }
+       if ((signal(SIGINT, 01) & 01) == 0)
+               signal(SIGINT, delexit);
+       unlink(lettmp);
+# ifdef NOTROOT
+       fout = creat(lettmp, 0666);
+# else
+       fout = creat(lettmp, 0600);
+# endif
+       if (fout < 0) {
+               fout = 1;
+               perror(lettmp);
+               delexit(1);
+       }
+       argc++, argv--;
+       bulkmail(argc, argv, namebuf);
+       delexit(0);
+}
+
+printmail(argc, argv, name)
+char **argv;
+char *name;
+{
+       extern int fin, fout;
+       register n, c, f;
+       char *mname;
+
+       mname = cat(SPOOLDIR, name);
+       if (stat(mname, &inode)>=0 && inode.nlinks==1 &&
+               fopen(mname, &fin)>=0 && (c = getchar())) {
+               putchar(c);
+               getput();
+               close(fin);
+               c = 'x';
+               if (argc<2) {
+                       if (ttyn(0)!='x') {
+                               printf("Save?");
+                               fin = 0;
+                               c = getchar();
+                       }
+               } else
+                       c = argv[1][1];
+               if (!any(c, "yn"))
+                       delexit(0);
+               if (c == 'y') {
+                       if (accesss("mbox")) {
+                               printf("Saved mail in 'mbox'\n");
+                               prepend(mname, "mbox", GETUID());
+                               unlink(mname);
+                       } else
+                               printf("In wrong directory\n");
+               } else
+                       unlink(mname);
+       } else
+               printf("No mail.\n");
+}
+
+bulkmail(argc, argv, from)
+char **argv, *from;
+{
+       extern int fin, fout;
+       register int c;
+       register char *cp;
+       char linebuf[128];
+       int tbuf[2], ttyn1;
+
+       fin = 0;
+       (&fin)[1] = 0;
+       time(tbuf);
+       ttyn1 = ttyn(1);
+       if (ttyn1 < 033) {
+               ttyn1 =+ 'a' - 1;
+               ttyn1 =<< 8;
+               ttyn1 =| '^';
+       }
+       printf("From %s  tty%c  %s", from, ttyn1, ctime(tbuf));
+
+       /*
+        * If delivering mail from the network via mail -r,
+        * Strip the leading line and throw it away, as long
+        * as it begins with "From ..."
+        */
+
+       if (chew) {
+               cp = linebuf;
+               do {
+                       c = getchar();
+                       if (cp - linebuf < 120)
+                               *cp++ = c;
+               } while (c != '\n' && c != 0);
+               *cp = '\0';
+               if (linebuf[0] != 'F' || linebuf[1] != 'r' ||
+                   linebuf[2] != 'o' || linebuf[3] != 'm')
+                       printf("%s", linebuf);
+       }
+       getput();
+       putchar('\n');
+       flush();
+       close(fout);
+       while (--argc > 0)
+               sendto(*++argv);
+       delexit(errs);
+}
+
+sendto(person)
+char *person;
+{
+       static int saved;
+       extern int fout, fin;
+       register char *filep;
+       register int him;
+       int i;
+
+       if ((person[0] == 'i' || person[0] == 'I') && person[1] == ':')
+               person += 2;
+       for (i = 0; person[i] != '\0'; i++)
+       {
+               if (person[i] == ':')
+               {
+                       person[i] = '\0';
+                       if (equal(person, "ing70") || equal(person, "ingres"))
+                               person += i + 1;
+                       else
+                               person[i] = ':';
+                       break;
+               }
+       }
+       if (person[i] == ':' || equal(person, "msgs"))
+       {
+               int i = fork();
+               int s;
+
+               if (i < 0) {
+                       perror("fork");
+                       goto assback;
+               }
+               if (i == 0) {
+                       close(0);
+                       open(lettmp, 0);
+                       if (any(':', person)) {
+                               execl(RMAILCMD, "sendmail", person, 0);
+                               execl("/usr/bin/sendmail", "sendmail", person, 0);
+                               execl("/bin/sendmail", "sendmail", person, 0);
+                               perror("sendmail");
+                       } else {
+                               execl("/usr/new/msgs", "msgs", "-s", 0);
+                               execl("/usr/ucb/msgs", "msgs", "-s", 0);
+                               execl("/usr/bin/msgs", "msgs", "-s", 0);
+                       }
+                       exit(12);
+               }
+               for (;;) {
+                       register int j = wait(&s);
+                       if (j == -1)
+                               goto assback;
+                       if (j == i)
+                               break;
+               }
+               if ((s & 0377) != 0 || (s >> 8) == 12)
+                       goto assback;
+               return;
+       }
+
+       if ((him = getuserid(person)) == -1) {
+assback:
+               fout = 1;
+               flush();
+               printf("Can't send to %s.\n", person);
+               errs++;
+               if (ttyn(0)!='x' && saved==0) {
+                       saved++;
+                       if (accesss("dead.letter")) {
+                               printf("Letter saved in 'dead.letter'\n");
+                               prepend(lettmp, "dead.letter", GETUID());
+                       } else
+                               printf("In wrong directory\n");
+               }
+               return;
+       }
+       filep = cat(SPOOLDIR, person);
+       lock(filep);
+       prepend(lettmp, filep, him);
+       unlock();
+}
+
+prepend(from, to, own)
+char *from, *to;
+{
+       extern int fin, fout;
+       register int sig;
+       int statb[18];
+
+       if (stat(to, statb) >= 0 && (statb[2] & 060000) != 0) {
+               write(2, "Exotic destination\n", 19);
+               delexit(1);
+       }
+       unlink(preptmp);
+       if (fcreat(preptmp, &fout) < 0) {
+               fout = 1;
+               perror("mail");
+               delexit(1);
+       }
+       chmod(preptmp, 0600);
+       if (fopen(from, &fin) < 0) {
+               close(fout);
+               fout = 1;
+               perror("mail");
+               unlink(preptmp);
+               return(0);
+       }
+       getput();
+       close(fin);
+       fopen(to, &fin);
+       getput();
+       close(fin);
+       flush();
+       close(fout);
+       sig = signal(SIGINT, 01);
+       unlink(to);
+       if (fcreat(to, &fout) < 0) {
+               unlink(preptmp);
+               fout = 1;
+               signal(SIGINT, sig);
+               return(0);
+       }
+# ifdef NOTROOT
+       chmod(to, 0666);
+# else
+       chmod(to, 0600);
+       chown(to, own);
+# endif
+       if(stat(to, &inode) < 0 || inode.nlinks != 1) {
+               close(fout);
+               fout = 1;
+               unlink(preptmp);
+               signal(SIGINT, sig);
+               return(0);
+       }
+       if (fopen(preptmp, &fin) < 0) {
+               fout = 1;
+               perror("mail");
+               signal(SIGINT, sig);
+               errs++;
+               return(0);
+       }
+       getput();
+       flush();
+       close(fout);
+       close(fin);
+       fout = 1;
+       signal(SIGINT, sig);
+       return(1);
+}
+
+delexit(ex)
+{
+       unlock();
+       unlink(lettmp);
+       unlink(preptmp);
+       exit(ex);
+}
+
+equal(as1, as2)
+{
+       register char *s1, *s2;
+
+       s1 = as1;
+       s2 = as2;
+       while (*s1++ == *s2)
+               if (*s2++ == 0)
+                       return(1);
+       return(0);
+}
+
+cat(ap1, ap2)
+char *ap1, *ap2;
+{
+       register char *p1, *p2;
+       static char fn[32];
+
+       p1 = ap1;
+       p2 = fn;
+       while (*p2++ = *p1++);
+       p2--;
+       p1 = ap2;
+       while (*p2++ = *p1++);
+       return(fn);
+}
+
+getput()
+{
+       extern int errno;
+       register c;
+
+       while(c = getchar()) {
+               errno = 0;
+               putchar(c);
+               if(errno) {
+                       perror("mail");
+                       delexit(1);
+               }
+       }
+}
+
+accesss(s1)
+{
+       if (access(".", 2) != -1 && (stat(s1, &inode)<0 || access(s1, 2)==0))
+               return(1);
+       return(0);
+}
+
+any(c, str)
+       char *str;
+{
+       register char *f;
+
+       f = str;
+       while (*f)
+               if (c == *f++)
+                       return(1);
+       return(0);
+}
+
+char   *maillock       = ".lock";              /* Lock suffix for mailname */
+char   *lockname       = "/usr/spool/mail/tmXXXXXX";
+char   locktmp[30];                            /* Usable lock temporary */
+char   curlock[50];                            /* Last used name of lock */
+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 unlink 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 30 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;
+       long age;
+       struct inode sbuf;
+       long curtime;
+
+       if (file == (char *) 0) {
+               printf("Locked = %d\n", locked);
+               return(0);
+       }
+       if (locked)
+               return(0);
+       strcpy(curlock, file);
+       strcat(curlock, maillock);
+       strcpy(locktmp, lockname);
+       mktemp(locktmp);
+       unlink(locktmp);
+       for (;;) {
+               f = lock1(locktmp, curlock);
+               if (f == 0) {
+                       locked = 1;
+                       return(0);
+               }
+               if (stat(curlock, &sbuf) < 0)
+                       return(0);
+               time(&curtime);
+               age = * ((long *) sbuf.modtime);
+               if (curtime < age + 30) {
+                       sleep(5);
+                       continue;
+               }
+               unlink(curlock);
+       }
+}
+
+/*
+ * Remove the mail lock, and note that we no longer
+ * have it locked.
+ */
+
+unlock()
+{
+
+       if (locked)
+               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);
+       close(fd);
+       if (link(tempfile, name) < 0) {
+               unlink(tempfile);
+               return(-1);
+       }
+       unlink(tempfile);
+       return(0);
+}
+
+/*
+ * Concatenate s2 on the end of s1.  S1's space must be large enough.
+ * Return s1.
+ */
+
+char *
+strcat(s1, s2)
+register char *s1, *s2;
+{
+       register os1;
+
+       os1 = s1;
+       while (*s1++)
+               ;
+       *--s1;
+       while (*s1++ = *s2++)
+               ;
+       return(os1);
+}
+
+/*
+ * Copy string s2 to s1.  s1 must be large enough.
+ * return s1
+ */
+
+char *
+strcpy(s1, s2)
+register char *s1, *s2;
+{
+       register os1;
+
+       os1 = s1;
+       while (*s1++ = *s2++)
+               ;
+       return(os1);
+}