change call to expand() to be more rational (and consistent!)
[unix-history] / usr / src / usr.sbin / sendmail / src / main.c
index 5693a93..b9c60ec 100644 (file)
@@ -13,7 +13,7 @@ static char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)main.c     8.57 (Berkeley) %G%";
+static char sccsid[] = "@(#)main.c     8.91 (Berkeley) %G%";
 #endif /* not lint */
 
 #define        _DEFINE
 #endif /* not lint */
 
 #define        _DEFINE
@@ -21,7 +21,6 @@ static char sccsid[] = "@(#)main.c    8.57 (Berkeley) %G%";
 #include "sendmail.h"
 #include <netdb.h>
 #if NAMED_BIND
 #include "sendmail.h"
 #include <netdb.h>
 #if NAMED_BIND
-#include <arpa/nameser.h>
 #include <resolv.h>
 #endif
 #include <pwd.h>
 #include <resolv.h>
 #endif
 #include <pwd.h>
@@ -74,16 +73,15 @@ char                *UserEnviron[MAXUSERENVIRON + 2];
 char           RealUserName[256];      /* the actual user id on this host */
 char           *CommandLineArgs;       /* command line args for pid file */
 bool           Warn_Q_option = FALSE;  /* warn about Q option use */
 char           RealUserName[256];      /* the actual user id on this host */
 char           *CommandLineArgs;       /* command line args for pid file */
 bool           Warn_Q_option = FALSE;  /* warn about Q option use */
+char           **SaveArgv;     /* argument vector for re-execing */
 
 /*
 **  Pointers for setproctitle.
 **     This allows "ps" listings to give more useful information.
 */
 
 
 /*
 **  Pointers for setproctitle.
 **     This allows "ps" listings to give more useful information.
 */
 
-# ifdef SETPROCTITLE
 char           **Argv = NULL;          /* pointer to argument vector */
 char           *LastArgv = NULL;       /* end of argv */
 char           **Argv = NULL;          /* pointer to argument vector */
 char           *LastArgv = NULL;       /* end of argv */
-# endif /* SETPROCTITLE */
 
 static void    obsolete();
 
 
 static void    obsolete();
 
@@ -93,7 +91,7 @@ ERROR %%%%   Cannot have daemon mode without SMTP   %%%% ERROR
 #endif /* SMTP */
 #endif /* DAEMON */
 
 #endif /* SMTP */
 #endif /* DAEMON */
 
-#define MAXCONFIGLEVEL 5       /* highest config version level known */
+#define MAXCONFIGLEVEL 6       /* highest config version level known */
 
 main(argc, argv, envp)
        int argc;
 
 main(argc, argv, envp)
        int argc;
@@ -103,7 +101,6 @@ main(argc, argv, envp)
        register char *p;
        char **av;
        char *locname;
        register char *p;
        char **av;
        char *locname;
-       extern int finis();
        extern char Version[];
        char *ep, *from;
        typedef int (*fnptr)();
        extern char Version[];
        char *ep, *from;
        typedef int (*fnptr)();
@@ -132,6 +129,7 @@ main(argc, argv, envp)
        extern char *optarg;
        extern char **environ;
        extern void sigusr1();
        extern char *optarg;
        extern char **environ;
        extern void sigusr1();
+       extern void sighup();
 
        /*
        **  Check to see if we reentered.
 
        /*
        **  Check to see if we reentered.
@@ -151,8 +149,8 @@ main(argc, argv, envp)
        /* do machine-dependent initializations */
        init_md(argc, argv);
 
        /* do machine-dependent initializations */
        init_md(argc, argv);
 
-       /* arrange to dump state on signal */
 #ifdef SIGUSR1
 #ifdef SIGUSR1
+       /* arrange to dump state on user-1 signal */
        setsignal(SIGUSR1, sigusr1);
 #endif
 
        setsignal(SIGUSR1, sigusr1);
 #endif
 
@@ -192,6 +190,8 @@ main(argc, argv, envp)
 # endif
 #endif 
 
 # endif
 #endif 
 
+       tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
+
        /* set up the blank envelope */
        BlankEnvelope.e_puthdr = putheader;
        BlankEnvelope.e_putbody = putbody;
        /* set up the blank envelope */
        BlankEnvelope.e_puthdr = putheader;
        BlankEnvelope.e_putbody = putbody;
@@ -220,15 +220,18 @@ main(argc, argv, envp)
        i = 0;
        for (av = argv; *av != NULL; )
                i += strlen(*av++) + 1;
        i = 0;
        for (av = argv; *av != NULL; )
                i += strlen(*av++) + 1;
+       SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1));
        CommandLineArgs = xalloc(i);
        p = CommandLineArgs;
        CommandLineArgs = xalloc(i);
        p = CommandLineArgs;
-       for (av = argv; *av != NULL; )
+       for (av = argv, i = 0; *av != NULL; )
        {
        {
+               SaveArgv[i++] = newstr(*av);
                if (av != argv)
                        *p++ = ' ';
                strcpy(p, *av++);
                p += strlen(p);
        }
                if (av != argv)
                        *p++ = ' ';
                strcpy(p, *av++);
                p += strlen(p);
        }
+       SaveArgv[i] = NULL;
 
        /* Handle any non-getoptable constructions. */
        obsolete(argv);
 
        /* Handle any non-getoptable constructions. */
        obsolete(argv);
@@ -238,23 +241,19 @@ main(argc, argv, envp)
        */
 
 #if defined(__osf__) || defined(_AIX3)
        */
 
 #if defined(__osf__) || defined(_AIX3)
-# define OPTIONS       "B:b:C:cd:e:F:f:h:Iimno:p:q:r:sTtvX:x"
+# define OPTIONS       "B:b:C:cd:e:F:f:h:IimnO:o:p:q:r:sTtvX:x"
 #endif
 #if defined(ultrix)
 #endif
 #if defined(ultrix)
-# define OPTIONS       "B:b:C:cd:e:F:f:h:IiM:mno:p:q:r:sTtvX:"
-#endif
-#if defined(NeXT)
-# define OPTIONS       "B:b:C:cd:e:F:f:h:IimnOo:p:q:r:sTtvX:"
+# define OPTIONS       "B:b:C:cd:e:F:f:h:IiM:mnO:o:p:q:r:sTtvX:"
 #endif
 #ifndef OPTIONS
 #endif
 #ifndef OPTIONS
-# define OPTIONS       "B:b:C:cd:e:F:f:h:Iimno:p:q:r:sTtvX:"
+# define OPTIONS       "B:b:C:cd:e:F:f:h:IimnO:o:p:q:r:sTtvX:"
 #endif
        while ((j = getopt(argc, argv, OPTIONS)) != EOF)
        {
                switch (j)
                {
                  case 'd':
 #endif
        while ((j = getopt(argc, argv, OPTIONS)) != EOF)
        {
                switch (j)
                {
                  case 'd':
-                       tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
                        tTflag(optarg);
                        setbuf(stdout, (char *) NULL);
                        printf("Version %s\n", Version);
                        tTflag(optarg);
                        setbuf(stdout, (char *) NULL);
                        printf("Version %s\n", Version);
@@ -272,14 +271,13 @@ main(argc, argv, envp)
 
        for (i = j = 0; j < MAXUSERENVIRON && (p = envp[i]) != NULL; i++)
        {
 
        for (i = j = 0; j < MAXUSERENVIRON && (p = envp[i]) != NULL; i++)
        {
-               if (strncmp(p, "FS=", 3) == 0 || strncmp(p, "LD_", 3) == 0)
+               if (strncmp(p, "IFS=", 4) == 0 || strncmp(p, "LD_", 3) == 0)
                        continue;
                UserEnviron[j++] = newstr(p);
        }
        UserEnviron[j] = NULL;
        environ = UserEnviron;
 
                        continue;
                UserEnviron[j++] = newstr(p);
        }
        UserEnviron[j] = NULL;
        environ = UserEnviron;
 
-# ifdef SETPROCTITLE
        /*
        **  Save start and extent of argv for setproctitle.
        */
        /*
        **  Save start and extent of argv for setproctitle.
        */
@@ -289,12 +287,9 @@ main(argc, argv, envp)
                LastArgv = envp[i - 1] + strlen(envp[i - 1]);
        else
                LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
                LastArgv = envp[i - 1] + strlen(envp[i - 1]);
        else
                LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
-# endif /* SETPROCTITLE */
 
        if (setsignal(SIGINT, SIG_IGN) != SIG_IGN)
                (void) setsignal(SIGINT, intsig);
 
        if (setsignal(SIGINT, SIG_IGN) != SIG_IGN)
                (void) setsignal(SIGINT, intsig);
-       if (setsignal(SIGHUP, SIG_IGN) != SIG_IGN)
-               (void) setsignal(SIGHUP, intsig);
        (void) setsignal(SIGTERM, intsig);
        (void) setsignal(SIGPIPE, SIG_IGN);
        OldUmask = umask(022);
        (void) setsignal(SIGTERM, intsig);
        (void) setsignal(SIGPIPE, SIG_IGN);
        OldUmask = umask(022);
@@ -303,7 +298,13 @@ main(argc, argv, envp)
 
 #if NAMED_BIND
        if (tTd(8, 8))
 
 #if NAMED_BIND
        if (tTd(8, 8))
+       {
+               res_init();
+       {
+               res_init();
                _res.options |= RES_DEBUG;
                _res.options |= RES_DEBUG;
+       }
+       }
 #endif
 
        errno = 0;
 #endif
 
        errno = 0;
@@ -311,6 +312,7 @@ main(argc, argv, envp)
 
        /* initialize some macros, etc. */
        initmacros(CurEnv);
 
        /* initialize some macros, etc. */
        initmacros(CurEnv);
+       init_vendor_macros(CurEnv);
 
        /* version */
        define('v', Version, CurEnv);
 
        /* version */
        define('v', Version, CurEnv);
@@ -368,7 +370,7 @@ main(argc, argv, envp)
                                printf("\ta.k.a.: %s\n", *av);
                        setclass('w', *av);
                }
                                printf("\ta.k.a.: %s\n", *av);
                        setclass('w', *av);
                }
-               if (hp->h_addrtype == AF_INET && hp->h_length == IPADDRSIZE)
+               if (hp->h_addrtype == AF_INET && hp->h_length == INADDRSZ)
                {
                        register int i;
 
                {
                        register int i;
 
@@ -441,9 +443,7 @@ main(argc, argv, envp)
                          case MD_TEST:
                          case MD_INITALIAS:
                          case MD_PRINT:
                          case MD_TEST:
                          case MD_INITALIAS:
                          case MD_PRINT:
-#ifdef MAYBE_NEXT_RELEASE
                          case MD_ARPAFTP:
                          case MD_ARPAFTP:
-#endif
                                OpMode = j;
                                break;
 
                                OpMode = j;
                                break;
 
@@ -460,7 +460,11 @@ main(argc, argv, envp)
                        break;
 
                  case 'B':     /* body type */
                        break;
 
                  case 'B':     /* body type */
-                       CurEnv->e_bodytype = newstr(optarg);
+                       if (strcasecmp(optarg, "7bit") == 0 ||
+                           strcasecmp(optarg, "8bitmime") == 0)
+                               CurEnv->e_bodytype = newstr(optarg);
+                       else
+                               usrerr("Illegal body type %s", optarg);
                        break;
 
                  case 'C':     /* select configuration file (already done) */
                        break;
 
                  case 'C':     /* select configuration file (already done) */
@@ -483,7 +487,7 @@ main(argc, argv, envp)
                                ExitStat = EX_USAGE;
                                break;
                        }
                                ExitStat = EX_USAGE;
                                break;
                        }
-                       from = newstr(optarg);
+                       from = newstr(denlstring(optarg, TRUE, TRUE));
                        if (strcmp(RealUserName, from) != 0)
                                warn_f_flag = j;
                        break;
                        if (strcmp(RealUserName, from) != 0)
                                warn_f_flag = j;
                        break;
@@ -510,14 +514,28 @@ main(argc, argv, envp)
                        setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv);
                        break;
 
                        setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv);
                        break;
 
+                 case 'O':     /* set option (long form) */
+                       setoption(' ', optarg, FALSE, TRUE, CurEnv);
+                       break;
+
                  case 'p':     /* set protocol */
                        p = strchr(optarg, ':');
                        if (p != NULL)
                  case 'p':     /* set protocol */
                        p = strchr(optarg, ':');
                        if (p != NULL)
+                       {
                                *p++ = '\0';
                                *p++ = '\0';
+                               if (*p != '\0')
+                               {
+                                       ep = xalloc(strlen(p) + 1);
+                                       cleanstrcpy(ep, p, MAXNAME);
+                                       define('s', ep, CurEnv);
+                               }
+                       }
                        if (*optarg != '\0')
                        if (*optarg != '\0')
-                               define('r', newstr(optarg), CurEnv);
-                       if (p != NULL && *p != '\0')
-                               define('s', newstr(p), CurEnv);
+                       {
+                               ep = xalloc(strlen(optarg) + 1);
+                               cleanstrcpy(ep, optarg, MAXNAME);
+                               define('r', ep, CurEnv);
+                       }
                        break;
 
                  case 'q':     /* run queue files at intervals */
                        break;
 
                  case 'q':     /* run queue files at intervals */
@@ -554,6 +572,7 @@ main(argc, argv, envp)
                        break;
 
                  case 'X':     /* traffic log file */
                        break;
 
                  case 'X':     /* traffic log file */
+                       setgid(RealGid);
                        setuid(RealUid);
                        TrafficLogFile = fopen(optarg, "a");
                        if (TrafficLogFile == NULL)
                        setuid(RealUid);
                        TrafficLogFile = fopen(optarg, "a");
                        if (TrafficLogFile == NULL)
@@ -578,9 +597,7 @@ main(argc, argv, envp)
                        break;
 
                  case 'e':     /* error message disposition */
                        break;
 
                  case 'e':     /* error message disposition */
-# if defined(ultrix)
                  case 'M':     /* define macro */
                  case 'M':     /* define macro */
-# endif
                        setoption(j, optarg, FALSE, TRUE, CurEnv);
                        break;
 
                        setoption(j, optarg, FALSE, TRUE, CurEnv);
                        break;
 
@@ -598,10 +615,6 @@ main(argc, argv, envp)
                  case 'x':     /* random flag that OSF/1 & AIX mailx passes */
                        break;
 # endif
                  case 'x':     /* random flag that OSF/1 & AIX mailx passes */
                        break;
 # endif
-# if defined(NeXT)
-                 case 'O':     /* random flag that NeXT Mail.app passes */
-                       break;
-# endif
 
                  default:
                        ExitStat = EX_USAGE;
 
                  default:
                        ExitStat = EX_USAGE;
@@ -636,6 +649,24 @@ main(argc, argv, envp)
                printf("\n");
        }
 
                printf("\n");
        }
 
+       /*
+       **  Initialize name server if it is going to be used.
+       */
+
+#if NAMED_BIND
+       if (!bitset(RES_INIT, _res.options))
+               res_init();
+#endif
+
+       /*
+       **  Initialize name server if it is going to be used.
+       */
+
+#if NAMED_BIND
+       if (UseNameServer && !bitset(RES_INIT, _res.options))
+               res_init();
+#endif
+
        /*
        **  Process authorization warnings from command line.
        */
        /*
        **  Process authorization warnings from command line.
        */
@@ -643,14 +674,18 @@ main(argc, argv, envp)
        if (warn_C_flag)
                auth_warning(CurEnv, "Processed by %s with -C %s",
                        RealUserName, ConfFile);
        if (warn_C_flag)
                auth_warning(CurEnv, "Processed by %s with -C %s",
                        RealUserName, ConfFile);
-/*
-       if (warn_f_flag != '\0')
+       if (warn_f_flag != '\0' &&
+           ((st = stab(RealUserName, ST_CLASS, ST_FIND)) == NULL ||
+            !bitnset('t', st->s_class)))
                auth_warning(CurEnv, "%s set sender to %s using -%c",
                        RealUserName, from, warn_f_flag);
                auth_warning(CurEnv, "%s set sender to %s using -%c",
                        RealUserName, from, warn_f_flag);
-*/
        if (Warn_Q_option)
                auth_warning(CurEnv, "Processed from queue %s", QueueDir);
 
        if (Warn_Q_option)
                auth_warning(CurEnv, "Processed from queue %s", QueueDir);
 
+       /* supress error printing if errors mailed back or whatever */
+       if (CurEnv->e_errormode != EM_PRINT)
+               HoldErrs = TRUE;
+
        /* Enforce use of local time (null string overrides this) */
        if (TimeZoneSpec == NULL)
                unsetenv("TZ");
        /* Enforce use of local time (null string overrides this) */
        if (TimeZoneSpec == NULL)
                unsetenv("TZ");
@@ -682,35 +717,30 @@ main(argc, argv, envp)
        if (MeToo)
                BlankEnvelope.e_flags |= EF_METOO;
 
        if (MeToo)
                BlankEnvelope.e_flags |= EF_METOO;
 
-# ifdef QUEUE
-       if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
+       switch (OpMode)
        {
        {
-               struct stat stbuf;
+         case MD_DAEMON:
+               /* remove things that don't make sense in daemon mode */
+               FullName = NULL;
 
 
-               /* check to see if we own the queue directory */
-               if (stat(QueueDir, &stbuf) < 0)
-                       syserr("main: cannot stat %s", QueueDir);
-               if (stbuf.st_uid != RealUid)
-               {
-                       /* nope, really a botch */
-                       usrerr("You do not have permission to process the queue");
-                       exit (EX_NOPERM);
-               }
-       }
-# endif /* QUEUE */
+               /* arrange to restart on hangup signal */
+               setsignal(SIGHUP, sighup);
+               break;
 
 
-       switch (OpMode)
-       {
          case MD_INITALIAS:
                Verbose = TRUE;
          case MD_INITALIAS:
                Verbose = TRUE;
-               break;
+               /* fall through... */
 
 
-         case MD_DAEMON:
-               /* remove things that don't make sense in daemon mode */
-               FullName = NULL;
+         default:
+               /* arrange to exit cleanly on hangup signal */
+               setsignal(SIGHUP, intsig);
                break;
        }
 
                break;
        }
 
+       /* full names can't have newlines */
+       if (FullName != NULL && strchr(FullName, '\n') != NULL)
+               FullName = newstr(denlstring(FullName, TRUE, TRUE));
+
        /* do heuristic mode adjustment */
        if (Verbose)
        {
        /* do heuristic mode adjustment */
        if (Verbose)
        {
@@ -727,8 +757,11 @@ main(argc, argv, envp)
        }
 
        /* our name for SMTP codes */
        }
 
        /* our name for SMTP codes */
-       expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
+       expand("\201j", jbuf, sizeof jbuf, CurEnv);
        MyHostName = jbuf;
        MyHostName = jbuf;
+       if (strchr(jbuf, '.') == NULL)
+               message("WARNING: local host name (%s) is not qualified; fix $j in config file",
+                       jbuf);
 
        /* make certain that this name is part of the $=w class */
        setclass('w', MyHostName);
 
        /* make certain that this name is part of the $=w class */
        setclass('w', MyHostName);
@@ -758,6 +791,30 @@ main(argc, argv, envp)
        else
                InclMailer = st->s_mailer;
 
        else
                InclMailer = st->s_mailer;
 
+       /* heuristic tweaking of local mailer for back compat */
+       if (ConfigLevel < 6)
+       {
+               if (LocalMailer != NULL)
+               {
+                       setbitn(M_ALIASABLE, LocalMailer->m_flags);
+                       setbitn(M_HASPWENT, LocalMailer->m_flags);
+                       setbitn(M_TRYRULESET5, LocalMailer->m_flags);
+                       setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);
+                       setbitn(M_CHECKPROG, LocalMailer->m_flags);
+                       setbitn(M_CHECKFILE, LocalMailer->m_flags);
+                       setbitn(M_CHECKUDB, LocalMailer->m_flags);
+               }
+               if (ProgMailer != NULL)
+                       setbitn(M_RUNASRCPT, ProgMailer->m_flags);
+               if (FileMailer != NULL)
+                       setbitn(M_RUNASRCPT, FileMailer->m_flags);
+       }
+
+       /* initialize standard MIME classes */
+       setclass('n', "message/rfc822");
+       setclass('n', "message/partial");
+       setclass('n', "message/external-body");
+       setclass('n', "multipart/signed");
 
        /* operate in queue directory */
        if (OpMode != MD_TEST && chdir(QueueDir) < 0)
 
        /* operate in queue directory */
        if (OpMode != MD_TEST && chdir(QueueDir) < 0)
@@ -766,6 +823,23 @@ main(argc, argv, envp)
                ExitStat = EX_SOFTWARE;
        }
 
                ExitStat = EX_SOFTWARE;
        }
 
+# ifdef QUEUE
+       if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
+       {
+               struct stat stbuf;
+
+               /* check to see if we own the queue directory */
+               if (stat(".", &stbuf) < 0)
+                       syserr("main: cannot stat %s", QueueDir);
+               if (stbuf.st_uid != RealUid)
+               {
+                       /* nope, really a botch */
+                       usrerr("You do not have permission to process the queue");
+                       exit (EX_NOPERM);
+               }
+       }
+# endif /* QUEUE */
+
        /* if we've had errors so far, exit now */
        if (ExitStat != EX_OK && OpMode != MD_TEST)
        {
        /* if we've had errors so far, exit now */
        if (ExitStat != EX_OK && OpMode != MD_TEST)
        {
@@ -822,27 +896,7 @@ main(argc, argv, envp)
 
                        if (m == NULL)
                                continue;
 
                        if (m == NULL)
                                continue;
-                       printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld F=", i, m->m_name,
-                               m->m_mailer, m->m_se_rwset, m->m_sh_rwset,
-                               m->m_re_rwset, m->m_rh_rwset, m->m_maxsize);
-                       for (j = '\0'; j <= '\177'; j++)
-                               if (bitnset(j, m->m_flags))
-                                       (void) putchar(j);
-                       printf(" E=");
-                       xputs(m->m_eol);
-                       if (m->m_argv != NULL)
-                       {
-                               char **a = m->m_argv;
-
-                               printf(" A=");
-                               while (*a != NULL)
-                               {
-                                       if (a != m->m_argv)
-                                               printf(" ");
-                                       xputs(*a++);
-                               }
-                       }
-                       printf("\n");
+                       printmailer(m);
                }
        }
 
                }
        }
 
@@ -889,13 +943,91 @@ main(argc, argv, envp)
                          case '#':
                                continue;
 
                          case '#':
                                continue;
 
-#ifdef MAYBENEXTRELEASE
-                         case 'C':             /* try crackaddr */
+                         case '?':             /* try crackaddr */
                                q = crackaddr(&buf[1]);
                                xputs(q);
                                printf("\n");
                                continue;
                                q = crackaddr(&buf[1]);
                                xputs(q);
                                printf("\n");
                                continue;
-#endif
+
+                         case '.':             /* config-style settings */
+                               switch (buf[1])
+                               {
+                                 case 'D':
+                                       define(buf[2], newstr(&buf[3]), CurEnv);
+                                       break;
+
+                                 case 'C':
+                                       setclass(buf[2], &buf[3]);
+                                       break;
+
+                                 case 'S':             /* dump rule set */
+                                       {
+                                               int rs;
+                                               struct rewrite *rw;
+                                               char *cp;
+                                               STAB *s;
+
+                                               if ((cp = strchr(buf, '\n')) != NULL)
+                                                       *cp = '\0';
+                                               if (cp == buf+2)
+                                                       continue;
+                                               s = stab(buf+2, ST_RULESET, ST_FIND);
+                                               if (s == NULL)
+                                               {
+                                                       if (!isdigit(buf[2]))
+                                                               continue;
+                                                       rs = atoi(buf+2);
+                                               }
+                                               else
+                                                       rs = s->s_ruleset;
+                                               if (rs < 0 || rs > MAXRWSETS)
+                                                       continue;
+                                               if ((rw = RewriteRules[rs]) == NULL)
+                                                       continue;
+                                               do
+                                               {
+                                                       char **s;
+                                                       putchar('R');
+                                                       s = rw->r_lhs;
+                                                       while (*s != NULL)
+                                                       {
+                                                               xputs(*s++);
+                                                               putchar(' ');
+                                                       }
+                                                       putchar('\t');
+                                                       putchar('\t');
+                                                       s = rw->r_rhs;
+                                                       while (*s != NULL)
+                                                       {
+                                                               xputs(*s++);
+                                                               putchar(' ');
+                                                       }
+                                                       putchar('\n');
+                                               } while (rw = rw->r_next);
+                                       }
+                                       break;
+
+                                 default:
+                                       printf("Unknown config command %s", buf);
+                                       break;
+                               }
+                               continue;
+
+                         case '-':             /* set command-line-like opts */
+                               switch (buf[1])
+                               {
+                                 case 'd':
+                                       if (buf[2] == '\n')
+                                               tTflag("");
+                                       else
+                                               tTflag(&buf[2]);
+                                       break;
+
+                                 default:
+                                       printf("Unknown \"-\" command %s", buf);
+                                       break;
+                               }
+                               continue;
                        }
 
                        for (p = buf; isascii(*p) && isspace(*p); p++)
                        }
 
                        for (p = buf; isascii(*p) && isspace(*p); p++)
@@ -1036,7 +1168,7 @@ main(argc, argv, envp)
        else
        {
                /* interactive -- all errors are global */
        else
        {
                /* interactive -- all errors are global */
-               CurEnv->e_flags |= EF_GLOBALERRS;
+               CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
        }
 
        /*
        }
 
        /*
@@ -1055,7 +1187,7 @@ main(argc, argv, envp)
 
                /* collect body for UUCP return */
                if (OpMode != MD_VERIFY)
 
                /* collect body for UUCP return */
                if (OpMode != MD_VERIFY)
-                       collect(FALSE, FALSE, CurEnv);
+                       collect(InChannel, FALSE, FALSE, NULL, CurEnv);
                finis();
        }
 
                finis();
        }
 
@@ -1077,7 +1209,7 @@ main(argc, argv, envp)
        if (OpMode != MD_VERIFY || GrabTo)
        {
                CurEnv->e_flags |= EF_GLOBALERRS;
        if (OpMode != MD_VERIFY || GrabTo)
        {
                CurEnv->e_flags |= EF_GLOBALERRS;
-               collect(FALSE, FALSE, CurEnv);
+               collect(InChannel, FALSE, FALSE, NULL, CurEnv);
        }
        errno = 0;
 
        }
        errno = 0;
 
@@ -1118,10 +1250,11 @@ main(argc, argv, envp)
 **             exits sendmail
 */
 
 **             exits sendmail
 */
 
+void
 finis()
 {
        if (tTd(2, 1))
 finis()
 {
        if (tTd(2, 1))
-               printf("\n====finis: stat %d e_flags %o, e_id=%s\n",
+               printf("\n====finis: stat %d e_flags %x, e_id=%s\n",
                        ExitStat, CurEnv->e_flags,
                        CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
        if (tTd(2, 9))
                        ExitStat, CurEnv->e_flags,
                        CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
        if (tTd(2, 9))
@@ -1286,7 +1419,6 @@ disconnect(droplev, e)
        }
 
        /* be sure we don't get nasty signals */
        }
 
        /* be sure we don't get nasty signals */
-       (void) setsignal(SIGHUP, SIG_IGN);
        (void) setsignal(SIGINT, SIG_IGN);
        (void) setsignal(SIGQUIT, SIG_IGN);
 
        (void) setsignal(SIGINT, SIG_IGN);
        (void) setsignal(SIGQUIT, SIG_IGN);
 
@@ -1422,7 +1554,7 @@ auth_warning(e, msg, va_alist)
                VA_START(msg);
                vsprintf(p, msg, ap);
                VA_END;
                VA_START(msg);
                vsprintf(p, msg, ap);
                VA_END;
-               addheader("X-Authentication-Warning", buf, e);
+               addheader("X-Authentication-Warning", buf, &e->e_header);
        }
 }
 \f/*
        }
 }
 \f/*
@@ -1437,15 +1569,13 @@ dumpstate(when)
 {
 #ifdef LOG
        register char *j = macvalue('j', CurEnv);
 {
 #ifdef LOG
        register char *j = macvalue('j', CurEnv);
-       register STAB *s;
 
        syslog(LOG_DEBUG, "--- dumping state on %s: $j = %s ---",
                when,
                j == NULL ? "<NULL>" : j);
        if (j != NULL)
        {
 
        syslog(LOG_DEBUG, "--- dumping state on %s: $j = %s ---",
                when,
                j == NULL ? "<NULL>" : j);
        if (j != NULL)
        {
-               s = stab(j, ST_CLASS, ST_FIND);
-               if (s == NULL || !bitnset('w', s->s_class))
+               if (!wordinclass(j, 'w'))
                        syslog(LOG_DEBUG, "*** $j not in $=w ***");
        }
        syslog(LOG_DEBUG, "--- open file descriptors: ---");
                        syslog(LOG_DEBUG, "*** $j not in $=w ***");
        }
        syslog(LOG_DEBUG, "--- open file descriptors: ---");
@@ -1475,3 +1605,19 @@ sigusr1()
 {
        dumpstate("user signal");
 }
 {
        dumpstate("user signal");
 }
+
+
+void
+sighup()
+{
+#ifdef LOG
+       if (LogLevel > 3)
+               syslog(LOG_INFO, "restarting %s on signal", SaveArgv[0]);
+#endif
+       execv(SaveArgv[0], SaveArgv);
+#ifdef LOG
+       if (LogLevel > 0)
+               syslog(LOG_ALERT, "could not exec %s: %m", SaveArgv[0]);
+#endif
+       exit(EX_OSFILE);
+}