4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / usr.bin / mail / main.c
index 73bce5c..2cd65ff 100644 (file)
@@ -1,21 +1,23 @@
 /*
 /*
- * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1980, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-char *copyright =
-"@(#) Copyright (c) 1980 Regents of the University of California.\n\
- All rights reserved.\n";
-#endif not lint
+static char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
 
 #ifndef lint
 
 #ifndef lint
-static char *sccsid = "@(#)main.c      5.4 (Berkeley) %G%";
-#endif not lint
+static char sccsid[] = "@(#)main.c     8.1 (Berkeley) %G%";
+#endif /* not lint */
 
 #include "rcv.h"
 
 #include "rcv.h"
-#include <sys/stat.h>
+#include <fcntl.h>
+#include "extern.h"
 
 /*
  * Mail -- a mail program
 
 /*
  * Mail -- a mail program
@@ -25,114 +27,62 @@ static char *sccsid = "@(#)main.c  5.4 (Berkeley) %G%";
 
 jmp_buf        hdrjmp;
 
 
 jmp_buf        hdrjmp;
 
-/*
- * 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.
- *
- * Command line syntax:
- *     Mail [ -i ] [ -r address ] [ -h number ] [ -f [ name ] ]
- * or:
- *     Mail [ -i ] [ -r address ] [ -h number ] people ...
- */
-
+int
 main(argc, argv)
 main(argc, argv)
-       char **argv;
+       int argc;
+       char *argv[];
 {
 {
-       register char *ef;
-       register int i, argp;
-       int mustsend, hdrstop(), (*prevint)(), f;
-       struct sgttyb tbuf;
+       register int i;
+       struct name *to, *cc, *bcc, *smopts;
+       char *subject;
+       char *ef;
+       char nosrc = 0;
+       void hdrstop();
+       sig_t prevint;
+       void sigchild();
 
        /*
         * Set up a reasonable environment.
 
        /*
         * Set up a reasonable environment.
-        * Figure out whether we are being run interactively, set up
-        * all the temporary files, buffer standard output, and so forth.
+        * Figure out whether we are being run interactively,
+        * start the SIGCHLD catcher, and so forth.
         */
         */
-
-#ifdef GETHOST
-       inithost();
-#endif GETHOST
-       mypid = getpid();
-       intty = isatty(0);
-       outtty = isatty(1);
-       if (outtty) {
-               gtty(1, &tbuf);
-               baud = tbuf.sg_ospeed;
-       } else
-               baud = B9600;
+       (void) signal(SIGCHLD, sigchild);
+       if (isatty(0))
+               assign("interactive", "");
        image = -1;
        image = -1;
-
        /*
         * Now, determine how we are being used.
        /*
         * Now, determine how we are being used.
-        * We successively pick off instances of -r, -h, -f, and -i.
-        * If called as "rmail" we note this fact for letter sending.
+        * We successively pick off - flags.
         * If there is anything left, it is the base of the list
         * of users to mail to.  Argp will be set to point to the
         * first of these users.
         */
         * If there is anything left, it is the base of the list
         * of users to mail to.  Argp will be set to point to the
         * first of these users.
         */
-
        ef = NOSTR;
        ef = NOSTR;
-       argp = -1;
-       mustsend = 0;
-       if (argc > 0 && **argv == 'r')
-               rmail++;
-       for (i = 1; i < argc; i++) {
-
-               /*
-                * If current argument is not a flag, then the
-                * rest of the arguments must be recipients.
-                */
-
-               if (*argv[i] != '-') {
-                       argp = i;
-                       break;
-               }
-               switch (argv[i][1]) {
-               case 'r':
-                       /*
-                        * Next argument is address to be sent along
-                        * to the mailer.
-                        */
-                       if (i >= argc - 1) {
-                               fprintf(stderr, "Address required after -r\n");
-                               exit(1);
-                       }
-                       mustsend++;
-                       rflag = argv[i+1];
-                       i++;
-                       break;
-
+       to = NIL;
+       cc = NIL;
+       bcc = NIL;
+       smopts = NIL;
+       subject = NOSTR;
+       while ((i = getopt(argc, argv, "INT:b:c:dfins:u:v")) != EOF) {
+               switch (i) {
                case 'T':
                        /*
                         * Next argument is temp file to write which
                         * articles have been read/deleted for netnews.
                         */
                case 'T':
                        /*
                         * Next argument is temp file to write which
                         * articles have been read/deleted for netnews.
                         */
-                       if (i >= argc - 1) {
-                               fprintf(stderr, "Name required after -T\n");
-                               exit(1);
-                       }
-                       Tflag = argv[i+1];
-                       if ((f = creat(Tflag, 0600)) < 0) {
+                       Tflag = optarg;
+                       if ((i = creat(Tflag, 0600)) < 0) {
                                perror(Tflag);
                                exit(1);
                        }
                                perror(Tflag);
                                exit(1);
                        }
-                       close(f);
-                       i++;
+                       close(i);
                        break;
                        break;
-
                case 'u':
                        /*
                         * Next argument is person to pretend to be.
                         */
                case 'u':
                        /*
                         * Next argument is person to pretend to be.
                         */
-                       if (i >= argc - 1) {
-                               fprintf(stderr, "Missing user name for -u\n");
-                               exit(1);
-                       }
-                       strcpy(myname, argv[i+1]);
-                       i++;
+                       myname = optarg;
                        break;
                        break;
-
                case 'i':
                        /*
                         * User wants to ignore interrupts.
                case 'i':
                        /*
                         * User wants to ignore interrupts.
@@ -140,175 +90,146 @@ main(argc, argv)
                         */
                        assign("ignore", "");
                        break;
                         */
                        assign("ignore", "");
                        break;
-
                case 'd':
                        debug++;
                        break;
                case 'd':
                        debug++;
                        break;
-
-               case 'h':
-                       /*
-                        * Specified sequence number for network.
-                        * This is the number of "hops" made so
-                        * far (count of times message has been
-                        * forwarded) to help avoid infinite mail loops.
-                        */
-                       if (i >= argc - 1) {
-                               fprintf(stderr, "Number required for -h\n");
-                               exit(1);
-                       }
-                       mustsend++;
-                       hflag = atoi(argv[i+1]);
-                       if (hflag == 0) {
-                               fprintf(stderr, "-h needs non-zero number\n");
-                               exit(1);
-                       }
-                       i++;
-                       break;
-
                case 's':
                        /*
                         * Give a subject field for sending from
                         * non terminal
                         */
                case 's':
                        /*
                         * Give a subject field for sending from
                         * non terminal
                         */
-                       if (i >= argc - 1) {
-                               fprintf(stderr, "Subject req'd for -s\n");
-                               exit(1);
-                       }
-                       mustsend++;
-                       sflag = argv[i+1];
-                       i++;
+                       subject = optarg;
                        break;
                        break;
-
                case 'f':
                        /*
                         * User is specifying file to "edit" with Mail,
                         * as opposed to reading system mailbox.
                         * If no argument is given after -f, we read his
                case 'f':
                        /*
                         * User is specifying file to "edit" with Mail,
                         * as opposed to reading system mailbox.
                         * If no argument is given after -f, we read his
-                        * mbox file in his home directory.
+                        * mbox file.
+                        *
+                        * getopt() can't handle optional arguments, so here
+                        * is an ugly hack to get around it.
                         */
                         */
-                       if (i >= argc - 1)
-                               ef = mbox;
+                       if ((argv[optind]) && (argv[optind][0] != '-'))
+                               ef = argv[optind++];
                        else
                        else
-                               ef = argv[i + 1];
-                       i++;
+                               ef = "&";
                        break;
                        break;
-
                case 'n':
                        /*
                         * User doesn't want to source /usr/lib/Mail.rc
                         */
                        nosrc++;
                        break;
                case 'n':
                        /*
                         * User doesn't want to source /usr/lib/Mail.rc
                         */
                        nosrc++;
                        break;
-
                case 'N':
                        /*
                         * Avoid initial header printing.
                         */
                case 'N':
                        /*
                         * Avoid initial header printing.
                         */
-                       noheader++;
+                       assign("noheader", "");
                        break;
                        break;
-
                case 'v':
                        /*
                         * Send mailer verbose flag
                         */
                        assign("verbose", "");
                        break;
                case 'v':
                        /*
                         * Send mailer verbose flag
                         */
                        assign("verbose", "");
                        break;
-
                case 'I':
                        /*
                         * We're interactive
                         */
                case 'I':
                        /*
                         * We're interactive
                         */
-                       intty = 1;
+                       assign("interactive", "");
                        break;
                        break;
-
-               default:
-                       fprintf(stderr, "Unknown flag: %s\n", argv[i]);
+               case 'c':
+                       /*
+                        * Get Carbon Copy Recipient list
+                        */
+                       cc = cat(cc, nalloc(optarg, GCC));
+                       break;
+               case 'b':
+                       /*
+                        * Get Blind Carbon Copy Recipient list
+                        */
+                       bcc = cat(bcc, nalloc(optarg, GBCC));
+                       break;
+               case '?':
+                       fputs("\
+Usage: mail [-iInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\
+            [- sendmail-options ...]\n\
+       mail [-iInNv] -f [name]\n\
+       mail [-iInNv] [-u user]\n",
+                               stderr);
                        exit(1);
                }
        }
                        exit(1);
                }
        }
-
+       for (i = optind; (argv[i]) && (*argv[i] != '-'); i++)
+               to = cat(to, nalloc(argv[i], GTO));
+       for (; argv[i]; i++)
+               smopts = cat(smopts, nalloc(argv[i], 0));
        /*
         * Check for inconsistent arguments.
         */
        /*
         * Check for inconsistent arguments.
         */
-
-       if (ef != NOSTR && argp != -1) {
-               fprintf(stderr, "Cannot give -f and people to send to.\n");
+       if (to == NIL && (subject != NOSTR || cc != NIL || bcc != NIL)) {
+               fputs("You must specify direct recipients with -s, -c, or -b.\n", stderr);
                exit(1);
        }
                exit(1);
        }
-       if (mustsend && argp == -1) {
-               fprintf(stderr, "The flags you gave make no sense since you're not sending mail.\n");
+       if (ef != NOSTR && to != NIL) {
+               fprintf(stderr, "Cannot give -f and people to send to.\n");
                exit(1);
        }
        tinit();
        setscreensize();
        input = stdin;
                exit(1);
        }
        tinit();
        setscreensize();
        input = stdin;
-       rcvmode = argp == -1;
+       rcvmode = !to;
+       spreserve();
        if (!nosrc)
        if (!nosrc)
-               load(MASTER);
-       load(mailrc);
-       if (argp != -1) {
-               mail(&argv[argp]);
-
+               load(_PATH_MASTER_RC);
+       /*
+        * Expand returns a savestr, but load only uses the file name
+        * for fopen, so it's safe to do this.
+        */
+       load(expand("~/.mailrc"));
+       if (!rcvmode) {
+               mail(to, cc, bcc, smopts, subject);
                /*
                 * why wait?
                 */
                /*
                 * why wait?
                 */
-
                exit(senderr);
        }
                exit(senderr);
        }
-
        /*
         * Ok, we are reading mail.
         * Decide whether we are editing a mailbox or reading
         * the system mailbox, and open up the right stuff.
         */
        /*
         * Ok, we are reading mail.
         * Decide whether we are editing a mailbox or reading
         * the system mailbox, and open up the right stuff.
         */
-
-       if (ef != NOSTR) {
-               char *ename;
-
-               edit++;
-               ename = expand(ef);
-               if (ename != ef) {
-                       ef = malloc((unsigned) strlen(ename) + 1);
-                       strcpy(ef, ename);
-               }
-               editfile = ef;
-               strcpy(mailname, ef);
-       }
-       if (setfile(mailname, edit) < 0) {
-               if (edit)
-                       perror(mailname);
-               else
-                       fprintf(stderr, "No mail for %s\n", myname);
-               exit(1);
-       }
-       if (!noheader && value("noheader") == NOSTR) {
-               if (setjmp(hdrjmp) == 0) {
-                       if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
-                               signal(SIGINT, hdrstop);
-                       announce(!0);
-                       fflush(stdout);
-                       signal(SIGINT, prevint);
-               }
-       }
-       if (!edit && msgCount == 0) {
-               printf("No mail\n");
+       if (ef == NOSTR)
+               ef = "%";
+       if (setfile(ef) < 0)
+               exit(1);                /* error already reported */
+       if (setjmp(hdrjmp) == 0) {
+               extern char *version;
+
+               if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
+                       signal(SIGINT, hdrstop);
+               if (value("quiet") == NOSTR)
+                       printf("Mail version %s.  Type ? for help.\n",
+                               version);
+               announce();
                fflush(stdout);
                fflush(stdout);
-               exit(0);
+               signal(SIGINT, prevint);
        }
        commands();
        }
        commands();
-       if (!edit) {
-               signal(SIGHUP, SIG_IGN);
-               signal(SIGINT, SIG_IGN);
-               signal(SIGQUIT, SIG_IGN);
-               quit();
-       }
+       signal(SIGHUP, SIG_IGN);
+       signal(SIGINT, SIG_IGN);
+       signal(SIGQUIT, SIG_IGN);
+       quit();
        exit(0);
 }
 
 /*
  * Interrupt printing of the headers.
  */
        exit(0);
 }
 
 /*
  * Interrupt printing of the headers.
  */
-hdrstop()
+void
+hdrstop(signo)
+       int signo;
 {
 
        fflush(stdout);
 {
 
        fflush(stdout);
@@ -317,35 +238,33 @@ hdrstop()
 }
 
 /*
 }
 
 /*
- * Compute what the screen size should be.
+ * Compute what the screen size for printing headers should be.
  * We use the following algorithm for the height:
  *     If baud rate < 1200, use  9
  *     If baud rate = 1200, use 14
  *     If baud rate > 1200, use 24 or ws_row
  * Width is either 80 or ws_col;
  */
  * We use the following algorithm for the height:
  *     If baud rate < 1200, use  9
  *     If baud rate = 1200, use 14
  *     If baud rate > 1200, use 24 or ws_row
  * Width is either 80 or ws_col;
  */
+void
 setscreensize()
 {
 setscreensize()
 {
-#ifdef TIOCGWINSZ
+       struct sgttyb tbuf;
        struct winsize ws;
 
        struct winsize ws;
 
-       if (ioctl(fileno(stdout), TIOCGWINSZ, (char *) &ws) < 0)
+       if (ioctl(1, TIOCGWINSZ, (char *) &ws) < 0)
                ws.ws_col = ws.ws_row = 0;
                ws.ws_col = ws.ws_row = 0;
-#endif
-       if (baud < B1200)
+       if (ioctl(1, TIOCGETP, &tbuf) < 0)
+               tbuf.sg_ospeed = B9600;
+       if (tbuf.sg_ospeed < B1200)
                screenheight = 9;
                screenheight = 9;
-       else if (baud == B1200)
+       else if (tbuf.sg_ospeed == B1200)
                screenheight = 14;
                screenheight = 14;
-#ifdef TIOCGWINSZ
        else if (ws.ws_row != 0)
                screenheight = ws.ws_row;
        else if (ws.ws_row != 0)
                screenheight = ws.ws_row;
-#endif
        else
                screenheight = 24;
        else
                screenheight = 24;
-#ifdef TIOCGWINSZ
-       if (ws.ws_col != 0)
-               screenwidth = ws.ws_col;
-       else
-#endif
+       if ((realscreenheight = ws.ws_row) == 0)
+               realscreenheight = 24;
+       if ((screenwidth = ws.ws_col) == 0)
                screenwidth = 80;
 }
                screenwidth = 80;
 }