LINT
[unix-history] / usr / src / usr.sbin / sendmail / src / main.c
index 5ddde24..8b85c5f 100644 (file)
@@ -1,11 +1,13 @@
+# define  _DEFINE
 # include <signal.h>
 # include <pwd.h>
 # include "sendmail.h"
 # include <signal.h>
 # include <pwd.h>
 # include "sendmail.h"
+# include <sys/stat.h>
 # ifdef LOG
 # include <syslog.h>
 # endif LOG
 
 # ifdef LOG
 # include <syslog.h>
 # endif LOG
 
-static char    SccsId[] = "@(#)main.c  3.23    %G%";
+static char    SccsId[] = "@(#)main.c  3.53    %G%";
 
 /*
 **  SENDMAIL -- Post mail to a set of destinations.
 
 /*
 **  SENDMAIL -- Post mail to a set of destinations.
@@ -40,7 +42,9 @@ static char   SccsId[] = "@(#)main.c  3.23    %G%";
 **             -Ffullname      Select what the full-name should be
 **                             listed as.
 **             -a              This mail should be in ARPANET std
 **             -Ffullname      Select what the full-name should be
 **                             listed as.
 **             -a              This mail should be in ARPANET std
-**                             format.
+**                             format (obsolete version).
+**             -am             Called from an FTP "MAIL" command.
+**             -af             Called from an FTP "MLFL" command.
 **             -n              Don't do aliasing.  This might be used
 **                             when delivering responses, for
 **                             instance.
 **             -n              Don't do aliasing.  This might be used
 **                             when delivering responses, for
 **                             instance.
@@ -72,6 +76,10 @@ static char  SccsId[] = "@(#)main.c  3.23    %G%";
 **                             front of messages.
 **             -v              Give blow-by-blow description of
 **                             everything that happens.
 **                             front of messages.
 **             -v              Give blow-by-blow description of
 **                             everything that happens.
+**             -t              Read "to" addresses from message.
+**                             Looks at To:, Cc:, and Bcc: lines.
+**             -I              Initialize the DBM alias files from
+**                             the text format files.
 **             -Cfilename      Use alternate configuration file.
 **             -Afilename      Use alternate alias file.
 **             -DXvalue        Define macro X to have value.
 **             -Cfilename      Use alternate configuration file.
 **             -Afilename      Use alternate alias file.
 **             -DXvalue        Define macro X to have value.
@@ -86,20 +94,6 @@ static char  SccsId[] = "@(#)main.c  3.23    %G%";
 **     Compilation Flags:
 **             LOG -- if set, everything is logged.
 **
 **     Compilation Flags:
 **             LOG -- if set, everything is logged.
 **
-**     Compilation Instructions:
-**             cc -c -O main.c conf.c deliver.c parse.c
-**             cc -n -s *.o -lS
-**             chown root a.out
-**             chmod 755 a.out
-**             mv a.out sendmail
-**
-**     Deficiencies:
-**             It ought to collect together messages that are
-**                     destined for a single host and send these
-**                     to the auxiliary mail server together.
-**             It should take "user at host" as three separate
-**                     parameters and combine them into one address.
-**
 **     Author:
 **             Eric Allman, UCB/INGRES
 */
 **     Author:
 **             Eric Allman, UCB/INGRES
 */
@@ -108,33 +102,8 @@ static char        SccsId[] = "@(#)main.c  3.23    %G%";
 
 
 
 
 
 
-int    ArpaMode;       /* specifies the ARPANET mode */
-bool   FromFlag;       /* from person is explicitly specified */
-bool   MailBack;       /* mail back response on error */
-bool   BerkNet;        /* called from BerkNet */
-bool   WriteBack;      /* write back response on error */
-bool   HasXscrpt;      /* if set, the transcript file exists */
-bool   NoAlias;        /* don't do aliasing */
-bool   ForceMail;      /* mail even if already sent a copy */
-bool   MeToo;          /* send to the sender also if in a group expansion */
-bool   SaveFrom;       /* save From lines on the front of messages */
-bool   IgnrDot;        /* if set, ignore dot when collecting mail */
-bool   SuprErrs;       /* supress errors if set */
-bool   Verbose;        /* set if blow-by-blow desired */
-int    Debug;          /* debug level */
-int    Errors;         /* count of errors */
-int    AliasLevel;     /* current depth of aliasing */
-char   InFileName[] = "/tmp/mailtXXXXXX";
-char   Transcript[] = "/tmp/mailxXXXXXX";
-ADDRESS        From;           /* the from person */
-char   *To;            /* the target person */
-int    HopCount;       /* hop count */
-int    ExitStat;       /* the exit status byte */
-HDR    *Header;        /* header list */
-long   CurTime;        /* current time */
-char   FromLine[80];   /* holds From line (UNIX style header) */
-int    NextMailer = 0; /* "free" index into Mailer struct */
-struct mailer  *Mailer[MAXMAILERS+1];  /* definition of mailers */
+int    NextMailer = 0;         /* "free" index into Mailer struct */
+static char    *FullName;      /* sender's full name */
 
 
 
 
 
 
@@ -146,36 +115,36 @@ main(argc, argv)
        char **argv;
 {
        register char *p;
        char **argv;
 {
        register char *p;
-       char *realname;
-       char *fullname = NULL;
        extern char *getlogin();
        char *locname;
        extern int finis();
        extern char Version[];
        char *from;
        typedef int (*fnptr)();
        extern char *getlogin();
        char *locname;
        extern int finis();
        extern char Version[];
        char *from;
        typedef int (*fnptr)();
-       char nbuf[MAXLINE];             /* holds full name */
-       struct passwd *pw;
-       extern char *arpadate();
-       char *cfname;
-       char *aliasname;
        register int i;
        register int i;
-       char pbuf[10];                  /* holds pid */
-       char tbuf[10];                  /* holds "current" time */
-       char cbuf[5];                   /* holds hop count */
-       char dbuf[30];                  /* holds ctime(tbuf) */
-       char ybuf[10];                  /* holds tty id */
+       bool verifyonly = FALSE;        /* only verify names */
+       bool safecf = TRUE;             /* this conf file is sys default */
+       char ibuf[30];                  /* holds HostName */
+       bool queuemode = FALSE;         /* process queue requests */
        bool aliasinit = FALSE;
        bool aliasinit = FALSE;
-       extern char *ttyname();
+       extern bool safefile();
+       STAB *st;
+       extern time_t convtime();
        bool canrename;
 
        bool canrename;
 
+       argv[argc] = NULL;
+       InChannel = stdin;
+       OutChannel = stdout;
        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                (void) signal(SIGINT, finis);
        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                (void) signal(SIGINT, finis);
+       if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+               (void) signal(SIGHUP, finis);
        (void) signal(SIGTERM, finis);
        (void) signal(SIGTERM, finis);
-       setbuf(stdout, (char *) NULL);
+       OldUmask = umask(0);
 # ifdef LOG
        openlog("sendmail", 0);
 # endif LOG
 # ifdef LOG
        openlog("sendmail", 0);
 # endif LOG
+       openxscrpt();
 # ifdef DEBUG
 # ifdef DEBUGFILE
        if ((i = open(DEBUGFILE, 1)) > 0)
 # ifdef DEBUG
 # ifdef DEBUGFILE
        if ((i = open(DEBUGFILE, 1)) > 0)
@@ -190,8 +159,6 @@ main(argc, argv)
 # endif
        errno = 0;
        from = NULL;
 # endif
        errno = 0;
        from = NULL;
-       cfname = CONFFILE;
-       aliasname = ALIASFILE;
 
        /*
        ** Crack argv.
 
        /*
        ** Crack argv.
@@ -224,7 +191,19 @@ main(argc, argv)
                        break;
 
                  case 'F':     /* set full name */
                        break;
 
                  case 'F':     /* set full name */
-                       fullname = &p[2];
+                       p += 2;
+                       if (*p == '\0')
+                       {
+                               p = *++argv;
+                               if (--argc <= 0 || *p == '-')
+                               {
+                                       syserr("Bad -F flag");
+                                       argc++;
+                                       argv--;
+                                       break;
+                               }
+                       }
+                       FullName = p;
                        break;
 
                  case 'h':     /* hop count */
                        break;
 
                  case 'h':     /* hop count */
@@ -254,18 +233,18 @@ main(argc, argv)
                                break;
 
                          case 'm':     /* mail back */
                                break;
 
                          case 'm':     /* mail back */
-                               MailBack++;
-                               openxscrpt();
+                               MailBack = TRUE;
+                               HoldErrs = TRUE;
                                break;
 
                          case 'e':     /* do berknet error processing */
                                break;
 
                          case 'e':     /* do berknet error processing */
-                               BerkNet++;
-                               openxscrpt();
+                               BerkNet = TRUE;
+                               HoldErrs = TRUE;
                                break;
 
                          case 'w':     /* write back (or mail) */
                                break;
 
                          case 'w':     /* write back (or mail) */
-                               WriteBack++;
-                               openxscrpt();
+                               WriteBack = TRUE;
+                               HoldErrs = TRUE;
                                break;
                        }
                        break;
                                break;
                        }
                        break;
@@ -275,26 +254,39 @@ main(argc, argv)
                        Debug = atoi(&p[2]);
                        if (Debug <= 0)
                                Debug = 1;
                        Debug = atoi(&p[2]);
                        if (Debug <= 0)
                                Debug = 1;
+                       setbuf(stdout, (char *) NULL);
                        printf("Version %s Debug %d\n", Version, Debug);
                        break;
 
                        printf("Version %s Debug %d\n", Version, Debug);
                        break;
 
-                 case 'D':     /* redefine internal macro */
+                 case 'M':     /* redefine internal macro */
                        define(p[2], &p[3]);
                        break;
 # endif DEBUG
 
                  case 'C':     /* select configuration file */
                        if (p[2] == '\0')
                        define(p[2], &p[3]);
                        break;
 # endif DEBUG
 
                  case 'C':     /* select configuration file */
                        if (p[2] == '\0')
-                               cfname = "sendmail.cf";
+                               ConfFile = "sendmail.cf";
                        else
                        else
-                               cfname = &p[2];
+                               ConfFile = &p[2];
+                       safecf = FALSE;
                        break;
 
                  case 'A':     /* select alias file */
                        if (p[2] == '\0')
                        break;
 
                  case 'A':     /* select alias file */
                        if (p[2] == '\0')
-                               aliasname = "aliases";
+                               AliasFile = "aliases";
                        else
                        else
-                               aliasname = &p[2];
+                               AliasFile = &p[2];
+                       break;
+
+                 case 'Q':     /* select queue dir */
+                       if (p[2] == '\0')
+                               AliasFile = "mqueue";
+                       else
+                               AliasFile = &p[2];
+                       break;
+
+                 case 'T':     /* set timeout interval */
+                       TimeOut = convtime(&p[2]);
                        break;
                
                  case 'n':     /* don't alias */
                        break;
                
                  case 'n':     /* don't alias */
@@ -304,6 +296,7 @@ main(argc, argv)
 # ifdef DBM
                  case 'I':     /* initialize alias DBM file */
                        aliasinit = TRUE;
 # ifdef DBM
                  case 'I':     /* initialize alias DBM file */
                        aliasinit = TRUE;
+                       Verbose = TRUE;
                        break;
 # endif DBM
 
                        break;
 # endif DBM
 
@@ -315,20 +308,16 @@ main(argc, argv)
                        IgnrDot++;
                        break;
 
                        IgnrDot++;
                        break;
 
+                 case 'V':     /* verify only */
+                       verifyonly = TRUE;
+                       break;
+
                  case 'a':     /* arpanet format */
                  case 'a':     /* arpanet format */
-                       switch (p[2])
+                       ArpaMode = TRUE;
+                       if (p[2] == 's')
                        {
                        {
-                         case 'f':     /* mail from file connection */
-                               ArpaMode = ARPA_FILE;
-                               break;
-
-                         case 'm':     /* mail over telnet connection */
-                               ArpaMode = ARPA_MAIL;
-                               break;
-
-                         default:
-                               ArpaMode = ARPA_OLD;
-                               break;
+                               /* running smtp */
+                               Smtp = TRUE;
                        }
                        break;
                
                        }
                        break;
                
@@ -340,6 +329,19 @@ main(argc, argv)
                        Verbose++;
                        break;
 
                        Verbose++;
                        break;
 
+                 case 't':     /* read recipients from message */
+                       GrabTo = TRUE;
+                       break;
+
+                 case 'D':     /* run as a daemon */
+                       Daemon = TRUE;
+                       /* explicit fall-through */
+
+                 case 'q':     /* run queue files at intervals */
+                       queuemode = TRUE;
+                       QueueIntvl = atoi(&p[1]);
+                       break;
+
                  default:
                        /* at Eric Schmidt's suggestion, this will not be an error....
                        syserr("Unknown flag %s", p);
                  default:
                        /* at Eric Schmidt's suggestion, this will not be an error....
                        syserr("Unknown flag %s", p);
@@ -349,58 +351,34 @@ main(argc, argv)
        }
 
        /*
        }
 
        /*
-       **  Read control file and initialize system macros.
-       **      Collect should be called first, so that the time
-       **      corresponds to the time that the messages starts
-       **      getting sent, rather than when it is first composed.
+       **  Read system control file.
+       **      Extract special fields for local use.
        */
 
        */
 
-       /* process id */
-       (void) sprintf(pbuf, "%d", getpid());
-       define('p', pbuf);
-
-       /* hop count */
-       (void) sprintf(cbuf, "%d", HopCount);
-       define('c', cbuf);
-
-       /* time as integer, unix time, arpa time */
-       (void) time(&CurTime);
-       (void) sprintf(tbuf, "%ld", &CurTime);
-       define('t', tbuf);
-       (void) strcpy(dbuf, ctime(&CurTime));
-       *index(dbuf, '\n') = '\0';
-       define('d', dbuf);
-       define('a', arpadate(dbuf));
-
-       /* version */
-       define('v', Version);
+       readcf(ConfFile, safecf);
+       initsys();
 
 
-       /* tty name */
-       p = ttyname(2);
-       if (p != NULL)
-       {
-               if (rindex(p, '/') != NULL)
-                       p = rindex(p, '/') + 1;
-               strcpy(ybuf, p);
-               define('y', ybuf);
-       }
-
-       readcf(cfname);
+       /* our name for SMTP codes */
+       (void) expand("$i", ibuf, &ibuf[sizeof ibuf - 1]);
+       HostName = ibuf;
 
 
-# ifndef V6
-       p = getenv("HOME");
-       if (p != NULL)
-       {
-               char cfbuf[60];
+       /* the indices of local and program mailers */
+       st = stab("local", ST_MAILER, ST_FIND);
+       if (st == NULL)
+               syserr("No local mailer defined");
+       else
+               LocalMailer = st->s_mailer;
+       st = stab("prog", ST_MAILER, ST_FIND);
+       if (st == NULL)
+               syserr("No prog mailer defined");
+       else
+               ProgMailer = st->s_mailer;
 
 
-               define('z', p);
-               (void) expand("$z/.mailcf", cfbuf, &cfbuf[sizeof cfbuf - 1]);
-               if (access(cfbuf, 2) == 0)
-                       readcf(cfbuf);
-       }
-# endif V6
+       /*
+       **  Initialize aliases.
+       */
 
 
-       initaliases(aliasname, aliasinit);
+       initaliases(AliasFile, aliasinit);
 # ifdef DBM
        if (aliasinit)
                exit(EX_OK);
 # ifdef DBM
        if (aliasinit)
                exit(EX_OK);
@@ -409,6 +387,7 @@ main(argc, argv)
 # ifdef DEBUG
        if (Debug > 15)
        {
 # ifdef DEBUG
        if (Debug > 15)
        {
+               /* print configuration table (or at least part of it) */
                printrules();
                for (i = 0; i < MAXMAILERS; i++)
                {
                printrules();
                for (i = 0; i < MAXMAILERS; i++)
                {
@@ -423,66 +402,38 @@ main(argc, argv)
 # endif DEBUG
 
        /*
 # endif DEBUG
 
        /*
-       locname = getname();
-       if (locname == NULL || locname[0] == '\0')
-       {
-               extern struct passwd *getpwuid();
-               int uid;
+       **  If a daemon, wait for a request.
+       **      getrequests will always return in a child.
+       */
 
 
-               uid = getuid();
-# ifdef V6
-               uid &= 0377;
-# endif
-               pw = getpwuid(uid);
-               if (pw == NULL)
-                       syserr("Who are you? (uid=%d)", uid);
-               else
-                       p = pw->pw_name;
-       }
-       else
+       if (Daemon)
+               getrequests();
+       
+       /*
+       if (Smtp)
        {
        {
-               extern struct passwd *getpwnam();
-
-               pw = getpwnam(p);
-               if (pw == NULL)
-                       syserr("Who are you? (name=%s)", p);
+               if (queuemode)
+                       runqueue(TRUE);
+               smtp();
        }
        }
-       if (p == NULL || p[0] == '\0' || pw == NULL)
-               finis();
 
 
-       realname = p;
+       /*
+       **  If collecting stuff from the queue, go start doing that.
+       */
 
 
-       /* extract full name from passwd file */
-       if ((fullname == NULL || fullname[0] == '\0') &&
-           pw != NULL && pw->pw_gecos != NULL)
+       if (queuemode)
        {
        {
-               register char *nb;
-
-               nb = nbuf;
-               p = pw->pw_gecos;
-               while (*p != '\0' && *p != ',' && *p != ';')
-               {
-                       if (*p == '&')
-                       {
-                               (void) strcpy(nb, realname);
-                               *nb = toupper(*nb);
-                               while (*nb != '\0')
-                                       nb++;
-                               p++;
-                       }
-                       else
-                               *nb++ = *p++;
-               }
-               *nb = '\0';
-               if (ArpaMode == ARPA_NONE && from == NULL && nbuf[0] != '\0')
-                       fullname = nbuf;
+               runqueue(FALSE);
+               finis();
        }
        }
-       if (fullname != NULL && fullname[0] != '\0')
-               define('x', fullname);
 
 
-       setfrom(from, realname);
+       /*
+       **  Set the sender
+       */
 
 
-       if (argc <= 0)
+       setsender(from);
+
+       if (!Daemon && argc <= 0 && !GrabTo)
                usrerr("Usage: /etc/sendmail [flags] addr...");
 
        /*
                usrerr("Usage: /etc/sendmail [flags] addr...");
 
        /*
@@ -497,69 +448,44 @@ main(argc, argv)
                syserr("Infinite forwarding loop (%s->%s)", From.q_paddr, *argv);
 
        /*
                syserr("Infinite forwarding loop (%s->%s)", From.q_paddr, *argv);
 
        /*
-       ** Scan argv and deliver the message to everyone.
+       **  Scan argv and deliver the message to everyone.
+       **      Actually, suppress delivery if we are taking To:
+       **      lines from the message.
        */
 
        */
 
-       for (; argc-- > 0; argv++)
-       {
-               p = argv[1];
-               if (argc >= 2 && p[2] == '\0' &&
-                   (p[0] == 'a' || p[0] == 'A') &&
-                   (p[1] == 't' || p[1] == 'T'))
-               {
-                       if (strlen(argv[0]) + strlen(argv[2]) + 2 > sizeof nbuf)
-                       {
-                               usrerr("address overflow");
-                               p = argv[0];
-                       }
-                       else
-                       {
-                               (void) strcpy(nbuf, argv[0]);
-                               (void) strcat(nbuf, "@");
-                               (void) strcat(nbuf, argv[2]);
-                               p = newstr(nbuf);
-                               argv += 2;
-                               argc -= 2;
-                       }
-               }
-               else
-                       p = argv[0];
-               sendto(p, 0);
-       }
+       if (GrabTo)
+               DontSend = TRUE;
+       sendtoargv(argv);
 
        /* if we have had errors sofar, drop out now */
        if (Errors > 0 && ExitStat == EX_OK)
                ExitStat = EX_USAGE;
 
        /* if we have had errors sofar, drop out now */
        if (Errors > 0 && ExitStat == EX_OK)
                ExitStat = EX_USAGE;
-       if (ArpaMode > ARPA_OLD && ExitStat != EX_OK)
-               finis();
-
-       /* no errors, tell arpanet to go ahead */
-       To = NULL;
-       if (ArpaMode == ARPA_MAIL)
-       {
-               extern char Arpa_Enter[];
-
-               message(Arpa_Enter, "Enter mail, end with \".\" on a line by itself");
-       }
-       errno = 0;
 
        /*
        **  Read the input mail.
        */
 
 
        /*
        **  Read the input mail.
        */
 
-       collect();
+       DontSend = FALSE;
+       To = NULL;
+       if (!verifyonly || GrabTo)
+               collect(FALSE);
+       errno = 0;
+       initsys();
 
 
-       (void) expand("$l", FromLine, &FromLine[sizeof FromLine - 1]);
-# ifdef DEBUG
-       if (Debug)
-               printf("From person = \"%s\"\n", From.q_paddr);
-# endif DEBUG
+       /* collect statistics */
+       Stat.stat_nf[From.q_mailer->m_mno]++;
+       Stat.stat_bf[From.q_mailer->m_mno] += kbytes(MsgSize);
 
        /*
        **  Arrange that the person who is sending the mail
        **  will not be expanded (unless explicitly requested).
        */
 
 
        /*
        **  Arrange that the person who is sending the mail
        **  will not be expanded (unless explicitly requested).
        */
 
+# ifdef DEBUG
+       if (Debug)
+               printf("From person = \"%s\"\n", From.q_paddr);
+# endif DEBUG
+
        From.q_flags |= QDONTSEND;
        if (!MeToo)
                recipient(&From);
        From.q_flags |= QDONTSEND;
        if (!MeToo)
                recipient(&From);
@@ -567,39 +493,18 @@ main(argc, argv)
 
        /*
        **  Actually send everything.
 
        /*
        **  Actually send everything.
+       **      If verifying, just ack.
        */
 
        */
 
-       for (i = 0; Mailer[i] != NULL; i++)
-       {
-               ADDRESS *q;
-
-               for (q = Mailer[i]->m_sendq; q != NULL; q = q->q_next)
-               {
-                       (void) deliver(q, (fnptr) NULL);
-               }
-       }
+       sendall(verifyonly);
 
        /*
        ** All done.
        */
 
        To = NULL;
 
        /*
        ** All done.
        */
 
        To = NULL;
-       if (Errors == 0)
-       {
-               switch (ArpaMode)
-               {
-                       static char *okmsg = "Mail accepted";
-                       extern char Arpa_Fmsg[], Arpa_Mmsg[];
-
-                 case ARPA_FILE:
-                       message(Arpa_Fmsg, okmsg);
-                       break;
-
-                 case ARPA_MAIL:
-                       message(Arpa_Mmsg, okmsg);
-                       break;
-               }
-       }
+       if (!verifyonly)
+               poststats(StatFile);
        finis();
 }
 \f/*
        finis();
 }
 \f/*
@@ -649,9 +554,18 @@ setfrom(from, realname)
 
        if (realname == NULL)
                realname = From.q_paddr;
 
        if (realname == NULL)
                realname = From.q_paddr;
+
+# ifdef DEBUG
+       if (Debug > 1)
+               printf("setfrom(%s, %s)\n", from, realname);
+# endif DEBUG
+
        if (from != NULL)
        {
                if (strcmp(realname, "network") != 0 && strcmp(realname, "uucp") != 0 &&
        if (from != NULL)
        {
                if (strcmp(realname, "network") != 0 && strcmp(realname, "uucp") != 0 &&
+# ifdef DEBUG
+                   (Debug == 0 || getuid() != geteuid()) &&
+# endif DEBUG
                    index(from, '!') == NULL && getuid() != 0)
                {
                        /* network sends -r regardless (why why why?) */
                    index(from, '!') == NULL && getuid() != 0)
                {
                        /* network sends -r regardless (why why why?) */
@@ -661,14 +575,19 @@ setfrom(from, realname)
        }
 
        SuprErrs = TRUE;
        }
 
        SuprErrs = TRUE;
-       if (from == NULL || parse(from, &From, 0) == NULL)
+       if (from == NULL || parse(from, &From, 1) == NULL)
        {
                from = newstr(realname);
        {
                from = newstr(realname);
-               (void) parse(from, &From, 0);
+               (void) parse(from, &From, 1);
        }
        else
                FromFlag = TRUE;
        SuprErrs = FALSE;
        }
        else
                FromFlag = TRUE;
        SuprErrs = FALSE;
+       From.q_uid = getuid();
+       From.q_gid = getgid();
+# ifndef V6
+       From.q_home = getenv("HOME");
+# endif V6
 
        /*
        **  Rewrite the from person to dispose of possible implicit
 
        /*
        **  Rewrite the from person to dispose of possible implicit
@@ -682,10 +601,7 @@ setfrom(from, realname)
                finis();
        }
        rewrite(pvp, 1);
                finis();
        }
        rewrite(pvp, 1);
-       frombuf[0] = '\0';
-       while (*pvp != NULL)
-               (void) strcat(frombuf, *pvp++);
-
+       cataddr(pvp, frombuf, sizeof frombuf);
        define('f', newstr(frombuf));
 }
 \f/*
        define('f', newstr(frombuf));
 }
 \f/*
@@ -699,25 +615,28 @@ setfrom(from, realname)
 **
 **     Side Effects:
 **             exits sendmail
 **
 **     Side Effects:
 **             exits sendmail
-**
-**     Called By:
-**             main
-**             via signal on interrupt.
-**
-**     Deficiencies:
-**             It may be that it should only remove the input
-**                     file if there have been no errors.
 */
 
 finis()
 {
 */
 
 finis()
 {
+# ifdef DEBUG
+       if (Debug > 2)
+               printf("\n====finis: stat %d\n", ExitStat);
+# endif DEBUG
+
        /* mail back the transcript on errors */
        if (ExitStat != EX_OK)
                savemail();
 
        /* mail back the transcript on errors */
        if (ExitStat != EX_OK)
                savemail();
 
-       if (HasXscrpt)
+       if (Transcript != NULL)
                (void) unlink(Transcript);
                (void) unlink(Transcript);
-       (void) unlink(InFileName);
+       if (QueueUp)
+       {
+               if (!QueueRun)
+                       queueup(InFileName);
+       }
+       else
+               (void) unlink(InFileName);
        exit(ExitStat);
 }
 \f/*
        exit(ExitStat);
 }
 \f/*
@@ -735,19 +654,175 @@ finis()
 **     Side Effects:
 **             Turns the standard output into a special file
 **                     somewhere.
 **     Side Effects:
 **             Turns the standard output into a special file
 **                     somewhere.
-**
-**     Called By:
-**             main
 */
 
 openxscrpt()
 {
        extern char *mktemp();
 */
 
 openxscrpt()
 {
        extern char *mktemp();
+       register char *p;
 
 
-       (void) mktemp(Transcript);
-       HasXscrpt++;
-       if (freopen(Transcript, "w", stdout) == NULL)
-               syserr("Can't create %s", Transcript);
-       (void) chmod(Transcript, 0600);
-       setbuf(stdout, (char *) NULL);
+       p = newstr(XcriptFile);
+       (void) mktemp(p);
+       Xscript = fopen(p, "w");
+       if (Xscript == NULL)
+       {
+               Xscript = stdout;
+               syserr("Can't create %s", p);
+       }
+       Transcript = p;
+       (void) chmod(p, 0600);
+}
+\f/*
+**  SETSENDER -- set sendmail's idea of the sender.
+**
+**     Parameters:
+**             from -- the person we would like to believe this
+**                     is from.
+**
+**     Returns:
+**             none.
+**
+**     Side Effects:
+**             Sets the idea of the sender.
+*/
+
+setsender(from)
+       char *from;
+{
+       register char *p;
+       extern char *getlogin();
+       register struct passwd *pw;
+       char *realname;
+       char cfbuf[40];
+
+       /*
+       **  Figure out the real user executing us.
+       **      Getlogin can return errno != 0 on non-errors.
+       */
+
+       if (!Smtp && !QueueRun)
+       {
+               errno = 0;
+               p = getlogin();
+               errno = 0;
+       }
+       else
+               p = from;
+       if (p != NULL)
+       {
+               extern struct passwd *getpwnam();
+
+               pw = getpwnam(p);
+               if (pw == NULL)
+               {
+                       if (!Smtp && !QueueRun)
+                               syserr("Who are you? (name=%s)", p);
+                       p = NULL;
+               }
+       }
+       if (p == NULL)
+       {
+               extern struct passwd *getpwuid();
+               int uid;
+
+               uid = getruid();
+               pw = getpwuid(uid);
+               if (pw == NULL)
+                       syserr("Who are you? (uid=%d)", uid);
+               else
+                       p = pw->pw_name;
+       }
+       if (p == NULL || p[0] == '\0' || pw == NULL)
+               finis();
+
+       realname = p;
+
+       /*
+       **  Process passwd file entry.
+       */
+
+       /* run user's .mailcf file */
+       define('z', pw->pw_dir);
+       (void) expand("$z/.mailcf", cfbuf, &cfbuf[sizeof cfbuf - 1]);
+       if (safefile(cfbuf, getruid(), S_IREAD))
+               readcf(cfbuf, FALSE);
+
+       /* extract full name from passwd file */
+       if ((FullName == NULL || FullName[0] == '\0') &&
+           pw != NULL && pw->pw_gecos != NULL)
+       {
+               char nbuf[MAXNAME];
+
+               buildfname(pw->pw_gecos, realname, nbuf);
+               if (nbuf[0] != '\0')
+                       FullName = newstr(nbuf);
+       }
+       if (FullName != NULL && FullName[0] != '\0')
+               define('x', FullName);
+
+       setfrom(from, realname);
+}
+\f/*
+**  INITSYS -- initialize instantiation of system
+**
+**     In Daemon mode, this is done in the child.
+**
+**     Parameters:
+**             none.
+**
+**     Returns:
+**             none.
+**
+**     Side Effects:
+**             Initializes the system macros, some global variables,
+**             etc.  In particular, the current time in various
+**             forms is set.
+*/
+
+initsys()
+{
+       static char cbuf[5];                    /* holds hop count */
+       static char dbuf[30];                   /* holds ctime(tbuf) */
+       static char pbuf[10];                   /* holds pid */
+       static char tbuf[10];                   /* holds "current" time */
+       static char ybuf[10];                   /* holds tty id */
+       register char *p;
+       extern char *ttyname();
+       extern char *arpadate();
+
+       /* convert timeout interval to absolute time */
+       TimeOut -= CurTime;
+       (void) time(&CurTime);
+       TimeOut += CurTime;
+
+       /* process id */
+       (void) sprintf(pbuf, "%d", getpid());
+       define('p', pbuf);
+
+       /* hop count */
+       (void) sprintf(cbuf, "%d", HopCount);
+       define('c', cbuf);
+
+       /* time as integer, unix time, arpa time */
+       (void) sprintf(tbuf, "%ld", &CurTime);
+       define('t', tbuf);
+       (void) strcpy(dbuf, ctime(&CurTime));
+       *index(dbuf, '\n') = '\0';
+       define('d', dbuf);
+       p =  newstr(arpadate(dbuf));
+       define('a', p);
+       define('b', p);
+
+       /* version */
+       define('v', Version);
+
+       /* tty name */
+       p = ttyname(2);
+       if (p != NULL)
+       {
+               if (rindex(p, '/') != NULL)
+                       p = rindex(p, '/') + 1;
+               strcpy(ybuf, p);
+               define('y', ybuf);
+       }
 }
 }