ignore -t in -bd mode
[unix-history] / usr / src / usr.sbin / sendmail / src / main.c
index f7b8678..f142636 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 1983 Eric P. Allman
+ * Copyright (c) 1983, 1995 Eric P. Allman
  * Copyright (c) 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
  * Copyright (c) 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
@@ -13,18 +13,15 @@ static char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)main.c     8.33 (Berkeley) %G%";
+static char sccsid[] = "@(#)main.c     8.123 (Berkeley) %G%";
 #endif /* not lint */
 
 #define        _DEFINE
 
 #include "sendmail.h"
 #endif /* not lint */
 
 #define        _DEFINE
 
 #include "sendmail.h"
-#include <sgtty.h>
-#ifdef NAMED_BIND
-#include <arpa/nameser.h>
+#if NAMED_BIND
 #include <resolv.h>
 #endif
 #include <resolv.h>
 #endif
-#include <pwd.h>
 
 # ifdef lint
 char   edata, end;
 
 # ifdef lint
 char   edata, end;
@@ -69,21 +66,17 @@ ENVELOPE    BlankEnvelope;  /* a "blank" envelope */
 ENVELOPE       MainEnvelope;   /* the envelope around the basic letter */
 ADDRESS                NullAddress =   /* a null address */
                { "", "", NULL, "" };
 ENVELOPE       MainEnvelope;   /* the envelope around the basic letter */
 ADDRESS                NullAddress =   /* a null address */
                { "", "", NULL, "" };
-char           *UserEnviron[MAXUSERENVIRON + 2];
-                               /* saved user environment */
-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           *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,8 +86,9 @@ 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 */
 
 
+int
 main(argc, argv, envp)
        int argc;
        char **argv;
 main(argc, argv, envp)
        int argc;
        char **argv;
@@ -103,7 +97,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)();
@@ -115,21 +108,24 @@ main(argc, argv, envp)
        bool warn_C_flag = FALSE;
        char warn_f_flag = '\0';
        static bool reenter = FALSE;
        bool warn_C_flag = FALSE;
        char warn_f_flag = '\0';
        static bool reenter = FALSE;
-       char *argv0 = argv[0];
        struct passwd *pw;
        struct stat stb;
        struct passwd *pw;
        struct stat stb;
+       struct hostent *hp;
        char jbuf[MAXHOSTNAMELEN];      /* holds MyHostName */
        char jbuf[MAXHOSTNAMELEN];      /* holds MyHostName */
+       static char rnamebuf[MAXNAME];  /* holds RealUserName */
        extern int DtableSize;
        extern int optind;
        extern time_t convtime();
        extern int DtableSize;
        extern int optind;
        extern time_t convtime();
-       extern putheader(), putbody();
        extern void intsig();
        extern void intsig();
-       extern char **myhostname();
+       extern struct hostent *myhostname();
        extern char *arpadate();
        extern char *getauthinfo();
        extern char *getcfname();
        extern char *optarg;
        extern char **environ;
        extern char *arpadate();
        extern char *getauthinfo();
        extern char *getcfname();
        extern char *optarg;
        extern char **environ;
+       extern void sigusr1();
+       extern void sighup();
+       extern void initmacros __P((ENVELOPE *));
 
        /*
        **  Check to see if we reentered.
 
        /*
        **  Check to see if we reentered.
@@ -147,7 +143,12 @@ main(argc, argv, envp)
        bool canrename;
 
        /* do machine-dependent initializations */
        bool canrename;
 
        /* do machine-dependent initializations */
-       init_md();
+       init_md(argc, argv);
+
+#ifdef SIGUSR1
+       /* arrange to dump state on user-1 signal */
+       setsignal(SIGUSR1, sigusr1);
+#endif
 
        /* in 4.4BSD, the table can be huge; impose a reasonable limit */
        DtableSize = getdtsize();
 
        /* in 4.4BSD, the table can be huge; impose a reasonable limit */
        DtableSize = getdtsize();
@@ -159,7 +160,7 @@ main(argc, argv, envp)
        **      But also be sure that 0, 1, & 2 are open.
        */
 
        **      But also be sure that 0, 1, & 2 are open.
        */
 
-       i = open("/dev/null", O_RDWR);
+       i = open("/dev/null", O_RDWR, 0);
        if (fstat(STDIN_FILENO, &stb) < 0 && errno != EOPNOTSUPP)
                (void) dup2(i, STDIN_FILENO);
        if (fstat(STDOUT_FILENO, &stb) < 0 && errno != EOPNOTSUPP)
        if (fstat(STDIN_FILENO, &stb) < 0 && errno != EOPNOTSUPP)
                (void) dup2(i, STDIN_FILENO);
        if (fstat(STDOUT_FILENO, &stb) < 0 && errno != EOPNOTSUPP)
@@ -177,12 +178,16 @@ main(argc, argv, envp)
        }
        errno = 0;
 
        }
        errno = 0;
 
-#ifdef LOG_MAIL
+#ifdef LOG
+# ifdef LOG_MAIL
        openlog("sendmail", LOG_PID, LOG_MAIL);
        openlog("sendmail", LOG_PID, LOG_MAIL);
-#else 
+# else 
        openlog("sendmail", LOG_PID);
        openlog("sendmail", LOG_PID);
+# 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;
@@ -201,25 +206,29 @@ main(argc, argv, envp)
        RealUid = getuid();
        RealGid = getgid();
 
        RealUid = getuid();
        RealGid = getgid();
 
-       pw = getpwuid(RealUid);
+       pw = sm_getpwuid(RealUid);
        if (pw != NULL)
        if (pw != NULL)
-               (void) strcpy(RealUserName, pw->pw_name);
+               (void) strcpy(rnamebuf, pw->pw_name);
        else
        else
-               (void) sprintf(RealUserName, "Unknown UID %d", RealUid);
+               (void) sprintf(rnamebuf, "Unknown UID %d", RealUid);
+       RealUserName = rnamebuf;
 
        /* save command line arguments */
        i = 0;
        for (av = argv; *av != NULL; )
                i += strlen(*av++) + 1;
 
        /* save command line arguments */
        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);
@@ -229,27 +238,86 @@ 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"
-#else
-# if defined(ultrix)
-#  define OPTIONS      "B:b:C:cd:e:F:f:h:IiM:mno:p:q:r:sTtvX:"
-# else
-#  define OPTIONS      "B:b:C:cd:e:F:f:h:Iimno:p:q:r:sTtvX:"
-# endif
+# define OPTIONS       "B:b:C:cd:e:F:f:h:IimnO:o:p:q:r:sTtvX:x"
+#endif
+#if defined(ultrix)
+# define OPTIONS       "B:b:C:cd:e:F:f:h:IiM:mnO:o:p:q:r:sTtvX:"
+#endif
+#if defined(sony_news)
+# define OPTIONS       "B:b:C:cd:E:e:F:f:h:IiJ:mnO:o:p:q:r:sTtvX:"
+#endif
+#ifndef OPTIONS
+# 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);
                        tTflag(optarg);
                        setbuf(stdout, (char *) NULL);
-                       printf("Version %s\n", Version);
                        break;
                }
        }
 
                        break;
                }
        }
 
+       if (tTd(0, 1))
+       {
+               int ll;
+               extern char *CompileOptions[];
+
+               printf("Version %s\nCompiled with:\t", Version);
+               av = CompileOptions;
+               ll = 7;
+               while (*av != NULL)
+               {
+                       if (ll + strlen(*av) > 63)
+                       {
+                               putchar('\n');
+                               ll = 0;
+                       }
+                       if (ll == 0)
+                       {
+                               putchar('\t');
+                               putchar('\t');
+                       }
+                       putchar(' ');
+                       printf("%s", *av);
+                       ll += strlen(*av++) + 1;
+               }
+               putchar('\n');
+       }
+       if (tTd(0, 10))
+       {
+               int ll;
+               extern char *OsCompileOptions[];
+
+               printf("OS Defines:\t", Version);
+               av = OsCompileOptions;
+               ll = 7;
+               while (*av != NULL)
+               {
+                       if (ll + strlen(*av) > 63)
+                       {
+                               putchar('\n');
+                               ll = 0;
+                       }
+                       if (ll == 0)
+                       {
+                               putchar('\t');
+                               putchar('\t');
+                       }
+                       putchar(' ');
+                       printf("%s", *av);
+                       ll += strlen(*av++) + 1;
+               }
+               putchar('\n');
+#ifdef _PATH_UNIX
+               printf("Unix path:\t  %s\n", _PATH_UNIX);
+#endif
+               printf("Config file:\t  %s\n", getcfname());
+               printf("Proc Id file:\t  %s\n", PidFile);
+       }
+
        InChannel = stdin;
        OutChannel = stdout;
 
        InChannel = stdin;
        OutChannel = stdout;
 
@@ -258,16 +326,16 @@ main(argc, argv, envp)
        **  the top of memory.
        */
 
        **  the top of memory.
        */
 
-       for (i = j = 0; j < MAXUSERENVIRON && (p = envp[i]) != NULL; i++)
-       {
-               if (strncmp(p, "FS=", 3) == 0 || strncmp(p, "LD_", 3) == 0)
-                       continue;
-               UserEnviron[j++] = newstr(p);
-       }
-       UserEnviron[j] = NULL;
-       environ = UserEnviron;
+       for (i = 0; envp[i] != NULL; i++)
+               continue;
+       environ = (char **) xalloc(sizeof (char *) * i);
+       for (i = 0; envp[i] != NULL; i++)
+               environ[i] = newstr(envp[i]);
+       environ[i] = NULL;
+
+       /* and prime the child environment */
+       setuserenv("AGENT", "sendmail");
 
 
-# ifdef SETPROCTITLE
        /*
        **  Save start and extent of argv for setproctitle.
        */
        /*
        **  Save start and extent of argv for setproctitle.
        */
@@ -277,21 +345,24 @@ 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);
        OpMode = MD_DELIVER;
        FullName = getenv("NAME");
 
        (void) setsignal(SIGTERM, intsig);
        (void) setsignal(SIGPIPE, SIG_IGN);
        OldUmask = umask(022);
        OpMode = MD_DELIVER;
        FullName = getenv("NAME");
 
-#ifdef NAMED_BIND
+#if NAMED_BIND
        if (tTd(8, 8))
        if (tTd(8, 8))
+       {
+               res_init();
+       {
+               res_init();
                _res.options |= RES_DEBUG;
                _res.options |= RES_DEBUG;
+       }
+       }
 #endif
 
        errno = 0;
 #endif
 
        errno = 0;
@@ -299,22 +370,22 @@ 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);
 
        /* hostname */
 
        /* version */
        define('v', Version, CurEnv);
 
        /* hostname */
-       av = myhostname(jbuf, sizeof jbuf);
+       hp = myhostname(jbuf, sizeof jbuf);
        if (jbuf[0] != '\0')
        {
                struct  utsname utsname;
 
                if (tTd(0, 4))
                        printf("canonical name: %s\n", jbuf);
        if (jbuf[0] != '\0')
        {
                struct  utsname utsname;
 
                if (tTd(0, 4))
                        printf("canonical name: %s\n", jbuf);
-               p = newstr(jbuf);
                define('w', newstr(jbuf), CurEnv);      /* must be new string */
                define('w', newstr(jbuf), CurEnv);      /* must be new string */
-               define('j', p, CurEnv);
-               setclass('w', p);
+               define('j', newstr(jbuf), CurEnv);
+               setclass('w', jbuf);
 
                p = strchr(jbuf, '.');
                if (p != NULL)
 
                p = strchr(jbuf, '.');
                if (p != NULL)
@@ -322,7 +393,6 @@ main(argc, argv, envp)
                        if (p[1] != '\0')
                        {
                                define('m', newstr(&p[1]), CurEnv);
                        if (p[1] != '\0')
                        {
                                define('m', newstr(&p[1]), CurEnv);
-                               setclass('m', &p[1]);
                        }
                        while (p != NULL && strchr(&p[1], '.') != NULL)
                        {
                        }
                        while (p != NULL && strchr(&p[1], '.') != NULL)
                        {
@@ -337,22 +407,46 @@ main(argc, argv, envp)
                        p = utsname.nodename;
                else
                {
                        p = utsname.nodename;
                else
                {
+                       if (tTd(0, 22))
+                               printf("uname failed (%s)\n", errstring(errno));
                        makelower(jbuf);
                        p = jbuf;
                }
                if (tTd(0, 4))
                        makelower(jbuf);
                        p = jbuf;
                }
                if (tTd(0, 4))
-                       printf("UUCP nodename: %s\n", p);
+                       printf(" UUCP nodename: %s\n", p);
                p = newstr(p);
                define('k', p, CurEnv);
                p = newstr(p);
                define('k', p, CurEnv);
+               setclass('k', p);
                setclass('w', p);
        }
                setclass('w', p);
        }
-       while (av != NULL && *av != NULL)
+       if (hp != NULL)
        {
        {
-               if (tTd(0, 4))
-                       printf("\ta.k.a.: %s\n", *av);
-               setclass('w', *av++);
+               for (av = hp->h_aliases; av != NULL && *av != NULL; av++)
+               {
+                       if (tTd(0, 4))
+                               printf("\ta.k.a.: %s\n", *av);
+                       setclass('w', *av);
+               }
+               if (hp->h_addrtype == AF_INET && hp->h_length == INADDRSZ)
+               {
+                       register int i;
+
+                       for (i = 0; hp->h_addr_list[i] != NULL; i++)
+                       {
+                               char ipbuf[100];
+
+                               sprintf(ipbuf, "[%s]",
+                                       inet_ntoa(*((struct in_addr *) hp->h_addr_list[i])));
+                               if (tTd(0, 4))
+                                       printf("\ta.k.a.: %s\n", ipbuf);
+                               setclass('w', ipbuf);
+                       }
+               }
        }
 
        }
 
+       /* probe interfaces and locate any additional names */
+       load_if_names();
+
        /* current time */
        define('b', arpadate((char *) NULL), CurEnv);
 
        /* current time */
        define('b', arpadate((char *) NULL), CurEnv);
 
@@ -409,6 +503,7 @@ main(argc, argv, envp)
                          case MD_TEST:
                          case MD_INITALIAS:
                          case MD_PRINT:
                          case MD_TEST:
                          case MD_INITALIAS:
                          case MD_PRINT:
+                         case MD_ARPAFTP:
                                OpMode = j;
                                break;
 
                                OpMode = j;
                                break;
 
@@ -425,7 +520,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) */
@@ -448,7 +547,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;
@@ -475,14 +574,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 */
@@ -519,6 +632,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)
@@ -543,9 +657,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;
 
@@ -563,6 +675,12 @@ 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(sony_news)
+                 case 'E':
+                 case 'J':     /* ignore flags for Japanese code conversion
+                                  impremented on Sony NEWS */
+                       break;
+# endif
 
                  default:
                        ExitStat = EX_USAGE;
 
                  default:
                        ExitStat = EX_USAGE;
@@ -578,7 +696,16 @@ main(argc, argv, envp)
        **      Extract special fields for local use.
        */
 
        **      Extract special fields for local use.
        */
 
+#ifdef XDEBUG
+       checkfd012("before readcf");
+#endif
+       vendor_pre_defaults(CurEnv);
        readcf(getcfname(), safecf, CurEnv);
        readcf(getcfname(), safecf, CurEnv);
+       vendor_post_defaults(CurEnv);
+
+       /* set up the $=m class now, after .cf has a chance to redefine $m */
+       expand("\201m", jbuf, sizeof jbuf, CurEnv);
+       setclass('m', jbuf);
 
        if (tTd(0, 1))
        {
 
        if (tTd(0, 1))
        {
@@ -594,6 +721,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.
        */
@@ -601,35 +746,22 @@ 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' && !wordinclass(RealUserName, 't'))
                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");
        else if (TimeZoneSpec[0] != '\0')
        /* Enforce use of local time (null string overrides this) */
        if (TimeZoneSpec == NULL)
                unsetenv("TZ");
        else if (TimeZoneSpec[0] != '\0')
-       {
-               char **evp = UserEnviron;
-               char tzbuf[100];
-
-               strcpy(tzbuf, "TZ=");
-               strcpy(&tzbuf[3], TimeZoneSpec);
-
-               while (*evp != NULL && strncmp(*evp, "TZ=", 3) != 0)
-                       evp++;
-               if (*evp == NULL)
-               {
-                       *evp++ = newstr(tzbuf);
-                       *evp = NULL;
-               }
-               else
-                       *evp++ = newstr(tzbuf);
-       }
+               setuserenv("TZ", TimeZoneSpec);
+       tzset();
 
        if (ConfigLevel > MAXCONFIGLEVEL)
        {
 
        if (ConfigLevel > MAXCONFIGLEVEL)
        {
@@ -640,42 +772,31 @@ 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))
-       {
-               struct stat stbuf;
-
-               /* 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 */
-
        switch (OpMode)
        {
        switch (OpMode)
        {
-         case MD_INITALIAS:
-               Verbose = TRUE;
-               break;
-
          case MD_DAEMON:
                /* remove things that don't make sense in daemon mode */
                FullName = NULL;
          case MD_DAEMON:
                /* remove things that don't make sense in daemon mode */
                FullName = NULL;
+               GrabTo = FALSE;
+
+               /* arrange to restart on hangup signal */
+               setsignal(SIGHUP, sighup);
                break;
 
                break;
 
-         case MD_SMTP:
-               if (RealUid != 0)
-                       auth_warning(CurEnv,
-                               "%s owned process doing -bs",
-                               RealUserName);
+         case MD_INITALIAS:
+               Verbose = TRUE;
+               /* fall through... */
+
+         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)
        {
@@ -692,8 +813,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);
@@ -709,13 +833,19 @@ main(argc, argv, envp)
        if (st == NULL)
                syserr("No prog mailer defined");
        else
        if (st == NULL)
                syserr("No prog mailer defined");
        else
+       {
                ProgMailer = st->s_mailer;
                ProgMailer = st->s_mailer;
+               clrbitn(M_MUSER, ProgMailer->m_flags);
+       }
 
        st = stab("*file*", ST_MAILER, ST_FIND);
        if (st == NULL)
                syserr("No *file* mailer defined");
        else
 
        st = stab("*file*", ST_MAILER, ST_FIND);
        if (st == NULL)
                syserr("No *file* mailer defined");
        else
+       {
                FileMailer = st->s_mailer;
                FileMailer = st->s_mailer;
+               clrbitn(M_MUSER, FileMailer->m_flags);
+       }
 
        st = stab("*include*", ST_MAILER, ST_FIND);
        if (st == NULL)
 
        st = stab("*include*", ST_MAILER, ST_FIND);
        if (st == NULL)
@@ -723,6 +853,36 @@ main(argc, argv, envp)
        else
                InclMailer = st->s_mailer;
 
        else
                InclMailer = st->s_mailer;
 
+       if (ConfigLevel < 6)
+       {
+               /* heuristic tweaking of local mailer for back compat */
+               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);
+
+               /* propogate some envariables into children */
+               setuserenv("ISP", NULL);
+               setuserenv("SYSTYPE", NULL);
+       }
+
+       /* MIME Content-Types that cannot be transfer encoded */
+       setclass('n', "multipart/signed");
+
+       /* MIME Content-Transfer-Encodings that can be encoded */
+       setclass('e', "7bit");
+       setclass('e', "8bit");
+       setclass('e', "binary");
 
        /* operate in queue directory */
        if (OpMode != MD_TEST && chdir(QueueDir) < 0)
 
        /* operate in queue directory */
        if (OpMode != MD_TEST && chdir(QueueDir) < 0)
@@ -731,6 +891,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)
        {
@@ -738,6 +915,10 @@ main(argc, argv, envp)
                exit(ExitStat);
        }
 
                exit(ExitStat);
        }
 
+#ifdef XDEBUG
+       checkfd012("before main() initmaps");
+#endif
+
        /*
        **  Do operation-mode-dependent initialization.
        */
        /*
        **  Do operation-mode-dependent initialization.
        */
@@ -763,6 +944,7 @@ main(argc, argv, envp)
                exit(EX_OK);
 
          case MD_DAEMON:
                exit(EX_OK);
 
          case MD_DAEMON:
+         case MD_SMTP:
                /* don't open alias database -- done in srvrsmtp */
                break;
 
                /* don't open alias database -- done in srvrsmtp */
                break;
 
@@ -775,35 +957,12 @@ main(argc, argv, envp)
        if (tTd(0, 15))
        {
                /* print configuration table (or at least part of it) */
        if (tTd(0, 15))
        {
                /* print configuration table (or at least part of it) */
-               printrules();
+               if (tTd(0, 90))
+                       printrules();
                for (i = 0; i < MAXMAILERS; i++)
                {
                for (i = 0; i < MAXMAILERS; i++)
                {
-                       register struct mailer *m = Mailer[i];
-                       int j;
-
-                       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");
+                       if (Mailer[i] != NULL)
+                               printmailer(Mailer[i]);
                }
        }
 
                }
        }
 
@@ -832,66 +991,19 @@ main(argc, argv, envp)
                }
                for (;;)
                {
                }
                for (;;)
                {
-                       register char **pvp;
-                       char *q;
-                       auto char *delimptr;
-                       extern bool invalidaddr();
-                       extern char *crackaddr();
+                       extern void testmodeline __P((char *, ENVELOPE *));
 
                        if (Verbose)
                                printf("> ");
                        (void) fflush(stdout);
                        if (fgets(buf, sizeof buf, stdin) == NULL)
                                finis();
 
                        if (Verbose)
                                printf("> ");
                        (void) fflush(stdout);
                        if (fgets(buf, sizeof buf, stdin) == NULL)
                                finis();
+                       p = strchr(buf, '\n');
+                       if (p != NULL)
+                               *p = '\0';
                        if (!Verbose)
                        if (!Verbose)
-                               printf("> %s", buf);
-                       switch (buf[0])
-                       {
-                         case '#':
-                               continue;
-
-#ifdef MAYBENEXTRELEASE
-                         case 'C':             /* try crackaddr */
-                               q = crackaddr(&buf[1]);
-                               xputs(q);
-                               printf("\n");
-                               continue;
-#endif
-                       }
-
-                       for (p = buf; isascii(*p) && isspace(*p); p++)
-                               continue;
-                       q = p;
-                       while (*p != '\0' && !(isascii(*p) && isspace(*p)))
-                               p++;
-                       if (*p == '\0')
-                       {
-                               printf("No address!\n");
-                               continue;
-                       }
-                       *p = '\0';
-                       if (invalidaddr(p + 1, NULL))
-                               continue;
-                       do
-                       {
-                               char pvpbuf[PSBUFSIZE];
-
-                               pvp = prescan(++p, ',', pvpbuf, &delimptr);
-                               if (pvp == NULL)
-                                       continue;
-                               p = q;
-                               while (*p != '\0')
-                               {
-                                       int stat;
-
-                                       stat = rewrite(pvp, atoi(p), CurEnv);
-                                       if (stat != EX_OK)
-                                               printf("== Ruleset %s status %d\n",
-                                                       p, stat);
-                                       while (*p != '\0' && *p++ != ',')
-                                               continue;
-                               }
-                       } while (*(p = delimptr) != '\0');
+                               printf("> %s\n", buf);
+                       testmodeline(buf, CurEnv);
                }
        }
 
                }
        }
 
@@ -920,7 +1032,7 @@ main(argc, argv, envp)
        {
                char dtype[200];
 
        {
                char dtype[200];
 
-               if (!tTd(0, 1))
+               if (!tTd(52, 100))
                {
                        /* put us in background */
                        i = fork();
                {
                        /* put us in background */
                        i = fork();
@@ -944,7 +1056,9 @@ main(argc, argv, envp)
                if (tTd(0, 1))
                        strcat(dtype, "+debugging");
 
                if (tTd(0, 1))
                        strcat(dtype, "+debugging");
 
+#ifdef LOG
                syslog(LOG_INFO, "starting daemon (%s): %s", Version, dtype + 1);
                syslog(LOG_INFO, "starting daemon (%s): %s", Version, dtype + 1);
+#endif
 #ifdef XLA
                xla_create_file();
 #endif
 #ifdef XLA
                xla_create_file();
 #endif
@@ -982,7 +1096,7 @@ main(argc, argv, envp)
        **  commands.  This will never return.
        */
 
        **  commands.  This will never return.
        */
 
-       if (OpMode == MD_SMTP)
+       if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
                smtp(CurEnv);
 # endif /* SMTP */
 
                smtp(CurEnv);
 # endif /* SMTP */
 
@@ -990,11 +1104,12 @@ main(argc, argv, envp)
        {
                CurEnv->e_sendmode = SM_VERIFY;
                CurEnv->e_errormode = EM_QUIET;
        {
                CurEnv->e_sendmode = SM_VERIFY;
                CurEnv->e_errormode = EM_QUIET;
+               PostMasterCopy = NULL;
        }
        else
        {
                /* interactive -- all errors are global */
        }
        else
        {
                /* interactive -- all errors are global */
-               CurEnv->e_flags |= EF_GLOBALERRS;
+               CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
        }
 
        /*
        }
 
        /*
@@ -1013,7 +1128,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();
        }
 
@@ -1035,7 +1150,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;
 
@@ -1076,12 +1191,18 @@ 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",
-                       ExitStat, CurEnv->e_flags,
+       {
+               extern void printenvflags();
+
+               printf("\n====finis: stat %d e_id=%s e_flags=",
+                       ExitStat,
                        CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
                        CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
+               printenvflags(CurEnv);
+       }
        if (tTd(2, 9))
                printopenfds(FALSE);
 
        if (tTd(2, 9))
                printopenfds(FALSE);
 
@@ -1102,7 +1223,7 @@ finis()
        if (LogLevel > 78)
                syslog(LOG_DEBUG, "finis, pid=%d", getpid());
 # endif /* LOG */
        if (LogLevel > 78)
                syslog(LOG_DEBUG, "finis, pid=%d", getpid());
 # endif /* LOG */
-       if (ExitStat == EX_TEMPFAIL)
+       if (ExitStat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET)
                ExitStat = EX_OK;
 
        /* reset uid for process accounting */
                ExitStat = EX_OK;
 
        /* reset uid for process accounting */
@@ -1180,6 +1301,7 @@ struct metamac    MetaMacros[] =
        '\0'
 };
 
        '\0'
 };
 
+void
 initmacros(e)
        register ENVELOPE *e;
 {
 initmacros(e)
        register ENVELOPE *e;
 {
@@ -1228,6 +1350,7 @@ initmacros(e)
 **             the controlling tty.
 */
 
 **             the controlling tty.
 */
 
+void
 disconnect(droplev, e)
        int droplev;
        register ENVELOPE *e;
 disconnect(droplev, e)
        int droplev;
        register ENVELOPE *e;
@@ -1237,14 +1360,13 @@ disconnect(droplev, e)
        if (tTd(52, 1))
                printf("disconnect: In %d Out %d, e=%x\n",
                        fileno(InChannel), fileno(OutChannel), e);
        if (tTd(52, 1))
                printf("disconnect: In %d Out %d, e=%x\n",
                        fileno(InChannel), fileno(OutChannel), e);
-       if (tTd(52, 5))
+       if (tTd(52, 100))
        {
                printf("don't\n");
                return;
        }
 
        /* be sure we don't get nasty signals */
        {
                printf("don't\n");
                return;
        }
 
        /* 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);
 
@@ -1252,6 +1374,7 @@ disconnect(droplev, e)
        HoldErrs = TRUE;
        CurEnv->e_errormode = EM_MAIL;
        Verbose = FALSE;
        HoldErrs = TRUE;
        CurEnv->e_errormode = EM_MAIL;
        Verbose = FALSE;
+       DisConnected = TRUE;
 
        /* all input from /dev/null */
        if (InChannel != stdin)
 
        /* all input from /dev/null */
        if (InChannel != stdin)
@@ -1303,7 +1426,8 @@ static void
 obsolete(argv)
        char *argv[];
 {
 obsolete(argv)
        char *argv[];
 {
-       char *ap;
+       register char *ap;
+       register char *op;
 
        while ((ap = *++argv) != NULL)
        {
 
        while ((ap = *++argv) != NULL)
        {
@@ -1311,10 +1435,22 @@ obsolete(argv)
                if (ap[0] != '-' || ap[1] == '-')
                        return;
 
                if (ap[0] != '-' || ap[1] == '-')
                        return;
 
+               /* skip over options that do have a value */
+               op = strchr(OPTIONS, ap[1]);
+               if (op != NULL && *++op == ':' && ap[2] == '\0' &&
+                   ap[1] != 'd' &&
+#if defined(sony_news)
+                   ap[1] != 'E' && ap[1] != 'J' &&
+#endif
+                   argv[1] != NULL && argv[1][0] != '-')
+               {
+                       argv++;
+                       continue;
+               }
+
                /* If -C doesn't have an argument, use sendmail.cf. */
 #define        __DEFPATH       "sendmail.cf"
                /* If -C doesn't have an argument, use sendmail.cf. */
 #define        __DEFPATH       "sendmail.cf"
-               if (ap[1] == 'C' && ap[2] == '\0' &&
-                   (argv[1] == NULL || argv[1][0] == '-'))
+               if (ap[1] == 'C' && ap[2] == '\0')
                {
                        *argv = xalloc(sizeof(__DEFPATH) + 2);
                        argv[0][0] = '-';
                {
                        *argv = xalloc(sizeof(__DEFPATH) + 2);
                        argv[0][0] = '-';
@@ -1323,14 +1459,22 @@ obsolete(argv)
                }
 
                /* If -q doesn't have an argument, run it once. */
                }
 
                /* If -q doesn't have an argument, run it once. */
-               if (ap[1] == 'q' && ap[2] == '\0' &&
-                   (argv[1] == NULL || argv[1][0] == '-'))
+               if (ap[1] == 'q' && ap[2] == '\0')
                        *argv = "-q0";
 
                /* if -d doesn't have an argument, use 0-99.1 */
                        *argv = "-q0";
 
                /* if -d doesn't have an argument, use 0-99.1 */
-               if (ap[1] == 'd' && ap[2] == '\0' &&
-                   (argv[1] == NULL || !isdigit(argv[1][0])))
+               if (ap[1] == 'd' && ap[2] == '\0')
                        *argv = "-d0-99.1";
                        *argv = "-d0-99.1";
+
+# if defined(sony_news)
+               /* if -E doesn't have an argument, use -EC */
+               if (ap[1] == 'E' && ap[2] == '\0')
+                       *argv = "-EC";
+
+               /* if -J doesn't have an argument, use -JJ */
+               if (ap[1] == 'J' && ap[2] == '\0')
+                       *argv = "-JJ";
+# endif
        }
 }
 \f/*
        }
 }
 \f/*
@@ -1362,7 +1506,7 @@ auth_warning(e, msg, va_alist)
        {
                register char *p;
                static char hostbuf[48];
        {
                register char *p;
                static char hostbuf[48];
-               extern char **myhostname();
+               extern struct hostent *myhostname();
 
                if (hostbuf[0] == '\0')
                        (void) myhostname(hostbuf, sizeof hostbuf);
 
                if (hostbuf[0] == '\0')
                        (void) myhostname(hostbuf, sizeof hostbuf);
@@ -1372,6 +1516,330 @@ 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);
+#if LOG
+               if (LogLevel > 3)
+                       syslog(LOG_INFO, "%s: Authentication-Warning: %s",
+                               e->e_id == NULL ? "[NOQUEUE]" : e->e_id, buf);
+#endif
        }
 }
        }
 }
+\f/*
+**  SETUSERENV -- set an environment in the propogated environment
+**
+**     Parameters:
+**             envar -- the name of the environment variable.
+**             value -- the value to which it should be set.  If
+**                     null, this is extracted from the incoming
+**                     environment.  If that is not set, the call
+**                     to setuserenv is ignored.
+**
+**     Returns:
+**             none.
+*/
+
+void
+setuserenv(envar, value)
+       const char *envar;
+       const char *value;
+{
+       int i;
+       char **evp = UserEnviron;
+       char *p;
+
+       if (value == NULL)
+       {
+               value = getenv(envar);
+               if (value == NULL)
+                       return;
+       }
+
+       i = strlen(envar);
+       p = (char *) xalloc(strlen(value) + i + 2);
+       strcpy(p, envar);
+       p[i++] = '=';
+       strcpy(&p[i], value);
+
+       while (*evp != NULL && strncmp(*evp, p, i) != 0)
+               evp++;
+       if (*evp != NULL)
+       {
+               *evp++ = p;
+       }
+       else if (evp < &UserEnviron[MAXUSERENVIRON])
+       {
+               *evp++ = p;
+               *evp = NULL;
+       }
+
+       /* make sure it is in our environment as well */
+       if (putenv(p) < 0)
+               syserr("setuserenv: putenv(%s) failed", p);
+}
+\f/*
+**  DUMPSTATE -- dump state
+**
+**     For debugging.
+*/
+
+void
+dumpstate(when)
+       char *when;
+{
+#ifdef LOG
+       register char *j = macvalue('j', CurEnv);
+
+       syslog(LOG_DEBUG, "--- dumping state on %s: $j = %s ---",
+               when,
+               j == NULL ? "<NULL>" : j);
+       if (j != NULL)
+       {
+               if (!wordinclass(j, 'w'))
+                       syslog(LOG_DEBUG, "*** $j not in $=w ***");
+       }
+       syslog(LOG_DEBUG, "--- open file descriptors: ---");
+       printopenfds(TRUE);
+       syslog(LOG_DEBUG, "--- connection cache: ---");
+       mci_dump_all(TRUE);
+       if (RewriteRules[89] != NULL)
+       {
+               int stat;
+               register char **pvp;
+               char *pv[MAXATOM + 1];
+
+               pv[0] = NULL;
+               stat = rewrite(pv, 89, 0, CurEnv);
+               syslog(LOG_DEBUG, "--- ruleset 89 returns stat %d, pv: ---",
+                       stat);
+               for (pvp = pv; *pvp != NULL; pvp++)
+                       syslog(LOG_DEBUG, "%s", *pvp);
+       }
+       syslog(LOG_DEBUG, "--- end of state dump ---");
+#endif
+}
+
+
+void
+sigusr1()
+{
+       dumpstate("user signal");
+}
+
+
+void
+sighup()
+{
+#ifdef LOG
+       if (LogLevel > 3)
+               syslog(LOG_INFO, "restarting %s on signal", SaveArgv[0]);
+#endif
+       execv(SaveArgv[0], (ARGV_T) SaveArgv);
+#ifdef LOG
+       if (LogLevel > 0)
+               syslog(LOG_ALERT, "could not exec %s: %m", SaveArgv[0]);
+#endif
+       exit(EX_OSFILE);
+}
+\f/*
+**  TESTMODELINE -- process a test mode input line
+**
+**     Parameters:
+**             line -- the input line.
+**             e -- the current environment.
+*/
+
+void
+testmodeline(line, e)
+       char *line;
+       ENVELOPE *e;
+{
+       register char *p;
+       char *q;
+       auto char *delimptr;
+       int mid;
+       ADDRESS a;
+       extern bool invalidaddr();
+       extern char *crackaddr();
+
+       switch (line[0])
+       {
+         case '#':
+               return;
+
+         case '.':             /* config-style settings */
+               switch (line[1])
+               {
+                 case 'D':
+                       mid = macid(&line[2], &delimptr);
+                       if (mid != '\0')
+                               define(mid, newstr(delimptr), e);
+                       break;
+
+                 case 'C':
+                       setclass(line[2], &line[3]);
+                       break;
+
+                 case 'S':             /* dump rule set */
+                       {
+                               int rs;
+                               struct rewrite *rw;
+                               STAB *s;
+
+                               if (line[2] == '\0')
+                                       return;
+                               s = stab(&line[2], ST_RULESET, ST_FIND);
+                               if (s == NULL)
+                               {
+                                       if (!isdigit(line[2]))
+                                               return;
+                                       rs = atoi(line+2);
+                               }
+                               else
+                                       rs = s->s_ruleset;
+                               if (rs < 0 || rs > MAXRWSETS)
+                                       return;
+                               if ((rw = RewriteRules[rs]) == NULL)
+                                       return;
+                               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", line);
+                       break;
+               }
+               return;
+
+         case '-':             /* set command-line-like opts */
+               switch (line[1])
+               {
+                 case 'd':
+                       tTflag(&line[2]);
+                       break;
+
+                 default:
+                       printf("Unknown \"-\" command %s", line);
+                       break;
+               }
+               return;
+
+         case '$':
+               mid = macid(&line[1], NULL);
+               if (mid == '\0')
+                       return;
+               p = macvalue(mid, e);
+               if (p == NULL)
+                       printf("Undefined\n");
+               else
+               {
+                       xputs(p);
+                       printf("\n");
+               }
+               return;
+
+         case '/':             /* miscellaneous commands */
+               p = &line[strlen(line)];
+               while (--p >= line && isascii(*p) && isspace(*p))
+                       *p = '\0';
+               p = strpbrk(line, " \t");
+               if (p != NULL)
+               {
+                       while (isascii(*p) && isspace(*p))
+                               *p++ = '\0';
+               }
+               else
+                       p = "";
+               if (strcasecmp(&line[1], "mx") == 0)
+               {
+#if NAMED_BIND
+                       /* look up MX records */
+                       int nmx;
+                       int i;
+                       auto int rcode;
+                       char *mxhosts[MAXMXHOSTS + 1];
+
+                       nmx = getmxrr(p, mxhosts, FALSE, &rcode);
+                       printf("getmxrr(%s) returns %d value(s):\n", p, nmx);
+                       for (i = 0; i < nmx; i++)
+                               printf("\t%s\n", mxhosts[i]);
+#else
+                       printf("No MX code compiled in\n");
+#endif
+               }
+               else if (strcasecmp(&line[1], "try") == 0)
+               {
+                       q = crackaddr(p);
+                       printf("Cracked address = ");
+                       xputs(q);
+                       printf("\n");
+                       if (parseaddr(p, &a, RF_COPYNONE, '\0', NULL, e) == NULL)
+                               printf("Cannot parse\n");
+                       else if (a.q_host != NULL && a.q_host[0] != '\0')
+                               printf("mailer %s, host %s, user %s\n",
+                                       a.q_mailer->m_name, a.q_host, a.q_user);
+                       else
+                               printf("mailer %s, user %s\n",
+                                       a.q_mailer->m_name, a.q_user);
+               }
+               else
+               {
+                       printf("Unknown test command %s\n", line);
+               }
+               return;
+       }
+
+       for (p = line; isascii(*p) && isspace(*p); p++)
+               continue;
+       q = p;
+       while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+               p++;
+       if (*p == '\0')
+       {
+               printf("No address!\n");
+               return;
+       }
+       *p = '\0';
+       if (invalidaddr(p + 1, NULL))
+               return;
+       do
+       {
+               register char **pvp;
+               char pvpbuf[PSBUFSIZE];
+
+               pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf,
+                             &delimptr, NULL);
+               if (pvp == NULL)
+                       continue;
+               p = q;
+               while (*p != '\0')
+               {
+                       int stat;
+
+                       stat = rewrite(pvp, atoi(p), 0, e);
+                       if (stat != EX_OK)
+                               printf("== Ruleset %s status %d\n",
+                                       p, stat);
+                       while (*p != '\0' && *p++ != ',')
+                               continue;
+               }
+       } while (*(p = delimptr) != '\0');
+}