home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume13 / cfc / cfc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-01-31  |  19.7 KB  |  1,075 lines

  1. #ifndef lint
  2. static char RCSid[] = "$Header: cfc.c,v 1.5 88/01/21 16:18:13 root Locked $";
  3. #endif
  4.  
  5. /*
  6.  * $Log:    cfc.c,v $
  7.  * Revision 1.5  88/01/21  16:18:13  root
  8.  * Eliminated Rutgers-ism, linted, smartened Mailer Argv handling. ADR.
  9.  * 
  10.  * Revision 1.4  88/01/21  15:57:52  root
  11.  * Added the 'y' factor; missed it last time. ADR.
  12.  * 
  13.  * Revision 1.3  87/04/08  10:23:02  root
  14.  * Small bug fixes, compatibility option added, also warnings for
  15.  * unrecognized flags and options. ADR.
  16.  * 
  17.  * Revision 1.2  87/02/18  15:26:39  root
  18.  * Fix to recognize multidigit ruleset numbers in $> (calls) in RHS. ADR.
  19.  * 
  20.  * Revision 1.1  87/02/16  15:25:00  arnold
  21.  * Initial revision
  22.  * 
  23.  * Revision 1.1  87/02/16  15:25:00  arnold
  24.  * Initial revision
  25.  * 
  26.  */
  27.  
  28. /*
  29.  * cfc.c
  30.  *
  31.  * Sendmail cf file compiler.
  32.  * Reads a raw sendmail.cf file and produces ease source.
  33.  *
  34.  * There are very few comments in this source. You will need both the
  35.  * "Sendmail Installation and Operation Guide" and the paper on Ease
  36.  * to really understand this.
  37.  *
  38.  * Arnold Robbins
  39.  * Emory University Computing Center
  40.  * 2/87
  41.  */
  42.  
  43. #include <stdio.h>
  44. #include <ctype.h>
  45.  
  46. char buffer[BUFSIZ];
  47. int line = 0;
  48. int inruleset = 0;
  49.  
  50. extern char *macro ();        /* convert sendmail to ease macro names */
  51. extern char *mflags ();        /* convert sendmail to ease mailer flag names */
  52. extern char *optionname ();    /* convert sendmail to ease option names */
  53. extern char *delivoption ();    /* delivery options */
  54. extern char *handle_option ();    /* handling options */
  55.  
  56. extern char *ngets ();        /* buffered gets () routine */
  57. extern void ungets ();        /* put a buffer back for getting */
  58.  
  59. #define endruleset()    if (inruleset) { inruleset = 0; printf ("\t}\n"); }
  60.  
  61. int compat = 0;            /* complain about new 4.3 options & flags */
  62.  
  63. main (argc, argv)
  64. int argc;
  65. char **argv;
  66. {
  67.     if (argc > 1)
  68.     {
  69.         if (strcmp (argv[1], "-c") == 0)
  70.             compat = 1;
  71.         else
  72.         {
  73.             fprintf (stderr, "usage: %s [ -c ]\n", argv[0]);
  74.             fprintf (stderr, "illegal argument '%s' ignored\n",
  75.                     argv[1]);
  76.         }
  77.     }
  78.  
  79.     printf ("/******************************************************/\n");
  80.     printf ("/* This ease file generated by cfc from a sendmail.cf */\n");
  81.     printf ("/* file. It must be edited by hand before being fed   */\n");
  82.     printf ("/* to ease!                                           */\n");
  83.     printf ("/******************************************************/\n");
  84.     printf ("\n\nbind\n\t/* RULESET BINDINGS GO HERE (cfc) */\n\n");
  85.  
  86.     /*
  87.      * For perfection, everything but the comment and rule cases
  88.      * should do an endruleset (), but practically speaking, it is
  89.      * usually only the mailer new ruleset definitions that end a
  90.      * previous ruleset. Occasionally a macro, too.
  91.      */
  92.  
  93.     while (ngets (buffer) != NULL)
  94.     {
  95.         line++;
  96.         switch (buffer[0]) {
  97.         case '#':
  98.             comment ();
  99.             continue;    /* skip code to end ruleset */
  100.         case 'S':
  101.             endruleset ();
  102.             ruleset ();
  103.             continue;    /* skip code to end ruleset */
  104.         case 'R':
  105.             rule ();
  106.             continue;    /* skip code to end ruleset */
  107.         case 'D':
  108.             endruleset ();
  109.             def ();
  110.             break;
  111.         case 'C':
  112.             class ();
  113.             break;
  114.         case 'F':
  115.             fileclass ();
  116.             break;
  117.         case 'M':
  118.             endruleset ();
  119.             mailer ();
  120.             break;
  121.         case 'H':
  122.             header ();
  123.             break;
  124.         case 'O':
  125.             option ();
  126.             break;
  127.         case 'T':
  128.             trusted ();
  129.             break;
  130.         case 'P':
  131.             precedence ();
  132.             break;
  133.         default:
  134.             other ();
  135.             continue;    /* skip code to end ruleset */
  136.         }
  137.         endruleset ();
  138.     }
  139.     endruleset ();        /* just in case */
  140.     exit (0);
  141.     /*NOTREACHED*/
  142. }
  143.  
  144. /* comment --- produce a comment */
  145.  
  146. comment ()
  147. {
  148.     static char format[] = "/* %s */\n";
  149.     register int i = strlen (buffer) - 1;
  150.  
  151.     /* try to be semi-intelligent about comments */
  152.  
  153.     if (buffer[1] == '\0')
  154.         printf ("\n");
  155.     else if (isspace (buffer[1]) && buffer[i] != '#')
  156.     {
  157.         for (i = 1; isspace (buffer[i]); i++)
  158.             ;
  159.         printf (format, buffer + i);
  160.     }
  161.     else
  162.         printf (format, buffer);
  163. }
  164.  
  165. /* ruleset --- name a ruleset */
  166.  
  167. ruleset ()
  168. {
  169.     static int first = 1;
  170.     register char *cp = buffer + 1;
  171.  
  172.     if (first)
  173.     {
  174.         first = 0;
  175.         printf ("\n/* These are sample field definitons (cfc) */\n");
  176.         printf ("\nfield\n\tzero_or_more : match (0*);\n");
  177.         printf ("\tone_or_more : match (1*);\n");
  178.         printf ("\texactly_one : match (1);\n");
  179.         printf ("\tany_in_? : match (1) in ?;\n");
  180.         printf ("\tany_not_in_? : match (0) in ?;\n\n");
  181.     }
  182.  
  183.     printf ("ruleset\n\tRULESET_");
  184.     while (*cp && ! isspace (*cp))
  185.     {
  186.         putchar (*cp);
  187.         cp++;
  188.     }
  189.  
  190.     printf (" {");
  191.     if (*cp)
  192.         printf ("\t/* %s */", cp);
  193.     putchar ('\n');
  194.     inruleset++;
  195. }
  196.  
  197. /* rule --- print out a rule */
  198.  
  199. rule ()
  200. {
  201.     register char *cp = buffer + 1;
  202.     register char *cp2;
  203.     register int com = 0;
  204.  
  205.     /* first, split it up into LHS, RHS, COMMENT */
  206.  
  207.     while (*cp != '\t')
  208.         cp++;
  209.     *cp = '\0';
  210.  
  211.     cp++;
  212.     while (*cp == '\t')
  213.         cp++;
  214.     cp2 = cp;
  215.     while (*cp && *cp != '\t')
  216.         cp++;
  217.     if (*cp == '\t' && cp[1])
  218.     {
  219.         *cp = '\0';
  220.         com++;
  221.         cp++;
  222.         while (*cp == '\t')
  223.             cp++;
  224.     }
  225.  
  226.     /* now print */
  227.     lhs (buffer + 1);    /* left hand side */
  228.     if (com)
  229.         printf ("\t/* %s */", cp);
  230.     putchar ('\n');
  231.     rhs (cp2);        /* right hand side */
  232. }
  233.  
  234. /* lhs --- left hand side of a production */
  235.  
  236. lhs (text)
  237. char *text;
  238. {
  239.     register char *cp = text;
  240.     register int conditional = 0;
  241.     register int quoting = 0;
  242.  
  243.     printf ("\tif (");
  244.     for (; *cp; cp++)
  245.     {
  246.         switch (*cp) {
  247.         case '$':
  248.             if (quoting)
  249.             {
  250.                 quoting = 0;
  251.                 putchar ('"');
  252.             }
  253.             switch (*++cp) {
  254.             case '*':
  255.                 printf (" zero_or_more ");
  256.                 break;
  257.             case '+':
  258.                 printf (" one_or_more ");
  259.                 break;
  260.             case '-':
  261.                 printf (" exactly_one ");
  262.                 break;
  263.             case '=':
  264.                 printf (" any_in_%c ", *++cp);
  265.                 break;
  266.             case '~':
  267.                 printf (" any_not_in_%c ", *++cp);
  268.                 break;
  269.             case '?':
  270.                 printf (" ifset (%s, ", macro (*++cp));
  271.                 conditional++;
  272.                 break;
  273.             case '|':
  274.                 printf (", ");
  275.                 break;
  276.             case '.':
  277.                 putchar (')');
  278.                 conditional--;
  279.                 break;
  280.             case '1':
  281.             case '2':
  282.             case '3':
  283.             case '4':
  284.             case '5':
  285.             case '6':
  286.             case '7':
  287.             case '8':
  288.             case '9':
  289.                 printf ("$%c", *cp);
  290.                 break;
  291.             default:
  292.                 if (quoting)
  293.                     printf ("${%s}", macro (*cp));
  294.                 else
  295.                     printf ("$%s", macro (*cp));
  296.                 break;
  297.             }
  298.             break;
  299.         default:
  300.             if (ispunct (*cp))
  301.             {
  302.                 if (quoting)    /* end a literal */
  303.                 {
  304.                     quoting = 0;
  305.                     putchar ('"');
  306.                 }
  307.                 /* else
  308.                     do nothing */
  309.             }
  310.             else
  311.             {
  312.                 if (! quoting)    /* start a literal */
  313.                 {
  314.                     quoting = 1;
  315.                     putchar ('"');
  316.                 }
  317.                 /* else
  318.                     do nothing */
  319.             }
  320.             putchar (*cp);    /* print the character */
  321.             break;
  322.         }
  323.     }
  324.     if (quoting)
  325.         putchar ('"');
  326.     if (conditional)
  327.         die ("lhs");
  328.     printf (")");
  329. }
  330.  
  331. /* rhs --- right hand side of a production */
  332.  
  333. rhs (text)
  334. char *text;
  335. {
  336.     register char *cp = text;
  337.     char *index ();
  338.     register int open = 0;
  339.     register int conditional = 0;
  340.     register int quoting = 0;
  341.  
  342.     printf ("\t\t");
  343.  
  344.     if (*cp == '$' && index ("#@:", cp[1]) != NULL)
  345.         ;    /* not the default */
  346.     else
  347.     {
  348.         printf ("retry (");
  349.         open++;
  350.     }
  351.  
  352.     for (; *cp; cp++)
  353.     {
  354.         switch (*cp) {
  355.         case '$':
  356.             if (quoting)
  357.             {
  358.                 quoting = 0;
  359.                 putchar ('"');
  360.             }
  361.             switch (*++cp) {
  362.             case '>':
  363.                 printf ("RULESET_");
  364.                 for (cp++; *cp && isdigit (*cp); cp++)
  365.                     putchar (*cp);
  366.                 cp--;
  367.                 printf (" (");
  368.                 open++;
  369.                 break;
  370.             case '[':
  371.                 printf ("canon (");
  372.                 open++;
  373.                 break;
  374.             case ']':
  375.                 putchar (')');
  376.                 open--;
  377.                 break;
  378.             case '?':
  379.                 printf ("ifset (%s, ", macro (*++cp));
  380.                 conditional++;
  381.                 break;
  382.             case '|':
  383.                 putchar (',');
  384.                 break;
  385.             case '.':
  386.                 putchar (')');
  387.                 conditional--;
  388.                 break;
  389.             case '#':
  390.                 printf ("resolve (mailer (");
  391.                 if (strncmp (cp+1, "local$", 6) == 0
  392.                     || strncmp (cp+1, "error$", 6) == 0)
  393.                     goto skiphost;
  394.             loop1:
  395.                 for (cp++; *cp != '$'; cp++)
  396.                     putchar (*cp);
  397.                 cp++;
  398.                 if (*cp != '@')
  399.                 {
  400.                     printf ("$%c", *cp);
  401.                     goto loop1;
  402.                 }
  403.                 printf ("),\n\t\t\t\thost (");
  404.             skiphost:
  405.             loop2:
  406.                 for (cp++; *cp != '$'; cp++)
  407.                     putchar (*cp);
  408.                 cp++;
  409.                 if (*cp != ':')
  410.                 {
  411.                     printf ("$%c", *cp);
  412.                     goto loop2;
  413.                 }
  414.                 printf ("),\n\t\t\t\tuser (");
  415.                 for (cp++; *cp; cp++)
  416.                     putchar (*cp);
  417.                 printf ("))");
  418.                 goto out;    /* string is exhausted */
  419.                 /* break; */
  420.             case '@':
  421.                 printf ("return (");
  422.                 open++;
  423.                 break;
  424.             case ':':
  425.                 printf ("next (");
  426.                 open++;
  427.                 break;
  428.             case '1':
  429.             case '2':
  430.             case '3':
  431.             case '4':
  432.             case '5':
  433.             case '6':
  434.             case '7':
  435.             case '8':
  436.             case '9':
  437.                 printf ("$%c", *cp);
  438.                 break;
  439.             default:
  440.                 if (quoting)
  441.                     printf ("${%s}", macro (*cp));
  442.                 else
  443.                     printf ("$%s", macro (*cp));
  444.                 break;
  445.             }
  446.             break;
  447.         default:
  448.             if (ispunct (*cp))
  449.             {
  450.                 if (quoting)    /* end a literal */
  451.                 {
  452.                     quoting = 0;
  453.                     putchar ('"');
  454.                 }
  455.                 /* else
  456.                     do nothing */
  457.             }
  458.             else
  459.             {
  460.                 if (! quoting)    /* start a literal */
  461.                 {
  462.                     quoting = 1;
  463.                     putchar ('"');
  464.                 }
  465.                 /* else
  466.                     do nothing */
  467.             }
  468.             putchar (*cp);    /* print the character */
  469.             break;
  470.         }
  471.     }
  472. out:
  473.     if (quoting)
  474.         putchar ('"');
  475.     while (open--)
  476.         putchar (')');
  477.     printf (";\n");
  478.     if (conditional)
  479.         die ("rhs");
  480. }
  481.  
  482. /* def --- define a macro */
  483.  
  484. def ()
  485. {
  486.     register char *mac = buffer + 1, *value = buffer + 2;
  487.     register int conditional = 0;
  488.  
  489.     printf ("macro\n\t%s = \"", macro (*mac));
  490.  
  491.     while (*value)
  492.     {
  493.         switch (*value) {
  494.         case '$':
  495.             switch (*++value) {
  496.             case '?':
  497.                 printf ("ifset (%s, ", macro (*++value));
  498.                 conditional++;
  499.                 break;
  500.             case '|':
  501.                 putchar (',');
  502.                 break;
  503.             case '.':
  504.                 putchar (')');
  505.                 conditional--;
  506.                 break;
  507.             default:
  508.                 printf ("${%s}", macro (*value));
  509.                 break;
  510.             }
  511.             break;
  512.         default:
  513.             putchar (*value);
  514.             break;
  515.         }
  516.         value++;
  517.     }
  518.     printf ("\";\n");
  519.     if (conditional)
  520.         die ("def");
  521. }
  522.  
  523. /* class --- define a class list */
  524.  
  525. class ()
  526. {
  527.     register char *name = buffer + 1, *value = buffer + 2;
  528.  
  529.     printf ("class\n\t%c = { ", *name);
  530.  
  531.     while (*value && isspace (*value))
  532.         value++;
  533.  
  534.     while (*value)
  535.     {
  536.         if (isspace (*value))
  537.         {
  538.             printf (", ");
  539.             while (isspace (*value))
  540.                 value++;
  541.             value--;    /* cancel loop */
  542.         }
  543.         else
  544.             putchar (*value);
  545.         value++;
  546.     }
  547.     printf (" };\n");
  548. }
  549.  
  550. /* fileclass --- define a class that is to be read from a file */
  551.  
  552. fileclass ()
  553. {
  554.     register char *name = buffer + 1, *value = buffer + 2;
  555.  
  556.     printf ("class\n\t%c = readclass (\"", *name);
  557.     for (; *value && !isspace (*value); value++)
  558.         putchar (*value);
  559.     putchar ('"');
  560.     while (*value && isspace (*value))
  561.         value++;
  562.     if (*value)
  563.         printf (", \"%s\"", value);
  564.     printf (");\n");
  565. }
  566.  
  567. /* mailer --- convert a mailer specification */
  568.  
  569. mailer ()
  570. {
  571.     register char *cp = buffer + 1;
  572.  
  573.     printf ("mailer\n\t");
  574.     for (; *cp != ','; cp++)
  575.         putchar (*cp);
  576.     cp++;
  577.     printf (" {\n");    /* just did mailer name */
  578.  
  579. #define skipname()    cp++; while (*cp != '=') cp++; cp++
  580. #define value()        for (; *cp && *cp != ','; cp++) putchar (*cp); cp++
  581.  
  582. loop:
  583.     while (*cp && isspace (*cp))
  584.         cp++;
  585.  
  586.     printf ("\t\t");
  587.     switch (*cp) {
  588.     case 'A':
  589.         skipname ();
  590.         printf ("Argv = \"");
  591.         for (; *cp && *cp != ','; cp++)
  592.         {
  593.             if (*cp == '$')    /* XXX: assume no conditionals */
  594.                 printf ("${%s}", macro (*++cp));
  595.             else if (*cp == '"')
  596.                 printf ("\\\"");
  597.             else
  598.                 putchar (*cp);
  599.         }
  600.         cp++;    /* do manually what value does */
  601.         putchar ('"');
  602.         break;
  603.  
  604.     case 'E':
  605.         skipname ();
  606.         printf ("Eol = \"");
  607.         value ();
  608.         putchar ('"');
  609.         break;
  610.  
  611.     case 'F':
  612.         skipname ();
  613.         printf ("Flags = { ");
  614.         for (; *cp && *cp != ','; cp++)
  615.         {
  616.             printf ("%s", mflags (*cp));
  617.             if (cp[1] && cp[1] != ',')
  618.                 printf (", ");
  619.         }
  620.         cp++;    /* do manually what value does */
  621.         printf (" }");
  622.         break;
  623.  
  624.     case 'M':
  625.         skipname ();
  626.         printf ("Maxsize = \"");
  627.         value ();
  628.         putchar ('"');
  629.         break;
  630.  
  631.     case 'P':
  632.         skipname ();
  633.         printf ("Path = \"");
  634.         value ();
  635.         putchar ('"');
  636.         break;
  637.  
  638.     case 'R':
  639.         skipname ();
  640.         printf ("Recipient = RULESET_");
  641.         value ();
  642.         break;
  643.  
  644.     case 'S':
  645.         skipname ();
  646.         printf ("Sender = RULESET_");
  647.         value ();
  648.         break;
  649.  
  650.     case '\0':
  651.         goto done;
  652.     }
  653.  
  654.     if (cp[-1] && cp[-1] == ',')
  655.     {
  656.         printf (",\n");
  657.         goto loop;
  658.     }
  659.     else
  660.         putchar ('\n');
  661.  
  662. done:
  663.     /* handle continuation lines */
  664.     if (ngets (buffer) != NULL)
  665.     {
  666.         line++;
  667.         if (buffer[0] == '\t')
  668.         {
  669.             cp = buffer;
  670.             goto loop;
  671.         }
  672.         else
  673.             ungets (buffer);
  674.     }
  675.     else
  676.         ungets ((char *) NULL);
  677.     
  678.     printf ("\t};\n");
  679.  
  680. #undef value
  681. #undef skipname
  682. }
  683.  
  684. /* header --- define sendmail headers */
  685.  
  686. header ()
  687. {
  688.     register char *cp = buffer + 1;
  689.     register int flags = 0;
  690.     register int conditional = 0;
  691.  
  692.     printf ("header\n\t");
  693.     if (*cp == '?')        /* header for mailers  with these flags */
  694.     {
  695.         flags++;
  696.         printf ("for (");
  697.         for (cp++; *cp != '?'; cp++)
  698.         {
  699.             printf ("%s", mflags (*cp));
  700.             if (cp[1] != '?')
  701.                 putchar (',');
  702.         }
  703.         printf (") {\n\t\t");
  704.         cp++;    /* skip final '?' */
  705.     }
  706.  
  707.     printf ("define (\"");
  708.     for (; *cp && ! isspace (*cp); cp++)
  709.         putchar (*cp);
  710.     printf ("\", \"");
  711.  
  712. body:
  713.     while (*cp)
  714.     {
  715.         switch (*cp) {
  716.         case '$':
  717.             switch (*++cp) {
  718.             case '?':
  719.                 printf ("ifset (%s, ", macro (*++cp));
  720.                 conditional++;
  721.                 break;
  722.             case '|':
  723.                 putchar (',');
  724.                 break;
  725.             case '.':
  726.                 putchar (')');
  727.                 conditional--;
  728.                 break;
  729.             default:
  730.                 printf ("${%s}", macro (*cp));
  731.                 break;
  732.             }
  733.             break;
  734.         default:
  735.             putchar (*cp);
  736.             break;
  737.         }
  738.         cp++;
  739.     }
  740.  
  741.     /* handle continuation lines */
  742.     if (ngets (buffer) != NULL)
  743.     {
  744.         line++;
  745.         if (buffer[0] == '\t')
  746.         {
  747.             printf ("\\\n");
  748.             cp = buffer + 1;
  749.             goto body;
  750.         }
  751.         else
  752.             ungets (buffer);
  753.     }
  754.     else
  755.         ungets ((char *) NULL);
  756.  
  757.     printf ("\");\n");
  758.  
  759.     if (flags)
  760.         printf ("\t};\n");
  761.  
  762.     if (conditional)
  763.         die ("header");
  764. }
  765.  
  766. /* option --- translate a sendmail option to an ease option */
  767.  
  768. option ()
  769. {
  770.     register char *name = buffer + 1, *value = buffer + 2;
  771.  
  772.     printf ("options\n\t");
  773.     if (*name == 'd')        /* delivery */
  774.         printf ("o_delivery = %s;\n", delivoption (*value));
  775.     else if (*name == 'e')        /* handling */
  776.         printf ("o_handling = %s;\n", handle_option (*value));
  777.     else
  778.         printf ("%s = \"%s\";\n", optionname (*name), value);
  779. }
  780.  
  781. /* trusted --- define the list of trusted users */
  782.  
  783. trusted ()
  784. {
  785.     register char *cp = buffer + 1;
  786.  
  787.     while (*cp)
  788.     {
  789.         if (isspace (*cp))
  790.             *cp = ',';
  791.         cp++;
  792.     }
  793.     printf ("trusted\n\t{ %s };\n", buffer+1);
  794. }
  795.  
  796. /* precedence --- define the precedence of a message class */
  797.  
  798. precedence ()
  799. {
  800.     register char *cp = buffer + 1;
  801.  
  802.     printf ("precedence\n\t");
  803.     for (; *cp && *cp != '='; cp++)
  804.         putchar (*cp);
  805.     printf (" = %s;\n", ++cp);
  806. }
  807.  
  808. /* other --- not a sendmail control line */
  809.  
  810. other ()
  811. {
  812.     printf ("%s\n", buffer);
  813. }
  814.  
  815. die (routine)
  816. char *routine;
  817. {
  818.     fprintf (stderr, "%s: malformed input line %d: fatal error\n",
  819.             routine, line);
  820.     exit (1);
  821. }
  822.  
  823. /* macro --- return name for sendmail predefined macro */
  824.  
  825. char *macro (c)
  826. char c;
  827. {
  828.     static char buf[2] = { '\0', '\0' };
  829.  
  830.     switch (c) {
  831.     case 'a':    /* The origination date in Arpanet format */
  832.         return ("m_odate");
  833.  
  834.     case 'b':    /* The current date in Arpanet format */
  835.         return ("m_adate");
  836.  
  837.     case 'c':    /* The hop count */
  838.         return ("m_hops");
  839.  
  840.     case 'd':    /* The date in UNIX (ctime) format */
  841.         return ("m_udate");
  842.  
  843.     case 'e':    /* The SMTP entry message */
  844.         return ("m_smtp");
  845.  
  846.     case 'f':    /* The sender (from) address */
  847.         return ("m_saddr");
  848.  
  849.     case 'g':    /* The sender address relative to the recipient */
  850.         return ("m_sreladdr");
  851.  
  852.     case 'h':    /* The recipient host */
  853.         return ("m_rhost");
  854.  
  855.     case 'i':    /* The queue id */
  856.         return ("m_qid");
  857.  
  858.     case 'j':    /* The official domain name for this site */
  859.         return ("m_oname");
  860.  
  861.     case 'l':    /* The format of the UNIX from line */
  862.         return ("m_ufrom");
  863.  
  864.     case 'n':    /* The name of the daemon (for error messages) */
  865.         return ("m_daemon");
  866.  
  867.     case 'o':    /* The set of "operators" in addresses */
  868.         return ("m_addrops");
  869.  
  870.     case 'p':    /* Sendmail's pid */
  871.         return ("m_pid");
  872.  
  873.     case 'q':    /* The default format of sender address */
  874.         return ("m_defaddr");
  875.  
  876.     case 'r':    /* Protocol used */
  877.         return ("m_protocol");
  878.  
  879.     case 's':    /* Sender's host name */
  880.         return ("m_shostname");
  881.  
  882.     case 't':    /* A numeric representation of the current time */
  883.         return ("m_ctime");
  884.  
  885.     case 'u':    /* The recipient user */
  886.         return ("m_ruser");
  887.  
  888.     case 'v':    /* The version number of sendmail */
  889.         return ("m_version");
  890.  
  891.     case 'w':    /* The hostname of this site */
  892.         return ("m_sitename");
  893.  
  894.     case 'x':    /* The full name of the sender */
  895.         return ("m_sname");
  896.  
  897.     case 'y':    /* The id of the sender's tty */
  898.         return ("m_stty");
  899.  
  900.     case 'z':    /* The home directory of the recipient */
  901.         return ("m_rhdir");
  902.  
  903.     default:
  904.         buf[0] = c;
  905.         return (buf);
  906.     }
  907. }
  908.  
  909. #define docompat(val)    if (compat) goto warn; else return (val)
  910.  
  911. /* mflags --- convert sendmail mailer flags to ease names */
  912.  
  913. char *mflags (c)
  914. char c;
  915. {
  916.     static char buf[2] = { '\0', '\0' };
  917.  
  918.     switch (c) {
  919.     case 'f':    return ("f_ffrom");
  920.     case 'r':    return ("f_rfrom");
  921.     case 'S':    return ("f_noreset");
  922.     case 'n':    return ("f_noufrom");
  923.     case 'l':    return ("f_locm");
  924.     case 's':    return ("f_strip"); 
  925.     case 'm':    return ("f_mult");
  926.     case 'F':    return ("f_from");
  927.     case 'D':    return ("f_date");
  928.     case 'M':    return ("f_mesg");
  929.     case 'x':    return ("f_full");    
  930.     case 'P':    return ("f_return");    
  931.     case 'u':    return ("f_upperu");    
  932.     case 'h':    return ("f_upperh");    
  933.     case 'A':    return ("f_arpa");    
  934.     case 'U':    return ("f_ufrom");    
  935.     case 'e':    return ("f_expensive");    
  936.     case 'X':    return ("f_dot");    
  937.     case 'L':    return ("f_llimit");    
  938.     case 'p':    return ("f_retsmtp");    
  939.     case 'I':    return ("f_smtp");    
  940.     case 'C':    return ("f_addrw");    
  941.     case 'E':    docompat ("f_escape");
  942.     default:
  943.     warn:
  944.         fprintf (stderr,
  945.             "warning: non standard mailer flag '%c' on line %d\n",
  946.                 c, line);
  947.         buf[0] = c;
  948.         return buf;
  949.     }
  950. }
  951.  
  952. /* optionname --- convert sendmail options to ease names */
  953.  
  954. char *optionname (c)
  955. char c;
  956. {
  957.     static char buf[2] = { '\0', '\0' };
  958.  
  959.     switch (c) {
  960.     case 'A':    return ("o_alias");
  961.     case 'a':    return ("o_ewait");
  962.     case 'B':    return ("o_bsub");
  963.     case 'c':    return ("o_qwait");
  964.     case 'd':    return ("o_delivery");
  965.     case 'D':    return ("o_rebuild");
  966.     case 'e':    return ("o_handling");
  967.     case 'F':    return ("o_tmode");
  968.     case 'f':    return ("o_usave");
  969.     case 'g':    return ("o_gid");
  970.     case 'H':    return ("o_fsmtp");
  971.     case 'i':    return ("o_skipd");
  972.     case 'L':    return ("o_slog");
  973.     case 'm':    return ("o_rsend");
  974.     case 'N':    return ("o_dnet");
  975.     case 'o':    return ("o_hformat");
  976.     case 'Q':    return ("o_qdir");
  977.     case 'q':    docompat ("o_qfactor");
  978.     case 'r':    return ("o_tread");
  979.     case 'S':    return ("o_flog");
  980.     case 's':    return ("o_safe");
  981.     case 'T':    return ("o_qtimeout");
  982.     case 't':    return ("o_timezone");
  983.     case 'u':    return ("o_dmuid");
  984.     case 'v':    return ("o_verbose");
  985.     case 'W':    return ("o_wizpass");
  986.     case 'x':    return ("o_loadq");
  987.     case 'X':    return ("o_loadnc");
  988.     case 'Y':    docompat ("o_newproc");
  989.     case 'y':    docompat ("o_recipfactor");
  990.     case 'Z':    docompat ("o_prifactor");
  991.     case 'z':    docompat ("o_waitfactor");
  992.     default:
  993.     warn:
  994.         fprintf (stderr,
  995.             "warning: non standard option '%c' on line %d\n",
  996.                 c, line);
  997.         buf[0] = c;
  998.         return buf;
  999.     }
  1000. }
  1001.  
  1002. /* delivoption --- convert sendmail delivery option value to ease name */
  1003.  
  1004. char *delivoption (c)
  1005. char c;
  1006. {
  1007.     static char buf[2] = { '\0', '\0' };
  1008.  
  1009.     switch (c) {
  1010.     case 'i':    return ("d_interactive");
  1011.     case 'b':    return ("d_background");
  1012.     case 'q':    return ("d_queue");
  1013.     default:
  1014.         fprintf (stderr,
  1015.     "warning: non standard delivery option '%c' on line %d\n", c, line);
  1016.         buf[0] = c;
  1017.         return buf;
  1018.     }
  1019. }
  1020.  
  1021. /* handle_option --- convert sendmail handling option value to ease name */
  1022.  
  1023. char *handle_option (c)
  1024. char c;
  1025. {
  1026.     static char buf[2] = { '\0', '\0' };
  1027.  
  1028.     switch (c) {
  1029.     case 'p':    return ("h_print");
  1030.     case 'q':    return ("h_exit");
  1031.     case 'm':    return ("h_mail");
  1032.     case 'w':    return ("h_write");
  1033.     case 'e':    return ("h_mailz");
  1034.     default:
  1035.         fprintf (stderr,
  1036.     "warning: non standard handling option '%c' on line %d\n", c, line);
  1037.         buf[0] = c;
  1038.         return buf;
  1039.     }
  1040. }
  1041.  
  1042. /*
  1043.  * "buffered" i/o routines. These are necessary since
  1044.  * mail headers may have continuation lines, and we can't see if
  1045.  * a continuation line is there without getting it. If it isn't,
  1046.  * just put it back.
  1047.  */
  1048.  
  1049. int saved = 0;
  1050. char *saveb = NULL;
  1051.  
  1052. /* ngets --- get a line of input from either saved buffer or stdin */
  1053.  
  1054. char *ngets (bp)
  1055. char *bp;
  1056. {
  1057.     if (! saved)
  1058.         return (gets (bp));
  1059.  
  1060.     saved = 0;
  1061.     bp = saveb;
  1062.     saveb = NULL;
  1063.     return (bp);
  1064. }
  1065.  
  1066. /* ungets --- put a buffer back on the input, so to speak */
  1067.  
  1068. void ungets (bp)
  1069. char *bp;
  1070. {
  1071.     saved = 1;
  1072.     saveb = bp;
  1073.     line--;
  1074. }
  1075.