home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume10 / cfc / cfc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-06-30  |  19.5 KB  |  1,065 lines

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