v08i053: Ease, a language for writing sendmail.cf files, Part01/04

sources-request at mirror.UUCP sources-request at mirror.UUCP
Thu Feb 12 06:26:25 AEST 1987


Submitted by: ksb at j.cc.purdue.edu
Mod.sources: Volume 8, Issue 53
Archive-name: ease/Part01

The Ease language is a high-level specification format for sendmail's
configuration file.  The motivation for its development was to fulfill
a goal of providing a readable and easily modifiable sendmail
configuration file format.  Ease fulfills this goal by shielding the
programmer from the cryptic configuration specification required by
sendmail and providing a high-level language with which the programmer
may specify all modifications to a configuration file.  The development
of Ease coincided with the development of an Ease translator, et, which
translates a configuration file written in Ease to an equivalent file
of the standard format accepted by sendmail.

Please let Kevin Braunsdorf, "ksb at j.cc.purdue.edu" know if you make any
modifications to Ease; he's taking care of this now (the original
author has since left Purdue) and we'd really like to keep the released
version exactly in step with our local version in order to make
supporting this a lot easier.

Thanks,
	"Wombat" <rsk at j.cc.purdue.edu>

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	doc
#	src
mkdir doc
chdir doc
cat << \SHAR_EOF > ap1
.DS C
\s+5\fBAppendix A\fR


\fBPre-Declared Macros\fR\s-5
.DE
.sp 5
.TS 
center box;
c|c|c
l|l|l.
\fBEase\fR Macro	Raw Equivalent	Meaning*
=
\fIm_odate\fR	a	The origination date in Arpanet format
\fIm_adate\fR	b	The current date in Arpanet format
\fIm_hops\fR	c	The hop count
\fIm_udate\fR	d	The date in UNIX (ctime) format
\fIm_smtp\fR	e	The SMTP entry message
\fIm_saddr\fR	f	The sender (from) address
\fIm_sreladdr\fR	g	The sender address relative to the recipient
\fIm_rhost\fR	h	The recipient host
\fIm_qid\fR	i	The queue id
\fIm_oname\fR	j	The official domain name for this site
\fIm_ufrom\fR	l	The format of the UNIX from line
\fIm_daemon\fR	n	The name of the daemon (for error messages)
\fIm_addrops\fR	o	The set of "operators" in addresses
\fIm_pid\fR	p	Sendmail's pid
\fIm_defaddr\fR	q	The default format of sender address
\fIm_protocol\fR	r	Protocol used
\fIm_shostname\fR	s	Sender's host name
\fIm_ctime\fR	t	A numeric representation of the current time
\fIm_ruser\fR	u	The recipient user
\fIm_version\fR	v	The version number of sendmail
\fIm_sitename\fR	w	The hostname of this site
\fIm_sname\fR	x	The full name of the sender
\fIm_stty\fR	y	The id of the sender's tty
\fIm_rhdir\fR	z	The home directory of the recipient
.TE
.FS
*  Taken from pages 15 and 16 of the Installation and Operation Guide
for Sendmail (UNIX Programmer's Manual, Volume 2c), by Eric Allman.
.FE
SHAR_EOF
if test 1384 -ne "`wc -c ap1`"
then
echo shar: error transmitting ap1 '(should have been 1384 characters)'
fi
cat << \SHAR_EOF > ap2
.DS C
\s+5\fBAppendix B\fR


\fBSendmail Options\fR\s-5
.DE
.sp 2
.PP
For a complete description of Sendmail's options and their values, refer to 
Appendix B of the Installation and Operation Guide for Sendmail (UNIX
Programmer's Manual, Volume 2c), by Eric Allman.
.sp 2
.TS 
center box;
c|c
l|l.
Sendmail Option (\fBEase\fR)	Sendmail Option (Raw)	Special Values
=
\fIo_alias\fR	A	
\fIo_ewait\fR	a	
\fIo_bsub\fR	B	
\fIo_qwait\fR	c	
\fIo_delivery\fR  (special values below)	d  (special values below)
     \fId_interactive\fR	     i 
     \fId_background\fR	    b 
     \fId_queue\fR	    q
\fIo_rebuild\fR	D
\fIo_handling\fR  (special values below)	e  (special values below)
     \fIh_print\fR	     p 
     \fIh_exit\fR	     q
     \fIh_mail\fR	     m
     \fIh_write\fR	     w
     \fIh_mailz\fR	     e
\fIo_tmode\fR	F	
\fIo_usave\fR	f	
\fIo_gid\fR	g	
\fIo_fsmtp\fR	H	
\fIo_skipd\fR	i	
\fIo_slog\fR	L	
\fIo_rsend\fR	m	
\fIo_dnet\fR	N	
\fIo_hformat\fR	o	
\fIo_qdir\fR	Q	
\fIo_tread\fR	r	
\fIo_flog\fR	S	
\fIo_safe\fR	s	
\fIo_qtimeout\fR	T	
\fIo_timezone\fR	t	
\fIo_dmuid\fR	u	
\fIo_verbose\fR	v	
\fIo_wizpass\fR	W	
\fIo_loadq\fR	x	
\fIo_loadnc\fR	X	
.TE
SHAR_EOF
if test 1153 -ne "`wc -c ap2`"
then
echo shar: error transmitting ap2 '(should have been 1153 characters)'
fi
cat << \SHAR_EOF > ap3
.DS C
\s+5\fBAppendix C\fR


\fBMailer Flags\fR\s-5
.DE
.sp 5
.PP
For a complete description of mailer flags, refer to 
Appendix C of the Installation and Operation Guide for Sendmail (UNIX
Programmer's Manual, Volume 2c), by Eric Allman.
.sp 5
.TS 
center box;
c|c
l|l.
Mailer Flag (\fBEase\fR)	Mailer Flag (Raw)
=
\fIf_ffrom\fR	f
\fIf_rfrom\fR	r
\fIf_noreset\fR	S
\fIf_noufrom\fR	n
\fIf_locm\fR	l
\fIf_strip\fR	s 
\fIf_mult\fR	m
\fIf_from\fR	F
\fIf_date\fR	D
\fIf_mesg\fR	M
\fIf_full\fR	x	
\fIf_return\fR	P	
\fIf_upperu\fR	u	
\fIf_upperh\fR	h	
\fIf_arpa\fR	A	
\fIf_ufrom\fR	U	
\fIf_expensive\fR	e	
\fIf_dot\fR	X	
\fIf_llimit\fR	L	
\fIf_retsmtp\fR	p	
\fIf_smtp\fR	I	
\fIf_addrw\fR	C	
.TE
SHAR_EOF
if test 689 -ne "`wc -c ap3`"
then
echo shar: error transmitting ap3 '(should have been 689 characters)'
fi
cat << \SHAR_EOF > cover
.DA
.sp 15
.nr PS 14
.ps 14
.DS C
 
.DE
.sp 10
.nr PS 36
.ps 36
.DS C
\fBEase:\fR
.DE
.sp 5
.nr PS 22
.ps 22
.DS C
A Configuration Language
  
for Sendmail
.DE
.sp 13
.nr PS 14
.ps 14
.DS C
by

\fIJames S. Schoner\fR
\fIPurdue University Computing Center\fR
.DE
SHAR_EOF
if test 262 -ne "`wc -c cover`"
then
echo shar: error transmitting cover '(should have been 262 characters)'
fi
cat << \SHAR_EOF > ease.paper
.LP
.TL
Ease: A Configuration Language
for Sendmail
.AU
James S. Schoner
.AI
Purdue University Computing Center
West Lafayette, Indiana  47907
.sp 2
.I
.ce
ABSTRACT
.R
.PP
The rapid expansion of computer networks and ensuing variation among mailing
address formats have made address interpretation an increasingly
complex task.  In the UNIX* 4.2BSD operating system, a program named 
\fIsendmail\fR was introduced which provided a
general internetwork mail routing facility.  This facility has significantly
diminished the complexity of handling address interpretation.
.PP
\fISendmail\fR's address interpretation is based on a rewriting
system composed of
a number of rewriting rules (or productions) arranged as part of a 
configuration file.  Unfortunately, the syntactical format of a
configuration file for \fIsendmail\fR is both terse and rigid, making it
rather difficult to modify.  The standard format certainly serves its 
purpose, but, as 
the need to change these configurations increases in frequency, a more 
readable format (i.e., one that is similar to the format 
of modern programming languages) is required to permit reasonably 
quick modifications to the configuration.  As a solution to this problem, 
\fBEase\fR 
provides a level of abstraction which eliminates most of the current
syntactic hindrances
faced by programmers who must reconfigure \fIsendmail\fR's 
address parsing scheme.  
.PP
As a high-level specification format, \fBEase\fR is proving to be an 
excellent alternative to \fIsendmail\fR's cryptic 
configuration file syntax.  The syntactic structures of \fBEase\fR 
are patterned after modern language constructs, making the language
easy to learn and easy to remember.  The format of the address rewriting
rule is perhaps the most significant syntactical improvement.  It was 
undoubtedly
the most needed improvement.  Nevertheless, every element of a configuration 
file is structurally enhanced through the use of \fBEase\fR. 
.FS
*  UNIX is a trademark of AT&T Bell Laboratories.
.FE
.sp 2
.NH
Introduction
.PP
The \fBEase\fR language is a high-level specification format for \fIsendmail\fR's
configuration file.  The motivation for its development
was to fulfill a goal of providing a readable and easily modifiable 
\fIsendmail\fR configuration file format.  \fBEase\fR fulfills this goal by
shielding the programmer from the cryptic configuration specification required
by \fIsendmail\fR and providing a high-level language with which the programmer
may specify all modifications to a configuration file.  The development 
of Ease coincided with
the development of an \fBEase\fR translator, \fIet\fR,
which translates a configuration file written 
in \fBEase\fR to an
equivalent file of the standard format accepted by \fIsendmail\fR.
.NH
Ease in Profile
.PP
As will be seen in the next section, the syntax of \fBEase\fR is quite
readable and easy to learn.  In order to acquire a relevant perspective
on this issue,
the reader is advised to examine a raw configuration file for \fIsendmail\fR (the 
output
of the \fBEase\fR translator, \fIet\fR, will do nicely).  The raw syntax, while
quite fitting for quick translation, can prove to be a programmer's nightmare.  
.PP
Undoubtedly, one of the more prominent features of \fBEase\fR is the ability 
to attach
names to address fields.  When address field names are well-chosen, a distinct,
self-documenting quality becomes a visible part of the address rewriting 
rules.  Ostensibly, address field names provide a new level of semantic 
abstraction.  A brief comparison of the formats can be accomplished by examining
the following equivalent representations of an address pattern:
.DS
	user_path at host_name			(\fBEase\fR format)
	$+@$-					(raw format)
.DE
In the above, \*Quser_path\*U represents a field of one or more address
tokens, and \*Qhost_name\*U represents one address token exactly.  These
token fields are represented by \*Q$+\*U and \*Q$-\*U in the raw format.  Clearly, 
the \fBEase\fR format is preferable, not only for increased readability, but 
structural comprehension as well.
.PP
Other features of \fBEase\fR include ruleset naming, long identifiers for 
macros and classes, flow-of-control structures, and free formatting.  In
addition, the C language preprocessor (cpp) can be used for file inclusion
and conditionally defined code constructs.  The next section describes
the \fBEase\fR language in complete detail.
.NH
Ease Syntax*
.FS
*  \fINo attempt is made to describe the complete semantic meaning 
associated with all of the constructs of a sendmail configuration file.  Items 
not covered in this document include the semantic distinction among rulesets, 
the special uses of
pre-defined macros, and the method of building configuration files.  To
obtain this information, the reader is advised to refer to
the Installation and Operation Guide for Sendmail (UNIX
Programmer's Manual, Volume 2c), by Eric Allman.\fR
.FE
.PP
At its highest level, \fBEase\fR can be viewed as a collection of 
block-structures, where each block begins with a keyword and is followed by
zero or more related definitions and/or declarations.  There are ten distinct 
block types.  The following is 
a list containing all ten block keywords and the block type it denotes.
.TS
center;
l l .
\fIbind\fR	-ruleset identifier bindings
\fImacro\fR	-macro definitions
\fIclass\fR	-class definitions
\fIoptions\fR	-\fIsendmail\fR option definitions
\fIprecedence\fR	-precedence definitions
\fItrusted\fR	-trusted users
\fIheader\fR	-mail header definitions
\fImailer\fR	-mailer definitions
\fIfield\fR	-address field definitions
\fIruleset\fR	-address rewriting rules
.TE
.sp 1
In general,
.TS
center ;
l .

* Letters are distinguished by case,

T{
* An \fBEase\fR identifier is defined to be a letter, followed by zero or 
more letters, digits, underscores (_), or dashes (-),
T}

T{
* A literal newline or double quotation (") character may be included in 
any quoted string by preceding the character with a backslash (\\\\\), and
T}

T{
* \fBEase\fR source is preprocessed by the C language preprocessor (cpp),
thus source comments (i.e., text enclosed by \*Q/*\*U and \*Q*/\*U) may appear 
anywhere as part of \fBEase\fR whitespace.
T}
.TE
.PP
For notational convenience, this document specifies all reserved
words of the \fBEase\fR language in italics.  In addition, quantities
enclosed in angle brackets (<..>) represent arbitrary 
identifiers, strings, or numbers.  
.NH 2
Ruleset Identifier Bindings
.PP
A ruleset (a set of rewriting rules) is identified solely by an integer 
in \fIsendmail\fR's
configuration file.  \fBEase\fR, however, allows each ruleset to be named with
a meaningful identifier.  Since a special numeric association for each 
ruleset is required by the address parsing scheme of \fIsendmail\fR, a \fIbind\fR
block must be present in any \fBEase\fR file which defines one or more 
rulesets.  A
\fIbind\fR block consists of the keyword \fIbind\fR, followed by zero or more
statements of the form:
.TS
center box;
l .
<ruleset-id> = \fIruleset\fR <ruleset-number> ;
.TE
The following example, 
.sp 1
\fIbind\fR
.PP
FINAL_RW = \fIruleset\fR 4;
.sp 1
specifies that FINAL_RW, the final rewriting ruleset, is \fIsendmail\fR's ruleset 
number 4.
.NH 2
Macro Definitions
.PP
A macro is an identifier which, when referenced in the text of a program,
is replaced by its value, a string of zero or more characters.  The value
of a macro may include references to other macros, but not itself!  \fISendmail\fR
allows a maximum of 26 user-declared macros in its configuration file.  In 
addition, there are a number of pre-declared macros which have special meaning
to \fIsendmail\fR (see Appendix A).  \fBEase\fR macros are defined in 
\fImacro\fR blocks.  \fBEase\fR allows any macro to be declared 
(which is equivalent to simply referencing it) before it is defined.  A macro
identifier is replaced by its value when it is preceded by the character
\*Q$\*U.  In addition, a macro reference inside a quoted string must always 
include braces ({}) around the macro identifier (for delimiting purposes).  
.PP
A \fImacro\fR block consists of the keyword \fImacro\fR, followed by zero
or more statements taking either of the following forms:
.TS
center box;
l .
<macro-identifier> = "<macro-value>" ;
<macro-identifier> = \fBconditional-expression\fR ;
.TE
The \fBconditional-expression\fR format will be discussed 
later.  
.sp 1
The following example,
.sp 1
\fImacro\fR
.PP
first_name = "James";
.PP
last_name = "Schoner";
.PP
whole_name = "${first_name} ${second_name}";
.sp 1
defines the macros first_name, last_name, and whole_name, where whole_name
is the string, "James Schoner".
.NH 2
Class definitions
.PP
A class is denoted by an identifier representing a logical grouping of zero 
or more names.  Classes are used to represent the range of values a token
may assume in the pattern matching of an address.  Further discussion on the
use of classes will be deferred until address fields are described.
.PP
One identifier may be used to distinctly represent both a macro
and class (i.e., the set of macro identifiers and the set of class identifiers
may form a non-empty intersection).  A name, or class element, may 
be an identifier or any quoted word.
.PP
A \fIclass\fR block consists of the keyword \fIclass\fR, followed by zero
or more statements taking any of the following forms:
.TS
center box;
l .
<class-identifier> = { <name1>, <name2>, <name3>, ... } ;
<class-identifier> = \fIreadclass\fR ( "<file-name>" ) ;
<class-identifier> = \fIreadclass\fR ( "<file-name>", "<read-format>" ) ;
.TE
The second and third forms cause \fIsendmail\fR to read the names of the class 
from the named
file.  The third form contains a read format, which should be a \fIscanf(3)\fR 
pattern yielding a single string.
.sp 1
The following example,
.sp 1
\fIclass\fR
.PP
campus_hosts = { statistics, engineering, chemistry, physics, physics-2 } ;
.PP
versions     = { "1.0", "1.1", "4.0", "4.2", latest-and-greatest } ;
.PP
phone_hosts  = \fIreadclass\fR ( "/tmp/phonenet.list" ) ;
.sp 1
defines the classes campus_hosts, versions, and phone_hosts.
.NH 2
Sendmail option definitions
.PP
A number of options to the \fIsendmail\fR program may be specified in 
an \fIoptions\fR
block.  For a description of the various \fIsendmail\fR options and their 
values, see Appendix B.  
.PP
An
\fIoptions\fR block consists of the keyword \fIoptions\fR, followed by zero
or more statements taking any of the following forms:
.TS
center box;
l l .
<option-identifier>	= "<option-value>" ;
\fIo_delivery\fR	= \fBspecial-value\fR ;
\fIo_handling\fR	= \fBspecial-value\fR ;
.TE
All but two options (\fIo_delivery\fR and \fIo_handling\fR) use the first 
form.  To specify an option without a value, simply assign to it the null 
string ("").  The \fBspecial-value\fR field of the second and third form
refers to special values (non-quoted) which are specified in Appendix B.
.sp 1
The following example,
.sp 1
\fIoptions\fR
.PP
\fIo_alias\fR = "/usr/lib/aliases" ;
.PP
\fIo_tmode\fR = "0600" ;
.PP
\fIo_delivery\fR = d_background ;
.sp 1
sets the options \fIo_alias\fR, \fIo_tmode\fR, and \fIo_delivery\fR.
.NH 2
Precedence definitions
.PP
Message headers may contain a \*QPrecedence:\*U field describing the precedence
of the message class.  Identifiers which may appear in the precedence field of
a message are given precedence values in a configuration file \fIprecedence\fR 
definition.  This association will be illustrated below in an example.
.PP
A \fIprecedence\fR block consists of the keyword \fIprecedence\fR, followed 
by zero or more statements of the form:
.KS
.TS
center box;
l .
<precedence-identifier> = <precedence-integer> ;
.TE
.KE
The following example,
.sp 1
\fIprecedence\fR
.PP
special-delivery = 100;
.PP
junk = -100;
.sp 1
defines the precedence level for the names \*Qspecial-delivery\*U and 
\*Qjunk\*U.  Thus, whenever the name \*Qjunk\*U appears in 
a \*QPrecedence:\*U field, the corresponding message class will be set to -100.
.NH 2
Trusted users
.PP
\fISendmail\fR's \fB-f\fR flag allows trusted users to override the sender's
machine address.  Trusted users are listed in \fItrusted\fR blocks.  A 
\fItrusted\fR block consists of the keyword \fItrusted\fR, followed 
by zero or more sets of users taking the form:
.TS
center box;
l .
{ <user1>, <user2>, <user3>, ... } ;
.TE
The following example,
.sp 1
\fItrusted\fR
.PP
{ root, uucp, network } ;
.PP
{ acu, kcs, jss } ;
.sp 1
specifies that the users root, uucp, network, acu, kcs, and jss can be trusted 
to use the \fIsendmail\fR flag, \fB-f\fR.
.NH 2
Mail header definitions
.PP
The format of the message headers inserted by \fIsendmail\fR is defined in one
or more \fIheader\fR blocks in the configuration file.  A \fIheader\fR block
consists of the keyword \fIheader\fR, followed by zero or more statements
taking any of the following forms:
.TS
center box;
l 
l
l
l
l
l
l
l
l
l
l .
\fIfor\fR ( <mailer-flag1>, <mailer-flag2>, ... )
       \fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;

\fIfor\fR ( <mailer-flag1>, <mailer-flag2>, ... ) {
       \fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
       \fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
       .
       .
} ;

\fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
.TE
The first form is used to define one header for one or more mailer
flags.  The second form differs from the first in that more than one
header may be defined for a given set of flags.  The third form is used to 
define a header,
regardless of mailer flags.  Refer to Appendix C for a list of \fBEase\fR 
identifiers representing mailer flags.  The header title is a simple
string of characters (no macro references), whereas the \fBheader-value\fR can
be either a string of characters (possibly containing macro references) or 
a \fBconditional-expression\fR (discussed later).
.sp 1
The following example,
.DS
\fIheader\fR

	\fIdefine\fR ( "Subject:", "") ;

	\fIfor\fR ( \fIf_return\fR )
		\fIdefine\fR ( "Return-Path:", "<${\fIm_sreladdr\fR}>" ) ;

	\fIfor\fR ( \fIf_date\fR ) {
		\fIdefine\fR ( "Resent-Date:", "${\fIm_odate\fR}" ) ;
		\fIdefine\fR ( "Date:", "${\fIm_odate\fR}" );
	} ;
.DE
defines a \*QSubject\*U field for all mailers, regardless of their flags, a
\*QReturn-Path\*U field for mailers whose definition specifies
the flag, \fIf_return\fR, and the headers, \*QResent-Date\*U and \*QDate\*U,
for mailers whose definition specifies the flag, \fIf_date\fR.
.NH 2
Mailer Definitions
.PP
\fISendmail\fR's definition of a mailer (or an interface to one) occurs in a
\fImailer\fR block.  A \fImailer\fR block consists of the keyword \fImailer\fR,
followed by zero or more statements of the form:
.TS
center box;
l .
<mailer-identifier> { \fBmailer-spec\fR } ;
.TE
The field, \fBmailer-spec\fR, is a list of zero or more of the
following attribute assignments (where successive assignment statements are
separated by commas):
.TS
center ;
l l 
l l
l l
l l
l l
l l
l l .
\fIPath\fR	= \fBstring-attribute\fR
\fIArgv\fR	= \fBstring-attribute\fR
\fIEol\fR	= \fBstring-attribute\fR
\fIMaxsize\fR	= \fBstring-attribute\fR
\fIFlags\fR	= { <mailer-flag1>, <mailer-flag2>, ... } 
\fISender\fR	= <sender-ruleset-id>
\fIRecipient\fR	= <recipient-ruleset-id>
.TE
The \fBstring-attribute\fR value can take the form of a quoted string
(possibly containing macro references) or a \fBconditional-expression\fR 
(discussed later).
.sp 1
The following example,
.sp 1
\fImailer\fR
.DS
	local {
		\fIPath\fR		= "/bin/mail",
		\fIFlags\fR		= { \fIf_from\fR, \fIf_locm\fR },
		\fISender\fR	= Sender_RW,
		\fIRecipient\fR	= Recip_RW,
		\fIArgv\fR		= "mail -d ${\fIm_ruser\fR}",
		\fIMaxsize\fR	= "200000"
	} ;
.DE
defines a mailer named \*Qlocal\*U.
.NH 2
Address field definitions
.PP
\fISendmail\fR's address parsing scheme treats an address as a group of tokens
(an address token is precisely defined in the Arpanet protocol RFC822).  In
general, \fIsendmail\fR divides an address into tokens based on a list of
characters assigned as a string to the special macro \fIm_addrops\fR.  These
characters will individually be considered as tokens and will separate tokens
when parsing is performed. 
.PP
For
the \fBEase\fR language, there is a distinct set of address tokens (defined
below) which are used in combination to represent generic forms of 
addresses.  In 
addition to literal address tokens, the pattern to be matched in a rewriting 
rule (often refered to as the LHS) may
include field identifiers which match one of five possibilities:
.DS
	- zero or more tokens
	- one or more tokens
	- one token exactly
	- one token which is an element of an aribitrary class \fBX\fR
	- one token which is not an element of an aribitrary class \fBX\fR
.DE
A particular field type may be assigned to one or more identifiers.  Each
field identifier is associated with (or defined to be) a field type in
a \fIfield\fR declarations block.  A \fIfield\fR declarations block consists
of the keyword \fIfield\fR, followed by zero or more field definitions of
the form:
.TS
center box;
l .
\fBfield-id-list\fR : \fBfield-type\fR ;
.TE
A \fBfield-id-list\fR is a list of one or more identifiers, each separated by
a comma.  A \fBfield-type\fR, on the other hand, is a representation of 
one of the five fields 
described above.  The syntax for each of the five forms follows:
.DS
	\fImatch\fR ( 0* )
	\fImatch\fR ( 1* )
	\fImatch\fR ( 1 )
	\fImatch\fR ( 1 ) in <class-X>
	\fImatch\fR ( 0 ) in <class-X>
.DE
The star in the first two forms means: "or more".  Thus, the first
form would read: "match zero or more tokens".  The fourth form describes
a field where one token is matched from an arbitrary class (class-X), whereas
the fifth form describes a field where one token is matched if it is not of the
given class (class-X).
.sp 1
The following example,
.sp 1
.DS
\fIfield\fR
	anypath		: \fImatch\fR ( 0* );
	recipient_host	: \fImatch\fR ( 1 );
	local_site		: \fImatch\fR ( 1 ) in \fIm_sitename\fR;
	remote_site		: \fImatch\fR ( 0 ) in \fIm_sitename\fR;
.DE
defines the fields anypath, recipient_host, local_site, and remote_site.
.NH 2
Address rewriting rules
.PP
Address rewriting rules are grouped according to the function they perform.  For
example, it is desirable to form a distinct group for those rewriting rules 
which perform transformations on recipient addresses.
.PP
Sets of rewriting rules are defined in \fIruleset\fR blocks.  A \fIruleset\fR
block consists of the keyword \fIruleset\fR, followed by zero or more
ruleset definitions of the form:
.TS
center box;
l .
<ruleset-id> { <rewriting-rule1> <rewriting-rule2> ... }
.TE
The ruleset identifier, ruleset-id, must be defined in a \fIbind\fR block, as
described earlier.  The rewriting rules have the form:
.DS
	\fIif\fR ( <match-pattern> )
		<match-action> ( <rewriting-pattern> ) ;
.DE
where match-pattern, rewriting-pattern, and match-action are described below.
.NH 3
Match-patterns
.PP
A match-pattern is a sequence of Ease address elements representing an
address format.  If the address being rewritten matches the pattern
\*Qmatch-pattern\*U,
then the address is reformatted using the pattern \*Qrewriting-pattern\*U, and 
the corresponding
action (\*Qmatch-action\*U) is performed.  The five distinct Ease address
elements which may constitute a match-pattern are as follows:
.TS
center ;
l .
1. Field Identifiers (refer to previous section)
T{
2. Non-alphanumeric characters (the exception is the case for literal 
double quotes, which must be preceded by a backslash (\\\\\)
T}
3. Macro references
4. Quoted strings ("...")
5. \fBConditional-expressions\fR (discussed later)
.TE
Below are two sample match-patterns, each describing the same address format:
.DS
	user-id @ hostname . $arpa_suffix
	user-id @ hostname ".ARPA"
.DE
where user-id and hostname are field identifiers, and arpa_suffix is a 
user-defined macro with the value \*QARPA\*U.
.NH 3
Rewriting-patterns
.PP
A rewriting-pattern specifies the form in which to rewrite a matched 
address.  The seven distinct elements which may be used to form 
a rewriting-pattern are as follows:
.TS
center ;
l .

T{
1. Non-alphanumeric characters (the exception is the case for literal
double quotes, left parentheses, or right parentheses, each of which 
must be preceded by a backslash (\\\\\). 
T}

T{
2. A call to another ruleset.  This is used to perform rewrites
on a suffix of the rewriting-pattern.  The proper use of this
feature will be demonstrated by example below. 
T}

3. Quoted strings ("...").

4. \fBConditional-expressions\fR (discussed later).

5. A macro reference.

T{
6. A positional reference in the matched address.  A positional 
reference takes the form: $<integer-position>.  For example, 
$3 references the value of the third \fBEase\fR address 
element in the matched address.
T}

T{
7. Canonicalized host names of the form \fIcanon\fR (<id-token>),
where id-token is a regular identifier, a quoted identifier (with
double quotes), a macro reference yielding an identifier, or a 
positional reference in the matched address.  The canonicalization of 
a host name is simply a mapping to its canonical (or official) form.
T}

.TE
Below are two sample rewriting-patterns:
.DS
	$1 % $2 < @ $3 ".ARPA" >
	OLDSTYLE_RW ( $1 )
.DE
The first form specifies an address such as a%b<@c.ARPA>, where a, b, and c
represent matched identifiers or paths.  The second form specifies a call to
the ruleset \*QOLDSTYLE_RW\*U, for old-style rewriting on the parameter 
$1, which probably references the entire matched address.  This will become 
clear in later examples.
.NH 3
Match-actions
.PP
When a ruleset is called, the address to be rewritten is compared (or matched)
sequentially against the match-address of each rewriting rule.  When a
match-address describes the address \fIsendmail\fR is attempting to rewrite, the
address is rewritten (or reformatted) using the rule's 
rewriting-pattern.  Following this rewrite, the corresponding match-action
is performed.  There are four match-actions:
.TS
center ;
l l .
\fIretry\fR	T{
-a standard action which causes the rewritten address
to be again compared to the match-address of the current rule. 
T}

\fInext\fR	T{
-an action which causes the rewritten address to be
compared to the match-address of the next rewriting rule of the current 
ruleset.  If the end of the list is reached, the ruleset returns the 
rewritten address.
T}

\fIreturn\fR	T{
-an action which causes an immediate return of the 
ruleset with the current rewritten address.
T}

\fIresolve\fR	T{
-an action which specifies that the address has been
completely resolved (i.e., no further rewriting is necessary).  The 
\fIresolve\fR action is described in more detail below. 
T}
.TE
.PP
The match-action, \fIresolve\fR, is special in that it terminates
the address rewriting altogether.  The semantic structure of \fIsendmail\fR's
rewriting scheme requires that a \fIresolve\fR action appear only in the 
ruleset whose numerical binding is to the number zero.  The \fIresolve\fR action
must specify three parameters: \fImailer\fR, \fIhost\fR, and \fIuser\fR.  If
the \fImailer\fR is local, the \fIhost\fR parameter may be omitted.  The
\fImailer\fR argument must be specified as a single word, macro, or positional
reference in the matched address.  The \fIhost\fR argument may be specified as 
a single word or as an expression which expands to a single word (i.e.,
\fIhost\fR ($1 ".ARPA")).  In addition, the \fIhost\fR argument may be a
canonicalization (as described above) or a numeric internet specification.  The
keyword \fIhostnum\fR is used for numeric internet specifications, as in 
\fIhostnum\fR ("00.00.00.00") or \fIhostnum\fR ( $2 ).  The \fIuser\fR 
specification is a rewriting-pattern, as described above.  
.PP
In general, the format of a \fIresolve\fR action will be as follows:
.DS
	\fIresolve\fR (	\fImailer\fR ( <mailer-name> ),
			\fIhost\fR   ( <host-name> ),
			\fIuser\fR   ( <user-address>)   );
.DE
Examples of the match-action statement are shown below:
.DS
\fIfield\fR
	anypath	: \fImatch\fR (0*);
	usr, path	: \fImatch\fR (1*);
	hostname	: \fImatch\fR (1);
	phone_host	: \fImatch\fR (1) in phonehosts;
.DE
.DS
\fIruleset\fR

	EXAMPLE_RW {
	
		\fIif\fR ( anypath < path > anypath )   /* basic RFC821/822 parse */
			\fIretry\fR ( $2 );
		\fIif\fR ( usr " at " path )		/* \*Qat\*U -> \*Q@\*U */
			\fInext\fR ( $1 @ $2 );
		\fIif\fR ( @path: usr )
			\fIreturn\fR ( LOCAL_RW ( < @$1 > : $2 ) );
		\fIif\fR ( anypath < @phone_host".ARPA" > anypath )
			\fIresolve\fR (	\fImailer\fR ( tcp ),
					\fIhost\fR ( csnet-relay ),
					\fIuser\fR ( $1 % $2 < @"csnet-relay" > $3 ) );
	}
.DE
.PP
The example above defines the ruleset \*QEXAMPLE_RW\*U, which contains four
rewriting rules.  The first rewriting rule discards all tokens of an address
which lie on either side of a pair of angle brackets (<>), thereby 
rewriting the address as
the sequence of tokens contained within the angle brackets ($2).  Following the
address rewrite, the rule is applied again (\fIretry\fR).  When the first rule
fails to match the address being rewritten, the second rule is applied.  
.PP
The second 
rule simply replaces the word \*Qat\*U by the symbol \*Q@\*U.  The \*Q\fInext\fR\*U
action specifies that if a match is made, a rewrite is performed and 
matching continues at the next (or following) rule.  
.PP
The third rule illustrates
the use of the \*Q\fIreturn\fR\*U action, which is executed if the 
pattern \*Q at path: usr\*U
describes the current format of the address being rewritten.  In this example,
the \fIreturn\fR action returns the result of a call to ruleset \*QLOCAL_RW\*U,
which rewrites the address \*Q<@$1>:$2\*U, where $1 and $2 are substituted
with the token(s) matched respectively by \*Qpath\*U and \*Qusr\*U.
.PP
The fourth (and final) rule signals a resolution (and termination) of the
rewriting process if the given pattern is matched.  The resolution specifies
that the mailer \*Qtcp\*U will be used to deliver the message to the host
\*Qcsnet-relay\*U.  The \fIuser\fR parameter specifies the final form of the address
which \fIsendmail\fR has just resolved.
.sp 2
.PP
The \fBEase\fR construct which remains to be examined is the 
\fBconditional-expression\fR.  The \fBconditional-expression\fR provides a 
method for
constructing strings based on the condition that some test macro is (or is not)
set.  The general form begins with the concatenation of a string and a
\fBstring-conditional\fR:
.DS
	\fIconcat\fR ( <quoted-string>, \fBstring-conditional\fR )
	\fIconcat\fR ( \fBstring-conditional\fR, <quoted-string> )
.DE
A \fBstring-conditional\fR assumes either of the following forms:
.DS
	\fIifset\fR ( <macro-name>, <ifset-string> )
	\fIifset\fR ( <macro-name>, <ifset-string>, <notset-string> )
.DE
A \fBstring-conditional\fR of the first form evaluates to \*Qifset-string\*U 
if the macro \*Qmacro-name\*U has been assigned a value; otherwise it
evaluates to the null string.  The second form behaves similarly, except
that the \fBstring-conditional\fR evaluates to \*Qnotset-string\*U, instead
of the null string, if the macro \*Qmacro-name\*U has no value.
.sp 1
The following \fBconditional-expression\fR,
.DS
	\fIconcat\fR ( "New ", \fIifset\fR ( city, "York", "Jersey" ) )
.DE
evaluates to the string "New York", if the macro \*Qcity\*U is set.  Otherwise,
the \fBconditional-expression\fR evaluates to the string "New Jersey".
.NH
Ease Translation
.PP
It is important to note that \fBEase\fR is translated by a stand-alone
translator to the raw configuration file format.  No modifications were
made to the \fIsendmail\fR program itself.  As a result, syntactical verification
of a configuration file can be performed without invoking \fIsendmail\fR.
.PP
The \fBEase\fR language is translated by invoking 
the C language preprocessor (cpp) with \fBEase\fR source as input, then piping
the output as input to the \fBEase\fR translator (\fIet\fR).  The \fBEase\fR
translator may be invoked on the command line in one of four ways:
.TS
center box ;
l l .
\fIet\fR  <input-file>  <output-file>	[read from a file, write to a file]
\fIet\fR  <input-file>	[read from a file, write to standard output]
\fIet\fR  -  <output-file>	[read from standard input, write to a file]
\fIet\fR	[read from standard input, write to standard output]
.TE
.NH
Conclusion
.PP
\fBEase\fR is currently in use at the Purdue University Computing 
Center.  Source code for the \fBEase\fR translator (\fIet\fR) may be
obtained on request by writing to:
.DS
U.S. Mail:
		James S. Schoner
		c/o Kevin S. Braunsdorf
		Purdue University Computing Center
		Purdue University
		West Lafayette, Indiana  47907

Electronic Mail:
		ksb at j.cc.purdue.edu
.DE
.PP
Much of the success of this project is attributable to the constant support 
and insight offered by Mark Shoemaker.  To him, I owe a debt of gratitude.  In 
addition, I would like to thank Kevin Smallwood, Paul Albitz, and Rich Kulawiec
for their many notable suggestions and valuable insight.
SHAR_EOF
if test 29063 -ne "`wc -c ease.paper`"
then
echo shar: error transmitting ease.paper '(should have been 29063 characters)'
fi
cat << \SHAR_EOF > Makefile
#
#	Makefile for Ease document.
#
#	James S. Schoner
#	Purdue University Computing Center
#
all:	cover mainbody apen1 apen2 apen3
	
cover: FRC
	troff -ms cover

mainbody:
	tbl ease.paper | troff -ms

apen1:
	tbl ap1 | troff -ms

apen2:
	tbl ap2 | troff -ms

apen3:
	tbl ap3 | troff -ms

FRC:

SHAR_EOF
if test 293 -ne "`wc -c Makefile`"
then
echo shar: error transmitting Makefile '(should have been 293 characters)'
fi
chdir ..
mkdir src
chdir src
cat << \SHAR_EOF > parser.y
%{
/*	$Header: /usr/src/local/etc/ease/RCS/parser.y,v 1.3 85/12/10 18:02:11 jss Exp $	*/

/*
 *	parser.y -- EASE parser.
 *
 *		    Contains code for yacc(1) which produces a parser (y.tab.c)
 *		    for Ease, a specification format for sendmail configuration
 *		    files.
 *
 *	author   -- James S. Schoner, Purdue University Computing Center,
 *		    		      West Lafayette, Indiana  47907
 *
 *	date     -- July 2, 1985
 *
 *	Copyright (c) 1985 by Purdue Research Foundation
 *
 *	All rights reserved.
 *
 */

#include <stdio.h>
#include "symtab.h"

extern void	   BindID ();
extern void	   EmitDef ();
extern char	  *ListAppend ();
extern char 	  *MakeCond ();
extern char	  *MakeRStr ();
extern char       *ConvOpt ();
extern char	  *ConvFlg ();
extern char	  *MacScan ();
extern char	  *ConvMat ();
extern void	   StartRuleset ();
extern char	  *MakePosTok ();
extern char	  *GetField ();
extern char	  *Bracket ();
extern char	  *MakeRSCall ();
extern char	  *CheckMailer ();
extern char	  *CheckRS ();
extern char	  *MakeField ();
extern char	   MakeMac ();
extern void	   AssignType ();
extern void	   RemoveSymbol ();
extern void	   yyerror ();

extern short RMatch;		/* ruleset match flag 		      */

char *Cbuf = " ";		/* character buffer   		      */
char *Mbuf = "$ ";		/* macro buffer	      		      */
char *Tsb;			/* pointer to temporary string buffer */
char *Flaglist;			/* pointer to header flag list	      */

%}

%union {			/* value stack element type    */
	int	  ival;		/* integer token 	       */
	char	  *psb;		/* string token		       */
	struct he *phe;		/* pointer to hash entry       */
	enum opts optval;	/* sendmail options	       */
	enum flgs flgval;	/* mailer flags		       */
	enum mats mpval;	/* mailer attribute parameters */
}

%start config

%token 	<phe>	IDENT
%token  <psb>	SCONST
%token  <ival>	ICONST SEPCHAR
%token BIND MACRO CLASS OPTIONS PRECEDENCE TRUSTED HEADER RULESET MAILER
%token IF RETRY NEXT RETURN RESOLVE CONCAT IFSET FOR CANON READCLASS
%token MPATH MFLAGS MSENDER MRECIPIENT MARGV MEOL MMAXSIZE
%token AAOPT AOPT BBOPT COPT DOPT DOPTI DOPTB DOPTQ DDOPT EOPT EOPTP EOPTE 
%token EOPTM EOPTW EOPTZ FFOPT FOPT GOPT HHOPT IOPT LLOPT MOPT NNOPT OOPT QQOPT
%token ROPT SSOPT SOPT TTOPT TOPT UOPT VOPT WWOPT XOPT XXOPT
%token FFLAG RFLAG SSFLAG NFLAG LFLAG SFLAG MFLAG FFFLAG DDFLAG MMFLAG XFLAG
%token PPFLAG UFLAG HFLAG AAFLAG UUFLAG EFLAG XXFLAG LLFLAG PFLAG IIFLAG CCFLAG
%token ASGN COMMA LBRACE RBRACE LPAREN RPAREN SEMI DOLLAR MATCH IN HOSTNUM
%token DEFINE FIELD COLON STAR HOST USER

%type	<psb>		mval strval ifcon conval ifres elseres nameset namelist
%type	<psb>		doptid eoptid idlist fcond dlist mflags route mdefs
%type	<psb>		matchaddr matchtok action actionstmt mailerspec mtdef
%type	<psb>		rwaddr rwtok ftype reftok rword cantok resolution
%type	<psb>		userspec hword hostid dheader
%type	<ival>		anychar
%type	<phe>		cdef
%type	<optval>	optid
%type	<flgval>	flagid
%type	<mpval>		mvar

%left COMMA
%left LPAREN RPAREN
%nonassoc SCONST

%%
config		:	/* empty */
		|	config blockdef
		|	error blockdef
		;

blockdef	:	BIND bindings
		|	MACRO macdefs
		|	CLASS classdefs
		|	OPTIONS optdefs
		|	PRECEDENCE precdefs
		|	TRUSTED tlist
		|	HEADER hdefs
		|	MAILER mlist
		|	RULESET rdef
		|	FIELD fdefs
		;

bindings	:	/* empty */
		|	bindings IDENT ASGN RULESET ICONST SEMI {
				BindID ($2, $5, ID_RULESET);
			}
		|	error SEMI {
				yyerrok;
			}
		;

macdefs		:	/* empty */
		|	macdefs IDENT ASGN mval SEMI {
				EmitDef (def_macro, $2, $4, (char *) NULL);
			}
		|	error SEMI {
				yyerrok;
			}
		;

mval		:	strval				%prec COMMA {
				$$ = $1;
			}
		|	CONCAT LPAREN conval RPAREN {
				$$ = $3;
			}
		;

strval		:	SCONST {
				$$ = $1;
			}
		|	strval SCONST {
				$$ = ListAppend ($1, $2, (char *) NULL);
				free ($1);
			}
		;

conval		:	strval COMMA ifcon {
				$$ = ListAppend ($1, $3, (char *) NULL);
				free ($1);
				free ($3);
			}
		|	ifcon COMMA strval {
				$$ = ListAppend ($1, $3, (char *) NULL);
				free ($1);
				free ($3);
			}
		|	error {
				$$ = NULL;
			}
		;

ifcon		:	IFSET LPAREN IDENT COMMA ifres RPAREN {
				$$ = MakeCond ($3, $5);
			}
		;

ifres		:	mval elseres {
				if ($2 != NULL) {
					$$ = ListAppend ($1, $2, "$|");
					free ($1);
					free ($2);
				} else
					$$ = $1;
			}
		|	error {
				$$ = NULL;
			}
		;

elseres		:	/* empty */ {
				$$ = NULL;
			}
		|	COMMA mval {
				$$ = $2;
			}
		;

classdefs	:	/* empty */ 
		|	classdefs IDENT ASGN nameset {
				EmitDef (def_class, $2, $4, (char *) NULL);
			}
		|	error
		;

nameset		:	LBRACE namelist RBRACE SEMI {
				$$ = $2;
			}
		|	LBRACE RBRACE SEMI {
				$$ = NULL;
			}
		|	LBRACE error RBRACE SEMI {
				$$ = NULL;
			}
		|	READCLASS LPAREN strval RPAREN SEMI {
				$$ = MakeRStr ($3, (char *) NULL);
			}
		|	READCLASS LPAREN strval COMMA strval RPAREN SEMI {
				$$ = MakeRStr ($3, $5);
			}
		|	READCLASS LPAREN error RPAREN SEMI {
				$$ = NULL;
			}
		|	error SEMI {
				$$ = NULL;
				yyerrok;
			}
		;

namelist	:	IDENT {
				$$ = ListAppend ($1->psb, (char *) NULL, (char *) NULL);
				RemoveSymbol ($1);
			}
		|	strval {
				$$ = $1;
			}
		|	namelist COMMA IDENT {
				$$ = ListAppend ($1, $3->psb, " ");
				free ($1);
				RemoveSymbol ($3);
			}
		|	namelist COMMA strval {
				$$ = ListAppend ($1, $3, " ");
				free ($1);
				free ($3);
			}
		;

optdefs		:	/* empty */
		|	optdefs optid ASGN strval SEMI {
				EmitDef (def_option, (struct he *) NULL, ConvOpt ($2), $4);
			}
		|	optdefs DOPT ASGN doptid SEMI {
				EmitDef (def_option, (struct he *) NULL, ConvOpt (opt_d), $4);
			}
		|	optdefs EOPT ASGN eoptid SEMI {
				EmitDef (def_option, (struct he *) NULL, ConvOpt (opt_e), $4);
			}
		|	error SEMI {
				yyerrok;
			}
		;

optid		:	AAOPT {
				$$ = opt_A;
			}
		|	AOPT {
				$$ = opt_a;
			}
		|	BBOPT {
				$$ = opt_B;
			}
		|	COPT {
				$$ = opt_c;
			}
		|	DDOPT {
				$$ = opt_D;
			}
		|	FFOPT {
				$$ = opt_F;
			}
		|	FOPT {
				$$ = opt_f;
			}
		|	GOPT {
				$$ = opt_g;
			}
		|	HHOPT {
				$$ = opt_H;
			}
		|	IOPT {
				$$ = opt_i;
			}
		|	LLOPT {
				$$ = opt_L;
			}
		|	MOPT {
				$$ = opt_m;
			}
		|	NNOPT {
				$$ = opt_N;
			}
		|	OOPT {
				$$ = opt_o;
			}
		|	QQOPT {
				$$ = opt_Q;
			}
		|	ROPT {
				$$ = opt_r;
			}
		|	SSOPT {
				$$ = opt_S;
			}
		|	SOPT {
				$$ = opt_s;
			}
		|	TTOPT {
				$$ = opt_T;
			}
		|	TOPT {
				$$ = opt_t;
			}
		|	UOPT {
				$$ = opt_u;
			}
		|	VOPT {
				$$ = opt_v;
			}
		|	WWOPT {
				$$ = opt_W;
			}
		|	XOPT {
				$$ = opt_x;
			}
		|	XXOPT {
				$$ = opt_X;
			}
		;

doptid		:	DOPTI {
				$$ = ConvOpt (d_opt_i);
			}
		|	DOPTB {
				$$ = ConvOpt (d_opt_b);
			}
		|	DOPTQ {
				$$ = ConvOpt (d_opt_q);
			}
		;

eoptid		:	EOPTP {
				$$ = ConvOpt (e_opt_p);
			}
		|	EOPTE {
				$$ = ConvOpt (e_opt_e);
			}
		|	EOPTM {
				$$ = ConvOpt (e_opt_m);
			}
		|	EOPTW {
				$$ = ConvOpt (e_opt_w);
			}
		|	EOPTZ {
				$$ = ConvOpt (e_opt_z);
			}
		;

precdefs	:	/* empty */
		|	precdefs IDENT ASGN ICONST SEMI {
				BindID ($2, $4, ID_PREC);
				EmitDef (def_prec, $2, (char *) NULL, (char *) NULL);
			}
		;

tlist		:	/* empty */
		|	tlist LBRACE IDENT idlist RBRACE SEMI {
				EmitDef (def_trusted, (struct he *) NULL, 
					 ListAppend ($3->psb, $4, " "), (char *) NULL);
				free ($4);
				RemoveSymbol ($3);
			}
		|	tlist LBRACE RBRACE SEMI
		|	error SEMI {
				yyerrok;
			}
		;

hdefs		:	/* empty */
		|	hdefs FOR fcond dheader SEMI {
				EmitDef (def_header, (struct he *) NULL, $3, $4);
			}
		|	hdefs FOR fcond LBRACE { Flaglist = $3; } 
				dheaders RBRACE SEMI
		|	hdefs DEFINE dlist SEMI {
				EmitDef (def_header, (struct he *) NULL, (char *) NULL, $3);
			}
		|	error SEMI {
				yyerrok;
			}
		;

fcond		:	LPAREN RPAREN {
				$$ = NULL;
			}
		|	LPAREN mflags RPAREN {
				$$ = $2;
			}
		|	LPAREN error RPAREN {
				$$ = NULL;
			}
		;

mflags		:	flagid {
				$$ = ListAppend (ConvFlg ($1), (char *) NULL, (char *) NULL);
			}
		|	mflags COMMA flagid {
				$$ = ListAppend ($1, ConvFlg($3), (char *) NULL);
				free ($1);
			}
		;

flagid		:	FFLAG {
				$$ = flg_f;
			}
		|	RFLAG {
				$$ = flg_r;
			}
		|	SSFLAG {
				$$ = flg_S;
			}
		|	NFLAG {
				$$ = flg_n;
			}
		|	LFLAG {
				$$ = flg_l;
			}
		|	SFLAG {
				$$ = flg_s;
			}
		|	MFLAG {
				$$ = flg_m;
			}
		|	FFFLAG {
				$$ = flg_F;
			}
		|	DDFLAG {
				$$ = flg_D;
			}
		|	MMFLAG {
				$$ = flg_M;
			}
		|	XFLAG {
				$$ = flg_x;
			}
		|	PPFLAG {
				$$ = flg_P;
			}
		|	UFLAG {
				$$ = flg_u;
			}
		|	HFLAG {
				$$ = flg_h;
			}
		|	AAFLAG {
				$$ = flg_A;
			}
		|	UUFLAG {
				$$ = flg_U;
			}
		|	EFLAG {
				$$ = flg_e;
			}
		|	XXFLAG {
				$$ = flg_X;
			}
		|	LLFLAG {
				$$ = flg_L;
			}
		|	PFLAG {
				$$ = flg_p;
			}
		|	IIFLAG {
				$$ = flg_I;
			}
		|	CCFLAG {
				$$ = flg_C;
			}
		;

dheader		:	/* empty */ {
				$$ = NULL;
			}
		|	DEFINE dlist {
				$$ = $2;
			}
		|	error {
				$$ = NULL;
			}
		;

dheaders	:	/* empty */
		|	dheaders DEFINE dlist SEMI {
				EmitDef (def_header, (struct he *) NULL, Flaglist, $3);
			}
		|	error
		;

dlist		:	LPAREN strval COMMA mval RPAREN {
				$$ = ListAppend ($2, MacScan ($4), " ");
				free ($2);
				free ($4);
			}
		|	LPAREN error RPAREN {
				$$ = NULL;
			}
		;

mlist		:	/* empty */
		|	mlist IDENT LBRACE mdefs RBRACE SEMI {
				EmitDef (def_mailer, $2, $4, (char *) NULL);
			}
		|	mlist IDENT LBRACE RBRACE SEMI {
				EmitDef (def_mailer, $2, (char *) NULL, (char *) NULL);
			}
		|	error SEMI {
				yyerrok;
			}
		;

mdefs		:	mtdef {
				$$ = $1;
			}
		|	mdefs COMMA mtdef {
				$$ = ListAppend ($1, $3, ", ");
				free ($1);
				free ($3);
			}
		;	

mtdef		:	mvar ASGN mval {
				$$ = ListAppend (ConvMat ($1), MacScan ($3), "=");
				free ($3);
			}
		|	MFLAGS ASGN LBRACE mflags RBRACE {
				$$ = ListAppend (ConvMat (mat_flags), $4, "=");
			}
		|	MSENDER ASGN IDENT {
				$$ = ListAppend (ConvMat (mat_sender), CheckRS ($3), "=");
			}
		|	MRECIPIENT ASGN IDENT {
				$$ = ListAppend (ConvMat (mat_recipient), CheckRS ($3), "=");
			}
		|	error {
				$$ = NULL;
			}
		;

mvar		:	MPATH {
				$$ = mat_path;
			}
		|	MARGV {
				$$ = mat_argv;
			}
		|	MEOL {
				$$ = mat_eol;
			}
		|	MMAXSIZE {
				$$ = mat_maxsize;
			}
		;

rdef		:	/* empty */
		|	rdef IDENT { StartRuleset ($2); } rulelist
		;

rulelist	:	LBRACE ruledefs RBRACE {
				RMatch = FALSE;
			}
		|	error {
				RMatch = FALSE;
			}
		;

ruledefs	:	/* empty */ {
				RMatch = TRUE;
			}
		|	ruledefs IF LPAREN matchaddr RPAREN actionstmt {
				EmitDef (def_ruleset, (struct he *) NULL, 
					 ListAppend ($4, $6, "\t"), (char *) NULL);
			free ($4);
			free ($6);
			}
		|	error SEMI {
				yyerrok;
			}
		;

matchaddr	:	/* empty */ {
				$$ = NULL;
			}
		|	matchaddr matchtok {
				$$ = ListAppend ($1, $2, (char *) NULL);
				free ($1);
			}
		|	error {
				$$ = NULL;
			}
		;

matchtok	:	IDENT {
				$$ = GetField ($1);
			}
		|	anychar {
				*Cbuf = $1;
				$$ = ListAppend (Cbuf, (char *) NULL, (char *) NULL);
			}
		|	mval {
				$$ = MacScan ($1);
			}
		|	DOLLAR IDENT {
				Mbuf[1] = MakeMac ($2, ID_MACRO);
				$$ = ListAppend (Mbuf, (char *) NULL, (char *) NULL);
			}
		;

actionstmt	:	action LPAREN rwaddr RPAREN SEMI {
				$$ = ListAppend ($1, $3, (char *) NULL);
				free ($3);
			}
		|	RESOLVE LPAREN resolution RPAREN SEMI {
				$$ = $3;
			}
		|	error SEMI {
				$$ = NULL;
				yyerrok;
			}
		;

action		:	RETRY {
				$$ = NULL;
			}
		|	NEXT {
				$$ = "$:";
			}
		|	RETURN {
				$$ = "$@";
			}
		;

rwaddr		:	/* empty */ {
				$$ = NULL;
			}
		|	rwaddr rwtok {
				$$ = ListAppend ($1, $2, (char *) NULL);
				free ($1);
			}
		|	rwaddr IDENT LPAREN rwaddr RPAREN {
				$$ = ListAppend ($1, (Tsb = MakeRSCall ($2, $4)), (char *) NULL);
				free ($1);
				free ($4);
				free (Tsb);
			}
		|	error {
				$$ = NULL;
			}
		;

rwtok		:	anychar {
				*Cbuf = $1;
				$$ = ListAppend (Cbuf, (char *) NULL, (char *) NULL);
			}
		|	mval {
				$$ = MacScan ($1);
			}
		|	cantok {
				$$ = $1;
			}
		|	reftok {
				$$ = $1;
			}
		;

cantok		:	CANON LPAREN IDENT RPAREN {
				$$ = Bracket ($3->psb, TRUE);
				RemoveSymbol ($3);
			}
		|	CANON LPAREN SCONST RPAREN {
				$$ = Bracket (MacScan ($3), TRUE);
				free ($3);
			}
		|	CANON LPAREN reftok RPAREN {
				$$ = Bracket ($3, TRUE);
				free ($3);
			}
		;

reftok		:	DOLLAR IDENT {
				Mbuf[1] = MakeMac ($2, ID_MACRO);
				$$ = ListAppend (Mbuf, (char *) NULL, (char *) NULL);
			}
		|	DOLLAR ICONST {
				$$ = ListAppend (MakePosTok ($2), (char *) NULL, (char *) NULL);
			}
		;

anychar		:	SEPCHAR {
				$$ = $1;
			}
		|	COLON {
				$$ = ':';
			}
		|	STAR {
				$$ = '*';
			}
		|	SEMI {
				$$ = ';';
			}
		|	LBRACE {
				$$ = '{';
			}
		|	RBRACE {
				$$ = '}';
			}
		|	COMMA {
				$$ = ',';
			}
		|	ASGN {
				$$ = '=';
			}
		;

resolution	:	mailerspec COMMA route {
				$$ = ListAppend ($1, $3, (char *) NULL);
				free ($1);
				free ($3);
			}
		|	error {
				$$ = NULL;
			}
		;

mailerspec	:	MAILER LPAREN rword RPAREN {
				$$ = ListAppend ("$#", $3, (char *) NULL);
			}
		;

route		:	HOST LPAREN hword RPAREN COMMA userspec {
				$$ = ListAppend (Tsb = ListAppend ("$@", $3, (char *) NULL),
						 $6, (char *) NULL);
				free (Tsb);
				free ($6);
			}
		|	userspec {
				$$ = $1;
			}
		;

hword		:	hostid {
				$$ = $1;
			}
		|	HOSTNUM LPAREN reftok RPAREN {
				$$ = Bracket ($3, FALSE);
				free ($3);
			}
		;

hostid		:	/* empty */ {
				$$ = NULL;
			}
		|	hostid IDENT {
				$$ = ListAppend ($1, $2->psb, (char *) NULL);
				RemoveSymbol ($2);
				free ($1);
			}
		|	hostid rwtok {
				$$ = ListAppend ($1, $2, (char *) NULL);
				free ($1);
			}
		;

userspec	:	USER LPAREN rwaddr RPAREN {
				$$ = ListAppend ("$:", $3, (char *) NULL);
				free ($3);
			}
		;

rword		:	IDENT {
				$$ = CheckMailer ($1);
			}
		|	reftok {
				$$ = $1;
			}
		;

fdefs		:	/* empty */
		|	fdefs IDENT idlist COLON ftype SEMI {
				AssignType (ListAppend ($2->psb, $3, " "), $5);
				free ($3);
			}
		|	error SEMI {
				yyerrok;
			}
		;

idlist		:	/* empty */ {
				$$ = NULL;
			}
		|	idlist COMMA IDENT {
				$$ = ListAppend ($1, $3->psb, " ");
				free ($1);
			}
		;

ftype		:	MATCH LPAREN ICONST RPAREN cdef {
				$$ = ListAppend (MakeField ($3, $5, FALSE), 
				    		 (char *) NULL, (char *) NULL);
			}
		|	MATCH LPAREN ICONST STAR RPAREN {
				$$ = ListAppend (MakeField ($3, (struct he *) NULL, TRUE), 
						 (char *) NULL, (char *) NULL);
			}
		|	error {
				$$ = NULL;
			}
		;

cdef		:	/* empty */ {
				$$ = NULL;
			}
		|	IN IDENT {
				$$ = $2;
			}
		;
SHAR_EOF
if test 14482 -ne "`wc -c parser.y`"
then
echo shar: error transmitting parser.y '(should have been 14482 characters)'
fi
chdir ..
#	End of shell archive
exit 0



More information about the Mod.sources mailing list