home *** CD-ROM | disk | FTP | other *** search
- Subject: v17i089: Ease2.0, a language for sendmail.cf files, Part03/03
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: "Arnold D. Robbins" <arnold@EMORYU1.ARPA>
- Posting-number: Volume 17, Issue 89
- Archive-name: ease2/part03
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 3 (of 3)."
- # Contents: cfc/cfc.c doc/ease.paper
- # Wrapped by rsalz@papaya.bbn.com on Wed Feb 8 16:55:44 1989
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'cfc/cfc.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'cfc/cfc.c'\"
- else
- echo shar: Extracting \"'cfc/cfc.c'\" \(21150 characters\)
- sed "s/^X//" >'cfc/cfc.c' <<'END_OF_FILE'
- X#ifndef lint
- Xstatic char RCSid[] = "$Header: cfc.c,v 2.0 88/06/15 15:16:48 root Exp $";
- X#endif
- X
- X/*
- X * $Log: cfc.c,v $
- X * Revision 2.0 88/06/15 15:16:48 root
- X * Baseline release for net posting. ADR.
- X *
- X * Revision 1.6 88/06/10 13:45:16 root
- X * Fix originally from Raymond A. Schnitzler (ras@sabre.bellcore.com) to
- X * add the (undocumented) 'P' option which sets the Postmaster address for
- X * receiving cc's of bad mail. ADR.
- X *
- X * Revision 1.5 88/01/21 16:18:13 root
- X * Eliminated Rutgers-ism, linted, smartened Mailer Argv handling. ADR.
- X *
- X * Revision 1.4 88/01/21 15:57:52 root
- X * Added the 'y' factor; missed it last time. ADR.
- X *
- X * Revision 1.3 87/04/08 10:23:02 root
- X * Small bug fixes, compatibility option added, also warnings for
- X * unrecognized flags and options. ADR.
- X *
- X * Revision 1.2 87/02/18 15:26:39 root
- X * Fix to recognize multidigit ruleset numbers in $> (calls) in RHS. ADR.
- X *
- X * Revision 1.1 87/02/16 15:25:00 arnold
- X * Initial revision
- X *
- X * Revision 1.1 87/02/16 15:25:00 arnold
- X * Initial revision
- X *
- X */
- X
- X/*
- X * cfc.c
- X *
- X * Sendmail cf file compiler.
- X * Reads a raw sendmail.cf file and produces ease source.
- X *
- X * There are very few comments in this source. You will need both the
- X * "Sendmail Installation and Operation Guide" and the paper on Ease
- X * to really understand this.
- X *
- X * Arnold Robbins
- X * Emory University Computing Center
- X * 2/87
- X */
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X
- Xchar buffer[BUFSIZ];
- Xint line = 0;
- Xint inruleset = 0;
- X
- Xextern char *macro (); /* convert sendmail to ease macro names */
- Xextern char *mflags (); /* convert sendmail to ease mailer flag names */
- Xextern char *optionname (); /* convert sendmail to ease option names */
- Xextern char *delivoption (); /* delivery options */
- Xextern char *handle_option (); /* handling options */
- X
- Xextern char *ngets (); /* buffered gets () routine */
- Xextern void ungets (); /* put a buffer back for getting */
- X
- X#define endruleset() if (inruleset) { inruleset = 0; printf ("\t}\n"); }
- X
- Xint compat = 0; /* complain about new 4.3 options & flags */
- Xint undoc = 0; /* complain about undocumented options, flags */
- X
- Xmain (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X extern int getopt ();
- X extern int optind;
- X int c;
- X
- X while ((c = getopt (argc, argv, "cu")) != EOF) {
- X switch (c) {
- X case 'c':
- X compat = 1;
- X break;
- X case 'u':
- X undoc = 1;
- X break;
- X case '?':
- X default:
- X fprintf (stderr, "usage: %s [ -c ] [ -u ]\n", argv[0]);
- X break;
- X }
- X }
- X
- X if (optind < argc)
- X fprintf (stderr,
- X "warning: ignoring non-flag command line arguments\n");
- X
- X printf ("/******************************************************/\n");
- X printf ("/* This ease file generated by cfc from a sendmail.cf */\n");
- X printf ("/* file. It must be edited by hand before being fed */\n");
- X printf ("/* to ease! */\n");
- X printf ("/******************************************************/\n");
- X printf ("\n\nbind\n\t/* RULESET BINDINGS GO HERE (cfc) */\n\n");
- X
- X /*
- X * For perfection, everything but the comment and rule cases
- X * should do an endruleset (), but practically speaking, it is
- X * usually only the mailer new ruleset definitions that end a
- X * previous ruleset. Occasionally a macro, too.
- X */
- X
- X while (ngets (buffer) != NULL)
- X {
- X line++;
- X switch (buffer[0]) {
- X case '#':
- X comment ();
- X continue; /* skip code to end ruleset */
- X case 'S':
- X endruleset ();
- X ruleset ();
- X continue; /* skip code to end ruleset */
- X case 'R':
- X rule ();
- X continue; /* skip code to end ruleset */
- X case 'D':
- X endruleset ();
- X def ();
- X break;
- X case 'C':
- X class ();
- X break;
- X case 'F':
- X fileclass ();
- X break;
- X case 'M':
- X endruleset ();
- X mailer ();
- X break;
- X case 'H':
- X header ();
- X break;
- X case 'O':
- X option ();
- X break;
- X case 'T':
- X trusted ();
- X break;
- X case 'P':
- X precedence ();
- X break;
- X default:
- X other ();
- X continue; /* skip code to end ruleset */
- X }
- X endruleset ();
- X }
- X endruleset (); /* just in case */
- X exit (0);
- X /*NOTREACHED*/
- X}
- X
- X/* comment --- produce a comment */
- X
- Xcomment ()
- X{
- X static char format[] = "/* %s */\n";
- X register int i = strlen (buffer) - 1;
- X
- X /* try to be semi-intelligent about comments */
- X
- X if (buffer[1] == '\0')
- X printf ("\n");
- X else if (isspace (buffer[1]) && buffer[i] != '#')
- X {
- X for (i = 1; isspace (buffer[i]); i++)
- X ;
- X printf (format, buffer + i);
- X }
- X else
- X printf (format, buffer);
- X}
- X
- X/* ruleset --- name a ruleset */
- X
- Xruleset ()
- X{
- X static int first = 1;
- X register char *cp = buffer + 1;
- X
- X if (first)
- X {
- X first = 0;
- X printf ("\n/* These are sample field definitons (cfc) */\n");
- X printf ("\nfield\n\tzero_or_more : match (0*);\n");
- X printf ("\tone_or_more : match (1*);\n");
- X printf ("\texactly_one : match (1);\n");
- X printf ("\tany_in_? : match (1) in ?;\n");
- X printf ("\tany_not_in_? : match (0) in ?;\n\n");
- X }
- X
- X printf ("ruleset\n\tRULESET_");
- X while (*cp && ! isspace (*cp))
- X {
- X putchar (*cp);
- X cp++;
- X }
- X
- X printf (" {");
- X if (*cp)
- X printf ("\t/* %s */", cp);
- X putchar ('\n');
- X inruleset++;
- X}
- X
- X/* rule --- print out a rule */
- X
- Xrule ()
- X{
- X register char *cp = buffer + 1;
- X register char *cp2;
- X register int com = 0;
- X
- X /* first, split it up into LHS, RHS, COMMENT */
- X
- X while (*cp != '\t')
- X cp++;
- X *cp = '\0';
- X
- X cp++;
- X while (*cp == '\t')
- X cp++;
- X cp2 = cp;
- X while (*cp && *cp != '\t')
- X cp++;
- X if (*cp == '\t' && cp[1])
- X {
- X *cp = '\0';
- X com++;
- X cp++;
- X while (*cp == '\t')
- X cp++;
- X }
- X
- X /* now print */
- X lhs (buffer + 1); /* left hand side */
- X if (com)
- X printf ("\t/* %s */", cp);
- X putchar ('\n');
- X rhs (cp2); /* right hand side */
- X}
- X
- X/* lhs --- left hand side of a production */
- X
- Xlhs (text)
- Xchar *text;
- X{
- X register char *cp = text;
- X register int conditional = 0;
- X register int quoting = 0;
- X
- X printf ("\tif (");
- X for (; *cp; cp++)
- X {
- X switch (*cp) {
- X case '$':
- X if (quoting)
- X {
- X quoting = 0;
- X putchar ('"');
- X }
- X switch (*++cp) {
- X case '*':
- X printf (" zero_or_more ");
- X break;
- X case '+':
- X printf (" one_or_more ");
- X break;
- X case '-':
- X printf (" exactly_one ");
- X break;
- X case '=':
- X printf (" any_in_%c ", *++cp);
- X break;
- X case '~':
- X printf (" any_not_in_%c ", *++cp);
- X break;
- X case '?':
- X printf (" ifset (%s, ", macro (*++cp));
- X conditional++;
- X break;
- X case '|':
- X printf (", ");
- X break;
- X case '.':
- X putchar (')');
- X conditional--;
- X break;
- X case '1':
- X case '2':
- X case '3':
- X case '4':
- X case '5':
- X case '6':
- X case '7':
- X case '8':
- X case '9':
- X printf ("$%c", *cp);
- X break;
- X default:
- X if (quoting)
- X printf ("${%s}", macro (*cp));
- X else
- X printf ("$%s", macro (*cp));
- X break;
- X }
- X break;
- X default:
- X if (ispunct (*cp))
- X {
- X if (quoting) /* end a literal */
- X {
- X quoting = 0;
- X putchar ('"');
- X }
- X /* else
- X do nothing */
- X }
- X else
- X {
- X if (! quoting) /* start a literal */
- X {
- X quoting = 1;
- X putchar ('"');
- X }
- X /* else
- X do nothing */
- X }
- X putchar (*cp); /* print the character */
- X break;
- X }
- X }
- X if (quoting)
- X putchar ('"');
- X if (conditional)
- X die ("lhs");
- X printf (")");
- X}
- X
- X/* rhs --- right hand side of a production */
- X
- Xrhs (text)
- Xchar *text;
- X{
- X register char *cp = text;
- X char *index ();
- X register int open = 0;
- X register int conditional = 0;
- X register int quoting = 0;
- X
- X printf ("\t\t");
- X
- X if (*cp == '$' && index ("#@:", cp[1]) != NULL)
- X ; /* not the default */
- X else
- X {
- X printf ("retry (");
- X open++;
- X }
- X
- X for (; *cp; cp++)
- X {
- X switch (*cp) {
- X case '$':
- X if (quoting)
- X {
- X quoting = 0;
- X putchar ('"');
- X }
- X switch (*++cp) {
- X case '>':
- X printf ("RULESET_");
- X for (cp++; *cp && isdigit (*cp); cp++)
- X putchar (*cp);
- X cp--;
- X printf (" (");
- X open++;
- X break;
- X case '[':
- X printf ("canon (");
- X open++;
- X break;
- X case ']':
- X putchar (')');
- X open--;
- X break;
- X case '?':
- X printf ("ifset (%s, ", macro (*++cp));
- X conditional++;
- X break;
- X case '|':
- X putchar (',');
- X break;
- X case '.':
- X putchar (')');
- X conditional--;
- X break;
- X case '#':
- X printf ("resolve (mailer (");
- X if (strncmp (cp+1, "local$", 6) == 0
- X || strncmp (cp+1, "error$", 6) == 0)
- X goto skiphost;
- X loop1:
- X for (cp++; *cp != '$'; cp++)
- X putchar (*cp);
- X cp++;
- X if (*cp != '@')
- X {
- X printf ("$%c", *cp);
- X goto loop1;
- X }
- X printf ("),\n\t\t\t\thost (");
- X skiphost:
- X loop2:
- X for (cp++; *cp != '$'; cp++)
- X putchar (*cp);
- X cp++;
- X if (*cp != ':')
- X {
- X printf ("$%c", *cp);
- X goto loop2;
- X }
- X printf ("),\n\t\t\t\tuser (");
- X for (cp++; *cp; cp++)
- X putchar (*cp);
- X printf ("))");
- X goto out; /* string is exhausted */
- X /* break; */
- X case '@':
- X printf ("return (");
- X open++;
- X break;
- X case ':':
- X printf ("next (");
- X open++;
- X break;
- X case '1':
- X case '2':
- X case '3':
- X case '4':
- X case '5':
- X case '6':
- X case '7':
- X case '8':
- X case '9':
- X printf ("$%c", *cp);
- X break;
- X default:
- X if (quoting)
- X printf ("${%s}", macro (*cp));
- X else
- X printf ("$%s", macro (*cp));
- X break;
- X }
- X break;
- X default:
- X if (ispunct (*cp))
- X {
- X if (quoting) /* end a literal */
- X {
- X quoting = 0;
- X putchar ('"');
- X }
- X /* else
- X do nothing */
- X }
- X else
- X {
- X if (! quoting) /* start a literal */
- X {
- X quoting = 1;
- X putchar ('"');
- X }
- X /* else
- X do nothing */
- X }
- X putchar (*cp); /* print the character */
- X break;
- X }
- X }
- Xout:
- X if (quoting)
- X putchar ('"');
- X while (open--)
- X putchar (')');
- X printf (";\n");
- X if (conditional)
- X die ("rhs");
- X}
- X
- X/* def --- define a macro */
- X
- Xdef ()
- X{
- X register char *mac = buffer + 1, *value = buffer + 2;
- X register int conditional = 0;
- X
- X printf ("macro\n\t%s = \"", macro (*mac));
- X
- X while (*value)
- X {
- X switch (*value) {
- X case '$':
- X switch (*++value) {
- X case '?':
- X printf ("ifset (%s, ", macro (*++value));
- X conditional++;
- X break;
- X case '|':
- X putchar (',');
- X break;
- X case '.':
- X putchar (')');
- X conditional--;
- X break;
- X default:
- X printf ("${%s}", macro (*value));
- X break;
- X }
- X break;
- X default:
- X putchar (*value);
- X break;
- X }
- X value++;
- X }
- X printf ("\";\n");
- X if (conditional)
- X die ("def");
- X}
- X
- X/* class --- define a class list */
- X
- Xclass ()
- X{
- X register char *name = buffer + 1, *value = buffer + 2;
- X
- X printf ("class\n\t%c = { ", *name);
- X
- X while (*value && isspace (*value))
- X value++;
- X
- X while (*value)
- X {
- X if (isspace (*value))
- X {
- X printf (", ");
- X while (isspace (*value))
- X value++;
- X value--; /* cancel loop */
- X }
- X else
- X putchar (*value);
- X value++;
- X }
- X printf (" };\n");
- X}
- X
- X/* fileclass --- define a class that is to be read from a file */
- X
- Xfileclass ()
- X{
- X register char *name = buffer + 1, *value = buffer + 2;
- X
- X printf ("class\n\t%c = readclass (\"", *name);
- X for (; *value && !isspace (*value); value++)
- X putchar (*value);
- X putchar ('"');
- X while (*value && isspace (*value))
- X value++;
- X if (*value)
- X printf (", \"%s\"", value);
- X printf (");\n");
- X}
- X
- X/* mailer --- convert a mailer specification */
- X
- Xmailer ()
- X{
- X register char *cp = buffer + 1;
- X
- X printf ("mailer\n\t");
- X for (; *cp != ','; cp++)
- X putchar (*cp);
- X cp++;
- X printf (" {\n"); /* just did mailer name */
- X
- X#define skipname() cp++; while (*cp != '=') cp++; cp++
- X#define value() for (; *cp && *cp != ','; cp++) putchar (*cp); cp++
- X
- Xloop:
- X while (*cp && isspace (*cp))
- X cp++;
- X
- X printf ("\t\t");
- X switch (*cp) {
- X case 'A':
- X skipname ();
- X printf ("Argv = \"");
- X for (; *cp && *cp != ','; cp++)
- X {
- X if (*cp == '$') /* XXX: assume no conditionals */
- X printf ("${%s}", macro (*++cp));
- X else if (*cp == '"')
- X printf ("\\\"");
- X else
- X putchar (*cp);
- X }
- X cp++; /* do manually what value does */
- X putchar ('"');
- X break;
- X
- X case 'E':
- X skipname ();
- X printf ("Eol = \"");
- X value ();
- X putchar ('"');
- X break;
- X
- X case 'F':
- X skipname ();
- X printf ("Flags = { ");
- X for (; *cp && *cp != ','; cp++)
- X {
- X printf ("%s", mflags (*cp));
- X if (cp[1] && cp[1] != ',')
- X printf (", ");
- X }
- X cp++; /* do manually what value does */
- X printf (" }");
- X break;
- X
- X case 'M':
- X skipname ();
- X printf ("Maxsize = \"");
- X value ();
- X putchar ('"');
- X break;
- X
- X case 'P':
- X skipname ();
- X printf ("Path = \"");
- X value ();
- X putchar ('"');
- X break;
- X
- X case 'R':
- X skipname ();
- X printf ("Recipient = RULESET_");
- X value ();
- X break;
- X
- X case 'S':
- X skipname ();
- X printf ("Sender = RULESET_");
- X value ();
- X break;
- X
- X case '\0':
- X goto done;
- X }
- X
- X if (cp[-1] && cp[-1] == ',')
- X {
- X printf (",\n");
- X goto loop;
- X }
- X else
- X putchar ('\n');
- X
- Xdone:
- X /* handle continuation lines */
- X if (ngets (buffer) != NULL)
- X {
- X line++;
- X if (buffer[0] == '\t')
- X {
- X cp = buffer;
- X goto loop;
- X }
- X else
- X ungets (buffer);
- X }
- X else
- X ungets ((char *) NULL);
- X
- X printf ("\t};\n");
- X
- X#undef value
- X#undef skipname
- X}
- X
- X/* header --- define sendmail headers */
- X
- Xheader ()
- X{
- X register char *cp = buffer + 1;
- X register int flags = 0;
- X register int conditional = 0;
- X
- X printf ("header\n\t");
- X if (*cp == '?') /* header for mailers with these flags */
- X {
- X flags++;
- X printf ("for (");
- X for (cp++; *cp != '?'; cp++)
- X {
- X printf ("%s", mflags (*cp));
- X if (cp[1] != '?')
- X putchar (',');
- X }
- X printf (") {\n\t\t");
- X cp++; /* skip final '?' */
- X }
- X
- X printf ("define (\"");
- X for (; *cp && ! isspace (*cp); cp++)
- X putchar (*cp);
- X printf ("\", \"");
- X
- Xbody:
- X while (*cp)
- X {
- X switch (*cp) {
- X case '$':
- X switch (*++cp) {
- X case '?':
- X printf ("ifset (%s, ", macro (*++cp));
- X conditional++;
- X break;
- X case '|':
- X putchar (',');
- X break;
- X case '.':
- X putchar (')');
- X conditional--;
- X break;
- X default:
- X printf ("${%s}", macro (*cp));
- X break;
- X }
- X break;
- X default:
- X putchar (*cp);
- X break;
- X }
- X cp++;
- X }
- X
- X /* handle continuation lines */
- X if (ngets (buffer) != NULL)
- X {
- X line++;
- X if (buffer[0] == '\t')
- X {
- X printf ("\\\n");
- X cp = buffer + 1;
- X goto body;
- X }
- X else
- X ungets (buffer);
- X }
- X else
- X ungets ((char *) NULL);
- X
- X printf ("\");\n");
- X
- X if (flags)
- X printf ("\t};\n");
- X
- X if (conditional)
- X die ("header");
- X}
- X
- X/* option --- translate a sendmail option to an ease option */
- X
- Xoption ()
- X{
- X register char *name = buffer + 1, *value = buffer + 2;
- X
- X printf ("options\n\t");
- X if (*name == 'd') /* delivery */
- X printf ("o_delivery = %s;\n", delivoption (*value));
- X else if (*name == 'e') /* handling */
- X printf ("o_handling = %s;\n", handle_option (*value));
- X else
- X printf ("%s = \"%s\";\n", optionname (*name), value);
- X}
- X
- X/* trusted --- define the list of trusted users */
- X
- Xtrusted ()
- X{
- X register char *cp = buffer + 1;
- X
- X while (*cp)
- X {
- X if (isspace (*cp))
- X *cp = ',';
- X cp++;
- X }
- X printf ("trusted\n\t{ %s };\n", buffer+1);
- X}
- X
- X/* precedence --- define the precedence of a message class */
- X
- Xprecedence ()
- X{
- X register char *cp = buffer + 1;
- X
- X printf ("precedence\n\t");
- X for (; *cp && *cp != '='; cp++)
- X putchar (*cp);
- X printf (" = %s;\n", ++cp);
- X}
- X
- X/* other --- not a sendmail control line */
- X
- Xother ()
- X{
- X printf ("%s\n", buffer);
- X}
- X
- Xdie (routine)
- Xchar *routine;
- X{
- X fprintf (stderr, "%s: malformed input line %d: fatal error\n",
- X routine, line);
- X exit (1);
- X}
- X
- X/* macro --- return name for sendmail predefined macro */
- X
- Xchar *macro (c)
- Xchar c;
- X{
- X static char buf[2] = { '\0', '\0' };
- X
- X switch (c) {
- X case 'a': /* The origination date in Arpanet format */
- X return ("m_odate");
- X
- X case 'b': /* The current date in Arpanet format */
- X return ("m_adate");
- X
- X case 'c': /* The hop count */
- X return ("m_hops");
- X
- X case 'd': /* The date in UNIX (ctime) format */
- X return ("m_udate");
- X
- X case 'e': /* The SMTP entry message */
- X return ("m_smtp");
- X
- X case 'f': /* The sender (from) address */
- X return ("m_saddr");
- X
- X case 'g': /* The sender address relative to the recipient */
- X return ("m_sreladdr");
- X
- X case 'h': /* The recipient host */
- X return ("m_rhost");
- X
- X case 'i': /* The queue id */
- X return ("m_qid");
- X
- X case 'j': /* The official domain name for this site */
- X return ("m_oname");
- X
- X case 'l': /* The format of the UNIX from line */
- X return ("m_ufrom");
- X
- X case 'n': /* The name of the daemon (for error messages) */
- X return ("m_daemon");
- X
- X case 'o': /* The set of "operators" in addresses */
- X return ("m_addrops");
- X
- X case 'p': /* Sendmail's pid */
- X return ("m_pid");
- X
- X case 'q': /* The default format of sender address */
- X return ("m_defaddr");
- X
- X case 'r': /* Protocol used */
- X return ("m_protocol");
- X
- X case 's': /* Sender's host name */
- X return ("m_shostname");
- X
- X case 't': /* A numeric representation of the current time */
- X return ("m_ctime");
- X
- X case 'u': /* The recipient user */
- X return ("m_ruser");
- X
- X case 'v': /* The version number of sendmail */
- X return ("m_version");
- X
- X case 'w': /* The hostname of this site */
- X return ("m_sitename");
- X
- X case 'x': /* The full name of the sender */
- X return ("m_sname");
- X
- X case 'y': /* The id of the sender's tty */
- X return ("m_stty");
- X
- X case 'z': /* The home directory of the recipient */
- X return ("m_rhdir");
- X
- X default:
- X buf[0] = c;
- X return (buf);
- X }
- X}
- X
- X#define docompat(val) if (compat) goto warn; else return (val)
- X#define dofundoc(val) if (undoc) \
- Xfprintf (stderr, "warning: undocumented flag '%c' used on line %d\n", c, line);\
- Xreturn (val)
- X
- X/* mflags --- convert sendmail mailer flags to ease names */
- X
- Xchar *mflags (c)
- Xchar c;
- X{
- X static char buf[2] = { '\0', '\0' };
- X
- X switch (c) {
- X case 'f': return ("f_ffrom");
- X case 'r': return ("f_rfrom");
- X case 'S': return ("f_noreset");
- X case 'n': return ("f_noufrom");
- X case 'l': return ("f_locm");
- X case 's': return ("f_strip");
- X case 'm': return ("f_mult");
- X case 'F': return ("f_from");
- X case 'D': return ("f_date");
- X case 'M': return ("f_mesg");
- X case 'x': return ("f_full");
- X case 'P': return ("f_return");
- X case 'u': return ("f_upperu");
- X case 'h': return ("f_upperh");
- X case 'A': return ("f_arpa");
- X case 'U': return ("f_ufrom");
- X case 'e': return ("f_expensive");
- X case 'X': return ("f_dot");
- X case 'L': return ("f_llimit");
- X case 'p': return ("f_retsmtp");
- X case 'I': return ("f_smtp");
- X case 'C': return ("f_addrw");
- X case 'E': docompat ("f_escape");
- X case 'R': dofundoc ("f_rport");
- X default:
- X warn:
- X fprintf (stderr,
- X "warning: non standard mailer flag '%c' on line %d\n",
- X c, line);
- X buf[0] = c;
- X return buf;
- X }
- X}
- X
- X#define doOundoc(val) if (undoc) \
- Xfprintf (stderr, "warning: undocumented option '%c' used on line %d\n", c, line);\
- Xreturn (val)
- X
- X/* optionname --- convert sendmail options to ease names */
- X
- Xchar *optionname (c)
- Xchar c;
- X{
- X static char buf[2] = { '\0', '\0' };
- X
- X switch (c) {
- X case 'A': return ("o_alias");
- X case 'a': return ("o_ewait");
- X case 'B': return ("o_bsub");
- X case 'C': doOundoc ("o_checkpoint");
- X case 'c': return ("o_qwait");
- X case 'd': return ("o_delivery");
- X case 'D': return ("o_rebuild");
- X case 'e': return ("o_handling");
- X case 'F': return ("o_tmode");
- X case 'f': return ("o_usave");
- X case 'g': return ("o_gid");
- X case 'H': return ("o_fsmtp");
- X case 'i': return ("o_skipd");
- X case 'L': return ("o_slog");
- X case 'm': return ("o_rsend");
- X case 'N': return ("o_dnet");
- X case 'n': doOundoc ("o_validate");
- X case 'o': return ("o_hformat");
- X case 'P': doOundoc ("o_pmaster");
- X case 'Q': return ("o_qdir");
- X case 'q': docompat ("o_qfactor");
- X case 'r': return ("o_tread");
- X case 'S': return ("o_flog");
- X case 's': return ("o_safe");
- X case 'T': return ("o_qtimeout");
- X case 't': return ("o_timezone");
- X case 'u': return ("o_dmuid");
- X case 'v': return ("o_verbose");
- X case 'W': return ("o_wizpass");
- X case 'x': return ("o_loadq");
- X case 'X': return ("o_loadnc");
- X case 'Y': docompat ("o_newproc");
- X case 'y': docompat ("o_recipfactor");
- X case 'Z': docompat ("o_prifactor");
- X case 'z': docompat ("o_waitfactor");
- X default:
- X warn:
- X fprintf (stderr,
- X "warning: non standard option '%c' on line %d\n",
- X c, line);
- X buf[0] = c;
- X return buf;
- X }
- X}
- X
- X/* delivoption --- convert sendmail delivery option value to ease name */
- X
- Xchar *delivoption (c)
- Xchar c;
- X{
- X static char buf[2] = { '\0', '\0' };
- X
- X switch (c) {
- X case 'i': return ("d_interactive");
- X case 'b': return ("d_background");
- X case 'q': return ("d_queue");
- X default:
- X fprintf (stderr,
- X "warning: non standard delivery option '%c' on line %d\n", c, line);
- X buf[0] = c;
- X return buf;
- X }
- X}
- X
- X/* handle_option --- convert sendmail handling option value to ease name */
- X
- Xchar *handle_option (c)
- Xchar c;
- X{
- X static char buf[2] = { '\0', '\0' };
- X
- X switch (c) {
- X case 'p': return ("h_print");
- X case 'q': return ("h_exit");
- X case 'm': return ("h_mail");
- X case 'w': return ("h_write");
- X case 'e': return ("h_mailz");
- X default:
- X fprintf (stderr,
- X "warning: non standard handling option '%c' on line %d\n", c, line);
- X buf[0] = c;
- X return buf;
- X }
- X}
- X
- X/*
- X * "buffered" i/o routines. These are necessary since
- X * mail headers may have continuation lines, and we can't see if
- X * a continuation line is there without getting it. If it isn't,
- X * just put it back.
- X */
- X
- Xint saved = 0;
- Xchar *saveb = NULL;
- X
- X/* ngets --- get a line of input from either saved buffer or stdin */
- X
- Xchar *ngets (bp)
- Xchar *bp;
- X{
- X if (! saved)
- X return (gets (bp));
- X
- X saved = 0;
- X bp = saveb;
- X saveb = NULL;
- X return (bp);
- X}
- X
- X/* ungets --- put a buffer back on the input, so to speak */
- X
- Xvoid ungets (bp)
- Xchar *bp;
- X{
- X saved = 1;
- X saveb = bp;
- X line--;
- X}
- END_OF_FILE
- if test 21150 -ne `wc -c <'cfc/cfc.c'`; then
- echo shar: \"'cfc/cfc.c'\" unpacked with wrong size!
- fi
- chmod +x 'cfc/cfc.c'
- # end of 'cfc/cfc.c'
- fi
- if test -f 'doc/ease.paper' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'doc/ease.paper'\"
- else
- echo shar: Extracting \"'doc/ease.paper'\" \(31245 characters\)
- sed "s/^X//" >'doc/ease.paper' <<'END_OF_FILE'
- X...
- X... $Header: ease.paper,v 1.6 88/06/15 10:12:36 root Locked $
- X...
- X... $Log: ease.paper,v $
- X... Revision 1.6 88/06/15 10:12:36 root
- X... Some editorial cleanup, added Acknowledgements section.
- X...
- X... Revision 1.5 88/01/21 17:19:35 root
- X... Several editorial changes. ADR.
- X...
- X... Revision 1.4 87/12/23 11:30:47 root
- X... Updated list of authors. Documented extended canon() capability.
- X... Integrated fluke changes in a little better. ADR.
- X...
- X... Revision 1.3 87/11/04 11:33:45 root
- X... Documented new keyword "while" which is equivalent to "if". ADR.
- X...
- X... Revision 1.2 87/08/13 17:08:05 root
- X... Changes from Jeff Stearns, fluke!jeff, for Sun. ADR.
- X...
- X... Revision 1.1 87/08/13 17:05:00 root
- X... Initial revision
- X...
- X...
- X.LP
- X.TL
- XEase: A Configuration Language
- Xfor Sendmail
- X.AU
- XJames S. Schoner
- X.AI
- XPurdue University Computing Center
- XWest Lafayette, Indiana 47907
- X.AU
- XJeff P. Stearns
- X.AI
- XJohn Fluke Manufacturing Company
- XEverett, Washington 98206
- X.AU
- XArnold D. Robbins
- X.AI
- XEmory University Computing Center
- XAtlanta, Georgia 30322
- X.sp 2
- X.I
- X.ce
- XABSTRACT
- X.R
- X.PP
- XThe rapid expansion of computer networks and ensuing variation among mailing
- Xaddress formats have made address interpretation an increasingly
- Xcomplex task. In the UNIX* 4.2BSD operating system, a program named
- X\fIsendmail\fR was introduced which provided a
- Xgeneral internetwork mail routing facility. This facility has significantly
- Xdiminished the complexity of handling address interpretation.
- X.PP
- X\fISendmail\fR's address interpretation is based on a rewriting
- Xsystem composed of
- Xa number of rewriting rules (or productions) arranged as part of a
- Xconfiguration file. Unfortunately, the syntactical format of a
- Xconfiguration file for \fIsendmail\fR is both terse and rigid, making it
- Xrather difficult to modify. The standard format certainly serves its
- Xpurpose, but, as
- Xthe need to change these configurations increases in frequency, a more
- Xreadable format (i.e., one that is similar to the format
- Xof modern programming languages) is required to permit reasonably
- Xquick modifications to the configuration. As a solution to this problem,
- X\fBEase\fR
- Xprovides a level of abstraction which eliminates most of the current
- Xsyntactic hindrances
- Xfaced by programmers who must reconfigure \fIsendmail\fR's
- Xaddress parsing scheme.
- X.PP
- XAs a high-level specification format, \fBEase\fR is proving to be an
- Xexcellent alternative to \fIsendmail\fR's cryptic
- Xconfiguration file syntax. The syntactic structures of \fBEase\fR
- Xare patterned after modern language constructs, making the language
- Xeasy to learn and easy to remember. The format of the address rewriting
- Xrule is perhaps the most significant syntactical improvement. It was
- Xundoubtedly
- Xthe most needed improvement. Nevertheless, every element of a configuration
- Xfile is structurally enhanced through the use of \fBEase\fR.
- X.FS
- X* UNIX is a registered trademark of AT&T.
- X.FE
- X.sp 2
- X.NH
- XIntroduction
- X.PP
- XThe \fBEase\fR language is a high-level specification format for \fIsendmail\fR's
- Xconfiguration file. The motivation for its development
- Xwas to fulfill a goal of providing a readable and easily modifiable
- X\fIsendmail\fR configuration file format. \fBEase\fR fulfills this goal by
- Xshielding the programmer from the cryptic configuration specification required
- Xby \fIsendmail\fR and providing a high-level language with which the programmer
- Xmay specify all modifications to a configuration file. The development
- Xof Ease coincided with
- Xthe development of an \fBEase\fR translator, \fIet\fR,
- Xwhich translates a configuration file written
- Xin \fBEase\fR to an
- Xequivalent file of the standard format accepted by \fIsendmail\fR.
- X.NH
- XEase in Profile
- X.PP
- XAs will be seen in the next section, the syntax of \fBEase\fR is quite
- Xreadable and easy to learn. In order to acquire a relevant perspective
- Xon this issue,
- Xthe reader is advised to examine a raw configuration file for \fIsendmail\fR (the
- Xoutput
- Xof the \fBEase\fR translator, \fIet\fR, will do nicely). The raw syntax, while
- Xquite fitting for quick translation, can prove to be a programmer's nightmare.
- X.PP
- XUndoubtedly, one of the more prominent features of \fBEase\fR is the ability
- Xto attach
- Xnames to address fields. When address field names are well-chosen, a distinct,
- Xself-documenting quality becomes a visible part of the address rewriting
- Xrules. Ostensibly, address field names provide a new level of semantic
- Xabstraction. A brief comparison of the formats can be accomplished by examining
- Xthe following equivalent representations of an address pattern:
- X.DS
- X user_path@host_name (\fBEase\fR format)
- X $+@$- (raw format)
- X.DE
- XIn the above, \*Quser_path\*U represents a field of one or more address
- Xtokens, and \*Qhost_name\*U represents one address token exactly. These
- Xtoken fields are represented by \*Q$+\*U and \*Q$-\*U in the raw format. Clearly,
- Xthe \fBEase\fR format is preferable, not only for increased readability, but
- Xstructural comprehension as well.
- X.PP
- XOther features of \fBEase\fR include ruleset naming, long identifiers for
- Xmacros and classes, flow-of-control structures, and free formatting. In
- Xaddition, the C language preprocessor (cpp) can be used for file inclusion
- Xand conditionally defined code constructs. The next section describes
- Xthe \fBEase\fR language in complete detail.
- X.NH
- XEase Syntax*
- X.FS
- X* \fINo attempt is made to describe the complete semantic meaning
- Xassociated with all of the constructs of a sendmail configuration file. Items
- Xnot covered in this document include the semantic distinction among rulesets,
- Xthe special uses of
- Xpre-defined macros, and the method of building configuration files. To
- Xobtain this information, the reader is advised to refer to
- Xthe Sendmail Installation and Operation Guide (SMM:7 in the 4.3 BSD
- XUNIX System Manager's Manual),
- Xby Eric Allman.\fR
- X.FE
- X.PP
- XAt its highest level, \fBEase\fR can be viewed as a collection of
- Xblock-structures, where each block begins with a keyword and is followed by
- Xzero or more related definitions and/or declarations. There are ten distinct
- Xblock types. The following is
- Xa list containing all ten block keywords and the block type it denotes.
- X.TS
- Xcenter;
- Xl l .
- X\fIbind\fR -ruleset identifier bindings
- X\fImacro\fR -macro definitions
- X\fIclass\fR -class definitions
- X\fIoptions\fR -\fIsendmail\fR option definitions
- X\fIprecedence\fR -precedence definitions
- X\fItrusted\fR -trusted users
- X\fIheader\fR -mail header definitions
- X\fImailer\fR -mailer definitions
- X\fIfield\fR -address field definitions
- X\fIruleset\fR -address rewriting rules
- X.TE
- X.sp 1
- XIn general,
- X.TS
- Xcenter ;
- Xl .
- X
- X* Letters are distinguished by case,
- X
- XT{
- X* An \fBEase\fR identifier is defined to be a letter, followed by zero or
- Xmore letters, digits, underscores (_), or dashes (-),
- XT}
- X
- XT{
- X* A literal newline or double quotation (") character may be included in
- Xany quoted string by preceding the character with a backslash (\\\\\), and
- XT}
- X
- XT{
- X* \fBEase\fR source is preprocessed by the C language preprocessor (cpp),
- Xthus source comments (i.e., text enclosed by \*Q/*\*U and \*Q*/\*U) may appear
- Xanywhere as part of \fBEase\fR whitespace.
- XT}
- X.TE
- X.PP
- XFor notational convenience, this document specifies all reserved
- Xwords of the \fBEase\fR language in italics. In addition, quantities
- Xenclosed in angle brackets (<..>) represent arbitrary
- Xidentifiers, strings, or numbers.
- X.NH 2
- XRuleset Identifier Bindings
- X.PP
- XA ruleset (a set of rewriting rules) is identified solely by an integer
- Xin \fIsendmail\fR's
- Xconfiguration file. \fBEase\fR, however, allows each ruleset to be named with
- Xa meaningful identifier. Since a special numeric association for each
- Xruleset is required by the address parsing scheme of \fIsendmail\fR, a \fIbind\fR
- Xblock must be present in any \fBEase\fR file which defines one or more
- Xrulesets. A
- X\fIbind\fR block consists of the keyword \fIbind\fR, followed by zero or more
- Xstatements of the form:
- X.TS
- Xcenter box;
- Xl .
- X<ruleset-id> = \fIruleset\fR <ruleset-number> ;
- X.TE
- XThe following example,
- X.sp 1
- X\fIbind\fR
- X.PP
- XFINAL_RW = \fIruleset\fR 4;
- X.sp 1
- Xspecifies that FINAL_RW, the final rewriting ruleset, is \fIsendmail\fR's ruleset
- Xnumber 4.
- X.NH 2
- XMacro Definitions
- X.PP
- XA macro is an identifier which, when referenced in the text of a program,
- Xis replaced by its value, a string of zero or more characters. The value
- Xof a macro may include references to other macros, but not itself! \fISendmail\fR
- Xallows a maximum of 26 user-declared macros in its configuration file. In
- Xaddition, there are a number of pre-declared macros which have special meaning
- Xto \fIsendmail\fR (see Appendix A). \fBEase\fR macros are defined in
- X\fImacro\fR blocks. \fBEase\fR allows any macro to be declared
- X(which is equivalent to simply referencing it) before it is defined. A macro
- Xidentifier is replaced by its value when it is preceded by the character
- X\*Q$\*U. In addition, a macro reference inside a quoted string must always
- Xinclude braces ({}) around the macro identifier (for delimiting purposes).
- X.PP
- XA \fImacro\fR block consists of the keyword \fImacro\fR, followed by zero
- Xor more statements taking either of the following forms:
- X.TS
- Xcenter box;
- Xl .
- X<macro-identifier> = "<macro-value>" ;
- X<macro-identifier> = \fBconditional-expression\fR ;
- X.TE
- XThe \fBconditional-expression\fR format will be discussed
- Xlater.
- X.sp 1
- XThe following example,
- X.sp 1
- X\fImacro\fR
- X.PP
- Xfirst_name = "James";
- X.PP
- Xlast_name = "Schoner";
- X.PP
- Xwhole_name = "${first_name} ${last_name}";
- X.sp 1
- Xdefines the macros first_name, last_name, and whole_name, where whole_name
- Xis the string, "James Schoner".
- X.NH 2
- XClass definitions
- X.PP
- XA class is denoted by an identifier representing a logical grouping of zero
- Xor more names. Classes are used to represent the range of values a token
- Xmay assume in the pattern matching of an address. Further discussion on the
- Xuse of classes will be deferred until address fields are described.
- X.PP
- XOne identifier may be used to distinctly represent both a macro
- Xand class (i.e., the set of macro identifiers and the set of class identifiers
- Xmay form a non-empty intersection). A name, or class element, may
- Xbe an identifier or any quoted word.
- X.PP
- XA \fIclass\fR block consists of the keyword \fIclass\fR, followed by zero
- Xor more statements taking any of the following forms:
- X.TS
- Xcenter box;
- Xl .
- X<class-identifier> = { <name1>, <name2>, <name3>, ... } ;
- X<class-identifier> = \fIreadclass\fR ( "<file-name>" ) ;
- X<class-identifier> = \fIreadclass\fR ( "<file-name>", "<read-format>" ) ;
- X.TE
- XThe second and third forms cause \fIsendmail\fR to read the names of the class
- Xfrom the named
- Xfile. The third form contains a read format, which should be a \fIscanf\fR(3)
- Xpattern yielding a single string.
- X.sp 1
- XThe following example,
- X.sp 1
- X\fIclass\fR
- X.PP
- Xcampus_hosts = { statistics, engineering, chemistry, physics, physics-2 } ;
- X.PP
- Xversions = { "1.0", "1.1", "4.0", "4.2", latest-and-greatest } ;
- X.PP
- Xphone_hosts = \fIreadclass\fR ( "/tmp/phonenet.list" ) ;
- X.sp 1
- Xdefines the classes campus_hosts, versions, and phone_hosts.
- X.NH 2
- XSendmail option definitions
- X.PP
- XA number of options to the \fIsendmail\fR program may be specified in
- Xan \fIoptions\fR
- Xblock. For a description of the various \fIsendmail\fR options and their
- Xvalues, see Appendix B.
- X.PP
- XAn
- X\fIoptions\fR block consists of the keyword \fIoptions\fR, followed by zero
- Xor more statements taking any of the following forms:
- X.TS
- Xcenter box;
- Xl l .
- X<option-identifier> = "<option-value>" ;
- X\fIo_delivery\fR = \fBspecial-value\fR ;
- X\fIo_handling\fR = \fBspecial-value\fR ;
- X.TE
- XAll but two options (\fIo_delivery\fR and \fIo_handling\fR) use the first
- Xform. To specify an option without a value, simply assign to it the null
- Xstring (""). The \fBspecial-value\fR field of the second and third form
- Xrefers to special values (non-quoted) which are specified in Appendix B.
- X.sp 1
- XThe following example,
- X.sp 1
- X\fIoptions\fR
- X.PP
- X\fIo_alias\fR = "/usr/lib/aliases" ;
- X.PP
- X\fIo_tmode\fR = "0600" ;
- X.PP
- X\fIo_delivery\fR = \fId_background\fR ;
- X.sp 1
- Xsets the options \fIo_alias\fR, \fIo_tmode\fR, and \fIo_delivery\fR.
- X.NH 2
- XPrecedence definitions
- X.PP
- XMessage headers may contain a \*QPrecedence:\*U field describing the precedence
- Xof the message class. Identifiers which may appear in the precedence field of
- Xa message are given precedence values in a configuration file \fIprecedence\fR
- Xdefinition. This association will be illustrated below in an example.
- X.PP
- XA \fIprecedence\fR block consists of the keyword \fIprecedence\fR, followed
- Xby zero or more statements of the form:
- X.KS
- X.TS
- Xcenter box;
- Xl .
- X<precedence-identifier> = <precedence-integer> ;
- X.TE
- X.KE
- XThe following example,
- X.sp 1
- X\fIprecedence\fR
- X.PP
- Xspecial-delivery = 100;
- X.PP
- Xjunk = -100;
- X.sp 1
- Xdefines the precedence level for the names \*Qspecial-delivery\*U and
- X\*Qjunk\*U. Thus, whenever the name \*Qjunk\*U appears in
- Xa \*QPrecedence:\*U field, the corresponding message class will be set to -100.
- X.NH 2
- XTrusted users
- X.PP
- X\fISendmail\fR's \fB\-f\fR flag allows trusted users to override the sender's
- Xmachine address. Trusted users are listed in \fItrusted\fR blocks. A
- X\fItrusted\fR block consists of the keyword \fItrusted\fR, followed
- Xby zero or more sets of users taking the form:
- X.TS
- Xcenter box;
- Xl .
- X{ <user1>, <user2>, <user3>, ... } ;
- X.TE
- XThe following example,
- X.sp 1
- X\fItrusted\fR
- X.PP
- X{ root, uucp, network } ;
- X.PP
- X{ acu, kcs, jss } ;
- X.sp 1
- Xspecifies that the users root, uucp, network, acu, kcs, and jss can be trusted
- Xto use the \fIsendmail\fR flag, \fB\-f\fR.
- X.NH 2
- XMail header definitions
- X.PP
- XThe format of the message headers inserted by \fIsendmail\fR is defined in one
- Xor more \fIheader\fR blocks in the configuration file. A \fIheader\fR block
- Xconsists of the keyword \fIheader\fR, followed by zero or more statements
- Xtaking any of the following forms:
- X.TS
- Xcenter box;
- Xl
- Xl
- Xl
- Xl
- Xl
- Xl
- Xl
- Xl
- Xl
- Xl
- Xl .
- X\fIfor\fR ( <mailer-flag1>, <mailer-flag2>, ... )
- X \fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
- X
- X\fIfor\fR ( <mailer-flag1>, <mailer-flag2>, ... ) {
- X \fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
- X \fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
- X .
- X .
- X} ;
- X
- X\fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
- X.TE
- XThe first form is used to define one header for one or more mailer
- Xflags. The second form differs from the first in that more than one
- Xheader may be defined for a given set of flags. The third form is used to
- Xdefine a header,
- Xregardless of mailer flags. Refer to Appendix C for a list of \fBEase\fR
- Xidentifiers representing mailer flags. The header title is a simple
- Xstring of characters (no macro references), whereas the \fBheader-value\fR
- Xis a series of one or more strings and
- X\fBconditional-expressions\fP (discussed later).
- XConcatenation is implicit (as in \fIawk\fP).
- X.sp 1
- XThe following example,
- X.DS
- X\fIheader\fR
- X
- X \fIdefine\fR ( "Subject:", "") ;
- X
- X \fIfor\fR ( \fIf_return\fR )
- X \fIdefine\fR ( "Return-Path:", "<${\fIm_sreladdr\fR}>" ) ;
- X
- X \fIfor\fR ( \fIf_date\fR ) {
- X \fIdefine\fR ( "Resent-Date:", "${\fIm_odate\fR}" ) ;
- X \fIdefine\fR ( "Date:", "${\fIm_odate\fR}" );
- X } ;
- X.DE
- Xdefines a \*QSubject\*U field for all mailers, regardless of their flags, a
- X\*QReturn-Path\*U field for mailers whose definition specifies
- Xthe flag, \fIf_return\fR, and the headers, \*QResent-Date\*U and \*QDate\*U,
- Xfor mailers whose definition specifies the flag, \fIf_date\fR.
- X.NH 2
- XMailer Definitions
- X.PP
- X\fISendmail\fR's definition of a mailer (or an interface to one) occurs in a
- X\fImailer\fR block. A \fImailer\fR block consists of the keyword \fImailer\fR,
- Xfollowed by zero or more statements of the form:
- X.TS
- Xcenter box;
- Xl .
- X<mailer-identifier> { \fBmailer-spec\fR } ;
- X.TE
- XThe field, \fBmailer-spec\fR, is a list of zero or more of the
- Xfollowing attribute assignments (where successive assignment statements are
- Xseparated by commas):
- X.TS
- Xcenter ;
- Xl l
- Xl l
- Xl l
- Xl l
- Xl l
- Xl l
- Xl l .
- X\fIPath\fR = \fBstring-attribute\fR
- X\fIArgv\fR = \fBstring-attribute\fR
- X\fIEol\fR = \fBstring-attribute\fR
- X\fIMaxsize\fR = \fBstring-attribute\fR
- X\fIFlags\fR = { <mailer-flag1>, <mailer-flag2>, ... }
- X\fISender\fR = <sender-ruleset-id>
- X\fIRecipient\fR = <recipient-ruleset-id>
- X.TE
- XThe \fBstring-attribute\fR value can take the form of a quoted string
- X(possibly containing macro references) or a \fBconditional-expression\fR
- X(discussed later).
- X.sp 1
- XThe following example,
- X.sp 1
- X\fImailer\fR
- X.DS
- X local {
- X \fIPath\fR = "/bin/mail",
- X \fIFlags\fR = { \fIf_from\fR, \fIf_locm\fR },
- X \fISender\fR = Sender_RW,
- X \fIRecipient\fR = Recip_RW,
- X \fIArgv\fR = "mail -d ${\fIm_ruser\fR}",
- X \fIMaxsize\fR = "200000"
- X } ;
- X.DE
- Xdefines a mailer named \*Qlocal\*U.
- X.NH 2
- XAddress field definitions
- X.PP
- X\fISendmail\fR's address parsing scheme treats an address as a group of tokens
- X(an address token is precisely defined in the Arpanet protocol RFC822). In
- Xgeneral, \fIsendmail\fR divides an address into tokens based on a list of
- Xcharacters assigned as a string to the special macro \fIm_addrops\fR. These
- Xcharacters will individually be considered as tokens and will separate tokens
- Xwhen parsing is performed.
- X.PP
- XFor
- Xthe \fBEase\fR language, there is a distinct set of address tokens (defined
- Xbelow) which are used in combination to represent generic forms of
- Xaddresses. In
- Xaddition to literal address tokens, the pattern to be matched in a rewriting
- Xrule (often referred to as the LHS) may
- Xinclude field identifiers which match one of five possibilities:
- X.DS
- X - zero or more tokens
- X - one or more tokens
- X - one token exactly
- X - one token which is an element of an arbitrary class \fBX\fR
- X - one token which is not an element of an arbitrary class \fBX\fR
- X.DE
- XA particular field type may be assigned to one or more identifiers. Each
- Xfield identifier is associated with (or defined to be) a field type in
- Xa \fIfield\fR declarations block. A \fIfield\fR declarations block consists
- Xof the keyword \fIfield\fR, followed by zero or more field definitions of
- Xthe form:
- X.TS
- Xcenter box;
- Xl .
- X\fBfield-id-list\fR : \fBfield-type\fR ;
- X.TE
- XA \fBfield-id-list\fR is a list of one or more identifiers, each separated by
- Xa comma. A \fBfield-type\fR, on the other hand, is a representation of
- Xone of the five fields
- Xdescribed above. The syntax for each of the five forms follows:
- X.DS
- X \fImatch\fR ( 0* )
- X \fImatch\fR ( 1* )
- X \fImatch\fR ( 1 )
- X \fImatch\fR ( 1 ) \fIin\fR <class-X>
- X \fImatch\fR ( 0 ) \fIin\fR <class-X>
- X.DE
- XThe star in the first two forms means: "or more". Thus, the first
- Xform would read: "match zero or more tokens". The fourth form describes
- Xa field where one token is matched from an arbitrary class (class-X), whereas
- Xthe fifth form describes a field where one token is matched if it is not of the
- Xgiven class (class-X).
- X.sp 1
- XIn addition, the Sun release 3.0 version of \fIsendmail\fR supports several
- Xnew pattern matching operations represented by the following forms:
- X.DS
- X \fImatch\fR ( 0 ) \fImap\fR <macro-identifier-X>
- X \fImatch\fR ( 1 ) \fImap\fR <macro-identifier-X>
- X \fImatch host\fR
- X.DE
- XThe macro \*Qmacro-identifier-X\*U should be assigned the name of the
- Xrelevant YP map.
- X.sp 1
- XThe following example,
- X.sp 1
- X.DS
- X\fIfield\fR
- X anypath : \fImatch\fR ( 0* );
- X recipient_host : \fImatch\fR ( 1 );
- X local_site : \fImatch\fR ( 1 ) \fIin m_sitename\fR;
- X remote_site : \fImatch\fR ( 0 ) \fIin m_sitename\fR;
- X.DE
- Xdefines the fields anypath, recipient_host, local_site, and remote_site.
- X.NH 2
- XAddress rewriting rules
- X.PP
- XAddress rewriting rules are grouped according to the function they perform. For
- Xexample, it is desirable to form a distinct group for those rewriting rules
- Xwhich perform transformations on recipient addresses.
- X.PP
- XSets of rewriting rules are defined in \fIruleset\fR blocks. A \fIruleset\fR
- Xblock consists of the keyword \fIruleset\fR, followed by zero or more
- Xruleset definitions of the form:
- X.TS
- Xcenter box;
- Xl .
- X<ruleset-id> { <rewriting-rule1> <rewriting-rule2> ... }
- X.TE
- XThe ruleset identifier, ruleset-id, must be defined in a \fIbind\fR block, as
- Xdescribed earlier. The rewriting rules have the form:
- X.DS
- X \fIif\fR ( <match-pattern> )
- X <match-action> ( <rewriting-pattern> ) ;
- X.DE
- Xwhere match-pattern, rewriting-pattern, and match-action are described below.
- XAn alternative form is available:
- X.DS
- X \fIwhile\fR ( <match-pattern> )
- X <match-action> ( <rewriting-pattern> ) ;
- X.DE
- Xwhich is somewhat more useful when the \*Qmatch-action\*U is \fIretry\fP
- X(see below).
- X.NH 3
- XMatch-patterns
- X.PP
- XA match-pattern is a sequence of Ease address elements representing an
- Xaddress format. If the address being rewritten matches the pattern
- X\*Qmatch-pattern\*U,
- Xthen the address is reformatted using the pattern \*Qrewriting-pattern\*U, and
- Xthe corresponding
- Xaction (\*Qmatch-action\*U) is performed. The five distinct Ease address
- Xelements which may constitute a match-pattern are as follows:
- X.TS
- Xcenter ;
- Xl .
- X1. Field Identifiers (refer to previous section)
- XT{
- X2. Non-alphanumeric characters (the exception is the case for literal
- Xdouble quotes, which must be preceded by a backslash (\\\\\)
- XT}
- X3. Macro references
- X4. Quoted strings ("...")
- X5. \fBConditional-expressions\fR (discussed later)
- X.TE
- XBelow are two sample match-patterns, each describing the same address format:
- X.DS
- X user-id @ hostname . $arpa_suffix
- X user-id @ hostname ".ARPA"
- X.DE
- Xwhere user-id and hostname are field identifiers, and arpa_suffix is a
- Xuser-defined macro with the value \*QARPA\*U.
- X.NH 3
- XRewriting-patterns
- X.PP
- XA rewriting-pattern specifies the form in which to rewrite a matched
- Xaddress. The seven distinct elements which may be used to form
- Xa rewriting-pattern are as follows:
- X.TS
- Xcenter ;
- Xl .
- X
- XT{
- X1. Non-alphanumeric characters (the exception is the case for literal
- Xdouble quotes, left parentheses, or right parentheses, each of which
- Xmust be preceded by a backslash (\\\\\).
- XT}
- X
- XT{
- X2. A call to another ruleset. This is used to perform rewrites
- Xon a suffix of the rewriting-pattern. The proper use of this
- Xfeature will be demonstrated by example below.
- XT}
- X
- X3. Quoted strings ("...").
- X
- X4. \fBConditional-expressions\fR (discussed later).
- X
- X5. A macro reference.
- X
- XT{
- X6. A positional reference in the matched address. A positional
- Xreference takes the form: $<integer-position>. For example,
- X$3 references the value of the third \fBEase\fR address
- Xelement in the matched address.
- XT}
- X
- XT{
- X7. Canonicalized host names of the form \fIcanon\fR (<id-token-list>),
- Xwhere \*Qid-token-list\*U is a list of one or more \*Qid-tokens.\*U
- XAn \*Qid-token\*U is a regular identifier, a quoted identifier (with
- Xdouble quotes), a macro reference yielding an identifier,
- Xa numeric internet specification (see below),
- Xa literal character (such as a \*Q.\*U or a \*Q[\*U), or a
- Xpositional reference in the matched address. The canonicalization of
- Xa host name is simply a mapping to its canonical (or official) form.
- XT}
- X
- X.TE
- XBelow are two sample rewriting-patterns:
- X.DS
- X $1 % $2 < @ $3 ".ARPA" >
- X OLDSTYLE_RW ( $1 )
- X.DE
- XThe first form specifies an address such as a%b<@c.ARPA>, where a, b, and c
- Xrepresent matched identifiers or paths. The second form specifies a call to
- Xthe ruleset \*QOLDSTYLE_RW\*U, for old-style rewriting on the parameter
- X$1, which probably references the entire matched address. This will become
- Xclear in later examples.
- X.NH 3
- XMatch-actions
- X.PP
- XWhen a ruleset is called, the address to be rewritten is compared (or matched)
- Xsequentially against the match-address of each rewriting rule. When a
- Xmatch-address describes the address \fIsendmail\fR is attempting to rewrite, the
- Xaddress is rewritten (or reformatted) using the rule's
- Xrewriting-pattern. Following this rewrite, the corresponding match-action
- Xis performed. There are four match-actions:
- X.TS
- Xcenter ;
- Xl l .
- X\fIretry\fR T{
- X-a standard action which causes the rewritten address
- Xto be again compared to the match-address of the current rule.
- XT}
- X
- X\fInext\fR T{
- X-an action which causes the rewritten address to be
- Xcompared to the match-address of the next rewriting rule of the current
- Xruleset. If the end of the list is reached, the ruleset returns the
- Xrewritten address.
- XT}
- X
- X\fIreturn\fR T{
- X-an action which causes an immediate return of the
- Xruleset with the current rewritten address.
- XT}
- X
- X\fIresolve\fR T{
- X-an action which specifies that the address has been
- Xcompletely resolved (i.e., no further rewriting is necessary). The
- X\fIresolve\fR action is described in more detail below.
- XT}
- X.TE
- X.PP
- XThe match-action, \fIresolve\fR, is special in that it terminates
- Xthe address rewriting altogether. The semantic structure of \fIsendmail\fR's
- Xrewriting scheme requires that a \fIresolve\fR action appear only in the
- Xruleset whose numerical binding is to the number zero. The \fIresolve\fR action
- Xmust specify three parameters: \fImailer\fR, \fIhost\fR, and \fIuser\fR. If
- Xthe \fImailer\fR is local, the \fIhost\fR parameter may be omitted. The
- X\fImailer\fR argument must be specified as a single word, macro, or positional
- Xreference in the matched address. The \fIhost\fR argument may be specified as
- Xa single word or as an expression which expands to a single word (e.g.,
- X\fIhost\fR ($1 ".ARPA")). In addition, the \fIhost\fR argument may be a
- Xcanonicalization (as described above) or a numeric internet specification. The
- Xkeyword \fIhostnum\fR is used for numeric internet specifications, as in
- X\fIhostnum\fR ("128.61.1.1") or \fIhostnum\fR ( $2 ). The \fIuser\fR
- Xspecification is a rewriting-pattern, as described above.
- X.PP
- XIn general, the format of a \fIresolve\fR action will be as follows:
- X.DS
- X \fIresolve\fR ( \fImailer\fR ( <mailer-name> ),
- X \fIhost\fR ( <host-name> ),
- X \fIuser\fR ( <user-address>) );
- X.DE
- XExamples of the match-action statement are shown below:
- X.DS
- X\fIfield\fR
- X anypath : \fImatch\fR (0*);
- X usr, path : \fImatch\fR (1*);
- X hostname : \fImatch\fR (1);
- X phone_host : \fImatch\fR (1) \fIin\fR phonehosts;
- X.DE
- X.DS
- X\fIruleset\fR
- X
- X EXAMPLE_RW {
- X
- X \fIif\fR ( anypath < path > anypath ) /* basic RFC821/822 parse */
- X \fIretry\fR ( $2 );
- X \fIif\fR ( usr " at " path ) /* \*Qat\*U -> \*Q@\*U */
- X \fInext\fR ( $1 @ $2 );
- X \fIif\fR ( @path: usr )
- X \fIreturn\fR ( LOCAL_RW ( < @$1 > : $2 ) );
- X \fIif\fR ( anypath < @phone_host".ARPA" > anypath )
- X \fIresolve\fR ( \fImailer\fR ( tcp ),
- X \fIhost\fR ( relay.cs.net ),
- X \fIuser\fR ( $1 % $2 < @"relay.cs.net" > $3 ) );
- X }
- X.DE
- X.PP
- XThe example above defines the ruleset \*QEXAMPLE_RW\*U, which contains four
- Xrewriting rules. The first rewriting rule discards all tokens of an address
- Xwhich lie on either side of a pair of angle brackets (<>), thereby
- Xrewriting the address as
- Xthe sequence of tokens contained within the angle brackets ($2). Following the
- Xaddress rewrite, the rule is applied again (\fIretry\fR). When the first rule
- Xfails to match the address being rewritten, the second rule is applied.
- X.PP
- XThe second
- Xrule simply replaces the word \*Qat\*U by the symbol \*Q@\*U. The \*Q\fInext\fR\*U
- Xaction specifies that if a match is made, a rewrite is performed and
- Xmatching continues at the next (or following) rule.
- X.PP
- XThe third rule illustrates
- Xthe use of the \*Q\fIreturn\fR\*U action, which is executed if the
- Xpattern \*Q@path: usr\*U
- Xdescribes the current format of the address being rewritten. In this example,
- Xthe \fIreturn\fR action returns the result of a call to ruleset \*QLOCAL_RW\*U,
- Xwhich rewrites the address \*Q<@$1>:$2\*U, where $1 and $2 are substituted
- Xwith the token(s) matched respectively by \*Qpath\*U and \*Qusr\*U.
- X.PP
- XThe fourth (and final) rule signals a resolution (and termination) of the
- Xrewriting process if the given pattern is matched. The resolution specifies
- Xthat the mailer \*Qtcp\*U will be used to deliver the message to the host
- X\*Qrelay.cs.net\*U.
- XThe \fIuser\fR parameter specifies the final form of the address
- Xwhich \fIsendmail\fR has just resolved.
- X.sp 2
- X.PP
- XThe \fBEase\fR construct which remains to be examined is the
- X\fBconditional-expression\fR. The \fBconditional-expression\fR provides a
- Xmethod for
- Xconstructing strings based on the condition that some test macro is (or is not)
- Xset. The general form begins with the concatenation of a string and a
- X\fBstring-conditional\fR:
- X.DS
- X \fIconcat\fR ( <quoted-string>, \fBstring-conditional\fR )
- X \fIconcat\fR ( \fBstring-conditional\fR, <quoted-string> )
- X.DE
- XA \fBstring-conditional\fR assumes either of the following forms:
- X.DS
- X \fIifset\fR ( <macro-name>, <ifset-string> )
- X \fIifset\fR ( <macro-name>, <ifset-string>, <notset-string> )
- X.DE
- XA \fBstring-conditional\fR of the first form evaluates to \*Qifset-string\*U
- Xif the macro \*Qmacro-name\*U has been assigned a value; otherwise it
- Xevaluates to the null string. The second form behaves similarly, except
- Xthat the \fBstring-conditional\fR evaluates to \*Qnotset-string\*U, instead
- Xof the null string, if the macro \*Qmacro-name\*U has no value.
- X.sp 1
- XThe following \fBconditional-expression\fR,
- X.DS
- X \fIconcat\fR ( "New ", \fIifset\fR ( city, "York", "Jersey" ) )
- X.DE
- Xevaluates to the string "New York", if the macro \*Qcity\*U is set. Otherwise,
- Xthe \fBconditional-expression\fR evaluates to the string "New Jersey".
- X.NH
- XEase Translation
- X.PP
- XIt is important to note that \fBEase\fR is translated by a stand-alone
- Xtranslator to the raw configuration file format. No modifications were
- Xmade to the \fIsendmail\fR program itself. As a result, syntactical verification
- Xof a configuration file can be performed without invoking \fIsendmail\fR.
- X.PP
- XThe \fBEase\fR language is translated by invoking
- Xthe C language preprocessor (cpp) with \fBEase\fR source as input, then piping
- Xthe output as input to the \fBEase\fR translator (\fIet\fR). The \fBEase\fR
- Xtranslator may be invoked on the command line in one of four ways:
- X.TS
- Xcenter box ;
- Xl l .
- X\fIet\fR <input-file> <output-file> [read from a file, write to a file]
- X\fIet\fR <input-file> [read from a file, write to standard output]
- X\fIet\fR - <output-file> [read from standard input, write to a file]
- X\fIet\fR [read from standard input, write to standard output]
- X.TE
- X.NH
- XConclusion
- X.PP
- X\fBEase\fR is currently in use at the Purdue University Computing
- XCenter. Source code for the \fBEase\fR translator (\fIet\fR) may be
- Xobtained on request by writing to:
- X.DS
- XU.S. Mail:
- X James S. Schoner
- X c/o Kevin S. Braunsdorf
- X Purdue University Computing Center
- X Purdue University
- X West Lafayette, Indiana 47907
- X
- XElectronic Mail:
- X ksb@j.cc.purdue.edu
- X.DE
- X.PP
- XMuch of the success of this project is attributable to the constant support
- Xand insight offered by Mark Shoemaker. To him, I owe a debt of gratitude. In
- Xaddition, I would like to thank Kevin Smallwood, Paul Albitz, and Rich Kulawiec
- Xfor their many notable suggestions and valuable insight.
- X.NH
- XAcknowledgements
- X.PP
- XArnold Robbins would like to acknowledge contributions from
- XStephen Schaefer of Bowling Green State University,
- XJeff Stearns of John Fluke Manufacturing Company,
- XRaymond A. Schnitzler of Bellcore,
- Xand
- XAndrew Partan of the Corporation for Open Systems.
- XThe good intentions of Rich Salz, of Bolt Beranak, and Newman,
- Xare also acknowledged.
- X.PP
- XThe most up to date version of \fBEase\fR should be gotten from the
- Xnearest USENET \fBcomp.sources.unix\fR archive site.
- END_OF_FILE
- if test 31245 -ne `wc -c <'doc/ease.paper'`; then
- echo shar: \"'doc/ease.paper'\" unpacked with wrong size!
- fi
- chmod +x 'doc/ease.paper'
- # end of 'doc/ease.paper'
- fi
- echo shar: End of archive 3 \(of 3\).
- cp /dev/null ark3isdone
- MISSING=""
- for I in 1 2 3 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 3 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-