home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / sendmail / src / readcf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  19.2 KB  |  950 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  *    This product includes software developed by the University of
  17.  *    California, Berkeley and its contributors.
  18.  * 4. Neither the name of the University nor the names of its contributors
  19.  *    may be used to endorse or promote products derived from this software
  20.  *    without specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  */
  34.  
  35. #ifndef lint
  36. static char sccsid[] = "@(#)readcf.c    5.22 (Berkeley) 3/12/91";
  37. #endif /* not lint */
  38.  
  39. # include "sendmail.h"
  40.  
  41. /*
  42. **  READCF -- read control file.
  43. **
  44. **    This routine reads the control file and builds the internal
  45. **    form.
  46. **
  47. **    The file is formatted as a sequence of lines, each taken
  48. **    atomically.  The first character of each line describes how
  49. **    the line is to be interpreted.  The lines are:
  50. **        Dxval        Define macro x to have value val.
  51. **        Cxword        Put word into class x.
  52. **        Fxfile [fmt]    Read file for lines to put into
  53. **                class x.  Use scanf string 'fmt'
  54. **                or "%s" if not present.  Fmt should
  55. **                only produce one string-valued result.
  56. **        Hname: value    Define header with field-name 'name'
  57. **                and value as specified; this will be
  58. **                macro expanded immediately before
  59. **                use.
  60. **        Sn        Use rewriting set n.
  61. **        Rlhs rhs    Rewrite addresses that match lhs to
  62. **                be rhs.
  63. **        Mn arg=val...    Define mailer.  n is the internal name.
  64. **                Args specify mailer parameters.
  65. **        Oxvalue        Set option x to value.
  66. **        Pname=value    Set precedence name to value.
  67. **
  68. **    Parameters:
  69. **        cfname -- control file name.
  70. **
  71. **    Returns:
  72. **        none.
  73. **
  74. **    Side Effects:
  75. **        Builds several internal tables.
  76. */
  77.  
  78. readcf(cfname)
  79.     char *cfname;
  80. {
  81.     FILE *cf;
  82.     int ruleset = 0;
  83.     char *q;
  84.     char **pv;
  85.     struct rewrite *rwp = NULL;
  86.     char buf[MAXLINE];
  87.     register char *p;
  88.     extern char **prescan();
  89.     extern char **copyplist();
  90.     char exbuf[MAXLINE];
  91.     char pvpbuf[PSBUFSIZE];
  92.     extern char *fgetfolded();
  93.     extern char *munchstring();
  94.  
  95.     cf = fopen(cfname, "r");
  96.     if (cf == NULL)
  97.     {
  98.         syserr("cannot open %s", cfname);
  99.         exit(EX_OSFILE);
  100.     }
  101.  
  102.     FileName = cfname;
  103.     LineNumber = 0;
  104.     while (fgetfolded(buf, sizeof buf, cf) != NULL)
  105.     {
  106.         /* map $ into \001 (ASCII SOH) for macro expansion */
  107.         for (p = buf; *p != '\0'; p++)
  108.         {
  109.             if (*p != '$')
  110.                 continue;
  111.  
  112.             if (p[1] == '$')
  113.             {
  114.                 /* actual dollar sign.... */
  115.                 (void) strcpy(p, p + 1);
  116.                 continue;
  117.             }
  118.  
  119.             /* convert to macro expansion character */
  120.             *p = '\001';
  121.         }
  122.  
  123.         /* interpret this line */
  124.         switch (buf[0])
  125.         {
  126.           case '\0':
  127.           case '#':        /* comment */
  128.             break;
  129.  
  130.           case 'R':        /* rewriting rule */
  131.             for (p = &buf[1]; *p != '\0' && *p != '\t'; p++)
  132.                 continue;
  133.  
  134.             if (*p == '\0')
  135.             {
  136.                 syserr("invalid rewrite line \"%s\"", buf);
  137.                 break;
  138.             }
  139.  
  140.             /* allocate space for the rule header */
  141.             if (rwp == NULL)
  142.             {
  143.                 RewriteRules[ruleset] = rwp =
  144.                     (struct rewrite *) xalloc(sizeof *rwp);
  145.             }
  146.             else
  147.             {
  148.                 rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
  149.                 rwp = rwp->r_next;
  150.             }
  151.             rwp->r_next = NULL;
  152.  
  153.             /* expand and save the LHS */
  154.             *p = '\0';
  155.             expand(&buf[1], exbuf, &exbuf[sizeof exbuf], CurEnv);
  156.             rwp->r_lhs = prescan(exbuf, '\t', pvpbuf);
  157.             if (rwp->r_lhs != NULL)
  158.                 rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
  159.  
  160.             /* expand and save the RHS */
  161.             while (*++p == '\t')
  162.                 continue;
  163.             q = p;
  164.             while (*p != '\0' && *p != '\t')
  165.                 p++;
  166.             *p = '\0';
  167.             expand(q, exbuf, &exbuf[sizeof exbuf], CurEnv);
  168.             rwp->r_rhs = prescan(exbuf, '\t', pvpbuf);
  169.             if (rwp->r_rhs != NULL)
  170.                 rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
  171.             break;
  172.  
  173.           case 'S':        /* select rewriting set */
  174.             ruleset = atoi(&buf[1]);
  175.             if (ruleset >= MAXRWSETS || ruleset < 0)
  176.             {
  177.                 syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS);
  178.                 ruleset = 0;
  179.             }
  180.             rwp = NULL;
  181.             break;
  182.  
  183.           case 'D':        /* macro definition */
  184.             define(buf[1], newstr(munchstring(&buf[2])), CurEnv);
  185.             break;
  186.  
  187.           case 'H':        /* required header line */
  188.             (void) chompheader(&buf[1], TRUE);
  189.             break;
  190.  
  191.           case 'C':        /* word class */
  192.           case 'F':        /* word class from file */
  193.             /* read list of words from argument or file */
  194.             if (buf[0] == 'F')
  195.             {
  196.                 /* read from file */
  197.                 for (p = &buf[2]; *p != '\0' && !isspace(*p); p++)
  198.                     continue;
  199.                 if (*p == '\0')
  200.                     p = "%s";
  201.                 else
  202.                 {
  203.                     *p = '\0';
  204.                     while (isspace(*++p))
  205.                         continue;
  206.                 }
  207.                 fileclass(buf[1], &buf[2], p);
  208.                 break;
  209.             }
  210.  
  211.             /* scan the list of words and set class for all */
  212.             for (p = &buf[2]; *p != '\0'; )
  213.             {
  214.                 register char *wd;
  215.                 char delim;
  216.  
  217.                 while (*p != '\0' && isspace(*p))
  218.                     p++;
  219.                 wd = p;
  220.                 while (*p != '\0' && !isspace(*p))
  221.                     p++;
  222.                 delim = *p;
  223.                 *p = '\0';
  224.                 if (wd[0] != '\0')
  225.                     setclass(buf[1], wd);
  226.                 *p = delim;
  227.             }
  228.             break;
  229.  
  230.           case 'M':        /* define mailer */
  231.             makemailer(&buf[1]);
  232.             break;
  233.  
  234.           case 'O':        /* set option */
  235.             setoption(buf[1], &buf[2], TRUE, FALSE);
  236.             break;
  237.  
  238.           case 'P':        /* set precedence */
  239.             if (NumPriorities >= MAXPRIORITIES)
  240.             {
  241.                 toomany('P', MAXPRIORITIES);
  242.                 break;
  243.             }
  244.             for (p = &buf[1]; *p != '\0' && *p != '=' && *p != '\t'; p++)
  245.                 continue;
  246.             if (*p == '\0')
  247.                 goto badline;
  248.             *p = '\0';
  249.             Priorities[NumPriorities].pri_name = newstr(&buf[1]);
  250.             Priorities[NumPriorities].pri_val = atoi(++p);
  251.             NumPriorities++;
  252.             break;
  253.  
  254.           case 'T':        /* trusted user(s) */
  255.             p = &buf[1];
  256.             while (*p != '\0')
  257.             {
  258.                 while (isspace(*p))
  259.                     p++;
  260.                 q = p;
  261.                 while (*p != '\0' && !isspace(*p))
  262.                     p++;
  263.                 if (*p != '\0')
  264.                     *p++ = '\0';
  265.                 if (*q == '\0')
  266.                     continue;
  267.                 for (pv = TrustedUsers; *pv != NULL; pv++)
  268.                     continue;
  269.                 if (pv >= &TrustedUsers[MAXTRUST])
  270.                 {
  271.                     toomany('T', MAXTRUST);
  272.                     break;
  273.                 }
  274.                 *pv = newstr(q);
  275.             }
  276.             break;
  277.  
  278.           default:
  279.           badline:
  280.             syserr("unknown control line \"%s\"", buf);
  281.         }
  282.     }
  283.     FileName = NULL;
  284. }
  285. /*
  286. **  TOOMANY -- signal too many of some option
  287. **
  288. **    Parameters:
  289. **        id -- the id of the error line
  290. **        maxcnt -- the maximum possible values
  291. **
  292. **    Returns:
  293. **        none.
  294. **
  295. **    Side Effects:
  296. **        gives a syserr.
  297. */
  298.  
  299. toomany(id, maxcnt)
  300.     char id;
  301.     int maxcnt;
  302. {
  303.     syserr("too many %c lines, %d max", id, maxcnt);
  304. }
  305. /*
  306. **  FILECLASS -- read members of a class from a file
  307. **
  308. **    Parameters:
  309. **        class -- class to define.
  310. **        filename -- name of file to read.
  311. **        fmt -- scanf string to use for match.
  312. **
  313. **    Returns:
  314. **        none
  315. **
  316. **    Side Effects:
  317. **
  318. **        puts all lines in filename that match a scanf into
  319. **            the named class.
  320. */
  321.  
  322. fileclass(class, filename, fmt)
  323.     int class;
  324.     char *filename;
  325.     char *fmt;
  326. {
  327.     FILE *f;
  328.     char buf[MAXLINE];
  329.  
  330.     f = fopen(filename, "r");
  331.     if (f == NULL)
  332.     {
  333.         syserr("cannot open %s", filename);
  334.         return;
  335.     }
  336.  
  337.     while (fgets(buf, sizeof buf, f) != NULL)
  338.     {
  339.         register STAB *s;
  340.         register char *p;
  341. # ifdef SCANF
  342.         char wordbuf[MAXNAME+1];
  343.  
  344.         if (sscanf(buf, fmt, wordbuf) != 1)
  345.             continue;
  346.         p = wordbuf;
  347. # else SCANF
  348.         p = buf;
  349. # endif SCANF
  350.  
  351.         /*
  352.         **  Break up the match into words.
  353.         */
  354.  
  355.         while (*p != '\0')
  356.         {
  357.             register char *q;
  358.  
  359.             /* strip leading spaces */
  360.             while (isspace(*p))
  361.                 p++;
  362.             if (*p == '\0')
  363.                 break;
  364.  
  365.             /* find the end of the word */
  366.             q = p;
  367.             while (*p != '\0' && !isspace(*p))
  368.                 p++;
  369.             if (*p != '\0')
  370.                 *p++ = '\0';
  371.  
  372.             /* enter the word in the symbol table */
  373.             s = stab(q, ST_CLASS, ST_ENTER);
  374.             setbitn(class, s->s_class);
  375.         }
  376.     }
  377.  
  378.     (void) fclose(f);
  379. }
  380. /*
  381. **  MAKEMAILER -- define a new mailer.
  382. **
  383. **    Parameters:
  384. **        line -- description of mailer.  This is in labeled
  385. **            fields.  The fields are:
  386. **               P -- the path to the mailer
  387. **               F -- the flags associated with the mailer
  388. **               A -- the argv for this mailer
  389. **               S -- the sender rewriting set
  390. **               R -- the recipient rewriting set
  391. **               E -- the eol string
  392. **            The first word is the canonical name of the mailer.
  393. **
  394. **    Returns:
  395. **        none.
  396. **
  397. **    Side Effects:
  398. **        enters the mailer into the mailer table.
  399. */
  400.  
  401. makemailer(line)
  402.     char *line;
  403. {
  404.     register char *p;
  405.     register struct mailer *m;
  406.     register STAB *s;
  407.     int i;
  408.     char fcode;
  409.     extern int NextMailer;
  410.     extern char **makeargv();
  411.     extern char *munchstring();
  412.     extern char *DelimChar;
  413.     extern long atol();
  414.  
  415.     /* allocate a mailer and set up defaults */
  416.     m = (struct mailer *) xalloc(sizeof *m);
  417.     bzero((char *) m, sizeof *m);
  418.     m->m_mno = NextMailer;
  419.     m->m_eol = "\n";
  420.  
  421.     /* collect the mailer name */
  422.     for (p = line; *p != '\0' && *p != ',' && !isspace(*p); p++)
  423.         continue;
  424.     if (*p != '\0')
  425.         *p++ = '\0';
  426.     m->m_name = newstr(line);
  427.  
  428.     /* now scan through and assign info from the fields */
  429.     while (*p != '\0')
  430.     {
  431.         while (*p != '\0' && (*p == ',' || isspace(*p)))
  432.             p++;
  433.  
  434.         /* p now points to field code */
  435.         fcode = *p;
  436.         while (*p != '\0' && *p != '=' && *p != ',')
  437.             p++;
  438.         if (*p++ != '=')
  439.         {
  440.             syserr("`=' expected");
  441.             return;
  442.         }
  443.         while (isspace(*p))
  444.             p++;
  445.  
  446.         /* p now points to the field body */
  447.         p = munchstring(p);
  448.  
  449.         /* install the field into the mailer struct */
  450.         switch (fcode)
  451.         {
  452.           case 'P':        /* pathname */
  453.             m->m_mailer = newstr(p);
  454.             break;
  455.  
  456.           case 'F':        /* flags */
  457.             for (; *p != '\0'; p++)
  458.                 setbitn(*p, m->m_flags);
  459.             break;
  460.  
  461.           case 'S':        /* sender rewriting ruleset */
  462.           case 'R':        /* recipient rewriting ruleset */
  463.             i = atoi(p);
  464.             if (i < 0 || i >= MAXRWSETS)
  465.             {
  466.                 syserr("invalid rewrite set, %d max", MAXRWSETS);
  467.                 return;
  468.             }
  469.             if (fcode == 'S')
  470.                 m->m_s_rwset = i;
  471.             else
  472.                 m->m_r_rwset = i;
  473.             break;
  474.  
  475.           case 'E':        /* end of line string */
  476.             m->m_eol = newstr(p);
  477.             break;
  478.  
  479.           case 'A':        /* argument vector */
  480.             m->m_argv = makeargv(p);
  481.             break;
  482.  
  483.           case 'M':        /* maximum message size */
  484.             m->m_maxsize = atol(p);
  485.             break;
  486.         }
  487.  
  488.         p = DelimChar;
  489.     }
  490.  
  491.     /* now store the mailer away */
  492.     if (NextMailer >= MAXMAILERS)
  493.     {
  494.         syserr("too many mailers defined (%d max)", MAXMAILERS);
  495.         return;
  496.     }
  497.     Mailer[NextMailer++] = m;
  498.     s = stab(m->m_name, ST_MAILER, ST_ENTER);
  499.     s->s_mailer = m;
  500. }
  501. /*
  502. **  MUNCHSTRING -- translate a string into internal form.
  503. **
  504. **    Parameters:
  505. **        p -- the string to munch.
  506. **
  507. **    Returns:
  508. **        the munched string.
  509. **
  510. **    Side Effects:
  511. **        Sets "DelimChar" to point to the string that caused us
  512. **        to stop.
  513. */
  514.  
  515. char *
  516. munchstring(p)
  517.     register char *p;
  518. {
  519.     register char *q;
  520.     bool backslash = FALSE;
  521.     bool quotemode = FALSE;
  522.     static char buf[MAXLINE];
  523.     extern char *DelimChar;
  524.  
  525.     for (q = buf; *p != '\0'; p++)
  526.     {
  527.         if (backslash)
  528.         {
  529.             /* everything is roughly literal */
  530.             backslash = FALSE;
  531.             switch (*p)
  532.             {
  533.               case 'r':        /* carriage return */
  534.                 *q++ = '\r';
  535.                 continue;
  536.  
  537.               case 'n':        /* newline */
  538.                 *q++ = '\n';
  539.                 continue;
  540.  
  541.               case 'f':        /* form feed */
  542.                 *q++ = '\f';
  543.                 continue;
  544.  
  545.               case 'b':        /* backspace */
  546.                 *q++ = '\b';
  547.                 continue;
  548.             }
  549.             *q++ = *p;
  550.         }
  551.         else
  552.         {
  553.             if (*p == '\\')
  554.                 backslash = TRUE;
  555.             else if (*p == '"')
  556.                 quotemode = !quotemode;
  557.             else if (quotemode || *p != ',')
  558.                 *q++ = *p;
  559.             else
  560.                 break;
  561.         }
  562.     }
  563.  
  564.     DelimChar = p;
  565.     *q++ = '\0';
  566.     return (buf);
  567. }
  568. /*
  569. **  MAKEARGV -- break up a string into words
  570. **
  571. **    Parameters:
  572. **        p -- the string to break up.
  573. **
  574. **    Returns:
  575. **        a char **argv (dynamically allocated)
  576. **
  577. **    Side Effects:
  578. **        munges p.
  579. */
  580.  
  581. char **
  582. makeargv(p)
  583.     register char *p;
  584. {
  585.     char *q;
  586.     int i;
  587.     char **avp;
  588.     char *argv[MAXPV + 1];
  589.  
  590.     /* take apart the words */
  591.     i = 0;
  592.     while (*p != '\0' && i < MAXPV)
  593.     {
  594.         q = p;
  595.         while (*p != '\0' && !isspace(*p))
  596.             p++;
  597.         while (isspace(*p))
  598.             *p++ = '\0';
  599.         argv[i++] = newstr(q);
  600.     }
  601.     argv[i++] = NULL;
  602.  
  603.     /* now make a copy of the argv */
  604.     avp = (char **) xalloc(sizeof *avp * i);
  605.     bcopy((char *) argv, (char *) avp, sizeof *avp * i);
  606.  
  607.     return (avp);
  608. }
  609. /*
  610. **  PRINTRULES -- print rewrite rules (for debugging)
  611. **
  612. **    Parameters:
  613. **        none.
  614. **
  615. **    Returns:
  616. **        none.
  617. **
  618. **    Side Effects:
  619. **        prints rewrite rules.
  620. */
  621.  
  622. printrules()
  623. {
  624.     register struct rewrite *rwp;
  625.     register int ruleset;
  626.  
  627.     for (ruleset = 0; ruleset < 10; ruleset++)
  628.     {
  629.         if (RewriteRules[ruleset] == NULL)
  630.             continue;
  631.         printf("\n----Rule Set %d:", ruleset);
  632.  
  633.         for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
  634.         {
  635.             printf("\nLHS:");
  636.             printav(rwp->r_lhs);
  637.             printf("RHS:");
  638.             printav(rwp->r_rhs);
  639.         }
  640.     }
  641. }
  642.  
  643. /*
  644. **  SETOPTION -- set global processing option
  645. **
  646. **    Parameters:
  647. **        opt -- option name.
  648. **        val -- option value (as a text string).
  649. **        safe -- set if this came from a configuration file.
  650. **            Some options (if set from the command line) will
  651. **            reset the user id to avoid security problems.
  652. **        sticky -- if set, don't let other setoptions override
  653. **            this value.
  654. **
  655. **    Returns:
  656. **        none.
  657. **
  658. **    Side Effects:
  659. **        Sets options as implied by the arguments.
  660. */
  661.  
  662. static BITMAP    StickyOpt;        /* set if option is stuck */
  663. extern char    *NetName;        /* name of home (local) network */
  664.  
  665. setoption(opt, val, safe, sticky)
  666.     char opt;
  667.     char *val;
  668.     bool safe;
  669.     bool sticky;
  670. {
  671.     extern bool atobool();
  672.     extern time_t convtime();
  673.     extern int QueueLA;
  674.     extern int RefuseLA;
  675.     extern bool trusteduser();
  676.     extern char *username();
  677.  
  678.     if (tTd(37, 1))
  679.         printf("setoption %c=%s", opt, val);
  680.  
  681.     /*
  682.     **  See if this option is preset for us.
  683.     */
  684.  
  685.     if (bitnset(opt, StickyOpt))
  686.     {
  687.         if (tTd(37, 1))
  688.             printf(" (ignored)\n");
  689.         return;
  690.     }
  691.  
  692.     /*
  693.     **  Check to see if this option can be specified by this user.
  694.     */
  695.  
  696.     if (!safe && getuid() == 0)
  697.         safe = TRUE;
  698.     if (!safe && index("deiLmorsv", opt) == NULL)
  699.     {
  700.         if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
  701.         {
  702.             if (tTd(37, 1))
  703.                 printf(" (unsafe)");
  704.             if (getuid() != geteuid())
  705.             {
  706.                 printf("(Resetting uid)\n");
  707.                 (void) setgid(getgid());
  708.                 (void) setuid(getuid());
  709.             }
  710.         }
  711.     }
  712.     else if (tTd(37, 1))
  713.         printf("\n");
  714.  
  715.     switch (opt)
  716.     {
  717.       case 'A':        /* set default alias file */
  718.         if (val[0] == '\0')
  719.             AliasFile = "aliases";
  720.         else
  721.             AliasFile = newstr(val);
  722.         break;
  723.  
  724.       case 'a':        /* look N minutes for "@:@" in alias file */
  725.         if (val[0] == '\0')
  726.             SafeAlias = 5;
  727.         else
  728.             SafeAlias = atoi(val);
  729.         break;
  730.  
  731.       case 'B':        /* substitution for blank character */
  732.         SpaceSub = val[0];
  733.         if (SpaceSub == '\0')
  734.             SpaceSub = ' ';
  735.         break;
  736.  
  737.       case 'c':        /* don't connect to "expensive" mailers */
  738.         NoConnect = atobool(val);
  739.         break;
  740.  
  741.       case 'C':        /* checkpoint after N connections */
  742.         CheckPointLimit = atoi(val);
  743.         break;
  744.  
  745.       case 'd':        /* delivery mode */
  746.         switch (*val)
  747.         {
  748.           case '\0':
  749.             SendMode = SM_DELIVER;
  750.             break;
  751.  
  752.           case SM_QUEUE:    /* queue only */
  753. #ifndef QUEUE
  754.             syserr("need QUEUE to set -odqueue");
  755. #endif QUEUE
  756.             /* fall through..... */
  757.  
  758.           case SM_DELIVER:    /* do everything */
  759.           case SM_FORK:        /* fork after verification */
  760.             SendMode = *val;
  761.             break;
  762.  
  763.           default:
  764.             syserr("Unknown delivery mode %c", *val);
  765.             exit(EX_USAGE);
  766.         }
  767.         break;
  768.  
  769.       case 'D':        /* rebuild alias database as needed */
  770.         AutoRebuild = atobool(val);
  771.         break;
  772.  
  773.       case 'e':        /* set error processing mode */
  774.         switch (*val)
  775.         {
  776.           case EM_QUIET:    /* be silent about it */
  777.           case EM_MAIL:        /* mail back */
  778.           case EM_BERKNET:    /* do berknet error processing */
  779.           case EM_WRITE:    /* write back (or mail) */
  780.             HoldErrs = TRUE;
  781.             /* fall through... */
  782.  
  783.           case EM_PRINT:    /* print errors normally (default) */
  784.             ErrorMode = *val;
  785.             break;
  786.         }
  787.         break;
  788.  
  789.       case 'F':        /* file mode */
  790.         FileMode = atooct(val) & 0777;
  791.         break;
  792.  
  793.       case 'f':        /* save Unix-style From lines on front */
  794.         SaveFrom = atobool(val);
  795.         break;
  796.  
  797.       case 'g':        /* default gid */
  798.         DefGid = atoi(val);
  799.         break;
  800.  
  801.       case 'H':        /* help file */
  802.         if (val[0] == '\0')
  803.             HelpFile = "sendmail.hf";
  804.         else
  805.             HelpFile = newstr(val);
  806.         break;
  807.  
  808.       case 'I':        /* use internet domain name server */
  809.         UseNameServer = atobool(val);
  810.         break;
  811.  
  812.       case 'i':        /* ignore dot lines in message */
  813.         IgnrDot = atobool(val);
  814.         break;
  815.  
  816.       case 'k':        /* checkpoint every N addresses */
  817.         CheckpointInterval = atoi(val);
  818.         break;
  819.  
  820.       case 'L':        /* log level */
  821.         LogLevel = atoi(val);
  822.         break;
  823.  
  824.       case 'M':        /* define macro */
  825.         define(val[0], newstr(&val[1]), CurEnv);
  826.         sticky = FALSE;
  827.         break;
  828.  
  829.       case 'm':        /* send to me too */
  830.         MeToo = atobool(val);
  831.         break;
  832.  
  833.       case 'n':        /* validate RHS in newaliases */
  834.         CheckAliases = atobool(val);
  835.         break;
  836.  
  837. # ifdef DAEMON
  838.       case 'N':        /* home (local?) network name */
  839.         NetName = newstr(val);
  840.         break;
  841. # endif DAEMON
  842.  
  843.       case 'o':        /* assume old style headers */
  844.         if (atobool(val))
  845.             CurEnv->e_flags |= EF_OLDSTYLE;
  846.         else
  847.             CurEnv->e_flags &= ~EF_OLDSTYLE;
  848.         break;
  849.  
  850.       case 'P':        /* postmaster copy address for returned mail */
  851.         PostMasterCopy = newstr(val);
  852.         break;
  853.  
  854.       case 'q':        /* slope of queue only function */
  855.         QueueFactor = atoi(val);
  856.         break;
  857.  
  858.       case 'Q':        /* queue directory */
  859.         if (val[0] == '\0')
  860.             QueueDir = "mqueue";
  861.         else
  862.             QueueDir = newstr(val);
  863.         break;
  864.  
  865.       case 'r':        /* read timeout */
  866.         ReadTimeout = convtime(val);
  867.         break;
  868.  
  869.       case 'S':        /* status file */
  870.         if (val[0] == '\0')
  871.             StatFile = "sendmail.st";
  872.         else
  873.             StatFile = newstr(val);
  874.         break;
  875.  
  876.       case 's':        /* be super safe, even if expensive */
  877.         SuperSafe = atobool(val);
  878.         break;
  879.  
  880.       case 'T':        /* queue timeout */
  881.         TimeOut = convtime(val);
  882.         /*FALLTHROUGH*/
  883.  
  884.       case 't':        /* time zone name */
  885.         break;
  886.  
  887.       case 'u':        /* set default uid */
  888.         DefUid = atoi(val);
  889.         setdefuser();
  890.         break;
  891.  
  892.       case 'v':        /* run in verbose mode */
  893.         Verbose = atobool(val);
  894.         break;
  895.  
  896.       case 'x':        /* load avg at which to auto-queue msgs */
  897.         QueueLA = atoi(val);
  898.         break;
  899.  
  900.       case 'X':        /* load avg at which to auto-reject connections */
  901.         RefuseLA = atoi(val);
  902.         break;
  903.  
  904.       case 'y':        /* work recipient factor */
  905.         WkRecipFact = atoi(val);
  906.         break;
  907.  
  908.       case 'Y':        /* fork jobs during queue runs */
  909.         ForkQueueRuns = atobool(val);
  910.         break;
  911.  
  912.       case 'z':        /* work message class factor */
  913.         WkClassFact = atoi(val);
  914.         break;
  915.  
  916.       case 'Z':        /* work time factor */
  917.         WkTimeFact = atoi(val);
  918.         break;
  919.  
  920.       default:
  921.         break;
  922.     }
  923.     if (sticky)
  924.         setbitn(opt, StickyOpt);
  925.     return;
  926. }
  927. /*
  928. **  SETCLASS -- set a word into a class
  929. **
  930. **    Parameters:
  931. **        class -- the class to put the word in.
  932. **        word -- the word to enter
  933. **
  934. **    Returns:
  935. **        none.
  936. **
  937. **    Side Effects:
  938. **        puts the word into the symbol table.
  939. */
  940.  
  941. setclass(class, word)
  942.     int class;
  943.     char *word;
  944. {
  945.     register STAB *s;
  946.  
  947.     s = stab(word, ST_CLASS, ST_ENTER);
  948.     setbitn(class, s->s_class);
  949. }
  950.