[alt.sources] Ease 3.0: High Level Language for Sendmail

barnett@grymoire.crd.ge.com (Bruce Barnett) (02/23/91)

#! /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 1 (of 6)."
# Contents:  CONVERTING Makefile README TESTING TODO cfc/Makefile
#   debug/Makefile debug/debug.in debug/showhow debug/showwhere
#   doc/Makefile doc/ap1 doc/ap2 doc/ap3 doc/ap4 doc/cover
#   doc/ease.man doc/et.man src/ease.sh src/fixstrings.c
#   src/fixstrings.h src/symtab.h test/README test/args
#   test/test.addresses test/test.cf utils/Makefile
#   utils/build-new-aliases utils/cfdiff.csh utils/cfstrip.csh
# Wrapped by barnett@grymoire on Sat Feb 23 01:13:46 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo mkdir cfc bin debug doc src test utils
mkdir cfc bin debug doc src test utils
if test -f CONVERTING -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"CONVERTING\"
else
echo shar: Extracting \"CONVERTING\" \(3448 characters\)
sed "s/^X//" >CONVERTING <<'END_OF_CONVERTING'
X=====================================================================
X	Converting a sendmail file into ease
X
X
XStep 1.  Use cfc to convert the sendmail file into ease.
X	You may want to use "make convert" in the top Makefile
X
X	As a start, use the following arguments to cfc 
X
X	SunOS 4.0, /usr/lib/sendmail.subsidiary.cf
X		=> cfc -s -C V < /usr/lib/sendmail.subsidiary.cf>sendmail.ease
X
X	SunOS 4.0, /usr/lib/sendmail.main.cf
X
X		=> cfc -s < /usr/lib/sendmail.main.cf>sendmail.ease
X
X
X	Ultrix 3.0: 
X
X		=> cfc -d -C SDIZFN </etc/sendmail.cf >sendmail.ease
X
X	IDA sendmail
X
X		=> cfc -i
X
X	4.2 sendmail
X
X		=> cfc -c
X
X	4.3 sendmail
X
X		=> cdc -u
X
X	HP/UX
X		=> cfc -i -CGUS
X
X
XStep 2.  Convert the ease file to cf: 
X
X	% et <sendmail.ease >sendmail.cf
X
X	Look at the errors and warnings.
X
X	Most of these errors can be eliminated by using the right
X	flags on cfc. Make sure that you specify all of the
X	classes (using the -C flag ) that you need, which generate
X	the matching field definitions for any_in_? fields.
X	Then repeat the cf-> ease translation with the necessary
X	-C XYZ flags.
X
X	The remaining errors are either warnings or mistakes
X	in the translation. NOTE: - some configuration files use macros 
X	that are not defined. For instance, Sun's sendmail.main.cf has 
X	an undefined D macro. Ultrix has several undefined macros, that if
X	you define them, cause your sendmail to exhibit change behavior.
X	These are warnings, and are perfectly fine. If you want to
X	you can define the missing rulesets. Don't define the missing
X	macros unless you examine the sendmail rules and see what happens with
X	the change.
X
X	So look at the warnings and errors, and repeat step 1 until you 
X	feel comfortable with the change.
X
X	If you can't get cfc/ease to accept the new syntax, use the
X	asm(" ") construct to work around it and report the bugs.
X
XStep 3. Verify the ease output matches the original sendmail
X
X	You can use  "make test_conversion" it you wish
X
X	At this point, you should verify that the ease output is identical to
X	the original sendmail.cf file. Use the script cfdiff to
X	compare the original sendmail.cf file with the ease output file.
X
X	That is, if your original sendmail file is /etc/sendmail.cf,
X	and the new one is ./sendmail.cf, do a
X
X	 set path = ( $cwd/bin $path );rehash;cfdiff /etc/sendmail.cf ./sendmail.cf
X
X	You will see some differences in lines that have been split into
X	two lines, and the "Ob" option is converted into the more
X	verbose "Obackground" option. If there is any other difference, 
X	please send me a bug report, and see if you can make changes to your
X	ease input file to match the original file. You may need the asm("")
X	command.
X
X	If your diff program has the -w option, you can ignore spaces in the
X	cf files. Occasionally ease inserts some extra spaces. Or the
X	original sendmail file has extra spaces. (e.g. SunOS).
X	See the script cfdiff.
X
XStep 4. Once you have the ease file in good form, put it under sccs
X	control, and put the version number (%W% in the V macro
X	definition, so the "Received-by" header line reflects the revision.)
X
XYou are now ready to debug your sendmail file.
XSee the file TESTING
X============================================================================
X
XIf you find these programs useful, or if you have suggestions or changes,
Xplease drop me a line.
X
X	Bruce Barnett
X	General Electric
X	Corporate Research and Development
X	P. O. Box 8, 1 River Road
X	Schenectady, NY 12302
X
X	barnett@crdgw1.ge.com
END_OF_CONVERTING
if test 3448 -ne `wc -c <CONVERTING`; then
    echo shar: \"CONVERTING\" unpacked with wrong size!
fi
chmod +x CONVERTING
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(2373 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X# where do you want to place the binaries and scripts?
X# the programs are: et cfc cfdiff cfstrip
XBINDIR=`pwd`/bin
X
X#where is your original sendmail file?
X#ORIGINAL=/etc/sendmail.cf
XORIGINAL=/usr/lib/sendmail.cf
X#ORIGINAL=/usr/lib/sendmail.main.cf
X#ORIGINAL=/usr/lib/sendmail.subsidiary.cf
X
X# What arguments to cfc do you want for cfc (see the file CONVERT)
XCONVERT_FLAGS=-s -CV
X
X#what extenstion do you want for the manual pages?
X#EXT=1
X#EXT=l
XEXT=n
XSHELL=/bin/sh
X
X
Xall:
X	cd cfc; ${MAKE} ${FLAGS}  $@
X	cd src; ${MAKE} ${FLAGS}  $@
X	cd utils; ${MAKE} ${FLAGS}  $@
X	touch all
X	
Xinstall:
X	test -d ${BINDIR} || mkdir ${BINDIR}
X#	cd cf; make $(MFLAGS) $@
X	BD=${BINDIR};cd cfc; ${MAKE} ${MFLAGS} BINDIR=$$BD $@
X	BD=${BINDIR};cd src; ${MAKE} ${MFLAGS} BINDIR=$$BD $@
X	BD=${BINDIR};cd utils; ${MAKE} ${MFLAGS} BINDIR=$$BD $@
X	cd doc; ${MAKE} ${MFLAGS} EXT=${EXT} $@
X
X
X
Xconvert:	${ORIGINAL} all 
X		${BINDIR}/cfc ${CONVERT_FLAGS} < ${ORIGINAL} >sendmail.ease
X
Xtest_conversion:	${ORIGINAL} sendmail.cf
X	PATH=${BINDIR}:$$PATH;export PATH;cfdiff ${ORIGINAL} sendmail.cf
X
Xclean:
X#	cd cf; make $(MFLAGS) $@
X	cd src; ${MAKE} ${MFLAGS} $@
X	cd cfc; ${MAKE} ${MFLAGS} $@
X	cd utils; ${MAKE} ${MFLAGS} $@
X
Xdebug:	all sendmail.ease
X	BD=${BINDIR};cd debug; ${MAKE} ${MFLAGS} BINDIR=$$BD $@
Xsendmail.ease:
X	@ echo where is the sendmail.ease file you want to debug?	
X
Xsendmail.cf: all sendmail.ease
X	${BINDIR}/et <sendmail.ease >sendmail.cf
X
Xhostname.ease: SCCS/s.hostname.ease
X	sccs get hostname.ease
X
Xhostname.cf:	hostname.ease
X	et -C <hostname.ease >hostname.cf
X
Xinstall_hostname: hostname.cf
X	@sccs check
X	/bin/mv ${ORIGINAL} ${ORIGINAL}.old
X	/bin/cp hostname.cf ${ORIGINAL}
X	build-new-aliases
X
Xmail: Part01 Part02 Part03 Part04 Part05 Part06
X	@ WHO=${WHO} && \
X	[ $${WHO:-missing} = missing ] && \
X	echo USAGE:  make mail WHO=address || \
X	(( mail -s "Ease 3.0: Part 1 of 6" $${WHO} <Part01) ;\
X	 ( mail -s "Ease 3.0: Part 2 of 6" $${WHO} <Part02) ;\
X	 ( mail -s "Ease 3.0: Part 3 of 6" $${WHO} <Part03) ;\
X	 ( mail -s "Ease 3.0: Part 4 of 6" $${WHO} <Part04) ;\
X	 ( mail -s "Ease 3.0: Part 5 of 6" $${WHO} <Part05) ;\
X	 ( mail -s "Ease 3.0: Part 6 of 6" $${WHO} <Part06; ))
X
Xdepend lint print:
X	-for dir in *; do [ -f $$dir/[Mm]akefile ] && (cd $$dir; make $(MFLAGS) $@); done
X
Xshar:
X	dirname=`basename $$PWD`; cd ..; shar `find $$dirname -name RCS -prune -o -type f -print` >/tmp/ease.shar
X
END_OF_Makefile
if test 2373 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(7378 characters\)
sed "s/^X//" >README <<'END_OF_README'
XREADME - Tue May  1 14:46:33 PDT 1990
X
XThis is release 3.0 of the CFC and Ease programs.
X
XEase is a compiler for sendmail configuration files.  It reads a high-level
Xmail configuration language and produces a sendmail.cf file.  If you've ever
Xstared at a sendmail.cf, you know why this is valuable.
X
XCfc is performs the inverse operation: it converts sendmail.cf files into
Xsource for ease.  It gives you hope for working with your existing sendmail.cf
Xfiles.
X
XThis is a fresh posting of the entire source for 'ease' and "cfc'.
XIt incorporates all of the previous netwide posting (version 2.0),
Xplus some additional support for new and undocumented sendmail features.
X
XEase was written by
X    James S. Schoner, Purdue University Computing Center,
X		      West Lafayette, Indiana  47907
Xand is copyright (c) 1985 by Purdue Research Foundation.
X
XEase has been enhanced and maintained by various persons, most notably
X    Arnold D. Robbins (arnold@unix.cc.emory.edu),
X    Bruce Barnett (barnett@crdgw1ge.com,  uunet!crdgw1!barnett)
X    Stephen Schaefer of Bowling Green State University,
X    Raymond A. Schnitzler of Bellcore,
X    Andrew Partan of the Corporation for Open Systems,
X    Rich Salz of Bolt Beranak, and Newman.
X
XCfc was written by Arnold D. Robbins, and has been enhanced by Bruce Barnett
X(see below).
X
XNotable changes to cfc since release 2.0 are described in the note
Xfrom Bruce Barnett below.
X
X
X	-----------------------------------------------------------
X
X		Ease 3.0 and cfc Release Notes:
X		Bruce Barnett barnett@crdgw1.ge.com
X		February 1991
X
XThis document describes Ease 3.0. This version was originally a
Xmodified version of the last official release of ease 2.1. I called it
X2.1 Beta and sent it to several dozen people. I sent the patches to the authors
Xof ease and cfc, but an updated version was never posted to the net.
XThe authors have decided to let me post the changes, so I guess I have
Xthe baton now.
X
XSince this is a major release, I decided to call it Ease 3.0
X
XThe main feature of Ease/Cfc 3.0:
X
X
X	I subjected the Cfc/Ease programs to a test suite
X	that converted *.cf files to ease files, and back again.
X	I compared the input of cfc  (The original .cf file)
X	to the output of ease. The goal was twofold:
X
X		1. To automatically produce an Ease file than can
X		   be used to generate a .cf file identical to the original
X		2. To produce an Ease file that can be used without
X			editing. You will see warnings, and possible errors 
X			that came from the vendor's supplied sendmail.cf
X			file. But in a few minutes time, you should have a 
X			working, and error free, ease version of your 
X			sendmail.cf file.
X
X	In other words, you can start using ease as a high level
Xlangauge and feel confident that you won't break anything.
X	
X
XCurrent status of Ease 3.0
X	It will handle 100% of the standard Ultrix, SunOS, HP, and Berkeley
X	versions of sendmail (I hope). It handles 99% of the IDA
X	enhancement package. See the TODO file for problems.
X
X	I don't plan to do any major work maintaining this package,
Xbut I will gladly accept bug fixes and enhancements.
X
XNew features of the Ease grammar at a glance:
X
XAdded asm("") command. This can be used to insert something strange into
X	the sendmail file. Or something Ease or cfc is too stupid to
X	translate properly. This is the work-around for the new/fancy
X	stuff.
X
XExample:
X	asm("Dq$?x$!x <$g>$|$g$.");
X
XAdded eval()	[$&]
X
XSunOS 4.0 support:
X	Added m_domain
X	Added o_maxempty
X	Added o_maxhops	
X	Added o_nfs	
X	Added o_aliasfile
X	Added ypmap()	[${   $} on RHS]
X
X	Added default definitions of
X		any_in_etc_hosts
X		any_in_mydomainname
X		any_in_myhostname
X
XUltrix 3.0 support:
X	Added f_mail11
X	Added ypalias()  [${ on LHS]
X	Added yppasswd() [$" on LHS]
X
XHP/UX support:
X	added o_nameserver	OI
X	added program()		$<
X
XIDA support:
X	Added f_relativize
X	Added m_uucpname
X	Added o_envelope
X	Added f_bsmtp
X	Support for Header/Envelope re-write rulesets (S=20/21)
X	alias()			$(@	in RHS
X	quote()			$!	in headers
X
X	resolved():
X	# 	if (resolved( one_or_more ))	/* found one, return it */
X	# 		resolve (mailer ($1));
X	R$#$+	$#$1
X
X	nested rulesets:
X	# 	if ( one_or_more @. one_or_more ? one_or_more )	/* relativize & return */
X	# 		resolve (mailer (TCP),
X	# 				host ($3 ),
X	# 				user (retry (RULESET_28($1@.$2))));
X	R$+@.$+?$+	$#TCP$@$3$:$>28 $1@.$2
X				user (retry (RULESET_28($1@.$2))));
X
X	canon with default value:
X	# 	if ( one_or_more @ exactly_one )	/* host: try name server */
X	# 		return ( $1@ canon ( $2 default (  $2."UUCP ")));
X	R$+@$-	$@$1@$[$2$:$2.UUCP $]
X
X
XNot everything in IDA is supported. (Remember to use the asm() command!)
X
X----------------
XGeneral Improvements to the Ease Program:
X	Improved reporting of syntax errors
X	Built in use of /lib/cpp
X		if et is given a CPP flag, it will call it.
X	If a macro is a single upper case letter, and has not been defined
X	the letter assigned to it will be the same as the macro name.
X	This allows the original input file to be compared to the ease
X	output.
X
X	There have been some substantial changes to the grammar handling.
X	Several improvements have been made to the error reporting.
X	In addition, ease supports the -d flag, which is used to debug
X	the parser.  (See the makefile if you are interested in this.)
X
X	Several bugs were fixed, including a lot of problems with the ifset()
X	construct. It's still not perfect. See the manual page for cfc(local)
X
X----------------------------
XChanges to CFC (Sendmail.cf to ease translator):
X
X	Added new flags to cfc:
X	-s => SunOS
X	-i => IDA sendmail
X	-d => Ultrix
X	-C [..] => add predefined classes 
X		e.g. -C ADG => added classes A, B, and G
X
XSee the file CONVERTING on tips to convert your sendmail file into ease.
XI have included some scritps that can compare the original sendmail
Xfile to the output of ease. If the rules are identical, then you can
Xfeel comfortable using ease instead of raw cf.
X
X
X--------------
XI have also included the document TESTING, along with some
Xshellscripts that I use to perform regression testing of sendmail.
XWhen I make a major change to my sendmail rules, I run a series of
Xaddresses through sendmail and look at the differences. This way I can
Xcheck for address rewrite errors before I install a new version.
X
XI have also include a document called INTRO, that gives a simple
Xintroduction to sendmail. You may want to look at the file
X	debug/Makefile
Xas this gives you an example how I do it.
X
XThis package also includes two more goodies:
X
X	build-new-aliases - this is a shell script I use to 
X		kill sendmail, rebuild the aliases, and restart
X		sendmail. The problem is sometimes a kill -15 won't
X		immediately stop sendmail from running. This gives
X		the daemons a change to clean up first.
X
XAlso - see the directory test. This includes a shell script to test
Xsendmail files, written by Simon Kenyon. You have two ways to debug
Xsendmail files now!
X
X============================================================================
X
XIf you find these programs useful, or if you have suggestions or changes,
Xplease drop me a line. I would really appreciate any patches to this
Xpackage, as I don't plan any major upgrade to support all of the IDA
Xextensions. I will merge any patches and release new versions, as they
Xare sent to me. 
X
X	Bruce Barnett
X	General Electric
X	Corporate Research and Development
X	P. O. Box 8, 1 River Road
X	Schenectady, NY 12301
X
X	barnett@crdgw1.ge.com
X
X
END_OF_README
if test 7378 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
chmod +x README
# end of overwriting check
fi
if test -f TESTING -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"TESTING\"
else
echo shar: Extracting \"TESTING\" \(2010 characters\)
sed "s/^X//" >TESTING <<'END_OF_TESTING'
X	Testing Sendmail Configuration files
X
XI have written some shell scripts called "showhow" and "showwhere"
Xthat can be used to test your sendmail configuration file.
X
XYou create an input file with a set of addresses to test.  You run the
Xscript and it generates an output file, showing the results of each
Xaddress. When I make a major change to a sendmail file, I run the test
Xsuite on it, comparing the results with the last time I tested the
Xaddress. I can use this to see in any of the 400 addresses in my test
Xsuite will behave differently with the new configuration file. My
Xaddresses won't help you, so you have to be creative and add your own.
XHere are some guidelines.
X
XThe format or the input file debug.in is:
X		rulesets	address
X	or
X		rulesets		address comment
X
XUse the second if ruleset does not start with a '0'. I'll explain this later.
X
X	Example:
X
X		0	user@some.do.main
X		0	site!user%site2@site3.com
X		22,4	user@localsite	Sender_via_UUCP
X
Xwhere 22 is a mailer rewrite ruleset for a mailer (i.e. UUCP).
X
XRuleset 0 must be avoided when testing the re-write rules for
Xmailers because ruleset 0 outputs a triple (user, host, mailer), 
Xand only one part (user) passed to the mailers.
X
XThe makefile generates a file in tbl(1) format that 
Xlists the following:
X
X	ruleset		address	  mailer hostname user
X
XShowing the resolved triplet for each address
X
XI think the scripts I have will work on IDA, SunOS 4.0, and Ultrix 3.0
Xsendmail executables. The problem is that older sendmails output debug
Xinfo using ^V, etc. instead of $#.  The script is set up to work with
XUltrix 3.0.  The sendmail with SunOS used a different set of
Xcharacters to indicate the results of a rule (^W instead of ^V).
X
XI have set up a makefile in the debug directory that you can use
X	
X	make	 - tests your sendmail file against a known good file
X		good.out. Once you have a working set of rules, copy
X		debug.out to good.out
X
X	make report 	will print a table of all of the addresses				resolved to the address, mailer, and hostname
X
END_OF_TESTING
if test 2010 -ne `wc -c <TESTING`; then
    echo shar: \"TESTING\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f TODO -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"TODO\"
else
echo shar: Extracting \"TODO\" \(670 characters\)
sed "s/^X//" >TODO <<'END_OF_TODO'
XThings to do for Ease 3.?
X	Support More IDA extensions
X		dbm()			$(x	in RHS
X		Keyed databases		OKP/usr/lib/aliases
X		Ignore case when checking for mailer names existance
X			(local vs. LOCAL)
X
X	Eliminate the concat() construct.
X
X	check for if (exactly_one) next($2); type error.
X	check for matching < and > in rulesets
X	Check for mailers "local" and "prog" 
X
XCFC improvements
X	Make it a real two-pass parser. This way, it can
X	properly specify the rulesets, macros, and classes it
X	needs.
X
XError Detections
X	Eliminate syntax errors that just report "syntax error"	
X
X--
XBruce G. Barnett        <barnett@crdgw1.ge.com>  a.k.a.
X<barnett@[192.35.44.4]>  uunet!crdgw1!barnett
END_OF_TODO
if test 670 -ne `wc -c <TODO`; then
    echo shar: \"TODO\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f cfc/Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"cfc/Makefile\"
else
echo shar: Extracting \"cfc/Makefile\" \(934 characters\)
sed "s/^X//" >cfc/Makefile <<'END_OF_cfc/Makefile'
XCC	      =	cc
XCFLAGS	      = -g 
XBINDIR		= ../bin
XEXTHDRS	      = /usr/include/ctype.h \
X		/usr/include/stdio.h
XHDRS	      =
XLDFLAGS	      =
XLIBS	      =
XLINKER	      = $(CC)
XMAKEFILE      = Makefile
XOBJS	      = cfc.o
XPRINT	      = pr
XPROGRAM	      = cfc
XSRCS	      = cfc.c
X#INSTALL	      = install -s
XINSTALL	      = cp
Xall:		$(PROGRAM)
X
X$(PROGRAM):     $(OBJS) $(LIBS)
X		@echo -n "Loading $(PROGRAM) ... "
X		@$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
X		@echo "done"
X
Xlint:
X		lint cfc.c
Xclean:;		@rm -f $(OBJS) $(PROGRAM) core
X
Xdepend:;	@mkmf -f $(MAKEFILE) "CFLAGS=$(CFLAGS)" PROGRAM=$(PROGRAM) BINDIR=$(BINDIR)
X
Xindex:;		@ctags -wx $(HDRS) $(SRCS)
X
Xinstall:	$(PROGRAM)
X		@echo Installing $(PROGRAM) in $(BINDIR)
X		${INSTALL} $(PROGRAM) $(BINDIR)
X
Xprint:;		@$(PRINT) $(HDRS) $(SRCS)
X
Xprogram:        $(PROGRAM)
X
Xtags:           $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS)
X
X###
Xcfc.o: /usr/include/stdio.h /usr/include/ctype.h
END_OF_cfc/Makefile
if test 934 -ne `wc -c <cfc/Makefile`; then
    echo shar: \"cfc/Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f debug/Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"debug/Makefile\"
else
echo shar: Extracting \"debug/Makefile\" \(988 characters\)
sed "s/^X//" >debug/Makefile <<'END_OF_debug/Makefile'
X# makefile for doing regression tests on sendmail files
XBINDIR=../bin
X
Xall: debug
Xdebug:	good.out debug.out sendmail.cf
X	diff debug.out good.out 
X
Xsendmail.ease: ../sendmail.ease
X	@echo getting your ease file from the top directory
X	cp ../sendmail.ease .
Xsendmail.cf:	sendmail.ease
X	${BINDIR}/et -C sendmail.ease >sendmail.cf
Xdebug.out:	debug.in sendmail.cf
X	showwhere < debug.in	>debug.out
Xdebug.tbl:	debug.out
X	echo ".TS"	>debug.tbl
X	echo "l l l l l"	>>debug.tbl
X	echo "l l l l l." >>debug.tbl
X	echo "Ruleset	Input	Mailer	hostname	User" >>debug.tbl
X	cat debug.out >>debug.tbl
X	echo ".TE" >>debug.tbl
Xreport:	debug.tbl
X	tbl debug.tbl | ptroff
X	
Xgood.out: 
X	@ echo you have to create this yourself by typing
X	@ echo "	cp debug.out good.out"
X	@ echo do this once you feel your sendmail test suite
X	@ echo has results that you feel are correct
X	@ echo 
X	@ echo do this everytime you feel you want to update
X	@ echo your test suite
X	@ cp good.out /dev/null
X
X
Xclean:
X	rm debug.out debug.tbl 
END_OF_debug/Makefile
if test 988 -ne `wc -c <debug/Makefile`; then
    echo shar: \"debug/Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f debug/debug.in -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"debug/debug.in\"
else
echo shar: Extracting \"debug/debug.in\" \(396 characters\)
sed "s/^X//" >debug/debug.in <<'END_OF_debug/debug.in'
X0	user
X0	user@localhost
X0	user%localhost@localhost
X0	barnett@crdgw1.ge.com
X0	crdgw1.uucp!barnett
X0	barnett@crdgw1.uucp
X0       user@some.do.main
X0       site!user%site2@site3.com
X0	site1!site2!site3!user
X0	site1!site2!site3!user@localhost
X0	site1!site2!site3!user@machine.edu
X0	site1!crd.ge.com!barnett
X0	site1!crd.ge.com!barnett@crd.ge.com
X0	user@bogus
X22,4    user@crdgw1.UUCP  Sender_via_UUCP
END_OF_debug/debug.in
if test 396 -ne `wc -c <debug/debug.in`; then
    echo shar: \"debug/debug.in\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f debug/showhow -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"debug/showhow\"
else
echo shar: Extracting \"debug/showhow\" \(1262 characters\)
sed "s/^X//" >debug/showhow <<'END_OF_debug/showhow'
X#!/bin/sh  
X# written by Bruce Barnett <barnett@crdgw1.ge.com>
X# Inspired from
X#	Dan Long
X# 	CSNET Technical Staff
X# 	long@sh.cs.net
X#
X#	This script converts the sendmail debug output into something 
X#	easier to parse.
X#	Some sendmail programs output ^V, ^W, ^X
X#	This script converts ^V to $#, ^X to $:, and ^W to $@
X#	This matches Ultrix 3.1. SunOS 3.5 is different
X#	Other sendmail versions output in the $:, $@, $# format
X#	So this script just ignores those characters, 
X#	as they are already correct.
X#
X#define your sendmail program compiled for debug
XSENDMAIL=/usr/lib/sendmail
Xif [ $# -lt 2 ]
Xthen
X	echo 'Usage: showhow rulesets address [mailer]' 1>&2;exit 2;
Xfi
X#FLAGS='-d21.12'
XFLAGS=''
Xcase $1 in
X0*)
X	echo "$1 $2" | ${SENDMAIL} -bt -Csendmail.cf $FLAGS  |\
X	egrep '\$\#|\^V' |\
X	tail -1 |tr -d '"' |\
X	sed \
X		-e 's/\^V/$#/' \
X		-e 's/\^X/$:/' \
X		-e 's/\^W/$@/' \
X		-e 's/^[a-zA-Z ][:a-zA-Z0-9 ]*//' \
X		-e 's/local \$:/local $@ local $:/' \
X		-e 's/\$# //' \
X		-e 's/ \$@ /	/' \
X		-e 's/ \$: /	/' \
X		-e 's/ //g' 
X	;;
X*)	# else a rewrite rule for a mailer
X	if [ X$3 = X ]
X	then
X		mailer='-';
X	else
X		mailer=$3;
X	fi
X	echo "$1 $2" | ${SENDMAIL} -bt -Csendmail.cf $FLAGS |\
X	egrep "^rewrite:"|tail -1 |tr -d '" '|\
X	sed "s/^.*:/$mailer	/"
X	;;
Xesac
X
X
X
X
END_OF_debug/showhow
if test 1262 -ne `wc -c <debug/showhow`; then
    echo shar: \"debug/showhow\" unpacked with wrong size!
fi
chmod +x debug/showhow
# end of overwriting check
fi
if test -f debug/showwhere -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"debug/showwhere\"
else
echo shar: Extracting \"debug/showwhere\" \(207 characters\)
sed "s/^X//" >debug/showwhere <<'END_OF_debug/showwhere'
X#!/bin/sh 
X# Written By Bruce Barnett
Xwhile :
Xdo
X	read username
X#	echo i just read in  $username
X	if [ $? -eq 0 ]
X	then
X		x="`./showhow $username`"
X			echo $username  $x | tr ' ' '	'
X	else
X		exit 0
X	fi
Xdone
END_OF_debug/showwhere
if test 207 -ne `wc -c <debug/showwhere`; then
    echo shar: \"debug/showwhere\" unpacked with wrong size!
fi
chmod +x debug/showwhere
# end of overwriting check
fi
if test -f doc/Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"doc/Makefile\"
else
echo shar: Extracting \"doc/Makefile\" \(869 characters\)
sed "s/^X//" >doc/Makefile <<'END_OF_doc/Makefile'
X#! /bin/make -f
X#
X# $Header: Makefile,v 1.2 87/12/23 11:30:27 root Locked $
X#
X# $Log:	Makefile,v $
X# Revision 1.2  87/12/23  11:30:27  root
X# Added new appendix. ADR.
X# 
X# Revision 1.1  87/12/23  10:40:45  root
X# Initial revision
X# 
X#
X#
X#	Makefile for Ease document.
X#
X#	James S. Schoner
X#	Purdue University Computing Center
X#
X
XEXT=l
XMANDEST = /usr/man/man${EXT}
XROFF=ptroff
X
Xall:	cover mainbody apen1 apen2 apen3 apen4
X	
Xcover: FRC
X	${ROFF} -ms cover
X
Xmainbody:
X	tbl ease.paper | ${ROFF} -ms
X
Xapen1:
X	tbl ap1 | ${ROFF} -ms
X
Xapen2:
X	tbl ap2 | ${ROFF} -ms
X
Xapen3:
X	tbl ap3 | ${ROFF} -ms
X
Xapen4:
X	tbl ap4 | ${ROFF} -ms
X
X
Xinstall:
X	install -c ease.man $(MANDEST)/ease.${EXT}
X	install -c et.man $(MANDEST)/et.${EXT}
X	install -c cfc.man $(MANDEST)/cdc.${EXT}
X
Xprintman: ease.man et.man cfc.man
X	${ROFF} -man ease.man
X	${ROFF} -man et.man
X	${ROFF} -man cfc.man
X
XFRC:
X
Xclean:
END_OF_doc/Makefile
if test 869 -ne `wc -c <doc/Makefile`; then
    echo shar: \"doc/Makefile\" unpacked with wrong size!
fi
chmod +x doc/Makefile
# end of overwriting check
fi
if test -f doc/ap1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"doc/ap1\"
else
echo shar: Extracting \"doc/ap1\" \(1490 characters\)
sed "s/^X//" >doc/ap1 <<'END_OF_doc/ap1'
X.DS C
X\s+5\fBAppendix A\fR
X
X
X\fBPre-Declared Macros\fR\s-5
X.DE
X.sp 5
X.TS 
Xcenter box;
Xc|c|c
Xl|l|l.
X\fBEase\fR Macro	Raw Equivalent	Meaning*
X=
X\fIm_odate\fR	a	The origination date in Arpanet format
X\fIm_adate\fR	b	The current date in Arpanet format
X\fIm_hops\fR	c	The hop count
X\fIm_udate\fR	d	The date in UNIX (ctime) format
X\fIm_smtp\fR	e	The SMTP entry message
X\fIm_saddr\fR	f	The sender (from) address
X\fIm_sreladdr\fR	g	The sender address relative to the recipient
X\fIm_rhost\fR	h	The recipient host
X\fIm_qid\fR	i	The queue id
X\fIm_oname\fR	j	The official domain name for this site
X\fIm_ufrom\fR	l	The format of the UNIX from line
X\fIm_daemon\fR	n	The name of the daemon (for error messages)
X\fIm_addrops\fR	o	The set of "operators" in addresses
X\fIm_pid\fR	p	Sendmail's pid
X\fIm_defaddr\fR	q	The default format of sender address
X\fIm_protocol\fR	r	Protocol used
X\fIm_shostname\fR	s	Sender's host name
X\fIm_ctime\fR	t	A numeric representation of the current time
X\fIm_ruser\fR	u	The recipient user
X\fIm_version\fR	v	The version number of sendmail
X\fIm_sitename\fR	w	The hostname of this site
X\fIm_sname\fR	x	The full name of the sender
X\fIm_stty\fR	y	The id of the sender's tty
X\fIm_rhdir\fR	z	The home directory of the recipient
X\fIm_domain\fR	m	The domain of the host (SunOS)
X\fIm_uucpname\fR	k	The official UUCP name (IDA)
X.TE
X.FS
X*  Taken from pages 19 and 20 of the Sendmail Installation and Operation Guide
X(SMM:7 in the 4.3 BSD UNIX System Manager's Manual), by Eric Allman.
X.FE
END_OF_doc/ap1
if test 1490 -ne `wc -c <doc/ap1`; then
    echo shar: \"doc/ap1\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f doc/ap2 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"doc/ap2\"
else
echo shar: Extracting \"doc/ap2\" \(2944 characters\)
sed "s/^X//" >doc/ap2 <<'END_OF_doc/ap2'
X...
X... $Header: /home/kreskin/u0/barnett/Src/ease/doc/RCS/ap2,v 2.1 1990/01/30 12:57:42 jeff Exp barnett $
X... 
X... $Log: ap2,v $
X... Revision 2.1  1990/01/30  12:57:42  jeff
X... Made changes corresponding to Ease release 2.1Alpha.
X... se.
X...
X... Version 2.0  90/01/30  12:50:12  jeff
X... Baseline version, corresponding to netwide release 2.0.
X... 
X... Revision 1.5  88/06/15  10:11:53  root
X... Added undocumented/unimplemented options. Fixed so it would troff well. ADR.
X... 
X... Revision 1.4  88/01/21  17:10:33  root
X... Added new option; change location of Sendmail doc to 4.3 SMM. ADR.
X... 
X... Revision 1.3  87/09/04  14:55:36  root
X... Fixed typo in new options. ADR.
X... 
X... Revision 1.2  87/03/03  17:05:41  root
X... Changes for 4.3 version of sendmail. ADR.
X... 
X... Revision 1.1  87/03/03  17:01:24  root
X... Initial revision
X... 
X...
X.DS C
X\s+5\fBAppendix B\fR
X
X\fBSendmail Options\fR\s-5
X.DE
X.PP
XFor a complete description of Sendmail's options and their values, refer to 
XAppendix B of the Sendmail Installation and Operation Guide (SMM:7 in the
X4.3 BSD UNIX System Manager's Manual), by Eric Allman.
X.sp
X.TS 
Xcenter box;
Xc|c
Xl|l.
XSendmail Option (\fBEase\fR)	Sendmail Option (Raw)	Special Values
X=
X\fIo_alias\fR	A	
X\fIo_ewait\fR	a	
X\fIo_bsub\fR	B	
X\fIo_checkpoint\fR	C *
X\fIo_qwait\fR	c	
X\fIo_delivery\fR  (special values below)	d  (special values below)
X     \fId_interactive\fR	     i 
X     \fId_background\fR	    b 
X     \fId_queue\fR	    q
X\fIo_rebuild\fR	D
X\fIo_handling\fR  (special values below)	e  (special values below)
X     \fIh_print\fR	     p 
X     \fIh_exit\fR	     q
X     \fIh_mail\fR	     m
X     \fIh_write\fR	     w
X     \fIh_mailz\fR	     e
X\fIo_tmode\fR	F	
X\fIo_usave\fR	f	
X\fIo_gid\fR	g	
X\fIo_fsmtp\fR	H	
X\fIo_skipd\fR	i	
X\fIo_nameserver\fR	I (HP/UX)
X\fIo_slog\fR	L	
X\fIo_rsend\fR	m	
X\fIo_dnet\fR	N (Ultrix)
X\fIo_validate\fR	n \(dg
X\fIo_hformat\fR	o	
X\fIo_pmaster\fR	P \(bu
X\fIo_qdir\fR	Q	
X\fIo_qfactor\fR	q
X\fIo_tread\fR	r	
X\fIo_flog\fR	S	
X\fIo_safe\fR	s	
X\fIo_qtimeout\fR	T	
X\fIo_timezone\fR	t	
X\fIo_dmuid\fR	u	
X\fIo_verbose\fR	v	
X\fIo_wizpass\fR	W	
X\fIo_loadq\fR	x	
X\fIo_loadnc\fR	X	
X\fIo_recipfactor\fR	y
X\fIo_newproc\fR	Y
X\fIo_prifactor\fR	z
X\fIo_waitfactor\fR	Z
X\fIo_maxempty\fR	b (SunOS)
X\fIo_maxhops\fR	h (SunOS)
X\fIo_remote\fR	R (SunOS)
X\fIo_aliasfile\fR	Y (SunOS)
X\fIo_envelope\fR	/ (IDA)
X
X
X
X.TE
X.PP
X* This option is undocumented and unimplemented in 4.3BSD. It is
Xfor checkpointing mail after \fIN\fR failed connections. \fBEase\fR supports
Xit in anticipation of future developments.
XUltrix uses this flag in Ultrix 3.0. I assume it means the same thing.
X.PP
X\(dg This option is undocumented in 4.3BSD. It specifies that the right hand
Xside of an alias definition should be checked for validity as an address
Xwhen the alias database is being rebuilt.
X.PP
X\(bu This option is undocumented in 4.3BSD.
XIt specifies the address of a Postmaster who should be carbon-copied on
Xall returned bad mail.
END_OF_doc/ap2
if test 2944 -ne `wc -c <doc/ap2`; then
    echo shar: \"doc/ap2\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f doc/ap3 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"doc/ap3\"
else
echo shar: Extracting \"doc/ap3\" \(1721 characters\)
sed "s/^X//" >doc/ap3 <<'END_OF_doc/ap3'
X...
X... $Header: /isis/usr2/share/src/local/tc/ease/doc/RCS/ap3,v 2.1 90/01/30 12:57:45 jeff Exp $
X... 
X... $Log:	/isis/usr2/share/src/local/tc/ease/doc/RCS/ap3,v $
X... Version 2.1  90/01/30  12:57:45  jeff
X... Made changes corresponding to Ease release 2.1Alpha.
X... se.
X... 
X... Version 2.0  90/01/30  12:50:38  jeff
X... Baseline version, corresponding to netwide release 2.0.
X... 
X... Revision 1.4  88/06/15  10:12:22  root
X... Added undocumented and unimplemented mailer flag.
X... 
X... Revision 1.3  88/01/21  17:10:57  root
X... Changed location of Sendmail doc to 4.3 SMM. ADR.
X... 
X... Revision 1.2  87/03/03  17:05:53  root
X... Changes for 4.3 version of sendmail. ADR.
X... 
X... Revision 1.1  87/03/03  17:04:52  root
X... Initial revision
X... 
X...
X.DS C
X\s+5\fBAppendix C\fR
X
X
X\fBMailer Flags\fR\s-5
X.DE
X.sp 5
X.PP
XFor a complete description of mailer flags, refer to 
XAppendix C of the Sendmail Installation and Operation Guide (SMM:7 in the
X4.3 BSD UNIX System Manager's Manual), by Eric Allman.
X.sp 5
X.TS 
Xcenter box;
Xc|c
Xl|l.
XMailer Flag (\fBEase\fR)	Mailer Flag (Raw)
X=
X\fIf_ffrom\fR	f
X\fIf_rfrom\fR	r
X\fIf_noreset\fR	S
X\fIf_noufrom\fR	n
X\fIf_locm\fR	l
X\fIf_strip\fR	s 
X\fIf_mult\fR	m
X\fIf_from\fR	F
X\fIf_date\fR	D
X\fIf_mesg\fR	M
X\fIf_full\fR	x	
X\fIf_return\fR	P	
X\fIf_upperu\fR	u	
X\fIf_upperh\fR	h	
X\fIf_arpa\fR	A	
X\fIf_ufrom\fR	U	
X\fIf_expensive\fR	e	
X\fIf_dot\fR	X	
X\fIf_llimit\fR	L	
X\fIf_retsmtp\fR	p	
X\fIf_smtp\fR	I	
X\fIf_addrw\fR	C	
X\fIf_escape\fR	E
X\fIf_rport\fR	R *
X\fIf_mail11\fR	H	Ultrix 3.0
X\fIf_relativize\fR	V	IDA
X.TE
X.FS
X*  This flag specifies the use of a reserved TCP port. In 4.3BSD it is
Xboth undocumented and unimplemented. \fBEase\fR supports it in anticipation
Xof future developments.
X.FE
END_OF_doc/ap3
if test 1721 -ne `wc -c <doc/ap3`; then
    echo shar: \"doc/ap3\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f doc/ap4 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"doc/ap4\"
else
echo shar: Extracting \"doc/ap4\" \(273 characters\)
sed "s/^X//" >doc/ap4 <<'END_OF_doc/ap4'
X.DS C
X\s+5\fBAppendix D\fR
X
X
X\fBPre-Defined Classes\fR\s-5
X.DE
X.sp 5
X.TS 
Xcenter box;
Xc|c|c
Xl|l|l.
X\fBEase\fR Class	Raw Equivalent	Meaning
X=
X\fIc_myname\fR	w	The list of names by which this host is known
X\fIc_mydomain\fR	m	The list of names by which this host is known
X.TE
END_OF_doc/ap4
if test 273 -ne `wc -c <doc/ap4`; then
    echo shar: \"doc/ap4\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f doc/cover -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"doc/cover\"
else
echo shar: Extracting \"doc/cover\" \(891 characters\)
sed "s/^X//" >doc/cover <<'END_OF_doc/cover'
X...
X... $Header: /home/kreskin/u0/barnett/Src/Ease/ease/doc/RCS/cover,v 2.0 1990/01/30 12:50:41 jeff Exp barnett $
X...
X... $Log: cover,v $
X... Revision 2.0  1990/01/30  12:50:41  jeff
X... Baseline version, corresponding to netwide release 2.0.
X...
X... Revision 1.2  87/12/23  11:30:36  root
X... Updated list of authors. ADR.
X... 
X... Revision 1.1  87/12/23  10:16:35  root
X... Initial revision
X... 
X...
X.DA
X.sp 15
X.nr PS 14
X.ps 14
X.DS C
X 
X.DE
X.sp 10
X.nr PS 36
X.ps 36
X.DS C
X\fBEase:\fR
X.DE
X.sp 5
X.nr PS 22
X.ps 22
X.DS C
XA Configuration Language
X  
Xfor Sendmail
X.DE
X.sp 8
X.nr PS 14
X.ps 14
X.DS C
Xby
X
X\fIJames S. Schoner\fR
X\fIPurdue University Computing Center\fR
X
XAmended by
X
X\fIJeff P. Stearns\fR
X\fIJohn Fluke Manufacturing Company\fR
X
X\fIArnold D. Robbins\fR
X\fIEmory University Computing Center\fR
X
X\fIBruce G. Barnett\fR
X\fIGeneral Electric\fR
X\fICorporate Research and Development\fR
X.DE
END_OF_doc/cover
if test 891 -ne `wc -c <doc/cover`; then
    echo shar: \"doc/cover\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f doc/ease.man -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"doc/ease.man\"
else
echo shar: Extracting \"doc/ease.man\" \(668 characters\)
sed "s/^X//" >doc/ease.man <<'END_OF_doc/ease.man'
X.\"	@(#)ease.l	(FLUKE) 25-feb-87
X.\"
X.TH EASE LOCAL "Feb 13, 1991"
X.UC 4
X.SH NAME
Xease \- precompiler for sendmail configuration files
X.SH SYNOPSIS
X.B ease
X[
X.B \-D
X\fIname\fP[=\fIvalue\fP] ...
X]
Xfile ...
X.br
X.SH DESCRIPTION
X.I Ease
Xcompiles a high-level language into a form understood by
X.I /usr/lib/sendmail.
XIt is fully documented in the files which reside in the source directory.
X.PP
X.I Ease
Xis actually a shell script which passes the source file through
X.I cpp
Xand thence into the actual ease translator
X.I et.
XOutput is printed to the standard output.
X.SH "SEE ALSO"
Xcpp(1), et(local), sendmail(8), cfc(local)
X.SH BUGS
X.SH BROUGHT TO YOU BY
Xjeff@tc.fluke.COM
END_OF_doc/ease.man
if test 668 -ne `wc -c <doc/ease.man`; then
    echo shar: \"doc/ease.man\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f doc/et.man -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"doc/et.man\"
else
echo shar: Extracting \"doc/et.man\" \(1305 characters\)
sed "s/^X//" >doc/et.man <<'END_OF_doc/et.man'
X.\"	@(#)et.man
X.\"
X.TH ET LOCAL "Feb 13, 1991"
X.UC 4
X.SH NAME
Xet \- translator for sendmail configuration files
X.SH SYNOPSIS
X.B Et
X[
X.B \-d
X]
X[
X.B \-q
X]
X[
X.B \-D
X\fIname\fP[=\fIvalue\fP] ...
X]
X[inputfile [outputfile]]
X.br
X.SH DESCRIPTION
X.I Et
Xcompiles a high-level language into a form understood by
X.I /usr/lib/sendmail.
XIt is fully documented by the documentation provided with the program source.
X.PP
X.I Et
Xoptionally passes the source file through
X.I cpp
Xbefore parsing it.  This allows all the power of
X.I cpp
Xto be applied to the input file.
X.PP
XIf no inputfile is specified, STDIN is used.
XIf no outputfile is specified, STDOUT is used.
XThe distinguished name "-" is synonymous with STDIN or STDOUT, as appropriate.
X.PP
XBy default,
X.I Et
Xpasses input lines along into the output stream as comments.
X.SH OPTIONS
X.IP -d
Xturns on the yydebug flag for the curious or desperate.
X.IP -q
Xturns off the feature which passes input lines along into the output
Xstream as comments.
X.PP
X.I Et
Xaccepts the options of
X.B cpp,
Xand passes them along to the C pre-processor when it is invoked.
X.B N.B 
XIf no such options are specified,
X.B cpp
Xis not invoked.
X.SH "SEE ALSO"
Xcpp(1), ease(local), sendmail(8), cfc(local)
X.SH BUGS
X.SH THIS MANUAL PAGE WRITTEN BY
Xjeff@tc.fluke.com, from inspection of the source code.
END_OF_doc/et.man
if test 1305 -ne `wc -c <doc/et.man`; then
    echo shar: \"doc/et.man\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/ease.sh -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/ease.sh\"
else
echo shar: Extracting \"src/ease.sh\" \(3614 characters\)
sed "s/^X//" >src/ease.sh <<'END_OF_src/ease.sh'
X#! /bin/sh
X#
X#  ease - front end for the ease translator (et).
X#
X#  This sh script simplifies the task of calling "et" with the proper flags.
X#
X#  It also defines a VERSION macro, known to cpp when preprocessing the
X#  input to et.  This allows you to automatically embed the RCS version
X#  number of your config file into the generated sendmail.cf. 
X#
X#  For example, if your ease input file contains the RCS version string
X#	$Revision: 1.6 $
X#  and the lines
X#	define ("Received:",
X#	    "by ${m_oname} (${VERSION})"
X#	    ifset (m_shostname, " from ${m_shostname} ") "for ${m_ruser}"
X#  then your sendmail.cf will define the "Received:" header line so that
X#  it contains the RCS version number of the ease input file.  This version
X#  number will ultimately be stamped into the header of every message which
X#  flows though this sendmail, thus allowing you to see at a glance whether
X#  some problem was due to an out-of-date sendmail.cf.
X#
X#  At our site, the "Received:" header lines thus have the following form:
X#
X#	Received: by isis.tc.fluke.COM (version 2.46)
X#	    from argv.tc.fluke.COM for jeff
X#	    id AA10285; Wed, 21 Feb 90 17:28:43 PST
X#	Received: by argv.tc.fluke.COM (version 2.46)
X#	    for jeff@isis
X#	    id AA06739; Wed, 21 Feb 90 17:28:39 PST
X#
X#  This makes it a little easier to track down problems in networks comprising
X#  dozens or hundreds of machines.
X#
X# $Source: /isis/usr2/share/src/local/tc/ease/src/RCS/ease.sh,v $
X# $Locker:  $
X#
X# $Revision: 1.6 $
X# Check-in $Date: 90/05/07 11:15:04 $
X# $State: Exp $
X#
X# $Author: jeff $
X#
X# $Log:	/isis/usr2/share/src/local/tc/ease/src/RCS/ease.sh,v $
X# Version 1.6  90/05/07  11:15:04  jeff
X# Add support for the "-q" flag added to ease.
X# 
X# Version 1.5  90/02/22  15:51:12  jeff
X# Improved the comments in preparation for netwide release.
X# 
X# Version 1.4  88/11/18  11:24:12  jeff
X# RCS mangled the previous change; try it again.  (It saw something that
X# looked like a keyword to it, so it expanded the token.  Yuck.)
X# 
X# Version 1.3  88/11/18  11:20:52  jeff
X# Change the VERSION macro from the date to the RCS revision of the
X# config.ease file.
X# 
X# Version 1.2  87/04/13  16:56:29  jeff
X# Change argument parsing to accomodate the new -C flag.
X# 
X# Version 1.1  87/04/08  12:20:58  jeff
X# Initial version
X# 
X#
X# @(#)FLUKE source file: $Header: /isis/usr2/share/src/local/tc/ease/src/RCS/ease.sh,v 1.6 90/05/07 11:15:04 jeff Exp $
X
XPATH=/bin:/usr/bin:/usr/ucb:/usr/local export PATH
X
Xecho    "#"
Xecho    "#   Compiled via: $0 $*"
Xecho	"# From directory: `pwd`"
Xecho    "#           Date: `date`"
Xecho    "#"
Xecho    "# This file was produced by the \"ease\" translator."
Xecho    "# You probably shouldn't edit it, since changes will be lost"
Xecho	"# the next time that ease is run.  Instead, edit the source file"
Xecho	"# located in the directory named above."
Xecho    "#"
X
Xcppflags= etflags='-q'
X
Xfor i in ${1+"$@"} ;do
X    case "$1" in
X	'')	break;;
X	-C)	etflags="${etflags-} $1";;
X	-D*)	cppflags="$cppflags $1";;
X	*)	file="$1";;
X    esac
X    shift
Xdone
X
X#
X#  Extract the RCS "Revision" string from the ease input file, and
X#  use it to define the VERSION symbol to cpp.
X#
X#  If you maintain your ease input file with SCCS, the appropriate change
X#  should be simple.
X#
XRev=`fgrep 'Revision:' $file | sed -e 's/^.*Revision:[	 ]*\([^	 ]*\).*/\1/'`
X
X# The sed commands delete empty comment lines and those preprocessor output
X# lines which indicate the linenumber and filename.
X/lib/cpp -DVERSION=\"version\ $Rev\" $cppflags $file |
X    et $etflags |
X    sed -e '/^# *$/d' \
X	-e '/^#[ 	]*[0123456789][0123456789]*[ 	]*".*"[	 ]*$/d'
END_OF_src/ease.sh
if test 3614 -ne `wc -c <src/ease.sh`; then
    echo shar: \"src/ease.sh\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/fixstrings.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/fixstrings.c\"
else
echo shar: Extracting \"src/fixstrings.c\" \(1812 characters\)
sed "s/^X//" >src/fixstrings.c <<'END_OF_src/fixstrings.c'
X/*
X * $Revision: 2.1 $
X * Check-in $Date: 90/01/30 14:25:14 $
X *
X * $Author: jeff $
X *
X * $Log:	/isis/usr2/share/src/local/tc/ease/src/RCS/fixstrings.c,v $
X * Version 2.1  90/01/30  14:25:14  jeff
X * Comment changes only.
X * 
X * Revision 2.0  88/06/15  14:41:19  root
X * Baseline release for net posting. ADR.
X * 
X * Version 1.2  87/02/25  16:55:13  jeff
X * Add RCS header lines.  No code changes.
X * 
X */
X#ifdef FLUKE
X# ifndef LINT
X    static char RCSid[] = "@(#)FLUKE  $Header: /isis/usr2/share/src/local/tc/ease/src/RCS/fixstrings.c,v 2.1 90/01/30 14:25:14 jeff Exp $";
X# endif LINT
X#endif FLUKE
X
X/*  FLUKE jps 16-apr-86 - special hacks for NULL pointers.
X *
X *  The author of ease used a *lot* of NULL pointers.  This isn't much
X *  of a problem on a vax, where NULL pointers look like "".  Not so on a Sun.
X *
X *  We hack around the problem by defining a set of wrappers for the
X *  standard string functions, making it appear as though they accept NULL
X *  pointers.  In the other C files, cpp macros are used to revector the
X *  standard string functions to this file.
X */
X#include <strings.h>
X#define fix(s) ((s) ? (s) : "")
X
Xchar *Xstrcat (s1, s2)
Xchar *s1, *s2; 
X{
X	return (strcat (s1, fix (s2)));
X}
X
Xchar *Xstrncat (s1, s2, n)
Xchar *s1, *s2; 
X{
X	return (strncat (s1, fix (s2), n));
X}
X
XXstrcmp (s1, s2)
Xchar *s1, *s2; 
X{
X	return (strcmp (fix (s1), fix (s2)));
X}
X
XXstrncmp (s1, s2, n)
Xchar *s1, *s2; 
X{
X	return (strncmp (fix (s1), fix (s2), n));
X}
X
Xchar *Xstrcpy (s1, s2)
Xchar *s1, *s2; 
X{
X	return (strcpy (s1, fix (s2)));
X}
X
Xchar *Xstrncpy (s1, s2, n)
Xchar *s1, *s2; 
X{
X	return (strncpy (s1, fix (s2), n));
X}
X
XXstrlen (s)
Xchar *s; 
X{
X	return (strlen (fix (s)));
X}
X
Xchar *Xindex (s, c)
Xchar *s, c; 
X{
X	return (index (fix (s), c));
X}
X
Xchar *Xrindex (s, c)
Xchar *s, c; 
X{
X	return (rindex (fix (s), c));
X}
END_OF_src/fixstrings.c
if test 1812 -ne `wc -c <src/fixstrings.c`; then
    echo shar: \"src/fixstrings.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/fixstrings.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/fixstrings.h\"
else
echo shar: Extracting \"src/fixstrings.h\" \(712 characters\)
sed "s/^X//" >src/fixstrings.h <<'END_OF_src/fixstrings.h'
X/*
X * $Revision: 2.1 $
X * Check-in $Date: 90/01/30 14:28:33 $
X * $State: Exp $
X *
X * $Author: jeff $
X *
X * $Log:	/isis/usr2/share/src/local/tc/ease/src/RCS/fixstrings.h,v $
X * Version 2.1  90/01/30  14:28:33  jeff
X * Bring RCS version number in line with netwide version 2.1.  No code
X * changes.
X * 
X * Revision 2.0  88/06/15  14:41:57  root
X * Baseline release for net posting. ADR.
X */
X
X/* FLUKE jps 16-apr-86 - revector the string routines to custom-coded ones
X *  which handle NULL pointers.
X */
X#define strcat	Xstrcat
X#define strncat	Xstrncat
X#define strcmp	Xstrcmp
X#define strncmp	Xstrncmp
X#define strcpy	Xstrcpy
X#define strncpy	Xstrncpy
X#define strlen	Xstrlen
X#define index	Xindex
X#define rindex	Xrindex
END_OF_src/fixstrings.h
if test 712 -ne `wc -c <src/fixstrings.h`; then
    echo shar: \"src/fixstrings.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/symtab.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/symtab.h\"
else
echo shar: Extracting \"src/symtab.h\" \(2671 characters\)
sed "s/^X//" >src/symtab.h <<'END_OF_src/symtab.h'
X/*
X *	symtab.h    -- Definitions related to the "et" symbol table. 
X *
X *	author	    -- James S. Schoner, Purdue University Computing Center,
X *					 West Lafayette, Indiana  47907
X *
X *	date	    -- July 1, 1985
X *
X *	Copyright (c) 1985 by Purdue Research Foundation
X *
X *	All rights reserved.
X *
X * $Log: symtab.h,v $
X * Revision 3.0  1991/02/22  18:50:27  barnett
X * Added support for HP/UX and IDA sendmail.
X *
X * Revision 2.1  1990/01/30  15:58:35  jeff
X * Added SunOS/Ultrix/IDA extensions  Jan 24, 1989 Bruce Barnett
X *
X * Revision 2.0  88/06/15  14:43:08  root
X * Baseline release for net posting. ADR.
X */
X
X#define TRUE      1
X#define FALSE     0
X#define SST       101		/* size of hash table (symbol table) 	     */
X#define RSNMAX    5		/* size of a ruleset number character buffer */
X#define VALRSNMAX 9999		/* max value of ruleset number		     */
X
X
X/* identifier types */
X#define ID_UNTYPED 0
X#define ID_MACRO   01
X#define ID_CLASS   02
X#define ID_RULESET 04
X#define ID_FIELD   010
X#define ID_PREC	   020
X#define ID_MAILER  040
X
X/* identifier type macros */
X#define ISTYPED(x) (x|ID_UNTYPED)
X#define ISMACRO(x) (x&ID_MACRO)
X#define ISCLASS(x) (x&ID_CLASS)
X#define ISRULESET(x) (x&ID_RULESET)
X#define ISFIELD(x) (x&ID_FIELD)
X#define ISPREC(x) (x&ID_PREC)
X#define ISMAILER(x) (x&ID_MAILER)
X
X/* block definition types */
Xenum bdefs {def_macro, def_class, def_option, def_prec, def_trusted, 
X	    def_header, def_mailer, def_ruleset};
X
X/* option types */
Xenum opts {opt_A, opt_a, opt_B, opt_C, opt_c, opt_D, opt_d, opt_e, opt_F,
X	   opt_f, opt_g, opt_H, opt_i, opt_L, opt_m, opt_N, opt_n, opt_o,
X	   opt_P, opt_Q, opt_q, opt_r, opt_S, opt_s, opt_T, opt_t, opt_u,
X	   opt_v, opt_W, opt_x, opt_X, opt_Y, opt_y, opt_Z, opt_z,
X	   opt_b, opt_R, opt_SL, opt_h, opt_I,
X	   d_opt_i, d_opt_b, d_opt_q,
X	   e_opt_p, e_opt_e, e_opt_m, e_opt_w, e_opt_z};
X
X/* flag types */
Xenum flgs {flg_f, flg_r, flg_S, flg_n, flg_l, flg_s, flg_m, flg_F, flg_D,
X	   flg_M, flg_x, flg_P, flg_u, flg_h, flg_A, flg_U, flg_e, flg_X,
X	   flg_H, flg_V, flg_B,
X	   flg_L, flg_p, flg_I, flg_C, flg_E, flg_R};
X
X/* mailer parameters */
Xenum mats {mat_path, mat_flags, mat_sender, mat_recipient, mat_argv, 
X	   mat_eol, mat_maxsize};
X
Xstruct he {	/* hash entry structure for symbol table node 	*/
X	unsigned   idtype;	/* identifier type 		*/
X	unsigned   idd;	  	/* identifier definition flag 	*/
X	char      *psb;		/* identifier string buffer 	*/
X	union {
X		char rsn[RSNMAX]; 	/* ruleset number   	      */
X		int prec;	  	/* precedence value 	      */
X		char idc;		/* one char id representation */
X		char *fstring;    	/* field string     	      */
X	} idval;
X	struct he *phe;		/* next hash entry 		*/
X};
END_OF_src/symtab.h
if test 2671 -ne `wc -c <src/symtab.h`; then
    echo shar: \"src/symtab.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f test/README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"test/README\"
else
echo shar: Extracting \"test/README\" \(1583 characters\)
sed "s/^X//" >test/README <<'END_OF_test/README'
XThis is my little package to work out what is going on inside sendmail.
XIt consists of a sendmail configuration file and a shell script. The sendmail
Xconfiguration file was created with ease (see previous messages in net.mail
Xabout ease - i think it's due in mod.sources). The ease source is included.
X
XWhat this is all about:
X
X	I was having difficulty creating a sendmail.cf. So, I wrote a
Xsendmail.cf whose sole function was to tag an address as it went through the
Xruleset. I coupled this with a little shell script, called args, which snarfs
Xit's arguments (and stdin) and write them to a log file (/tmp/log is what I
Xhave used - you can alter it to taste, bearing in mind that it will probably
Xhave to suid to write to your directory :-()
X
XWhat do you do:
X
X	Unpack all this junk. You should have test.mc, test.cf, args and
XREADME. Put args in your search path. Create a dummy mail message. It helps
Xto know how you mailer calls sendmail. I used args to find out. (I briefly
Xreplaced /usr/lib/sendmail with args and sent some mail). Call sendmail with
Xthe dummy mail item as stdin. ie:
X
X	/usr/lib/sendmail -Ctest.cf foobar <<eof
X	To: foobar
X	Subject: test
X
X	test mail
X	eof
X
Xthen have a look at what is in /tmp/log
X
XThats all there is folks. I also use args with real configuration files, so
Xthat I can test them without disrupting the mail service through my machine.
XIf you have any problems with this stuff, mail me and I'll try and help.
X
X	Simon Kenyon
X	The National Software Centre,
X	28 Enterprise Centre,
X	Pearse Street,
X	Dublin 2
X	IRELAND
X	+353 1 716255
X	simon@einode.UUCP
END_OF_test/README
if test 1583 -ne `wc -c <test/README`; then
    echo shar: \"test/README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f test/args -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"test/args\"
else
echo shar: Extracting \"test/args\" \(507 characters\)
sed "s/^X//" >test/args <<'END_OF_test/args'
X#!/bin/sh
X#
X# little shell script to snarf it's arguments and stdin and put them
X# in a log file. this way you can see what is being given to the various
X# mailers and also what is being done to addresses.
X# it's a real hack, but it works for me
X#
X#			Simon Kenyon, The NSC, Dublin, IRELAND. 24th Nov 86
X#
Xecho '-------------'`date`'------------------' >>/tmp/log
Xecho -n "Command line: " >>/tmp/log
Xfor i in "$@"
Xdo
Xecho -n "$i " >>/tmp/log
Xdone
Xecho >>/tmp/log
Xwhile read foo
Xdo
Xecho $foo >>/tmp/log
Xdone
END_OF_test/args
if test 507 -ne `wc -c <test/args`; then
    echo shar: \"test/args\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f test/test.addresses -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"test/test.addresses\"
else
echo shar: Extracting \"test/test.addresses\" \(210 characters\)
sed "s/^X//" >test/test.addresses <<'END_OF_test/test.addresses'
X#! /bin/sh
X
X/usr/lib/sendmail -bt -Csun.cf	\
X| awk				\
X    '/^> >/ {printf "\n\n"};
X	    {print}
X    '				\
X| sed 				\
X    -e 's/ \$# / mailer = /'	\
X    -e 's/ \$: / user = /'	\
X    -e 's/ \$@ / host = /'	
X
END_OF_test/test.addresses
if test 210 -ne `wc -c <test/test.addresses`; then
    echo shar: \"test/test.addresses\" unpacked with wrong size!
fi
chmod +x test/test.addresses
# end of overwriting check
fi
if test -f test/test.cf -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"test/test.cf\"
else
echo shar: Extracting \"test/test.cf\" \(2437 characters\)
sed "s/^X//" >test/test.cf <<'END_OF_test/test.cf'
X###################################################
X##                                               ##
X##  WARNING: THIS FILE IS TO BE MODIFIED BY      ##
X##           THE EASE TRANSLATOR (ET) ONLY.      ##
X##                                               ##
X##           ALL OTHER MODIFICATIONS WILL        ##
X##           DISAPPEAR THE NEXT TIME ET IS RUN.  ##
X##                                               ##
X##           MAKE MODIFICATIONS TO THE EASE      ##
X##           SOURCE ONLY.                        ##
X##                                               ##
X###################################################
XDAmy_domain
XDBruleset tester V1.0
XDwwhatever
XDj$w.$A
XDnMAILER-DAEMON
XDlFrom $g  $d
XDo.:%@!^=/[]{}
XDq$?x$x	<$g>$|$g$.
XDe$j Sendmail $v/$B ready at $b
XOA/usr/lib/aliases
XOdb
XOu1
XOS/usr/lib/sendmail.st
XOH/usr/lib/sendmail.hf
XOg1
XOo
XOQ/usr/spool/mqueue
XOT3d
XOs
XOL9
XOtWET
XOF0644
XOrr2h
XOW*
XPfirst-class=0
XPspecial-delivery=100
XPjunk=-100
XTroot daemon uucp network
XTsimon 
XHa: The origination date in Arpanet format = $a
XHb: The current date in Arpanet format = $b
XHc: The hop count = $c
XHd: The date in UNIX (ctime) format = $d
XHe: The SMTP entry message = $e
XHf: The sender (from) address = $f
XHg: The sender address relative to the recipient = $g
XHh: The recipient host = $h
XHi: The queue id = $i
XHj: The official domain name for this site = $j
XHl: The format of the UNIX from line = $l
XHn: The name of the daemon (for error messages) = $n
XHo: The set of operators in addresses = $o
XHp: Sendmail's pid = $p
XHq: The default format of sender address = $q
XHr: Protocol used = $r
XHs: Sender's host name = $s
XHt: A numeric representation of the current time = $t
XHu: The recipient user = $u
XHv: The version number of sendmail = $v
XHw: The hostname of this site = $w
XHx: The full name of the sender = $x
XHy: The id of the sender's tty = $y
XHz: The home directory of the recipient = $z
XS3
XR$+	$:{3}$1
XS0
XR$+@$+	$#uucp$@{0_uucp}$2$:{0_uucp}$1
XR$+!$+	$#uucp$@{0_uucp}$1$:{0_uucp}$2
XR$+	$#local$:{0_local}$1
XS1
XR$+	$@{1}$1
XS2
XR$+	$@{2}$1
XS4
XR$+	$@{4}$1
XS10
XR$+	$@{S_local}$1
XS20
XR$+	$@{R_local}$1
XS11
XR$+	$@{S_uucp}$1
XS21
XR$+	$@{R_uucp}$1
XMlocal, P=/usr/src/local/EUnet/ease/test/args, F=DFlMmnrs, S=10, R=20, A=args mail -d $u
XMprog, P=/usr/src/local/EUnet/ease/test/args, F=DeFlMns, S=10, R=20, A=args sh -c $u
XMuucp, P=/usr/src/local/EUnet/ease/test/args, F=DFMsUhu, S=11, R=21, M=65535, A=args uumail -h -oc -gA -f$g $h!$u
END_OF_test/test.cf
if test 2437 -ne `wc -c <test/test.cf`; then
    echo shar: \"test/test.cf\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f utils/Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"utils/Makefile\"
else
echo shar: Extracting \"utils/Makefile\" \(206 characters\)
sed "s/^X//" >utils/Makefile <<'END_OF_utils/Makefile'
X
XBINDIR=../bin
X#INSTALL=install -m 755 
XINSTALL=cp
X
Xall:	
Xclean:
X
Xinstall:
X	${INSTALL} cfdiff.csh  ${BINDIR}/cfdiff
X	${INSTALL} cfstrip.csh ${BINDIR}/cfstrip
X	chmod 755 ${BINDIR}/cfstrip  ${BINDIR}/cfdiff
X
END_OF_utils/Makefile
if test 206 -ne `wc -c <utils/Makefile`; then
    echo shar: \"utils/Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f utils/build-new-aliases -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"utils/build-new-aliases\"
else
echo shar: Extracting \"utils/build-new-aliases\" \(1226 characters\)
sed "s/^X//" >utils/build-new-aliases <<'END_OF_utils/build-new-aliases'
X#!/bin/csh -f
X# build-new-aliases
X# Bruce Barnett
X#
X# this script makes a new alias file
X#
X# first it has to shutdown sendmail
X# But do it nicely, using kill -15 at first.
X
X# how many sendmail processes are running?
Xset j = (`ps ax |grep sendmail|grep -v grep`);
X
Xset loopcount = 0
Xif ( $#j > 0 ) then
X
Xloop:
X@	loopcount++
X	# wait 30 * 30 seconds for all of the sendmail processes to quit
X	if ( $loopcount > 30 ) then
X		echo ERROR - can not kill sendmail
X		goto problem
X	endif
X	kill -15 $j[1]
X	sleep 30
X	set j = (`ps ax |grep sendmail|grep -v grep`);		
X	if ( $#j > 0 ) then
X		goto loop
X	endif
Xendif
Xgoto good
Xproblem:
X# could not kill sendmail - try something drastic
X	echo `date` kill sendmail >>/usr/spool/adm/build-new-aliases.log
X	kill -9 $j[1]
Xgood:
Xset frozen = 0
Xif ( -f /etc/sendmail.fc )  then
X	set frozen = 1
X	/bin/cp /dev/null /etc/sendmail.fc
Xendif
X# clean up any lock files
Xtouch /usr/spool/mqueue/lf0
X/bin/rm -f /usr/spool/mqueue/lf*
X
X# see the documentation about the 'a' option of sendmail
X# or the "D" option
X#/usr/lib/newaliases
X# rebuild aliases
X/usr/lib/sendmail -bi
X
Xif ( $frozen > 0 ) then
X	/usr/lib/sendmail -bz
Xendif
X
X# restart the daemon with 30 minutes between cycles
X/usr/lib/sendmail -bd -q30m -om
END_OF_utils/build-new-aliases
if test 1226 -ne `wc -c <utils/build-new-aliases`; then
    echo shar: \"utils/build-new-aliases\" unpacked with wrong size!
fi
chmod +x utils/build-new-aliases
# end of overwriting check
fi
if test -f utils/cfdiff.csh -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"utils/cfdiff.csh\"
else
echo shar: Extracting \"utils/cfdiff.csh\" \(576 characters\)
sed "s/^X//" >utils/cfdiff.csh <<'END_OF_utils/cfdiff.csh'
X#!/bin/csh -f
X# Bruce Barnett
X# usage:
X# cfdiff file1.cf file2.cf
X# this removes all comments from the cf file
Xif ( $#argv != 2 ) then
X	echo usage cfdiff file1 file2
X	exit 1
Xendif
Xonintr bomb
X# if SunOS, use the -b -w option
Xset DIFF = "diff -b"
Xif ( -f /bin/arch ) then
X	if ( `/bin/arch` =~ sun* ) then
X		set DIFF = "diff -b -w"
X	endif
Xendif
Xif ( ! -f $1 ) then
X	echo file $1 does not exist
X	exit 1
Xendif
Xif ( ! -f $2 ) then
X	echo file $2 does not exist
X	exit 1
Xendif
Xcfstrip <$1>/tmp/$1:t
Xcfstrip <$2>/tmp/$2:t
X
Xcd /tmp
X${DIFF} $1:t $2:t
X
Xbomb:
X	/bin/rm /tmp/$1:t /tmp/$2:t
END_OF_utils/cfdiff.csh
if test 576 -ne `wc -c <utils/cfdiff.csh`; then
    echo shar: \"utils/cfdiff.csh\" unpacked with wrong size!
fi
chmod +x utils/cfdiff.csh
# end of overwriting check
fi
if test -f utils/cfstrip.csh -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"utils/cfstrip.csh\"
else
echo shar: Extracting \"utils/cfstrip.csh\" \(594 characters\)
sed "s/^X//" >utils/cfstrip.csh <<'END_OF_utils/cfstrip.csh'
X#!/bin/csh -f
X# usage:
X#	cfstrip <infile >outfile
X# Bruce Barnett
X#
X# this file strips out all comments from a sendmail.cf file
X# it also converts 
X#	<tab>[whitespace] 	to 	<tab>
X#	<space>[whitespace]	to	<space>
X#	<space>$		to	$
X#	<space><		to	<
X#	<space>@		to	@
Xif ( $#argv != 0 ) then
X	echo no arguments are allowed
X	exit 1
Xendif
Xsed -e 's/^#.*//' \
X	-e 's/^\(R[^	]*[	][	]*[^	]*\)[	]*.*$/\1/' \
X	-e 's/^\(R[^	]*[	][	]*[^	]*\)[	]*$/\1/' \
X	-e 's/^\(R[^	]*[	][	]*[^	]*\)$/\1/' \
X	-e 's/	[	 ]*/	/g' \
X	-e 's/ [	 ]*/ /g' \
X	-e 's/ \$/$/g' \
X	-e 's/ </</g' \
X	-e 's/ @/@/g' \
X	 |grep -v '^[ 	]*$'
END_OF_utils/cfstrip.csh
if test 594 -ne `wc -c <utils/cfstrip.csh`; then
    echo shar: \"utils/cfstrip.csh\" unpacked with wrong size!
fi
chmod +x utils/cfstrip.csh
# end of overwriting check
fi
echo shar: End of archive 1 \(of 6\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 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
--
Bruce G. Barnett	barnett@crd.ge.com	uunet!crdgw1!barnett

barnett@grymoire.crd.ge.com (Bruce Barnett) (02/23/91)

#! /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 2 (of 6)."
# Contents:  doc/cfc.man src/Makefile src/errors.c src/idman.c
#   src/lexan.patch src/main.c src/symtab.c test/test.mc
# Wrapped by barnett@grymoire on Sat Feb 23 01:13:52 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f doc/cfc.man -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"doc/cfc.man\"
else
echo shar: Extracting \"doc/cfc.man\" \(5708 characters\)
sed "s/^X//" >doc/cfc.man <<'END_OF_doc/cfc.man'
X...
X... $Header: /home/kreskin/u0/barnett/Src/Ease/ease/doc/RCS/cfc.man,v 1.2 1990/04/04 15:42:51 jeff Exp barnett $
X... 
X... $Log: cfc.man,v $
X... Revision 1.2  1990/04/04  15:42:51  jeff
X... Reformatted somewhat for readability.  Added some bugs
X... described by Bruce Barnett.
X...
X... Version 1.1  90/04/04  14:57:38  jeff
X... Initial version
X... 
X... Revision 2.0  88/06/15  15:17:36  arnold
X... Baseline release for net posting. ADR.
X... 
X... Revision 1.3  88/01/21  16:23:21  arnold
X... Some typo fixes.
X... 
X... Revision 1.2  87/04/08  10:21:47  arnold
X... Small bug fixes, compatibility option added, also warnings for
X... unrecognized flags and options. ADR.
X... 
X... Revision 1.1  87/02/16  15:25:32  arnold
X... Initial revision
X... 
X...
X.TH CFC local
X.SH NAME
Xcfc \- Sendmail cf file compiler
X.SH SYNOPSIS
X.B cfc
X[
X.B \-s
X] [
X.B \-i
X] [
X.B \-d
X] [
X.B \-c
X] [
X.B \-u
X] [
X.B \-C \fICLASSES\fP
X] <
X.I sendmail.cf-file
X>
X.I ease-source-file
X.SH DESCRIPTION
X.I Cfc
Xis a filter that reads a raw
X.IR sendmail (8)
Xconfiguration file on its standard input, and produces almost useable
X.IR ease (1)
Xsource on its standard output.
X.P
XIt is designed as a conversion tool, to translate an existing
X.B sendmail.cf
Xfile into
X.I ease
Xwith the idea that all future work will be done in
X.IR ease .
X.P
X.I Cfc
Xpasses all comments through to the output, and converts all predefined
X.I sendmail
Xmacros, options, option values, and mailer flags into the names used by
X.IR ease .
X.P
XIt is suggested you use
X.I cfc
Xto convert a 
X.I sendmail.cf
Xfile into 
X.I ease
Xformat, and then convert the
X.I ease
Xfile back into
X.I sendmail
Xformat.
XYou may have to experiment with the right options and the right combinations
Xbefore
X.I ease
Xwill generate an output file with no errors.
XThen use the
X.I cfdiff
Xscript to compare the original
X.I sendmail.cf
Xfile to the output of
X.IR ease .
XYou should see some differences in formatting, as some 
X.I sendmail
Xlines can be on one or two lines, and some options have more than one form.
XOnce it is determined that these are the only difference, you should feel
Xvery comfortable using 
X.I ease
Xas a high level langauge for 
X.I sendmail 
Xfiles.
XIf you are unable to make the two files identical, you may need to modify the 
X.I ease
Xinput file so the output is correct.
XIf necessary, you can use the
X.IR asm ()
Xfunction in
X.I ease
Xto pass the characters, unchanged, to the output.
X.P
X.I Cfc
Xisn't perfect. 
XYou may wish to modify the 
X.I ease
Xfile for cosmetic reasons:
X.IP
X.I Cfc
Xintroduces tabs on its own, as well as often passing through tabs
Xfrom the
X.I sendmail
Xinput.
XIt will also print a header for each different type of line, e.g. if the
Xinput had seven
X.B O
X(option) lines, there will be seven option blocks.
XThese are usually succesive, and can therefore be merged.
X.IP
XMove some comments.
XThe block close on rulesets often comes after the comments that
Xprecede the next ruleset or mailer specification.
X
X.RE
X.P
XIn short,
X.I cfc
Xdoes over 99% of the tedious work of translating a
X.B sendmail.cf
Xinto
X.I ease
Xformat.
XSuprisingly, the combination of
X.I cfc
Xand
X.I ease
Xcan find bugs in a current
X.B sendmail.cf
Xfile!
X.P
X.I Cfc
Xtakes five options.
X.RS
X.TP
X.B \-c
XIndicates that
X.I cfc
Xshould run in 4.2BSD compatibility mode.
XIn this case, options and mailer flags which are new in the 4.3BSD
Xversion of
X.I sendmail
Xwill not be recognized.
X.TP
X.B \-u
X.I Cfc
Xwill warn about the use of any undocumented options or mailer flags in
Xthe 4.3BSD
X.IR sendmail .
XThe correct
X.I ease
Xoutput will still be produced.
X.TP
X.B \-s
X.I Cfc
Xwill assume the input file is for Sun's sendmail.
XIt will produce a ruleset definition for rule number 30, which Sun uses
Xin their standard configuration file, and older implementations
Xcomplain about. It also adds some declarations that match Sun's
Xadditions to sendmail, so errors won't occur.
X.TP
X.B \-d
X.I Cfc
Xwill cause some definitions to be added that will convert the Ultrix
X.i sendmail.cf
Xfile with fewer errors.
X.TP
X.B \-i
X.I Cfc
Xwill add some declarations that the IDA version of 
X.I sendmail
Xlikes to see.
X.TP
X.B \-C
X<LETTER><LETTER>...
X.I Cfc
Xwill add an additional header of the form
X.I any_in_<LETTER>
Xand
X.I any_not_in_<LETTER>
Xwhere
X.I <LETTER>
Xis a single character that specifes a class used in the sendmail file,
Xbut not defined.
XThis prevents 
X.I ease
Xfrom complaining about undefined classes.
X.RE
X.P
XWith the right compination of options and class definitions, it is
Xeasy to convert a 
X.I sendmail
Xfile into 
X.I ease ,
Xedit the file, and run 
X.I ease
Xon the file, and install the output.
X.\" .SH FILES
X.SH SEE ALSO
X.I "Sendmail Installation and Operation Guide"
Xby Eric Allman
X(SMM:7 in the 4.3 BSD UNIX System Manager's Manual),
X.I "Ease: A Configuration Language for Sendmail"
Xby James S. Schoner, amended by Jeff P. Stearns, Arnold D. Robbins, and Bruce G. Barnett.
X.IR sendmail (8),
X.IR ease (1).
X.SH DIAGNOSTICS
X``\c
X.IR Routine :
Xmalformed input line
X.IR line :
Xfatal error''
Xfor input it doesn't understand.
X.I Routine
Xis the name of the routine in
X.I cfc
Xwhich choked, and
X.I line
Xis the line number in the input.
X.SH BUGS
XOnly recognizes continuation lines (lines that begin with a \s-1TAB\s+1)
Xfor header (H) and mailer (M) definitions.
X.P
XShould read from files on the command line, instead of being a pure filter.
X.P
XShould be a two pass program, and learn the classes which need
Xdefining automatically. The
X.B \-C
Xoption is really a kludge.
X.PP
XIn some cases, you can use the
X\fIasm(".......")\fP
Xcommand to work around problems.
X.SH AUTHOR
X.nf
XArnold Robbins
XEmory University Computing Center
Xarnold@emory.edu
X
XModifications by Bruce G. Barnett
XGeneral Electric, Corporate Research and Development
Xbarnett@crdgw1.ge.com
X
X.fi
END_OF_doc/cfc.man
if test 5708 -ne `wc -c <doc/cfc.man`; then
    echo shar: \"doc/cfc.man\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/Makefile\"
else
echo shar: Extracting \"src/Makefile\" \(3877 characters\)
sed "s/^X//" >src/Makefile <<'END_OF_src/Makefile'
X# Makefile for Ease Translator (et).
X#
X#	$Header: /home/kreskin/u0/barnett/Src/Ease/ease/src/RCS/Makefile,v 2.1 1990/01/30 13:54:13 jeff Exp barnett $
X#
X#	$Log: Makefile,v $
X# Revision 2.1  1990/01/30  13:54:13  jeff
X# Updated for release 2.1 Aplha.
X#
X# Revision 2.0  88/06/15  14:47:35  root
X# Baseline release for net posting. ADR.
X# 
X#
X#	James S. Schoner, Purdue University Computing Center,
X#			  West Lafayette, Indiana  47907
X#
X#	Copyright (c) 1985 by Purdue Research Foundation
X#
X#	All rights reserved.
X#
X
XINCLUDE =
X
X# where to install the binaries
XBINDIR          =	../bin
X
XOWNER = root
XGROUP = staff
XMODE = 755
X#INSTALL = install -c -m ${MODE} -o ${OWNER} -g ${GROUP}
XINSTALL=cp
X# define this for grammar debugging
X#DEFS =-DYYDEBUG
XDEFS =
X# I had strange errors happen when I use SunOS Optimizer.....
X# In particular, with SunOS 4.0.3, Sparc, and -O (-O2)....
X# Maybe you better not use -O with SunOS
XCFLAGS = -g  ${DEFS} ${INCLUDE}
X#CFLAGS = -O ${DEFS} ${INCLUDE}
X
XLP = lpr
XLPFLAGS = -J"Ease Source"
X
XHDR = symtab.h
XSRC = main.c emitcf.c errors.c idman.c strops.c symtab.c fixstrings.c
XLST = Makefile lexan.l parser.y ${HDR} ${SRC}
XDEP = parser.c lexan.c ${SRC}
XOBJ = parser.o lexan.o main.o emitcf.o errors.o idman.o strops.o symtab.o \
X	fixstrings.o
XCFILES= $(SRC) $(DEP)
X
Xall: et
X
Xet: ${OBJ}
X	cc ${CFLAGS} -o et ${OBJ} -ll
X
Xclean: FRC
X	rm -f et *.o lexan.c parser.c y.output yacc.acts yacc.tmp \
X	      lexdefs.h y.tab.h errs Makefile.bak y.output y.tab.c y.tok.h
X
Xdepend:
X	${CC} -M ${CFLAGS} ${CFILES} | \
X	sed -e ':loop' \
X	    -e 's/\.\.\/[^ /]*\/\.\./../' \
X	    -e 't loop' | \
X	awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
X		else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
X		       else rec = rec " " $$2 } } ; \
X	      END { print rec } ' > makedep
X	echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
X	echo '$$r makedep' >>eddep
X	echo 'w' >>eddep
X	cp Makefile Makefile.bak
X	ex - Makefile < eddep
X	rm eddep makedep
X
Xinstall: et FRC
X	${INSTALL} et ${BINDIR}
X	${INSTALL} ease.sh ${BINDIR}/ease
X
X
Xlint:   ${DEP} symtab.h FRC
X	lint -hxn ${DEP}
X
Xprint:  ${LST} FRC
X	@pr -f ${LST} | ${LP} ${LPFLAGS}
X
Xspotless: clean FRC
X	rcsclean ${LST}
X
Xy.tab.h parser.c: parser.y
X	@rm -f parser.c
X	yacc -v -d parser.y
X	sed 's/=yylex/=yyyylex/' < y.tab.c >parser.c
X
X# the following dummy rule is because of the results of 'make depend'
X# However, under SunOS Make - it complains. You may have to comment it out
X./lexdefs.h:	lexdefs.h
X
Xlexdefs.h:	y.tab.h
X	-(cmp -s y.tab.h lexdefs.h || cp y.tab.h lexdefs.h)
X
Xlexan.c: lexan.l
X
Xparser.o: y.tok.h
Xy.tok.h:	y.tab.h
X	grep '^#.*define' y.tab.h |\
X	sed 's/^# define \([^ ]*\) [^ ]*$$/	"\1",/' >y.tok.h
X
X${HDR} ${SRC} lexan.l parser.y:
X	co $@
X
XFRC:
X
X# DO NOT DELETE THIS LINE -- make depend uses it
X
Xmain.o: main.c ./fixstrings.h /usr/include/stdio.h
Xemitcf.o: emitcf.c /usr/include/stdio.h ./symtab.h ./fixstrings.h
Xerrors.o: errors.c /usr/include/stdio.h ./fixstrings.h
Xidman.o: idman.c /usr/include/stdio.h ./symtab.h ./fixstrings.h
Xstrops.o: strops.c ./fixstrings.h /usr/include/stdio.h /usr/include/strings.h
Xstrops.o: ./symtab.h
Xsymtab.o: symtab.c ./fixstrings.h /usr/include/stdio.h /usr/include/ctype.h
Xsymtab.o: ./symtab.h
Xfixstrings.o: fixstrings.c /usr/include/strings.h
Xparser.o: parser.c ./fixstrings.h /usr/include/stdio.h ./symtab.h
Xlexan.o: lexan.c /usr/include/stdio.h ./fixstrings.h ./symtab.h ./lexdefs.h
Xmain.o: main.c ./fixstrings.h /usr/include/stdio.h
Xemitcf.o: emitcf.c /usr/include/stdio.h ./symtab.h ./fixstrings.h
Xerrors.o: errors.c /usr/include/stdio.h ./fixstrings.h
Xidman.o: idman.c /usr/include/stdio.h ./symtab.h ./fixstrings.h
Xstrops.o: strops.c ./fixstrings.h /usr/include/stdio.h /usr/include/strings.h
Xstrops.o: ./symtab.h
Xsymtab.o: symtab.c ./fixstrings.h /usr/include/stdio.h /usr/include/ctype.h
Xsymtab.o: ./symtab.h
Xfixstrings.o: fixstrings.c /usr/include/strings.h
END_OF_src/Makefile
if test 3877 -ne `wc -c <src/Makefile`; then
    echo shar: \"src/Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/errors.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/errors.c\"
else
echo shar: Extracting \"src/errors.c\" \(4962 characters\)
sed "s/^X//" >src/errors.c <<'END_OF_src/errors.c'
X#ifdef FLUKE
X# ifndef LINT
X    static char RCSid[] = "@(#)FLUKE  $Header: /isis/usr2/share/src/local/tc/ease/src/RCS/errors.c,v 2.1 90/01/30 14:17:29 jeff Exp $";
X# endif LINT
X#endif FLUKE
X
X/*
X *  	errors.c   -- Contains error initialization and reporting routines.
X *
X *  	author     -- James S. Schoner, Purdue University Computing Center,
X *				        West Lafayette, Indiana  47907
X *
X *  	date       -- July 9, 1985
X *
X *	Copyright (c) 1985 by Purdue Research Foundation
X *
X *	All rights reserved.
X *
X * $Log:	/isis/usr2/share/src/local/tc/ease/src/RCS/errors.c,v $
X * Version 2.1  90/01/30  14:17:29  jeff
X * Bruce Barnett - extensions for SunOS/Ultrix.
X * 
X * Revision 2.0  88/06/15  14:41:10  root
X * Baseline release for net posting. ADR.
X */
X
X#include <stdio.h>
X#include "fixstrings.h"
X#include <ctype.h>
Xextern int  ErrorCount;	 /* error count	               */
Xextern char FNbuf[];	 /* input file name   	       */
Xextern int  Lcount;	 /* line count	     	       */
XFILE *DIAGf = {stderr};  /* file for diagnostic output */
Xextern char yytext[];	/* current token */
Xextern int yyleng;	/* and it's length */
Xextern int	yylineno;	/* current input line number */
Xextern char *infile;		/* input file name */
Xstatic char *source;
X
X/*
X * yywhere() -- input position for yyparse()
X * from Schreiner and Friedman's book on compiler construction
X */
Xvoid
Xyywhere() 	/* position stamp */
X{
X    char	colon = 0;	/* flag */
X    if (source && *source && strcmp(source,"\"\"")) {
X	char	*cp = source;
X	int	len = strlen(source);
X	
X	if (*cp == '"')
X	  ++cp, len -= 2;
X	if (strlen(cp, "./", 2) == 0)
X	  cp += 2, len -= 2;
X	if (len > 0 )
X	  fprintf(DIAGf, "\"%.*s\"", len, cp);
X	colon = 1;
X    } 	else if (infile && strcmp(infile,"-")) {
X	  fprintf(DIAGf, "\"%s\"",infile);
X	  colon = 1;
X      }
X    if (yylineno > 0 ) {
X	if (colon)
X	  fputs(", ",DIAGf);
X	fprintf(DIAGf, "line %d",
X		yylineno - (*yytext == '\n' || ! *yytext));
X	colon = 1;
X/*	if ((yylineno - (*yytext == '\n' || ! *yytext)) != Lcount)
X	  fprintf(DIAGf, "?%d:?", Lcount); */
X    }
X    if (*yytext) {
X	register int i;
X	for (i=0;i<20;++i)
X	  if (!yytext[i] || yytext[i] == '\n')
X	    break;
X	if (i) {
X	    if (colon)
X	      putc(' ',DIAGf);
X	    fprintf(DIAGf, "near \"%.*s\"",i,yytext);
X	    colon = 1;
X	}
X    }
X    if (colon)
X      fputs(": ",DIAGf);
X}
X
X
X/*
X *	yymark - keep track of source file and line number 
X */
X
Xvoid
Xyymark()	/* retreive from '# digit text' */
X{
X    if (source)
X      cfree(source); 
X    source = (char *) calloc(yyleng,sizeof(char));
X    if (source) {
X      sscanf(yytext, "# %d%s",&yylineno, source);
X/*      fprintf(stderr,"source = '%s' on %s",source,yytext); */
X      Lcount = yylineno;
X      if (strcmp(source,"\"\""))
X	strcpy(FNbuf,source);
X      else if ( infile && strcmp(infile,"-"))
X	sprintf(FNbuf,"\"%s\"",infile);
X/*      fprintf(stderr,"FNbuf = '%s', infile = '%s'\n",FNbuf,infile); */
X	       
X  }
X}
X
X
X
X/*
X *	yyerror () -- Prints source file name (FNbuf), line number (Lcount),
X *		      and error message (sbErr) for each invokation.
X *		      it also prints out a message where the error is.
X *
X */
Xvoid
Xyyerror (sbErr)
Xchar *sbErr;
X{
X    extern int yynerrs;
X    ++ErrorCount;
X    yywhere();
X/*    fprintf(DIAGf, " %s\t[error %d]\n", sbErr, ErrorCount); */
X    fprintf(DIAGf, " %s\n", sbErr);
X/* yynerrs is the number of yacc errors, ErrorCount is larger */
X}
X
X
X
X/*
X *	ErrorReport () -- Prints source file name (FNbuf), line number (Lcount),
X *			  and error message (sbErr) for each invokation.
X *
X */
Xvoid
XErrorReport (sbErr)
Xchar *sbErr;
X{
X/*	fprintf (DIAGf, "%s, line %d: %s", FNbuf, Lcount, sbErr);
X	ErrorCount++; */
X    yyerror(sbErr);
X}
X
X
X/*
X *	FatalError () -- Translator fatal error routine which prints 
X *			 error message (sbErr) and an argument (sbArg).
X *
X */
Xvoid
XFatalError (sbErr, sbArg)
Xchar *sbErr,
X     *sbArg;
X{
X	fprintf (DIAGf, "%s, line %d: Fatal Error In Translator: %s %s\n", 
X		 FNbuf, Lcount, sbErr, sbArg); 
X	exit (1);
X}
X
X
X/*
X *	PrintError () -- Prints source file name (FNbuf), line number
X *			 (cline), error message (sbErr), and argument
X *			 (sbArg) for each invokation.
X *
X */
Xvoid
XPrintError (sbErr, sbArg)
Xchar *sbErr;
Xchar *sbArg;
X{
X    char	Ebuffer[1000];
X    sprintf(Ebuffer,sbErr,sbArg);
X    yyerror(Ebuffer);
X/*    fprintf (DIAGf, "%s, line %d: %s %s.\n", FNbuf, Lcount, sbErr, sbArg);
X	ErrorCount++; */
X}
X
X
X/*
X *	PrintWarning () -- Prints a warning message with source file
X *			   name (FNbuf), line number (Lcount), warning
X *			   (sbWarn), and a possible identifier (sbID).
X *
X */
Xvoid
XPrintWarning (sbWarn, sbID)
Xchar *sbWarn;
Xchar *sbID;
X{
X/*	fprintf (DIAGf, "%s, line %d: Warning: ", FNbuf, Lcount); */
X        yywhere();
X	fprintf(DIAGf,"Warning: ");
X	if (sbID != NULL)
X		fprintf (DIAGf, sbWarn, sbID);
X	else
X		fprintf (DIAGf, sbWarn);
X}
X
X
X/*
X *	InitError () -- Initialize line count (Lcount) to one and error count
X *		        (ErrorCount) to zero.
X *
X */
Xvoid
XInitError ()
X{
X	Lcount     = 1;
X	ErrorCount = 0;
X}
END_OF_src/errors.c
if test 4962 -ne `wc -c <src/errors.c`; then
    echo shar: \"src/errors.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/idman.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/idman.c\"
else
echo shar: Extracting \"src/idman.c\" \(6609 characters\)
sed "s/^X//" >src/idman.c <<'END_OF_src/idman.c'
X#ifdef FLUKE
X# ifndef LINT
X    static char RCSid[] = "@(#)FLUKE  $Header: /tmp_mnt/home/kreskin/u0/barnett/Src/Ease/ease/src/RCS/idman.c,v 3.0 1991/02/22 18:50:27 barnett Exp $";
X# endif LINT
X#endif FLUKE
X
X/*
X *  	idman.c	-- Contains routines for manipulating identifiers and their
X *		   symbolic associations.
X *
X *  	author	-- James S. Schoner, Purdue University Computing Center,
X *				     West Lafayette, Indiana  47907
X *
X *  	date	-- July 9, 1985
X *
X *	Copyright (c) 1985 by Purdue Research Foundation
X *
X *	All rights reserved.
X *
X * $Log: idman.c,v $
X * Revision 3.0  1991/02/22  18:50:27  barnett
X * Added support for HP/UX and IDA sendmail.
X *
X * Revision 2.1  1990/01/30  14:33:52  jeff
X * Bruce Barnett - changed UniqMac.
X *
X * Revision 2.0  88/06/15  14:42:14  root
X * Baseline release for net posting. ADR.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include "symtab.h"
X#include "fixstrings.h"
X
Xextern struct he *LookupSymbol ();
Xextern void	  FatalError (),
X		  ErrorReport (),
X		  PrintWarning (),
X		  PrintError ();
X
X
Xchar	IDused[] = "                          "; /* 26 blanks */
X/*
X *	UniqMac () -- Assigns and returns a unique one-character macro
X *		      name (upper-case) for an Ease macro name.
X *
X *	Bruce Barnett:
X *	Special enhancement - if idval is a single character,
X *	and the corresponding letter has not been assigned,
X *	Make the idc character the same as the macro name 
X *
X *	This makes it nice to test cfc/ease completeness.
X *	Also makes reading the ease output easier.
X *
X */
Xchar
XUniqMac (phe)
Xstruct he *phe;		/* symbol table entry for Ease macro */
X{
X    short i;
X
X    if ((strlen(phe->psb) == 1) && 
X	isupper(*(phe->psb)) &&
X	IDused[*(phe->psb) - 'A'] == ' ' ) {
X	IDused[*(phe->psb) - 'A'] = (phe->idval.idc) = *(phe->psb);
X    } else {
X	for (i=0;i<26 && IDused[i] != ' ';i++) 
X	  ;	/* find first unused letter */
X	if (i==26) FatalError ("Too many macro names (26 max)", (char *) NULL);
X	IDused[i] = 
X	  (phe->idval.idc) = 
X	    'A' + i;
X    }
X    return (phe->idval.idc);
X}
X
X
X/*
X *	BindID () -- Binds either a ruleset or precedence identifier (phe) to
X * 		     an integer (vid).  The id type distinction is passed in
X *		     the parameter idt.
X *
X */
Xvoid
XBindID (phe, vid, idt)
Xregister struct he *phe;	/* symbol table entry for an identifier    */
Xint vid;			/* value of the identifier		   */
Xunsigned idt;			/* identifier type (ruleset or precedence) */
X{
X	if (ISTYPED(phe->idtype)) {	/* should be undefined */
X		PrintWarning ("Redeclaration of %s.\n", phe->psb);
X		phe->idtype = ID_UNTYPED;
X	}
X	phe->idtype |= idt;		/* make defined	       */
X	if (ISRULESET(phe->idtype)) {
X		if (vid > VALRSNMAX) {
X			ErrorReport ("Ruleset number too large.\n");
X			return;
X		} else if (vid < 0) {
X			ErrorReport ("Ruleset number must be non-negative.\n");
X			return;
X		}
X		sprintf (phe->idval.rsn, "%d", vid);
X	} else 
X		phe->idval.prec = vid;
X}
X
X
X/*
X *	CheckRS () -- Checks validity of a ruleset identifier (phe) and 
X *		      returns the ruleset string to which the identifier
X *		      is bound.  If the ruleset identifier is invalid, the
X *		      null string is returned.
X *
X */
Xchar *
XCheckRS (phe)
Xstruct he *phe;		/* symbol table entry for ruleset identifier */
X{
X	if (!ISRULESET(phe->idtype)) {
X		if (!ISTYPED(phe->idtype))
X			PrintError ("Ruleset identifier not bound to a number: %s", phe->psb);
X		else
X			PrintError ("Identifier not of ruleset type: %s", phe->psb);
X		return (NULL);
X	} else
X		return (phe->idval.rsn);
X}
X
X
X/*
X *	MakeMac () -- Declare a macro name (pmac) as a class and/or macro type 
X *		      (targtype) and return the unique cf character assigned 
X *		      to it.
X *
X */
Xchar
XMakeMac (pmac, targtype)
Xregister struct he *pmac;	/* symbol table entry for macro identifier */
Xunsigned targtype;		/* target declaration type for the macro   */
X{
X	/*
X	 *	An Ease macro may be declared as both a singular macro and
X	 *	a class macro.
X	 *
X	 */
X	if (ISMACRO(pmac->idtype) || ISCLASS(pmac->idtype)) {
X		pmac->idtype |= targtype;
X		return (pmac->idval.idc);
X	}
X	if (ISTYPED(pmac->idtype)) {	/* not a macro or class id */
X		PrintError ("Redeclaring or using as macro or class: %s", pmac->psb);
X		return ('\0');
X	}
X	pmac->idtype |= targtype;	/* previously untyped; declare here */
X	return (UniqMac (pmac));
X}
X	
X
X/*
X *	GetField () -- Returns a field type string given a field 
X *		       identifier (fid).
X *
X */
Xchar *
XGetField (fid)
Xregister struct he *fid;	/* field identifier */
X{
X	if (!ISFIELD(fid->idtype)) {
X		PrintError ("Field type not defined for %s", fid->psb);
X		return (NULL);
X	} else 
X		return (fid->idval.fstring);
X}
X
X
X/*
X *	CheckMailer () -- Declares a mailer identifier (mid) as type mailer,
X *			  checking that the identifier was not previously 
X *			  declared a different type. 
X *
X */
Xchar *
XCheckMailer (mid)
Xregister struct he *mid;
X{
X	if (ISTYPED (mid->idtype) && !ISMAILER (mid->idtype)) {
X		PrintError ("Redeclaration as mailer: %s", mid->psb);
X		return (NULL);
X	}
X	mid->idtype |= ID_MAILER;
X	return (mid->psb);
X}
X
X
X/*
X *	AssignType () -- Assigns to each field identifier in fidlist the
X *			 type (in string form) fidtype.  This is accomplished
X *			 by making each field identifier symbol table entry
X *			 "point" to the type found in fidtype.
X *
X */
Xvoid
XAssignType (fidlist, fidtype)
Xregister char *fidlist;		/* field identifier list, blank separated */
Xchar *fidtype;			/* field identifier type string		  */
X{
X	register struct he *fid;	/* pointer to a field identifier  */
X	char *fres;			/* field type result string	  */
X	register char *srch;		/* fidlist search pointer	  */
X	char  sep;			/* fidlist separator character    */
X
X	fres = (char *) malloc (strlen (fidtype) + 1);
X	if (fres == NULL)
X		FatalError ("System out of string space in AssignType ()", (char *) NULL);
X	strcpy (fres, fidtype);		/* make clean copy of string type */
X
X	/*
X	 *	Search for all field identifiers and make the type assignment. 
X 	 *
X	 */
X	srch = fidlist;
X	while (*srch != '\0') {
X		while ((*++srch != ' ') && (*srch != '\0'))
X			/* null */ ;
X		if (*fidlist != '\0') {		        /* found a field id       */
X			sep = *srch;
X			*srch = '\0';
X			fid = LookupSymbol (fidlist);	/* get symbol table entry */
X			if (ISFIELD(fid->idtype)) {
X				if (strcmp (fid->idval.fstring, fres))
X					PrintWarning ("Redefinition of field type for %s.\n", fid->psb);
X			} else if (ISTYPED(fid->idtype)) {
X				PrintError ("Redeclaration of identifier as a field: %s", fid->psb);
X				return;
X			}
X			fid->idtype |= ID_FIELD;	/* type the identifier    */
X			fid->idval.fstring = fres;	/* type the field	  */
X			if ((*srch = sep) != '\0')
X				fidlist = ++srch;
X		}
X	}
X}
END_OF_src/idman.c
if test 6609 -ne `wc -c <src/idman.c`; then
    echo shar: \"src/idman.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/lexan.patch -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/lexan.patch\"
else
echo shar: Extracting \"src/lexan.patch\" \(5320 characters\)
sed "s/^X//" >src/lexan.patch <<'END_OF_src/lexan.patch'
X*** /home/kreskin/u0/barnett/Src/ease/src/lexan.l	Wed Mar  1 15:43:53 1989
X--- lexan.l	Mon May  7 14:12:53 1990
X***************
X*** 59,78 ****
X  	static char linbuf[BUFSIZ], *pc = linbuf;
X  	char c;
X  
X- 
X- 
X- 
X- 
X  	/* initialize buffer: first call only */
X  	if (*pc == '\0' && pc == linbuf) {
X  		if (fgets(linbuf, BUFSIZ, yyin)==NULL)
X  			return EOF;
X!                 if (linbuf[0] == '#' )
X!                     fprintf(yyout, "%s", linbuf);  /* echo input as comment */
X!                 else
X!                     fprintf(yyout, "# %s", linbuf);  /* echo input as comment */
X! 
X  	}
X  	c = *pc++;
X  	if (c == '\n') {
X  		pc = linbuf;
X--- 68,82 ----
X  	static char linbuf[BUFSIZ], *pc = linbuf;
X  	char c;
X  
X  	/* initialize buffer: first call only */
X  	if (*pc == '\0' && pc == linbuf) {
X  		if (fgets(linbuf, BUFSIZ, yyin)==NULL)
X  			return EOF;
X! 		/* echo input as comment */
X! 		if (EchoInputAsComments) {
X! 		    fprintf(yyout, "%s%s", (linbuf[0] == '#' ? "" : "# "), linbuf);
X  		}
X+ 	}
X  	c = *pc++;
X  	if (c == '\n') {
X  		pc = linbuf;
X***************
X*** 79,90 ****
X  		if (fgets(linbuf, BUFSIZ, yyin) == NULL)
X  			*pc = EOF;
X  		else
X! 			/* echo input as comment except cpp comments */
X!                     if (linbuf[0] == '#' )
X!                         fprintf(yyout, "%s", linbuf);  /* echo input as comment */
X!                     else
X!                         fprintf(yyout, "# %s", linbuf);  /* echo input as comment */
X  	}
X  	return c;
X  }
X  
X--- 83,94 ----
X  		if (fgets(linbuf, BUFSIZ, yyin) == NULL)
X  			*pc = EOF;
X  		else
X! 			/* echo input as comment (except cpp comments) */
X! 			if (EchoInputAsComments) {
X! 			    fprintf(yyout, "%s%s",
X! 				(linbuf[0] == '#' ? "" : "# "), linbuf);
X  			}
X+ 	}
X  	return c;
X  }
X  
X***************
X*** 103,109 ****
X  	{ "Path",		MPATH },
X  	{ "Recipient",		MRECIPIENT },
X  	{ "Sender",		MSENDER },
X- 	{ "asm",		ASM },
X  	{ "bind",		BIND },
X  	{ "canon",		CANON },
X  	{ "class",		CLASS },
X--- 107,112 ----
X***************
X*** 112,121 ****
X  	{ "d_interactive",	DOPTI },
X  	{ "d_queue",		DOPTQ },
X  	{ "define",		DEFINE },
X- 	{ "eval",		EVAL },
X  	{ "f_addrw",		CCFLAG },
X  	{ "f_arpa",		AAFLAG },
X- 	{ "f_bsmtp",		BBFLAG },	/* IDA */
X  	{ "f_date",		DDFLAG },
X  	{ "f_dot",		XXFLAG },
X  	{ "f_escape",		EEFLAG },
X--- 115,122 ----
X***************
X*** 125,136 ****
X  	{ "f_full",		XFLAG },
X  	{ "f_llimit",		LLFLAG },
X  	{ "f_locm",		LFLAG },
X- 	{ "f_mail11",		HHFLAG },
X  	{ "f_mesg",		MMFLAG },
X  	{ "f_mult",		MFLAG },
X  	{ "f_noreset",		SSFLAG },
X  	{ "f_noufrom",		NFLAG },
X- 	{ "f_relativize",	VVFLAG },
X  	{ "f_retsmtp",		PFLAG },
X  	{ "f_return",		PPFLAG },
X  	{ "f_rfrom",		RFLAG },
X--- 126,135 ----
X***************
X*** 159,171 ****
X  	{ "match",		MATCH },
X  	{ "next",		NEXT },
X  	{ "o_alias",		AAOPT },
X- 	{ "o_aliasfile",	YYOPT },
X  	{ "o_bsub",		BBOPT },
X  	{ "o_checkpoint",	CCOPT },
X  	{ "o_delivery",		DOPT },
X  	{ "o_dmuid",		UOPT },
X  	{ "o_dnet",		NNOPT },
X- 	{ "o_envelope",		SLOPT },
X  	{ "o_ewait",		AOPT },
X  	{ "o_flog",		SSOPT },
X  	{ "o_fsmtp",		HHOPT },
X--- 158,168 ----
X***************
X*** 174,183 ****
X  	{ "o_hformat",		OOPT },
X  	{ "o_loadnc",		XXOPT },
X  	{ "o_loadq",		XOPT },
X- 	{ "o_maxempty",		BOPT },
X- 	{ "o_maxhops",		HOPT },
X  	{ "o_newproc",		YYOPT },
X- 	{ "o_nfs",		RROPT },	/* SunOS 4.0 */
X  	{ "o_pmaster",		PPOPT },
X  	{ "o_prifactor",	ZOPT },
X  	{ "o_qdir",		QQOPT },
X--- 171,177 ----
X***************
X*** 200,209 ****
X  	{ "o_wizpass",		WWOPT },
X  	{ "options",		OPTIONS },
X  	{ "precedence",		PRECEDENCE },
X- 	{ "quote",		QUOTE },
X  	{ "readclass",		READCLASS },
X  	{ "resolve",		RESOLVE },
X- 	{ "resolved",		RESOLVED },
X  	{ "retry",		RETRY },
X  	{ "return",		RETURN },
X  	{ "ruleset",		RULESET },
X--- 194,201 ----
X***************
X*** 210,218 ****
X  	{ "trusted",		TRUSTED },
X  	{ "user",		USER },
X  	{ "while",		IF },
X- 	{ "ypalias",		YPALIAS },
X- 	{ "ypmap",		YPMAP },
X- 	{ "yppasswd",		YPPASSWD },
X  };
X  %}
X  
X--- 202,207 ----
X***************
X*** 221,231 ****
X  
X  [ \t\f]+			; 	/* discard whitepsace  */
X  [\n]				Lcount++;
X! ^\#[ \t]*[0-9]+[ \t]*\".*\"[ \t]*.*[\n]	{
X! /*			        sscanf (yytext, "%*c%d%s", &Lcount, FNbuf); */
X! 	                        yymark();
X  			        }
X! [A-Za-z_][A-Za-z0-9_-]*		{
X  				register int l, h, m, r, c;
X  
X  				l = 0;
X--- 210,219 ----
X  
X  [ \t\f]+			; 	/* discard whitepsace  */
X  [\n]				Lcount++;
X! ^\#[ \t]*[0-9]+[ \t]*\".*\"[ \t]*[\n]	{
X! 			        sscanf (yytext, "%*c%d%s", &Lcount, FNbuf);
X  			        }
X! [A-Za-z][A-Za-z0-9_-]*		{
X  				register int l, h, m, r, c;
X  
X  				l = 0;
X***************
X*** 292,305 ****
X  						INch = input ();
X  				}
X  				}
X- "/"				return (SLASH);
X  [\\]?.				{
X  				if (RMatch) {	/* in rulesets, return literal character */
X  					yylval.ival = (yytext[0] == '\\') ? yytext[1] : yytext[0];
X  					return (SEPCHAR);
X- 
X  				} else {
X! 					PrintError ("Illegal delimiter character: (octal code) \\%03o", *yytext);
X  				}
X  				}
X  %%
X--- 280,292 ----
X  						INch = input ();
X  				}
X  				}
X  [\\]?.				{
X  				if (RMatch) {	/* in rulesets, return literal character */
X  					yylval.ival = (yytext[0] == '\\') ? yytext[1] : yytext[0];
X  					return (SEPCHAR);
X  				} else {
X! 					ErrorReport ("Illegal delimiter character");
X! 					printf (": (octal code) \\%03o\n", *yytext);
X  				}
X  				}
X  %%
END_OF_src/lexan.patch
if test 5320 -ne `wc -c <src/lexan.patch`; then
    echo shar: \"src/lexan.patch\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/main.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/main.c\"
else
echo shar: Extracting \"src/main.c\" \(7308 characters\)
sed "s/^X//" >src/main.c <<'END_OF_src/main.c'
X#ifdef FLUKE
X# ifndef LINT
X    static char RCSid[] = "@(#)FLUKE  $Header: /isis/usr2/share/src/local/tc/ease/src/RCS/main.c,v 2.2 90/05/07 11:14:02 jeff Exp $";
X# endif LINT
X#endif FLUKE
X
X/*
X *  	main.c     -- Main procedure for Ease Translator.
X *
X *  	author     -- James S. Schoner, Purdue University Computing Center
X *				        West Lafayette, Indiana  47907
X *
X *  	date       -- July 9, 1985
X *
X *	Copyright (c) 1985 by Purdue Research Foundation
X *
X *	All rights reserved.
X *
X * $Log:	/isis/usr2/share/src/local/tc/ease/src/RCS/main.c,v $
X * Version 2.2  90/05/07  11:14:02  jeff
X * Add support for the "-q" flag which controls whether input lines
X * are passed through as comments in the output stream.
X * 
X * Version 2.1  90/01/30  15:37:16  jeff
X * Filter input file through cpp before processing it.
X * 
X * Revision 2.0  88/06/15  14:42:41  root
X * Baseline release for net posting. ADR.
X * 
X */
X
X
X#ifndef CPP	/* filename of preprocessor */
X#	define CPP	"/lib/cpp"
X#endif	CPP
X
X#ifndef CPPARGS		/* valid arguments  of preprocessor */
X#ifdef sun		/* Sun's cpp has more options - I guess */
X#	define CPPARGS	"BCHpPRTDIUY"
X#else
X#	define CPPARGS	"CDEIPU"
X#endif sun
X#endif	CPP
X
X#include "fixstrings.h"
X#include <stdio.h>
X#include <ctype.h>
X
Xextern FILE *DIAGf;			/* diagnostic file */
Xchar *infile = 0;			/* input file name */
Xchar *outfile = 0;			/* output file name */
Xextern void InitError (), 
X	    InitSymbolTable (),
X	    DefScan (),
X	    FatalError (),
X            PreLoad ();
X
Xint EchoInputAsComments = 1;		/* should input lines be echoed
X					 * as comments?
X					 */
Xint ErrorCount;				/* translation error count */
Xvoid GetArgs ();			/* gets arguments to "et"  */
X
X#ifdef YYDEBUG
Xextern int yydebug;
X#else
Xstatic int yydebug;
X#endif
X
X/*
X *	main () -- Main procedure for the Ease Translator et.  If no files are 
X *	       	   given as arguments to et, stdin is translated and written to 
X *	           stdout.  If one file is given, it is translated and written 
X *	           to stdout.  If two files are given, the first is translated
X *	           and written to the second.  If the first filename is "-",
X *	           standard input is assumed.  A translation is performed on 
X *	           valid Ease input only, producing a regular sendmail 
X *		   configuration file. 
X *
X */
Xvoid
Xmain (argc, argv)
Xint argc;		/* argument count for "et"  */
Xchar *argv[];		/* argument vector for "et" */
X{
X	InitError ();			/* initialize error conditions */
X	InitSymbolTable ();		/* initialize the symbol table */
X	PreLoad ();			/* preload special identifiers */
X	GetArgs (argc, argv);		/* set up argument files       */
X	(void) yyparse ();		/* perform translation	       */
X	if (fflush (stdout) == EOF)
X		FatalError ("Cannot flush output stream/file", (char *) NULL);
X	DefScan ();		        /* warn about undefined idents */
X	if (ErrorCount)
X		fprintf (DIAGf, "\n\n*** %d error(s) detected.\n", ErrorCount);
X	exit (ErrorCount);
X}
X
X
X/*
X *	GetArgs () -- Processes arguments to the Ease translator "et".  The
X *		      arguments are files (margv) which may replace either/both
X *		      of the files standard input and standard output.  The 
X *		      following cases are possible:
X *			
X *		      -- et f.e f.cf
X *				Translate Ease file f.e and write result
X *				to f.cf.
X *
X *		      -- et f.e
X *				Translate Ease file f.e and write result to
X *				standard output.
X *
X *		      -- et - f.cf
X *				Translate standard input and write result to
X *				f.cf.
X *
X *		      -- et
X *				Translate standard input and write result to
X *				standard output.
X *
X *		      et also accepts arguments. These include the /lib/cpp arguments
X *		      and the -d argument for debugging grammars.
X *
X *		      Finally, a message indicating the volatility of the 
X *		      Ease output is written.
X *
X */
Xvoid
XGetArgs (margc, margv)
Xregister int   margc;		/* argument count  */
Xregister char **margv;		/* argument vector */
X{
X     register char  **argp;
X     int	cppflags = 0;
X     int	otherflags = 0;
X     int arg;
X 
X     for (arg = 1; arg < margc; ++arg) {		/* scan arguments */
X 	if (margv[arg][0] == '-') {		/* a flag?*/
X 	    if (isalpha(margv[arg][1])) {	/* yes - a flag */
X 		if (index(CPPARGS,margv[arg][1])) ++cppflags;	/* one belonging to the CPP */
X 		else if (margv[arg][1] == 'd' ) yydebug = 1;
X 		else if (margv[arg][1] == 'q' ) EchoInputAsComments = 0;
X 		else ++otherflags;
X 	    } else if (! margv[arg][1]) { 	/* this argument is just a '-' */
X 		if ( (arg - yydebug - cppflags - otherflags) == 1 )
X 		  infile = margv[arg];	
X 		else if ( (arg - yydebug - cppflags - otherflags) == 2 )
X 		  outfile = margv[arg];
X 		else
X 		  FatalError ("Usage: et [-%s] [infile [outfile]]", CPPARGS);
X 	    } else {
X 		FatalError ("Usage: et [-%s] [infile [outfile]]", CPPARGS);
X 	    } /* end if a -argument */
X 	} else {	/* a filename - i guess */
X 	    if ( (arg - yydebug - cppflags - otherflags) == 1 )
X 	      infile = margv[arg];	
X 	    else if ( (arg - yydebug - cppflags - otherflags) == 2 )
X 	      outfile = margv[arg];
X 	    else
X 	      FatalError ("Usage: et [-d] [-q] [-%s] [infile [outfile]]", CPPARGS);
X 	} /* end if a filename argument */
X     }	/* done with parsing all of the arguments */
X     if (otherflags)
X       FatalError ("Usage: et [-%s] [infile [outfile]]", CPPARGS);
X     if (infile && strcmp(infile,"-") )
X       if (freopen (infile, "r", stdin) == NULL)
X 	FatalError ("Cannot open input stream/file:", infile);
X     if (outfile && strcmp(outfile,"-") )
X       if (freopen (outfile, "w", stdout) == NULL)
X 	FatalError ("Cannot open output stream/file:", outfile);
X     if (cppflags && cpp(margc,margv))
X 	FatalError ("Cannot open preprocessor", CPP);
X 
X	printf ("###################################################\n");
X	printf ("##                                               ##\n");
X	printf ("##  WARNING: THIS FILE IS THE OUTPUT OF THE      ##\n");
X	printf ("##           `EASE' PRECOMPILER FOR SENDMAIL     ##\n");
X	printf ("##           CONFIGURATION FILES.                ##\n");
X	printf ("##                                               ##\n");
X	printf ("##           MAKE MODIFICATIONS TO THE SOURCE    ##\n");
X	printf ("##           FILE ONLY.  CHANGES MADE DIRECTLY   ##\n");
X	printf ("##           TO THIS FILE WILL DISAPPEAR THE     ##\n");
X	printf ("##           NEXT TIME THAT EASE IS RUN.         ##\n");
X	printf ("##                                               ##\n");
X	printf ("###################################################\n");
X}
X
X/* cpp preprocessor code
X * copied from Schreiner and Friedman's book:
X * Introduction to Compiler Construction with Unix
X *
X * Bruce Barnett
X */
X
Xint cpp(argc,argv)
X     int argc;
X     char **argv;
X{
X    char **argp, *cmd;
X    extern FILE *yyin;	/* for lex input */
X    extern FILE *popen();
X    int i;
X
X    for (i = 0, argp = argv; *++argp; )
X      if (**argp == '-' &&
X	  index(CPPARGS, (*argp)[1]))
X	i+=strlen(*argp) + 1;
X    if ( ! (cmd = (char *) calloc(i + sizeof CPP, sizeof(char))))
X      return -1;	/* no room */
X    (void *) strcpy(cmd,CPP);
X    for (argp = argv; *++argp; )
X      if (**argp == '-' &&
X	  index(CPPARGS, (*argp)[1]))
X	strcat(cmd, " "), strcat(cmd, *argp);
X    if (yyin = popen(cmd,"r"))
X      i = 0;	/* all's well */
X    else
X      i = -1;	/* no preprocessor */
X    cfree(cmd);
X    return i;
X}
END_OF_src/main.c
if test 7308 -ne `wc -c <src/main.c`; then
    echo shar: \"src/main.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/symtab.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/symtab.c\"
else
echo shar: Extracting \"src/symtab.c\" \(6485 characters\)
sed "s/^X//" >src/symtab.c <<'END_OF_src/symtab.c'
X#ifdef FLUKE
X# ifndef LINT
X    static char RCSid[] = "@(#)FLUKE  $Header: /tmp_mnt/home/kreskin/u0/barnett/Src/Ease/ease/src/RCS/symtab.c,v 3.0 1991/02/22 18:50:27 barnett Exp $";
X# endif LINT
X#endif FLUKE
X
X/*
X *  	symtab.c   -- Contains Ease Translator symbol table routines.
X *
X *  	author     -- James S. Schoner, Purdue University Computing Center,
X *				        West Lafayette, Indiana  47907
X *
X *  	date       -- July 9, 1985
X *
X *	Copyright (c) 1985 by Purdue Research Foundation
X *
X *	All rights reserved.
X *
X * $Log: symtab.c,v $
X * Revision 3.0  1991/02/22  18:50:27  barnett
X * Added support for HP/UX and IDA sendmail.
X *
X * Revision 2.1  1990/01/30  15:55:54  jeff
X * SunOS/Ultrix/Ida additions Jan 25 1988 Bruce Barnett
X *
X * Revision 2.0  88/06/15  14:43:04  root
X * Baseline release for net posting. ADR.
X */
X
X#include "fixstrings.h"
X#include <stdio.h>
X#include <ctype.h>
X#include "symtab.h"
X
X#define ERRORMAILER "error"		/* predefined error mailer name */
X
Xextern void FatalError (),
X	    PrintWarning ();
X
Xstruct he *LookupSymbol ();
X
Xstruct Defmac {				/* predefined macro struct def  */
X	char *macname;
X	char  macrep;
X};
X
Xstatic struct he *SymTab[SST];		/* hash table base array        */
Xstatic struct Defmac MacDefs[] = {	/* predefined macros	        */
X			{"m_smtp",	'e'},
X			{"m_oname",	'j'},
X			{"m_uucpname",	'k'}, /* IDA */
X			{"m_ufrom",	'l'},
X			{"m_daemon",	'n'},
X			{"m_domain",	'm'},	/* SunOS */
X			{"m_addrops",	'o'},
X			{"m_defaddr",	'q'},
X			{"m_sitename",	'w'},
X			{"m_odate",	'a'},
X			{"m_adate",	'b'},
X			{"m_hops",	'c'},
X			{"m_udate",	'd'},
X			{"m_saddr",	'f'},
X			{"m_sreladdr",	'g'},
X			{"m_rhost",	'h'},
X			{"m_qid",	'i'},
X			{"m_pid",	'p'},
X			{"m_protocol",	'r'},
X			{"m_shostname", 's'},
X			{"m_ctime",	't'},
X			{"m_ruser",	'u'},
X			{"m_version",	'v'},
X			{"m_sname",	'x'},
X			{"m_stty",	'y'},
X			{"m_rhdir",	'z'},
X			{"sentinel",	'\0'}
X};
X
X/* FLUKE jps 28-apr-86 - Install some wired-in class names */
Xstatic struct Defmac ClassDefs[] = {	/* predefined classes */
X			{"c_myname",	'w'},
X			{"c_mydomain",	'm'},
X			{"class_sentinel",	'\0'}
X};
X
X/*
X *	DefScan () -- Scan symbol table to find macros, classes, mailers, 
X *		      and rulesets which have been referenced or declared, but
X *		      not defined.  A warning is printed for each such 
X *		      occurence.  This routine is usually called at the end
X *		      of a successful Ease translation.
X *
X */
Xvoid
XDefScan ()
X{
X	register int stindex;		/* symbol table hash index   */
X	register struct he *hcsearch;	/* hash chain search pointer */
X
X	for (stindex = 0; stindex < SST; stindex++) {
X		if ((hcsearch = SymTab[stindex]) != NULL)
X			while (hcsearch != NULL) {
X				if ((ISMACRO(hcsearch->idtype) && 
X				     isupper(hcsearch->idval.idc)) &&
X				     !ISMACRO(hcsearch->idd))
X					PrintWarning ("Macro not defined: %s\n", hcsearch->psb);
X#ifdef notdef
X				if (ISCLASS(hcsearch->idtype) && !ISCLASS(hcsearch->idd))
X#else
X				/* FLUKE jps 28-apr-86 */
X				/* print warnings for UPPER CASE names only */
X				if (ISCLASS(hcsearch->idtype) &&
X				    isupper(hcsearch->idval.idc) &&
X				    !ISCLASS(hcsearch->idd))
X#endif
X					PrintWarning ("Class not defined: %s\n", hcsearch->psb);
X				if (ISMAILER(hcsearch->idtype) && !ISMAILER(hcsearch->idd))
X					PrintWarning ("Mailer not defined: %s\n", hcsearch->psb);
X				if (ISRULESET(hcsearch->idtype) && !ISRULESET(hcsearch->idd))
X					PrintWarning ("Ruleset not defined: %s\n", hcsearch->psb);
X				hcsearch = hcsearch->phe;
X			}
X	}
X}
X				     
X
X/*
X *	InitSymbolTable () -- Invoked by main () to initialize the symbol table.
X *
X */
Xvoid
XInitSymbolTable ()
X{
X	int i;
X
X	for (i = 0; i < SST; i++)		/* initialize base array */
X		SymTab[i] = NULL;
X}
X
X
X/*
X *	PreLoad () -- Invoked by main () to preload special macro names 
X *		      and mailer declarations.
X *
X */
Xvoid
XPreLoad ()
X{
X	struct Defmac *macptr;
X	struct he     *symptr;
X
X	/* preload special (lower-case) macros */
X	for (macptr = &MacDefs[0]; (*macptr).macrep != '\0'; macptr++) {
X		symptr = LookupSymbol ((*macptr).macname);
X		symptr->idtype |= ID_MACRO;
X		symptr->idval.idc = (*macptr).macrep;
X	}
X
X	/* preload special (lower-case) classes */
X	for (macptr = &ClassDefs[0]; (*macptr).macrep != '\0'; macptr++) {
X		symptr = LookupSymbol ((*macptr).macname);
X		symptr->idtype |= ID_CLASS;
X		symptr->idval.idc = (*macptr).macrep;
X	}
X
X	/* preload error mailer declaration */
X	symptr = LookupSymbol (ERRORMAILER);
X	symptr->idtype |= ID_MAILER;
X	symptr->idd |= ID_MAILER;
X}
X	
X
X/*
X *	LookupSymbol () -- Returns a pointer to the hash entry already 
X *			   existing, or newly created, which corresponds 
X *			   to string sb.
X *
X */
Xstruct he *
XLookupSymbol (sb)
Xchar sb[];			/* string buffer containing identifier */
X{
X	struct he *phe;		/* hash entry search pointer  */
X	int	  hc;		/* hash code of sb identifier */
X	extern char *malloc ();
X
X	phe = SymTab[hc = HashCode (sb)];
X	while (phe != NULL)			/* find hash entry for sb */
X		if (!strcmp (phe->psb, sb))
X			return (phe);
X		else
X			phe = phe->phe;
X	/* make new symbol table entry */
X	if ((phe = (struct he *) malloc (sizeof (struct he))) == NULL)
X		FatalError ("System out of space in LookupSymbol ()", (char *) NULL);
X	if ((phe->psb = (char *) malloc (strlen (sb) + 1)) == NULL)
X		FatalError ("System out of space in LookupSymbol ()", (char *) NULL);
X	strcpy (phe->psb, sb);
X	phe->idval.idc = '\0';
X	phe->idtype = ID_UNTYPED;
X	phe->idd = ID_UNTYPED;
X	phe->phe = SymTab[hc];
X	return (SymTab[hc] = phe);
X}
X
X
X/*
X *	RemoveSymbol () -- Removes the symbol table entry phe from the 
X *			   symbol table.
X *
X */
Xvoid
XRemoveSymbol (phe)
Xstruct he *phe;	   /* pointer to hash entry to be removed from symbol table */
X{
X	int hc;	   		/* hash code of entry phe       */
X	struct he *sphe;	/* search pointer for entry phe */
X
X	if (phe == NULL)
X		return;
X	else {			/* search and remove entry phe  */
X		sphe = SymTab[hc = HashCode (phe->psb)];
X		free (phe->psb);
X		if (sphe == phe)
X			SymTab[hc] = phe->phe;
X		else
X			while (sphe != NULL)
X				if (sphe->phe == phe) {
X					sphe->phe = phe->phe;
X					return;
X				} else
X					sphe = sphe->phe;
X	}
X}
X
X
X/*
X *	HashCode () -- Returns the hash code of the string in sb by adding 
X *		       the character values and applying mod by the hash 
X *		       table size.
X *
X */
Xint
XHashCode (sb)
Xchar sb[];
X{
X	int ccSum = 0;			/* sum of char values in string sb */
X	int i;
X
X	for (i = 0; sb[i]; i++)		/* add char codes for sb chars     */
X		ccSum += sb[i];
X	return (ccSum % SST);		/* return sum mod table size	   */
X}
END_OF_src/symtab.c
if test 6485 -ne `wc -c <src/symtab.c`; then
    echo shar: \"src/symtab.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f test/test.mc -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"test/test.mc\"
else
echo shar: Extracting \"test/test.mc\" \(4506 characters\)
sed "s/^X//" >test/test.mc <<'END_OF_test/test.mc'
X/*
X * Sendmail configuration file for test rulesets
X *
X * Simon Kenyon November 20th, 1986
X */
X
Xbind
X	EnvelopeTo 		= ruleset  0;
X	From			= ruleset  1;
X	HeaderTo		= ruleset  2;
X	Canonicalize		= ruleset  3;
X	Externalize		= ruleset  4;
X
X	LocalHeaderFrom		= ruleset 10;
X	UucpHeaderFrom		= ruleset 11;
X
X	LocalHeaderTo		= ruleset 20;
X	UucpHeaderTo		= ruleset 21;
X
Xmacro
X	Domain		= "my_domain";
X	Version		= "ruleset tester V1.0";
X
X	m_sitename	= "whatever";
X	m_oname		= "${m_sitename}.${Domain}";
X	m_daemon	= "MAILER-DAEMON";
X	/*m_ufrom		= "From ${m_sreladdr}  ${m_udate} remote from ${m_sitename}";*/
X	m_ufrom		= "From ${m_sreladdr}  ${m_udate}";
X	m_addrops	= ".:%@!^=/[]{}";
X	m_defaddr	= concat (
X				ifset (m_sname, "${m_sname}	<${m_sreladdr}>",
X						"${m_sreladdr}"),
X				""
X			  );
X	m_smtp		= "${m_oname} Sendmail ${m_version}/${Version} ready at ${m_adate}";
X
Xoptions
X	o_alias		= "/usr/lib/aliases";
X	o_delivery	= d_background;
X	o_dmuid		= "1";
X	o_flog		= "/usr/lib/sendmail.st";
X	o_fsmtp		= "/usr/lib/sendmail.hf";
X	o_gid		= "1";
X	o_hformat	= "";
X	o_qdir		= "/usr/spool/mqueue";
X	o_qtimeout	= "3d";
X	o_safe		= "";
X	o_slog		= "9";
X	o_timezone	= "WET";
X	o_tmode		= "0644";
X	o_tread		= "r2h";
X	o_wizpass	= "*";
X
Xprecedence
X	first-class		=    0;
X	special-delivery	=  100;
X	junk			= -100;
X
Xtrusted
X	{root, daemon, uucp, network};
X	{simon};
X
Xheader
X	define ("a:", "The origination date in Arpanet format = ${m_odate}");
X	define ("b:", "The current date in Arpanet format = ${m_adate}");
X	define ("c:", "The hop count = ${m_hops}");
X	define ("d:", "The date in UNIX (ctime) format = ${m_udate}");
X	define ("e:", "The SMTP entry message = ${m_smtp}");
X	define ("f:", "The sender (from) address = ${m_saddr}");
X	define ("g:", "The sender address relative to the recipient = ${m_sreladdr}");
X	define ("h:", "The recipient host = ${m_rhost}");
X	define ("i:", "The queue id = ${m_qid}");
X	define ("j:", "The official domain name for this site = ${m_oname}");
X	define ("l:", "The format of the UNIX from line = ${m_ufrom}");
X	define ("n:", "The name of the daemon (for error messages) = ${m_daemon}");
X	define ("o:", "The set of operators in addresses = ${m_addrops}");
X	define ("p:", "Sendmail's pid = ${m_pid}");
X	define ("q:", "The default format of sender address = ${m_defaddr}");
X	define ("r:", "Protocol used = ${m_protocol}");
X	define ("s:", "Sender's host name = ${m_shostname}");
X	define ("t:", "A numeric representation of the current time = ${m_ctime}");
X	define ("u:", "The recipient user = ${m_ruser}");
X	define ("v:", "The version number of sendmail = ${m_version}");
X	define ("w:", "The hostname of this site = ${m_sitename}");
X	define ("x:", "The full name of the sender = ${m_sname}");
X	define ("y:", "The id of the sender's tty = ${m_stty}");
X	define ("z:", "The home directory of the recipient = ${m_rhdir}");
X
Xfield
X	path		: match (1*);
X
Xruleset Canonicalize {
X	if (path)
X		next ("{3}" $1);
X}
X
Xruleset EnvelopeTo {
X	if (path @ path)
X		resolve (mailer (uucp),
X			 host ("{0_uucp}" $2),
X			 user ("{0_uucp}" $1));
X	if (path ! path)
X		resolve (mailer (uucp),
X			 host ("{0_uucp}" $1),
X			 user ("{0_uucp}" $2));
X	if (path)
X		resolve (mailer (local),
X			 user ("{0_local}" $1));
X}
X
Xruleset From {
X	if (path)
X		return ("{1}" $1);
X}
X
Xruleset HeaderTo {
X	if (path)
X		return ("{2}" $1);
X}
X
Xruleset Externalize {
X	if (path)
X		return ("{4}" $1);
X}
X
Xruleset LocalHeaderFrom {
X	if (path)
X		return ("{S_local}" $1);
X}
X
Xruleset LocalHeaderTo {
X	if (path)
X		return ("{R_local}" $1);
X}
X
Xruleset UucpHeaderFrom {
X	if (path)
X		return ("{S_uucp}" $1);
X}
X
Xruleset UucpHeaderTo {
X	if (path)
X		return ("{R_uucp}" $1);
X}
X
Xmailer
X	local {
X		Path		= "/usr/src/local/EUnet/ease/test/args",
X		Flags		= {f_date,
X				   f_from,
X				   f_locm,
X				   f_mesg,
X				   f_mult,
X				   f_noufrom,
X				   f_rfrom,
X				   f_strip},
X		Sender		= LocalHeaderFrom,
X		Recipient 	= LocalHeaderTo,
X		Argv		= "args mail -d ${m_ruser}"
X	};
X	prog {
X		Path		= "/usr/src/local/EUnet/ease/test/args",
X		Flags		= {f_date,
X				   f_expensive,
X				   f_from,
X				   f_locm,
X				   f_mesg,
X				   f_noufrom,
X				   f_strip},
X		Sender		= LocalHeaderFrom,
X		Recipient 	= LocalHeaderTo,
X		Argv		= "args sh -c ${m_ruser}"
X	};
X	uucp {
X		Path		= "/usr/src/local/EUnet/ease/test/args",
X		Flags		= {f_date,
X				   f_from,
X				   f_mesg,
X				   f_strip,
X				   f_ufrom,
X				   f_upperh,
X				   f_upperu},
X		Sender		= UucpHeaderFrom,
X		Recipient 	= UucpHeaderTo,
X		Maxsize		= "65535",
X		Argv		= "args uumail -h -oc -gA -f${m_sreladdr} ${m_rhost}!${m_ruser}"
X	};
END_OF_test/test.mc
if test 4506 -ne `wc -c <test/test.mc`; then
    echo shar: \"test/test.mc\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 2 \(of 6\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 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
--
Bruce G. Barnett	barnett@crd.ge.com	uunet!crdgw1!barnett

barnett@grymoire.crd.ge.com (Bruce Barnett) (02/23/91)

#! /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 6)."
# Contents:  INTRO src/emitcf.c src/lexan.l src/strops.c
# Wrapped by barnett@grymoire on Sat Feb 23 01:13:53 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f INTRO -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"INTRO\"
else
echo shar: Extracting \"INTRO\" \(7739 characters\)
sed "s/^X//" >INTRO <<'END_OF_INTRO'
X		An introduction to Sendmail Rules
X		Copyright 1991, All rights reserved
X		Bruce Barnett
X
X	First of all, sendmail is easy to learn, once you learned all
Xabout electronic mail. Figuring out how to handle the address
X
X	bigvax::a!b!another.domain!c%d%domain.com@another.domain
X
Xis much more challenging. Here's the scoop.
X
X	When sendmail gets a, address, it always passes it to rule 3.
X
X	Rule 3 with transform the address, and eventually sent it to
X	rule 0.
X
X	Rule 0 makes the final decision, and selects three things:
X
X			The address
X			The Machine to send the address to
X			The mailer to use.
X				This could be UUCP, ethernet, DECNet,
X				a local user, a program, etc.
X
X	Once the above has been decided on, the address is transformed
X	in the following way:
X
X	Ruleset 1 is applied to the From: line
X	Ruleset 2 is applied to the To: and Cc: line
X	
X	Each mailer then applies a rule. These rules are other unique
X	for each mailer.
X
X	Finally ruleset 4 is applied.
X
X
XNow let's go through an example in detail.
X
Xgrymoire% /usr/lib/sendmail -bt -C/etc/sendmail.cf
XADDRESS TEST MODE
XEnter <ruleset> <address>
X> 0 user@crdgw1.crd		# <---- I typed this line here 
Xrewrite: ruleset  3   input: "user" "@" "crdgw1" "." "crd"
Xrewrite: ruleset  6   input: "user" "<" "@" "crdgw1" "." "crd" ">"
Xrewrite: ruleset  6 returns: "user" "<" "@" "crdgw1" "." "LOCAL" ">"
Xrewrite: ruleset  3 returns: "user" "<" "@" "crdgw1" "." "LOCAL" ">"
Xrewrite: ruleset  0   input: "user" "<" "@" "crdgw1" "." "LOCAL" ">"
Xrewrite: ruleset  0 returns: $# "ether" $@ "crdgw1" $: "user" "<" "@" "crdgw1" ">"
X> 
X
XRule 3 can be given any address at all. It must determine the machine
Xand domain which corresponds to the address. Determining the machine
Xcan be tricky, because it depends o the address. What it uses to
Xspecify the address is to surround the hostname and @ sign with angle brackets.
XIt also added a imaginary domain to the hostname to indicate the type
Xof network it is on. The set of angle brackets is used to "focus" on a machine.
X
XSome typical values are:
X
X	< @ machine . LOCAL > 	=> a local host
X	< @ machine >		=> same as above
X	< @ machine . UUCP >	=> a machine on the UUCP network
X
XThe angle brackets indicate the important part - the machine and
Xperhaps what mail agent to use. However, the username isn't included
Xin the set of charatcers surrounded by angle brackets. The problem is,
Xdifferent mailers have the username in a different format. In some
Xcasess, the host is the first word, in others it's the last word.
X
XHere is an example of an address going into rule 3 and the expected
Xoutput:
X
X	Input		Output
X	a!b!c!d!user		<@a.UUCP>!b!c!d!user
X	user@a.uucp		user<@a.uucp>
X	bigvax::user		user<@bigvax.DECNET>
X	user%a.com@b.edu	user%a.com<@b.edu>	
X	a!b!user@abc.edu	a!b!user<@abc.edu>
X	@a:user@b.com		<@a>:user@b.com
X
XAs you can see, the machine that will accept the message will be
Xdifferent depending on the address. Ruleset 3 must find the right
Xmachine, and also clean up any addresses if appropriate.
XIt does it's work by looking for a pattern, and transforming the
Xaddress when it matches the pattern.
X
XThe cleaning up part can be confusing, but typically ruleset 3 calls
Xother rules to do this. One rule is used to clean up addresses before
Xthe < and > are added. Another rule is used to clean up addresses
Xafter it has been converted into the < @ machine > format.
X
XHere is the ease version of the rule that transforms a UUCP address:
X
X	if ( exactly_one ! one_or_more )	/* uucphost!user */
X		return (RULESET_6 ($2<@$1."uucp">));
X
XThis transforms the address, but calls ruleset 6, which cleans up the
Xaddresses with < and >. The variables "exactly_one" and "one_or_more"
Xmatch that number of tokens, and are replaced by the $1 or $2 on the 
Xreturned rule. ($1 is exactly_one, $2 is one_or_more).
X
XHere is a rule in ruleset 6 that looks for an address to the local
Xdomain, and replaces the domain with "LOCAL":
X
X	if ( zero_or_more <@ zero_or_more  any_in_mydomainname > zero_or_more )	/* convert local domain */
X		retry ($1<@$2"LOCAL">$4);
X
Xzero_or_more is a pattern, which matches $1, $2, or $4.
Xany_in_mydomain is a special pattern that matches the domain. It is
Xnot necessary to have a $3 because the domain is known.
XSo the test of the address user@crdgw1.crd reports this:
X
Xrewrite: ruleset  3   input: "user" "@" "crdgw1" "." "crd"
Xrewrite: ruleset  6   input: "user" "<" "@" "crdgw1" "." "crd" ">"
Xrewrite: ruleset  6 returns: "user" "<" "@" "crdgw1" "." "LOCAL" ">"
Xrewrite: ruleset  3 returns: "user" "<" "@" "crdgw1" "." "LOCAL" ">"
X
XOnce ruleset 3 is down, it passes the address to 0.
XThis eventually gets to the rule:
X
X/* deliver to known ethernet hosts explicitly specified in our domain */
X	if ( zero_or_more <@ any_in_etc_hosts."LOCAL"> zero_or_more )	/* user@host.sun.com */
X		resolve (mailer (ether),
X				host ($2 ),
X				user ($1<@$2>$3));
X
XThis matches, so the ether mailer is used, and the address is
X$1<@2>$3, or in this case:
X
X
Xrewrite: ruleset  0 returns: $# "ether" $@ "crdgw1" $: "user" "<" "@" "crdgw1" ">"
X
XThe $#, $@, and $: are sendmail talk for the mailer, machine, and
Xaddress. 
X
XStill more to come. The specificalion of the mailer is:
X
Xmailer
X	ether {
X		Path = "[TCP]",
X		Flags = { f_mult, f_strip, f_date, f_from, f_mesg, f_upperu, f_addrw, f_dot },
X		Sender = RULESET_11,
X		Recipient = RULESET_21,
X		Argv = "TCP ${m_rhost}"
X	};
X
X
XThis says the sender's address must go thru rule 11, which means rules
X1, 11, and 4. The recipient's address goes through 2, 21, and 4.
X
XTo test this, type the address from ruleset 0 and specify either 1,
X11, and 4 or perhaps 2, 21, and 4:
X
X> 1,11,4 user@crdgw1
Xrewrite: ruleset  3   input: "user" "@" "crdgw1"
Xrewrite: ruleset  6   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  6 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  3 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  1   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  1 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset 11   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset 11 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  4   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  9   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  9 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  4 returns: "user" "@" "crdgw1"
X
XAs you can see, ruleset 3 is always applied first, which calls 6, 
XThen rule 1 is applied, followed by rule 11, and then followed by
Xrule 4. The end result tells me the From: line would look like
Xuser@crdgw1
X
X
XThe uucp mailer has a diffent set of rewrite rules.
XIn sun's sendmail.main.cf, it uses 13 and 23. To test this address,
XI typed 1,13,4 and got this:
X
X> 1,13,4 user@crdgw1
Xrewrite: ruleset  3   input: "user" "@" "crdgw1"
Xrewrite: ruleset  6   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  6 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  3 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  1   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  1 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset 13   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  5   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  5 returns: "crdgw1" "!" "user"
Xrewrite: ruleset 13 returns: "grymoire" "!" "crdgw1" "!" "user"
Xrewrite: ruleset  4   input: "grymoire" "!" "crdgw1" "!" "user"
Xrewrite: ruleset  9   input: "grymoire" "!" "crdgw1" "!" "user"
Xrewrite: ruleset  9 returns: "grymoire" "!" "crdgw1" "!" "user"
Xrewrite: ruleset  4 returns: "grymoire" "!" "crdgw1" "!" "user"
X> 
X
XAs you can see, it converted the address into a uucp path relative to
Xmy machine.
X
XTo test these three cases, add the following to your debug.in file:
X
X0	user@crdgw1
X1,11,4	user@crdgw1	From_Ethernet_to_Ethernet
X1,13,4	user@crdgw1	From_Ethernet_to_UUCP
X
END_OF_INTRO
if test 7739 -ne `wc -c <INTRO`; then
    echo shar: \"INTRO\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/emitcf.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/emitcf.c\"
else
echo shar: Extracting \"src/emitcf.c\" \(7850 characters\)
sed "s/^X//" >src/emitcf.c <<'END_OF_src/emitcf.c'
X#ifdef FLUKE
X# ifndef LINT
X    static char RCSid[] = "@(#)FLUKE  $Header: /tmp_mnt/home/kreskin/u0/barnett/Src/Ease/ease/src/RCS/emitcf.c,v 3.0 1991/02/22 18:50:27 barnett Exp $";
X# endif LINT
X#endif FLUKE
X
X/*
X *	emitcf.c  -- This file contains routines associated with the writing
X *		     and formatting of a translated sendmail configuration file.
X *
X *	author	  -- James S. Schoner, Purdue University Computing Center,
X *			  	       West Lafayette, Indiana  47907
X *
X *  	date	  -- July 9, 1985
X *
X *	Copyright (c) 1985 by Purdue Research Foundation
X *
X *	All rights reserved.
X *
X * $Log: emitcf.c,v $
X * Revision 3.0  1991/02/22  18:50:27  barnett
X * Added support for HP/UX and IDA sendmail.
X *
X * Revision 2.1  1990/01/30  14:09:49  jeff
X * Changes by Bruce Barnett - extensions for SunOS/Ultrix.
X *
X * Revision 2.0  88/06/15  14:40:47  root
X * Baseline release for net posting. ADR.
X */
X
X#include <stdio.h>
X#include "symtab.h"
X#include "fixstrings.h"
X
X#define REGLINE 60	/* length of output lines which may be continued */
X#define MAXLINE 256	/* liberal maximum line length			 */
X
Xextern short Rformat;			/* read-format flag for a class  */
Xextern char *MacScan ();
Xextern char  MakeMac ();
Xextern void  PrintError (),
X	     FatalError (),
X	     PrintWarning (),
X	     ErrorReport ();
X
Xvoid  PrintDef ();
X
Xstatic char ClassCH;			/* printable class macro char    */
X
X/*
X *	EmitDef () -- Emit a definition line (Ease block definition) in cf 
X *		      format.
X *
X */
Xvoid
XEmitDef (blockdef, targ, defstr1, defstr2)
Xregister enum bdefs blockdef;	/* type of definition   	 */
Xregister struct he *targ;	/* target to be defined 	 */
Xchar *defstr1, *defstr2;	/* one or two definition strings */
X{
X	/*
X	 *  This routine is about as pretty as a translated ease file...
X	 *  Each type of line (Ease block) is handled case by case below.
X	 *
X	 */
X	switch (blockdef) {
X		case def_macro:		printf ("D%c", MakeMac (targ, ID_MACRO));
X					PrintDef (def_macro, MacScan (defstr1));
X					if (ISMACRO(targ->idd))
X						PrintWarning ("Redefining macro %s.\n", targ->psb);
X					targ->idd |= ID_MACRO;  /* signal definition */
X					break;
X
X		case def_class:		if (Rformat)	/* read format */
X						printf ("F");
X					else
X						printf ("C");
X					printf ("%c", ClassCH = MakeMac (targ, ID_CLASS));
X					if (Rformat) {	/* read format */
X						printf ("%s\n", defstr1);
X						Rformat = FALSE;
X					} else
X						PrintDef (def_class, MacScan(defstr1));
X					if (ISCLASS(targ->idd))
X						PrintWarning ("Appending to previously defined class %s.\n", targ->psb);
X					targ->idd |= ID_CLASS;  /* signal definition */
X					break;
X
X		case def_option:	if (defstr1 == NULL)
X						FatalError ("No option passed in EmitDef()", (char *)NULL);
X					printf ("O%c", *defstr1);
X					PrintDef (def_option, defstr2);
X					break;
X
X		case def_prec:		printf ("P%s=%d\n", targ->psb, targ->idval.prec);
X					break;
X
X		case def_trusted:	printf ("T");
X					PrintDef (def_trusted, defstr1);
X					break;
X
X		case def_header:	printf ("H");
X					if (defstr1 != NULL)
X						printf ("?%s?", defstr1);
X					PrintDef (def_header, defstr2);
X					break;
X
X		case def_mailer:	if (ISMAILER(targ->idtype)) {
X						if (ISMAILER(targ->idd))
X							PrintWarning ("Redefining mailer %s.\n", targ->psb);
X					} else if (ISTYPED(targ->idtype)) {
X						PrintError ("Redeclaration of identifier as mailer: %s", targ->psb);
X						return;
X					}
X					targ->idd |= ID_MAILER;  /* signal definition */
X					printf ("M%s, ", targ->psb);
X					PrintDef (def_mailer, defstr1);
X					break;
X
X		case def_ruleset:	printf ("R");
X					PrintDef (def_ruleset, defstr1);
X					break;
X
X		default:		FatalError ("Bad case in EmitDef ()", (char *) NULL);
X	}
X}
X
X
X/*
X *  	PrintContinued () -- Print a line definition (buf) by splitting it over
X *			     more than one line.  The two definition types 
X *			     accepted for this method of continuation are class
X *			     and trusted user lists, indicated in the argument 
X *			     btype 
X *
X */
Xvoid
XPrintContinued (btype, buf)
Xenum bdefs     btype;	/* block (line) type for definition */
Xregister char *buf;	/* buffer containing the definition */
X{
X	register char *tmp;	/* breakpoint search pointer   */
X	register char  tc;	/* temporary swap byte         */
X	int  buflen;		/* length of definition buffer */	
X
X	buflen = strlen (buf);
X	tmp = buf + REGLINE;
X	while ((*--tmp != ' ') && (tmp != buf))	 /* look for suitable break */
X		/* null */ ;
X	if (tmp == buf) {
X		for (tmp = buf + REGLINE; (*tmp != ' ') && (tmp - buf != buflen); tmp++)
X			/* null */ ;
X		if ((tmp - buf) >= MAXLINE)
X			PrintWarning ("Member name may be too long.\n", (char *) NULL);
X	}
X	tc = *tmp;		/* swap break char with null char */
X	*tmp = '\0';
X	printf ("%s\n", buf);
X	if ((*tmp = tc) == '\0')
X		return;
X	else
X		tmp++;
X	if (btype == def_class)		/* start next line   */
X		printf ("C%c", ClassCH);
X	else
X		printf ("T");
X	if (strlen (tmp) < REGLINE)	/* continue the line */
X		printf ("%s\n", tmp);
X	else
X		PrintContinued (btype, tmp);
X}
X
X
X/*
X *	PrintDef () -- Handles special cases (like line continuation) when 
X *		       printing definitions.
X *
X */
Xvoid
XPrintDef (btype, dstr)
Xregister enum bdefs btype;	/* block type (output line type) */
Xregister char *dstr;		/* definition string		 */
X{
X	register char *tmp;
X
X	if (dstr == (char *)NULL)
X		dstr = "";
X
X	for (tmp = dstr; *tmp != '\0'; tmp++) 	/* search for line continuations */
X		if ((*tmp == '\\') && (*++tmp == '\n'))
X			if (btype != def_header) {
X				ErrorReport ("Non-header string contains line continuation\n");
X				return;
X			} else
X				break;
X
X	/*
X	 *  Perform case by case handling of definition printing.
X	 *
X	 */
X	switch (btype) {
X		case def_header :  if (*tmp-- == '\n') {
X					*tmp = '\0';
X					if (tmp - dstr >= MAXLINE)
X						PrintWarning ("Header may be too long.\n", 
X							      (char *) NULL);
X					printf ("%s\n\t", dstr);
X					tmp += 2;
X				        PrintDef (def_header, tmp);
X				   } else {
X					if (strlen (dstr) >= MAXLINE)
X						PrintWarning ("Header may be too long.\n", 
X							      (char *) NULL);
X					printf ("%s\n", dstr);
X				   }
X				   break;
X
X		case def_mailer :  if (strlen (dstr) >= MAXLINE)
X					PrintWarning ("Mailer definition may be too long.\n", 
X						      (char *) NULL);
X				   printf ("%s\n", dstr);
X				   break;
X
X		case def_ruleset:  if (strlen (dstr) >= MAXLINE)
X					PrintWarning ("Rewriting rule may be too long.\n", 
X						      (char *) NULL);
X				   printf ("%s\n", dstr);
X				   break;
X
X		case def_option :  if (strlen (dstr) >= MAXLINE)
X					PrintWarning ("Option assignment may be too long.\n", 
X						      (char *) NULL);
X				   printf ("%s\n", dstr);
X				   break;
X
X		case def_macro  :  if (strlen (dstr) >= MAXLINE)
X					PrintWarning ("Macro assignment may be too long.\n", 
X						      (char *) NULL);
X				   printf ("%s\n", dstr);
X				   break;
X
X		case def_prec   :  if (strlen (dstr) >= MAXLINE)
X					PrintWarning ("Precedence relation may be too long.\n", 
X						      (char *) NULL);
X				   printf ("%s\n", dstr);
X				   break;
X
X		case def_trusted:
X		case def_class  :  if (strlen (dstr) < REGLINE)
X					printf ("%s\n", dstr);
X				   else		/* use line continuation feature */
X				   	PrintContinued (btype, dstr);
X				   break;
X
X		default         :  FatalError ("Invalid case in PrintDef ()", (char *) NULL);
X	}
X}
X
X
X/*
X *	StartRuleset () -- Prints a ruleset heading for the ruleset identifier
X *		           contained in the argument rsid.
X *
X */
Xvoid
XStartRuleset (rsid)
Xregister struct he *rsid;	/* ruleset identifier */
X{
X	if (!ISRULESET(rsid->idtype))
X		if (ISTYPED(rsid->idtype))
X			PrintError ("Identifier not of ruleset type: %s", rsid->psb);
X		else
X			PrintError ("Ruleset identifier not bound to a number: %s", rsid->psb);
X	else {
X		if (ISRULESET(rsid->idd))
X			PrintWarning ("Redefining ruleset %s.\n", rsid->psb);
X		rsid->idd |= ID_RULESET;
X		printf ("S%s\n", rsid->idval.rsn);
X	}
X}
END_OF_src/emitcf.c
if test 7850 -ne `wc -c <src/emitcf.c`; then
    echo shar: \"src/emitcf.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/lexan.l -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/lexan.l\"
else
echo shar: Extracting \"src/lexan.l\" \(8488 characters\)
sed "s/^X//" >src/lexan.l <<'END_OF_src/lexan.l'
X%{
X
X#ifdef FLUKE
X# ifndef LINT
X    static char RCSid[] = "@(#)FLUKE  $Header: /tmp_mnt/home/kreskin/u0/barnett/Src/Ease/ease/src/RCS/lexan.l,v 3.0 1991/02/22 18:50:27 barnett Exp $";
X# endif LINT
X#endif FLUKE
X
X/*
X *	lexan.l -- Lexical Analyzer for EASE.
X *
X *		   Contains code for lex(1) which generates a lexical
X *		   analyzer (lex.yy.c) for Ease, a high-level specification 
X *		   format for sendmail configuration files.
X *
X *	author -- James S. Schoner, Purdue University Computing Center,
X *				    West Lafayette, Indiana  47907
X *
X *	date   -- July 1, 1985
X *
X *	Copyright (c) 1985 by Purdue Research Foundation
X *
X *	All rights reserved.
X *
X * $Log: lexan.l,v $
X * Revision 3.0  1991/02/22  18:50:27  barnett
X * Added support for HP/UX and IDA sendmail.
X *
X * Revision 2.3  1991/02/12  20:49:34  barnett
X * Added several new tokens.
X * Merged Jeff's changes with my own.
X *
X * Revision 2.2  1990/05/07  11:12:53  jeff
X * Add support for the "Cflag" variable which controls whether or not
X * input lines are passed through as comments in the output stream.
X *
X * Version 2.1  90/01/30  15:26:23  jeff
X * If -C flag is specified, emit input as comments in the output stream.
X * 
X * Revision 2.0  88/06/15  15:11:30  root
X * Baseline release for net posting. ADR.
X * 
X */
X
X#include "fixstrings.h"
X#include "symtab.h"
X#include "lexdefs.h"
X
X#define  LEXnewline '\n'
X#define	 LEXeof	    '\0'
X#define  MaxFN	    200			/* maximum file name length */
X
Xextern int	  EchoInputAsComments;
Xextern struct he *LookupSymbol ();
Xextern void	  ErrorReport ();
Xextern void	  yymark();
X
Xint  Lcount;				/* line counter		    */
Xchar FNbuf[MaxFN];			/* file name buffer	    */
Xshort RMatch  = FALSE;			/* ruleset match flag  	    */
X
X#ifdef YYDEBUG
Xextern int yychar;
X#else
Xint   yychar;
X#endif
X
X#undef input
X# define input() (((yytchar=yychar=yysptr>yysbuf?U(*--yysptr):Getc(yyin,yyout))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar)
X
Xchar
XGetc (yyin, yyout)
X	FILE *yyin, *yyout;
X{
X	static char linbuf[BUFSIZ], *pc = linbuf;
X	char c;
X
X	/* initialize buffer: first call only */
X	if (*pc == '\0' && pc == linbuf) {
X		if (fgets(linbuf, BUFSIZ, yyin)==NULL)
X			return EOF;
X		/* echo input as comment */
X		if (EchoInputAsComments) {
X		    fprintf(yyout, "%s%s", (linbuf[0] == '#' ? "" : "# "), linbuf);
X		}
X	}
X	c = *pc++;
X	if (c == '\n') {
X		pc = linbuf;
X		if (fgets(linbuf, BUFSIZ, yyin) == NULL)
X			*pc = EOF;
X		else
X			/* echo input as comment (except cpp comments) */
X			if (EchoInputAsComments) {
X			    fprintf(yyout, "%s%s",
X				(linbuf[0] == '#' ? "" : "# "), linbuf);
X			}
X	}
X	return c;
X}
X
X/*
X * Table of keywords. NOTE: This is in sorted order, and
X * must stay that way if anything else is added to it.
X */
Xstatic struct resword {
X	char	*r_text;
X	int	r_tokval;
X} reswords[] = {
X	{ "Argv",		MARGV },
X	{ "Eol",		MEOL },
X	{ "Flags",		MFLAGS },
X	{ "Maxsize",		MMAXSIZE },
X	{ "Path",		MPATH },
X	{ "Recipient",		MRECIPIENT },
X	{ "Sender",		MSENDER },
X 	{ "alias",		ALIAS },
X 	{ "asm",		ASM },
X	{ "bind",		BIND },
X	{ "canon",		CANON },
X	{ "class",		CLASS },
X	{ "concat",		CONCAT },
X	{ "d_background",	DOPTB },
X	{ "d_interactive",	DOPTI },
X	{ "d_queue",		DOPTQ },
X	{ "default",		DEFAULT }, /* IDA */
X	{ "define",		DEFINE },
X 	{ "eval",		EVAL },
X	{ "f_addrw",		CCFLAG },
X	{ "f_arpa",		AAFLAG },
X 	{ "f_bsmtp",		BBFLAG },	/* IDA */
X	{ "f_date",		DDFLAG },
X	{ "f_dot",		XXFLAG },
X	{ "f_escape",		EEFLAG },
X	{ "f_expensive",	EFLAG },
X	{ "f_ffrom",		FFLAG },
X	{ "f_from",		FFFLAG },
X	{ "f_full",		XFLAG },
X	{ "f_llimit",		LLFLAG },
X	{ "f_locm",		LFLAG },
X	{ "f_mail11",		HHFLAG },  /* Ultrix */
X	{ "f_mesg",		MMFLAG },
X	{ "f_mult",		MFLAG },
X	{ "f_noreset",		SSFLAG },
X	{ "f_noufrom",		NFLAG },
X 	{ "f_relativize",	VVFLAG },	/* IDA */
X	{ "f_retsmtp",		PFLAG },
X	{ "f_return",		PPFLAG },
X	{ "f_rfrom",		RFLAG },
X	{ "f_rport",		RRFLAG },
X	{ "f_smtp",		IIFLAG },
X	{ "f_strip",		SFLAG },
X	{ "f_ufrom",		UUFLAG },
X	{ "f_upperh",		HFLAG },
X	{ "f_upperu",		UFLAG },
X	{ "field",		FIELD },
X	{ "for",		FOR },
X	{ "h_exit",		EOPTE },
X	{ "h_mail",		EOPTM },
X	{ "h_mailz",		EOPTZ },
X	{ "h_print",		EOPTP },
X	{ "h_write",		EOPTW },
X	{ "header",		HEADER },
X	{ "host",		HOST },
X	{ "hostnum",		HOSTNUM },
X	{ "if",			IF },
X	{ "ifset",		IFSET },
X	{ "in",			IN },
X	{ "macro",		MACRO },
X	{ "mailer",		MAILER },
X	{ "map",		MAP },
X	{ "match",		MATCH },
X	{ "next",		NEXT },
X	{ "o_alias",		AAOPT },
X 	{ "o_aliasfile",	YYOPT },	/* SunOS */
X	{ "o_bsub",		BBOPT },
X	{ "o_checkpoint",	CCOPT },
X	{ "o_delivery",		DOPT },
X	{ "o_dmuid",		UOPT },
X	{ "o_dnet",		NNOPT },
X 	{ "o_envelope",		SLOPT },	/* IDA */
X	{ "o_ewait",		AOPT },
X	{ "o_flog",		SSOPT },
X	{ "o_fsmtp",		HHOPT },
X	{ "o_gid",		GOPT },
X	{ "o_handling",		EOPT },
X	{ "o_hformat",		OOPT },
X	{ "o_loadnc",		XXOPT },
X	{ "o_loadq",		XOPT },
X	{ "o_maxempty",		BOPT },	/* SunOS */
X 	{ "o_maxhops",		HOPT }, /* SunOS */
X  	{ "o_nameserver",	IIOPT }, /* HP/UX */
X  	{ "o_newproc",		YYOPT },
X 	{ "o_nfs",		RROPT },	/* SunOS 4.0 */
X	{ "o_pmaster",		PPOPT },
X	{ "o_prifactor",	ZOPT },
X	{ "o_qdir",		QQOPT },
X	{ "o_qfactor",		QOPT },
X	{ "o_qtimeout",		TTOPT },
X	{ "o_qwait",		COPT },
X	{ "o_rebuild",		DDOPT },
X	{ "o_recipfactor",	YOPT },
X	{ "o_rsend",		MOPT },
X	{ "o_safe",		SOPT },
X	{ "o_skipd",		IOPT },
X	{ "o_slog",		LLOPT },
X	{ "o_timezone",		TOPT },
X	{ "o_tmode",		FFOPT },
X	{ "o_tread",		ROPT },
X	{ "o_usave",		FOPT },
X	{ "o_validate",		NOPT },
X	{ "o_verbose",		VOPT },
X	{ "o_waitfactor",	ZZOPT },
X	{ "o_wizpass",		WWOPT },
X	{ "options",		OPTIONS },
X	{ "precedence",		PRECEDENCE },
X 	{ "program",		PROGRAM },	/* HP/UX */
X 	{ "quote",		QUOTE },
X	{ "readclass",		READCLASS },
X	{ "resolve",		RESOLVE },
X 	{ "resolved",		RESOLVED },
X	{ "retry",		RETRY },
X	{ "return",		RETURN },
X	{ "ruleset",		RULESET },
X	{ "trusted",		TRUSTED },
X	{ "user",		USER },
X	{ "while",		IF },
X 	{ "ypalias",		YPALIAS },	/* Ultrix */
X 	{ "ypmap",		YPMAP },	/* SunOS */
X 	{ "yppasswd",		YPPASSWD },	/* Ultrix */
X};
X%}
X
X%%
X	int INch;			/* any input character */
X
X[ \t\f]+			; 	/* discard whitepsace  */
X[\n]				Lcount++;
X^\#[ \t]*[0-9]+[ \t]*\".*\"[ \t]*.*[\n]	{
X/*			        sscanf (yytext, "%*c%d%s", &Lcount, FNbuf); */
X	                        yymark();
X			        }
X[A-Za-z_][A-Za-z0-9_-]*		{
X				register int l, h, m, r, c;
X
X				l = 0;
X				h = (sizeof (reswords) / sizeof(reswords[0])) - 1;
X				while (l <= h) {
X					m = (h + l) / 2;
X					c = yytext[0] - reswords[m].r_text[0];
X					r = c ? c : strcmp (yytext, reswords[m].r_text);
X					if (r < 0)
X						h = m - 1;
X					else if (r > 0)
X						l = m + 1;
X					else
X						return reswords[m].r_tokval;
X				}
X
X				/* not a keyword */
X
X				/* store identifiers in symbol table */
X				yylval.phe = LookupSymbol (yytext);
X				return (IDENT);
X				}
X["]((\\\n)|(\\\")|[^"\n])*	{
X				if ((INch = input()) == LEXnewline) {
X					ErrorReport ("End of line in string.\n");
X					unput (INch);
X				}
X				fixquotes ();
X				yylval.psb = (char *) malloc (strlen (yytext) + 1);
X				strcpy (yylval.psb, yytext + 1);
X				return (SCONST);
X				}
X[0][0-7]*			{
X				sscanf (yytext, "%o", &yylval.ival);  /* octal constant */
X				return (ICONST);
X				}
X[-]?[1-9][0-9]*			{
X				yylval.ival = atoi (yytext);
X				return (ICONST);
X				}
X"="				return (ASGN);
X","				return (COMMA);
X"{"				return (LBRACE);
X"}"				return (RBRACE);
X"("				return (LPAREN);
X")"				return (RPAREN);
X";"				return (SEMI);
X"$"				return (DOLLAR);
X":"				return (COLON);
X"*"				return (STAR);
X"/*"				{
X				/* eat C comments */
X				INch = input ();
X				while ((INch != '*') || 
X				      ((INch = input ()) != '/')) {
X					if (INch == LEXnewline)
X						Lcount++;
X					else
X						if (INch == LEXeof) {
X							ErrorReport ("End of file in comment.\n");
X							break;
X						}
X					if (INch != '*')
X						INch = input ();
X				}
X				}
X"/"				return (SLASH);
X[\\]?.				{
X				if (RMatch) {	/* in rulesets, return literal character */
X					yylval.ival = (yytext[0] == '\\') ? yytext[1] : yytext[0];
X					return (SEPCHAR);
X				} else {
X					PrintError ("Illegal delimiter character: (octal code) \\%03o", *yytext);
X				}
X				}
X%%
X
X/*
X * fixquotes --- inside a "quoted string", turn `\"' into just `"'
X *
X * this is most useful inside the Argv strings for mailers,
X * particularly when debugging.
X */
X
Xfixquotes ()
X{
X	register char *cp1, *cp2;
X
X	cp1 = cp2 = yytext;
X	while (*cp2) {
X		/*
X		 * if we really wanted to get fancy,
X		 * at this point we'd handle C escapes,
X		 * but I don't think it's necessary.
X		 */
X		if (*cp2 == '\\' && cp2[1] == '"')
X			cp2++;
X		*cp1++ = *cp2++;
X	}
X	*cp1++ = *cp2++;	/* final '\0' */
X}
END_OF_src/lexan.l
if test 8488 -ne `wc -c <src/lexan.l`; then
    echo shar: \"src/lexan.l\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/strops.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/strops.c\"
else
echo shar: Extracting \"src/strops.c\" \(14822 characters\)
sed "s/^X//" >src/strops.c <<'END_OF_src/strops.c'
X#ifdef FLUKE
X# ifndef LINT
X    static char RCSid[] = "@(#)FLUKE  $Header: /tmp_mnt/home/kreskin/u0/barnett/Src/Ease/ease/src/RCS/strops.c,v 3.0 1991/02/22 18:50:27 barnett Exp $";
X# endif LINT
X#endif FLUKE
X
X/*
X *	strops.c   -- Contains string operation routines used for constructing
X *		      definitions in cf format.
X *
X *	author	   -- James S. Schoner, Purdue University Computing Center,
X *				        West Lafayette, Indiana  47907
X *
X *	date	   -- July 9, 1985
X *
X *	Copyright (c) 1985 by Purdue Research Foundation
X *
X *	All rights reserved.
X *
X * $Log: strops.c,v $
X * Revision 3.0  1991/02/22  18:50:27  barnett
X * Added support for HP/UX and IDA sendmail.
X *
X * Revision 2.1  1990/01/30  15:52:55  jeff
X * Added SunOS/Ultrix/IDA extensions  Jan 24, 1989 Bruce Barnett
X *
X * Revision 2.0  88/06/15  14:42:55  root
X * Baseline release for net posting. ADR.
X */
X
X#include "fixstrings.h"
X#include <stdio.h>
X#include <strings.h>
X#include <ctype.h>
X#include "symtab.h"
X
X#define MAXTOKPOS   99		/* maximum number of token positions */
X#define MAXNAME	    1024	/* maximum length of an identifier   */
X
Xextern struct he *LookupSymbol ();
Xextern char       MakeMac ();
Xextern void	  FatalError (),
X		  PrintError (),
X		  ErrorReport ();
X
Xshort  Rformat = FALSE;			/* class read format flag	  */
Xstatic char   *Ptok   = "$  ";		/* positional token structure     */
Xstatic char   *Cfield = "$= ";		/* class reference structure	  */
Xstatic char   *Ofield = "$-";		/* one token match structure	  */
Xstatic char   *Zfield = "$*";		/* zero or more tokens structure  */
Xstatic char   *Pfield = "$+";		/* one or more tokens structure	  */
X
X/*
X *  FLUKE jps 25-apr-86
X *
X *  Add the three new $%x, $%y, and $!x match operators that Sun introduced
X *  with release 3.0.
X *
X *  BUG (probably) - Sun has assigned a predefined meaning to the $y macro;
X *  I imagine we will need to teach ease to avoid this letter.
X */
Xstatic char   *Hfield = "$%y";		/*    match in /etc/hosts */
Xstatic char   *Mfield = "$% ";		/*    match in specified YP map */
Xstatic char   *Nfield = "$! ";		/* no match in specified YP map */
X
Xstatic char   *Mtest  = "$? ";		/* conditional macro test string  */
X
X
X/*
X *	ConvOpt () -- Convert an Ease option identifier (optid) by returning a
X *		      string representation of the cf format.  
X *
X */
Xchar *
XConvOpt (optid) 
Xregister enum opts optid;
X{
X	switch (optid) {
X		case opt_A  :	return ("A");
X		case opt_a  :	return ("a");
X		case opt_B  :	return ("B");
X		case opt_b  :	return ("b");
X		case d_opt_b:	return ("b");
X		case opt_C  :	return ("C");
X		case opt_c  :	return ("c");
X		case opt_D  :	return ("D");
X		case opt_d  :	return ("d");
X		case opt_e  :
X		case e_opt_e:	return ("e");
X		case opt_F  :	return ("F");
X		case opt_f  :	return ("f");
X		case opt_g  :	return ("g");
X		case opt_h  :	return ("h");	/* SunOS Maxhops */
X		case opt_H  :	return ("H");
X		case opt_I  :   return ("I");	/* HP/UX */
X		case opt_i  :
X		case d_opt_i:	return ("i");
X		case opt_L  :	return ("L");
X		case opt_m  :
X		case e_opt_m:	return ("m");
X		case opt_N  :	return ("N");
X		case opt_n  :	return ("n");
X		case opt_o  :	return ("o");
X		case opt_P  :	return ("P");
X		case e_opt_p:	return ("p");
X		case opt_Q  :	return ("Q");
X		case opt_q  :	return ("q");
X		case d_opt_q:	return ("q");
X		case opt_r  :	return ("r");
X		case opt_R  :	return ("R");
X		case opt_S  :	return ("S");
X		case opt_s  :	return ("s");
X		case opt_T  :	return ("T");
X		case opt_t  :	return ("t");
X		case opt_u  :	return ("u");
X		case opt_v  :	return ("v");
X		case opt_W  :	return ("W");
X		case e_opt_w:	return ("w");
X		case opt_x  :	return ("x");
X		case opt_X  :	return ("X");
X		case opt_y  :	return ("y");
X		case opt_Y  :	return ("Y");
X		case opt_z  :	return ("z");
X		case opt_Z  :	return ("Z");
X		case e_opt_z:	return ("z");
X		case opt_SL  :	return ("/");
X		default     :	FatalError ("Bad case in ConvOpt ()", (char *) NULL);
X	}
X	/*NOTREACHED*/
X}
X
X
X/*
X *	ConvFlg () -- Convert an Ease mailer flag identifier (flgid) by 
X *		      string representation of the cf format.  
X *
X */
Xchar *
XConvFlg (flgid)
Xregister enum flgs flgid;	/* flag identifier */
X{
X	switch (flgid) {
X		case flg_f:	return ("f");
X		case flg_r:	return ("r");
X		case flg_S:	return ("S");
X		case flg_n:	return ("n");
X		case flg_l:	return ("l");
X		case flg_s:	return ("s");
X		case flg_m:	return ("m");
X		case flg_F:	return ("F");
X		case flg_D:	return ("D");
X		case flg_M:	return ("M");
X		case flg_x:	return ("x");
X		case flg_P:	return ("P");
X		case flg_u:	return ("u");
X		case flg_h:	return ("h");
X		case flg_H:	return ("H");
X		case flg_A:	return ("A");
X		case flg_U:	return ("U");
X		case flg_e:	return ("e");
X		case flg_X:	return ("X");
X		case flg_L:	return ("L");
X		case flg_p:	return ("p");
X		case flg_I:	return ("I");
X		case flg_C:	return ("C");
X		case flg_E:	return ("E");
X		case flg_R:	return ("R");
X		case flg_V:	return ("V");	/* IDA */
X		case flg_B:	return ("B");	/* IDA */
X		default   :	FatalError ("Bad case in ConvFlg ()", (char *) NULL);
X	}
X	/*NOTREACHED*/
X}
X
X
X/*
X *	ConvMat () -- Convert an Ease mailer attribute (mat) by returning a
X *		      string representation of the cf format.  
X *
X */
Xchar *
XConvMat (mat)
Xregister enum mats mat;		/* mailer attribute flag */
X{
X	switch (mat) {
X		case mat_path		: return ("P");
X		case mat_flags		: return ("F");
X		case mat_sender		: return ("S");
X		case mat_recipient	: return ("R");
X		case mat_argv		: return ("A");
X		case mat_eol		: return ("E");
X		case mat_maxsize	: return ("M");
X		default			: FatalError ("Bad case in ConvMat ()", (char *) NULL);
X	}
X	/*NOTREACHED*/
X}
X
X
X/*
X *	MacScan () -- Scan a string (pstring) for macros, replacing the Ease
X *		      form with the one-character form required by cf format.
X *
X */
Xchar *
XMacScan (pstring)
Xchar *pstring;		/* macro expandable string */
X{
X	register char *searchptr;	/* string search pointer 	*/
X	register char *bptr, *eptr;	/* macro begin and end pointers */
X	char macname [MAXNAME];		/* macro name buffer		*/
X	char s[11];			/* temp storage for warning below */
X	int	quote;			/* flag for detecting a quote() function */
X
X	if ((searchptr = pstring) == NULL)
X		return ((char *) NULL);
X	while (*searchptr != '\0') 	/* find and rewrite all macros  */
X		if (*searchptr == '\\') {
X			searchptr = searchptr + 2;
X			continue;
X		} else if (*searchptr++ == '$') {
X		    if (*searchptr == '{') {
X			if (sscanf (searchptr + 1, "quote(%[^)])", macname) == 1) {
X			    /* a quote(macro) sequence */
X			        quote++;
X			} else if (sscanf (searchptr + 1, "%[^}]", macname) != 1) {
X				PrintError ("Invalid macro format: %s", searchptr + 1);
X				return ((char *) NULL);
X			} 
X			if (quote) {
X			    quote=0;
X			    *searchptr++='!'; /* insert a quote */
X			    /* insert the macro letter */
X			    *searchptr++ = MakeMac (LookupSymbol (macname), ID_MACRO);
X			    /* now looking at quote(   */
X			    /* must skip over everything until )}, and then rewrite
X			       the rest of the macro */
X			    bptr = eptr = searchptr; 
X			    while (*eptr && *eptr != ')') /* skip to quote */
X			      eptr++;
X			    while (*eptr && *eptr != '}') /* skip past } */
X			      eptr++;
X			    eptr++;
X			    do	/* copy everything from eptr to end of line */
X			      *bptr++ = *eptr;
X			    while (*eptr++ != '\0');
X			} else {
X			    *searchptr++ = MakeMac (LookupSymbol (macname), ID_MACRO);
X			    bptr = eptr = searchptr;
X			    while (*eptr++ != '}')	/* delete until end of {name} */
X			      /* empty */ ;
X			    do	/* copy rest of line */
X			      *bptr++ = *eptr;
X			    while (*eptr++ != '\0');
X			}
X		    } else if (isupper(*searchptr)){ /* $ not followed by { */
X			/* macro name might be one character */
X			/* but or might be more than one.    */
X			if (sscanf (searchptr, "%[A-Z]", macname) != 1) {
X				PrintError ("Invalid macro format: %s", searchptr + 1);
X				return ((char *) NULL);
X			} 
X			*searchptr++ = MakeMac (LookupSymbol (macname), ID_MACRO);
X			bptr = eptr = searchptr;
X			while (isupper(*eptr))	/* delete old macro chars */
X				eptr++;
X			do
X				*bptr++ = *eptr;
X			while (*eptr++ != '\0');
X		    } 
X		} /* end of (if char == '$' ) */
X	return (pstring);
X}
X
X
X/*
X *	MakeRStr () -- Construct and return a pointer to a class read string 
X *		       using the filename fname and read format rformat.  
X *
X */
Xchar *
XMakeRStr (fname, rformat)
Xchar *fname,			/* file name for class read */
X     *rformat;			/* format for class read    */
X{
X	register char *res;	/* resultant read string    */
X
X	Rformat = TRUE;		/* set read format flag     */
X	if (rformat == NULL)
X		return (fname);
X	res = (char *) realloc (fname, strlen (fname) + strlen (rformat) + 2);
X	if (res == NULL)
X		FatalError ("System out of string space in MakeRStr ()", (char *) NULL);
X	res = strcat (res, " ");	/* construct read string */
X	res = strcat (res, rformat);
X	free (rformat);
X	return (res);
X}
X
X
X/*
X *	ListAppend () -- Append string list2 to string list1 using the 
X *			 separator sep.  A pointer to the newly constructed
X *			 string is returned.
X *
X */
Xchar *
XListAppend (list1, list2, sep)
Xchar *list1,			/* first string 	*/
X     *list2,			/* second string  	*/
X     *sep;			/* string separator	*/
X{
X	register char *res;	/* resultant string	*/
X
X	res = (char *) malloc (strlen (list1) + strlen (list2) + strlen (sep) + 1);
X	if (res == NULL)
X		FatalError ("System out of string space in ListAppend ()", (char *) NULL);
X	res = strcpy (res, list1);
X	if (list1 != NULL)	/* use separator if first string not null */
X		res = strcat (res, sep);
X	res = strcat (res, list2);
X	return (res);
X}
X
X
X/*
X *	MakeCond () -- Construct a macro conditional string in cf format.  The
X *		       conditional is based on the macro testmac, with an "if
X *		       set" result ifstring, which may contain an optional 
X *		       "if not set" result string appended to it.
X *
X */
Xchar *
XMakeCond (testmac, ifstring)
Xstruct he *testmac;		/* macro for conditional testing 	     */
Xchar 	  *ifstring; 		/* "if macro set" result string(s)  	     */
X{
X	register char *res;	/* resultant conditional string		     */
X
X	Mtest[2] = MakeMac (testmac, ID_MACRO);	   /* get one-char macro rep */
X	res = (char *) malloc (strlen (ifstring) + 6);
X	if (res == NULL)
X		FatalError ("System out of string space in MakeCond ()", (char *) NULL);
X	res = strcpy (res, Mtest);
X	res = strcat (res, ifstring);		/* build result part	  */
X	res = strcat (res, "$.");		/* end of conditional     */
X	free (ifstring);
X	return (res);
X}
X
X
X/*
X *	MakePosTok () -- Construct and return a positional token string 
X *			 representation from the parameter num.
X *
X */
Xchar *
XMakePosTok (num)
Xregister int num;	        /* numerical value of positional token */
X{
X	if (num > MAXTOKPOS) {
X		ErrorReport ("Positional token too large.\n");
X		return ((char *) NULL);
X	} else {
X		if (num > 9) {	/* two-digit positional token */
X			Ptok[1] = '0' + (num / 10);
X			Ptok[2] = '0' + (num % 10);
X			Ptok[3] = '\0';
X		} else {
X			Ptok[1] = '0' + num;
X			Ptok[2] = '\0';
X		}
X	return (Ptok);
X	}
X}
X
X
X/*
X *	Bracket () -- Construct and return a cf string form of the 
X *		      canonicalization of the string identifier passed in
X *		      the string parameter psb if dflag is true, else
X *		      simply bracket the identifier without dollar signs
X *		      for numeric hostname specifications.
X *
X */
Xchar *
XBracket (psb, dflag)
Xchar *psb;			/* identifier to be canonicalized */
Xshort dflag;			/* dollar flag 			  */
X{
X	register char *res;	/* resultant cf form 		  */
X	register short extra;	/* extra space needed for malloc  */
X	
X	extra = dflag ? 5 : 3;
X	res = (char *) malloc (strlen (psb) + extra);
X	if (res == NULL)
X		FatalError ("System out of string space in Bracket ()", (char *) NULL);
X	if (dflag)
X		res = strcpy (res, "$[");
X	else
X		res = strcpy (res, "[");
X	res = strcat (res, psb);
X	if (dflag)
X		res = strcat (res, "$");
X	res = strcat (res, "]");
X	return (res);
X}
X
X
X/*
X *	MakeRSCall () -- Construct and return a cf string form of a call
X *			 to a ruleset (cid), which would pass to it the
X *			 remainder of a rewriting address (rwaddr).
X *
X */
Xchar *
XMakeRSCall (cid, rwaddr)
Xregister struct he *cid;	/* called ruleset identifier	     */
Xregister char *rwaddr;		/* remainder of rewriting address    */
X{
X	register char *res;	/* resultant cf string for the call  */
X	
X	if (!ISRULESET(cid->idtype)) {	/* check validity of ruleset */
X		PrintError ("Undefined ruleset identifier: %s", cid->psb);
X		return ((char *) NULL);
X	}
X	/*
X	 * FLUKE jps - 8-may-86 - boost string size by 1 to accomodate space
X	 * character.
X	 */
X	res = (char *) malloc (strlen (cid->idval.rsn) + strlen (rwaddr) + 4);
X	if (res == NULL)
X		FatalError ("System out of string space in MakeRSCall ()", (char *) NULL);
X	res = strcpy (res, "$>");	/* construct the call string */
X	res = strcat (res, cid->idval.rsn);
X	res = strcat (res, " ");  /* FLUKE jps - work around sendmail bug:
X				   * whitespace is needed to separate tokens:
X				   * for example:  $>30$D will confuse
X				   * sendmail, but $>30 $D is OK.
X				   */
X	res = strcat (res, rwaddr);
X	return (res);
X}
X
X
X/*
X *	MakeField () -- Construct and return the cf string format for a
X *			field variable.  The match count (count), an optional
X *			class (class), and a match repetition flag (fstar)
X *			are used to determine what type of field string to
X *			construct.
X *
X *  FLUKE jps 25-apr-86 - Modified to add a fourth parameter "isYPmap".  This
X *  supports Sun's new Yellow Pages match patterns added in release 3.0.
X *
X */
Xchar *
X    MakeField (count, class, fstar, isYPmap)
Xregister int count;		/* match count (0 or 1) */
Xregister struct he *class;	/* optional class type  */
Xregister short fstar;		/* repetition flag	*/
Xregister short isYPmap;		/* "class" name is really a YP map name */
X{
X	switch (count) {
X		case 0:	  if (class == NULL)	/* any token is valid */
X				if (fstar)
X					return (Zfield);
X				else {
X					ErrorReport ("Invalid field type.\n");
X					return ((char *) NULL);
X				}
X			  else {		/* match 0 from class or map */
X				if (isYPmap) {
X				    /*  "class" is a misnomer here; it's really
X				     *  a simple macro name for a YP map.
X				     *  FLUKE jps 25-apr-86
X				     */
X				    Nfield[2] = MakeMac (class, ID_MACRO);
X				    return (Nfield);
X				} else {
X				Cfield[1] = '~';
X				Cfield[2] = MakeMac (class, ID_CLASS);
X				return (Cfield);
X			  }
X			  }
X		case 1:	  if (class == NULL)	/* any token is valid */
X				if (fstar)
X					return (Pfield);
X				else
X					return (Ofield);
X			  else {		/* match 1 from class or map */
X				if (isYPmap) {
X				    /*  "class" is a misnomer here; it's really
X				     *  a simple macro name for a YP map.
X				     *  FLUKE jps 25-apr-86
X				     */
X				    Mfield[2] = MakeMac (class, ID_MACRO);
X				    return (Mfield);
X				} else {
X				Cfield[1] = '=';
X				Cfield[2] = MakeMac (class, ID_CLASS);
X				return (Cfield);
X				}
X			  }
X		default:  ErrorReport ("Invalid field type.\n");
X	}
X	/*NOTREACHED*/
X}
END_OF_src/strops.c
if test 14822 -ne `wc -c <src/strops.c`; then
    echo shar: \"src/strops.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 3 \(of 6\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 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
--
Bruce G. Barnett	barnett@crd.ge.com	uunet!crdgw1!barnett

barnett@grymoire.crd.ge.com (Bruce Barnett) (02/23/91)

#! /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 4 (of 6)."
# Contents:  src/parser.y
# Wrapped by barnett@grymoire on Sat Feb 23 01:13:55 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f src/parser.y -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/parser.y\"
else
echo shar: Extracting \"src/parser.y\" \(21605 characters\)
sed "s/^X//" >src/parser.y <<'END_OF_src/parser.y'
X%{
X#ifdef FLUKE
X# ifndef LINT
X    static char RCSid[] = "@(#)FLUKE  $Header: /tmp_mnt/home/kreskin/u0/barnett/Src/Ease/ease/src/RCS/parser.y,v 3.0 1991/02/22 18:50:27 barnett Exp $";
X# endif LINT
X#endif FLUKE
X
X/*
X *	parser.y -- EASE parser.
X *
X *		    Contains code for yacc(1) which produces a parser (y.tab.c)
X *		    for Ease, a specification format for sendmail configuration
X *		    files.
X *
X *	author   -- James S. Schoner, Purdue University Computing Center,
X *		    		      West Lafayette, Indiana  47907
X *
X *	date     -- July 2, 1985
X *
X *	Copyright (c) 1985 by Purdue Research Foundation
X *
X *	All rights reserved.
X *
X * $Log: parser.y,v $
X * Revision 3.0  1991/02/22  18:50:27  barnett
X * Added support for HP/UX and IDA sendmail.
X *
X * Revision 2.1  1990/01/30  15:48:35  jeff
X * Added SunOS/Ultrix/IDA extensions  Jan 24, 1989 Bruce Barnett
X *
X * Version 2.0  90/01/30  15:44:34  jeff
X * Baseline release for netwide posting.
X * 
X */
X
X#include "fixstrings.h"
X#include <stdio.h>
X#include "symtab.h"
X#include <ctype.h>
Xextern void	   BindID ();
Xextern void	   EmitDef ();
Xextern char	  *ListAppend ();
Xextern char 	  *MakeCond ();
Xextern char	  *MakeRStr ();
Xextern char       *ConvOpt ();
Xextern char	  *ConvFlg ();
Xextern char	  *MacScan ();
Xextern char	  *ConvMat ();
Xextern void	   StartRuleset ();
Xextern char	  *MakePosTok ();
Xextern char	  *GetField ();
Xextern char	  *Bracket ();
Xextern char	  *MakeRSCall ();
Xextern char	  *CheckMailer ();
Xextern char	  *CheckRS ();
Xextern char	  *MakeField ();
Xextern char	   MakeMac ();
Xextern void	   AssignType ();
Xextern void	   RemoveSymbol ();
Xextern void	   yyerror ();
X
Xextern short RMatch;		/* ruleset match flag 		      */
X
Xchar *Cbuf = " ";		/* character buffer   		      */
Xchar *Mbuf = "$ ";		/* macro buffer	      		      */
Xchar *Tsb;			/* pointer to temporary string buffer */
Xchar *Tsb1;			/* pointer to another temporary string buffer */
Xchar *Flaglist;			/* pointer to header flag list	      */
X
X#define DIM(x)	(sizeof x/sizeof x[0])
Xextern int yychar;
Xextern int	yydebug;
X
Xstatic char *
Xyydisplay(ch)
X     register int ch;
X{
X    static char buf[15];
X    static char * token[] = {
X#include "y.tok.h"
X	0 };
X
X    switch (ch) {
X      case 0:
X	return "[end of file]";
X/* YYERRCODE is 256. See below */
X/*      case YYERRCODE:
X	return "[error]"; */
X      case '\b':
X	return "'\\b'";
X      case '\f':
X	return "'\\f'";
X      case '\n':
X	return "'\\n'";
X      case '\r':
X	return "'\\r'";
X      case '\t':
X	return "'\\t'";
X    }
X    /* I should use YYERRCODE - but it hasn't been defined yet */
X    /* when /usr/lib/yaccpar is added to this file, it will be defined */
X    if (ch == 256 ) return ("[error]"); 
X    if (ch > 256 && ch < 256 + DIM(token))
X      return token[ch - 257];
X    if (isascii(ch) && isprint(ch))
X      sprintf(buf, "'%c'",ch);
X    else if (ch < 256)
X      sprintf(buf, "Char %o4.3o", ch);
X    else 
X      sprintf(buf, "token %d", ch);
X    return buf;
X}
Xstatic yyyylex() 
X{
X	if (yychar < 0) {
X	    /* don't make this match =yylex - because sed changes
X	       =yylex to =yyyylex in the Makefile. 
X	       the pieces it changes is in /usr/lib/yaccparr and I don't
X	       want to modify THAT!  - bgb */
X
X		if ((yychar = yylex ()) < 0)	/* call yylex, not yyyylex */
X			yychar = 0;
X#ifdef YYDEBUG
X	if (yydebug)
X		printf("[yydebug] reading %s\n",
X			yydisplay(yychar));
X#endif
X		return yychar;
X	}
X}
X 	
X
X%}
X
X%union {			/* value stack element type    */
X	int	  ival;		/* integer token 	       */
X	char	  *psb;		/* string token		       */
X	struct he *phe;		/* pointer to hash entry       */
X	enum opts optval;	/* sendmail options	       */
X	enum flgs flgval;	/* mailer flags		       */
X	enum mats mpval;	/* mailer attribute parameters */
X}
X
X%start config
X
X%token 	<phe>	IDENT
X%token  <psb>	SCONST
X%token  <ival>	ICONST SEPCHAR
X%token BIND CANON CLASS CONCAT FOR HEADER HOST HOSTNUM IF IFSET IN
X%token MACRO MAILER MAP MARGV MATCH MEOL MFLAGS MMAXSIZE MPATH
X%token MRECIPIENT MSENDER NEXT OPTIONS PRECEDENCE READCLASS RESOLVE
X%token RETRY RETURN RULESET TRUSTED USER
X%token YPALIAS YPMAP YPPASSWD EVAL RESOLVED QUOTE ASM PROGRAM DEFAULT ALIAS
X
X%token ASGN COLON COMMA DEFINE DOLLAR FIELD LBRACE LPAREN RBRACE
X%token RPAREN SEMI STAR SLASH
X
X%token AAOPT AOPT BBOPT CCOPT COPT DDOPT DOPT DOPTB DOPTI DOPTQ EOPT
X%token EOPTE EOPTM EOPTP EOPTW EOPTZ FFOPT FOPT GOPT HHOPT IOPT LLOPT
X%token MOPT NNOPT NOPT OOPT PPOPT QOPT QQOPT ROPT SOPT SSOPT TOPT TTOPT
X%token UOPT VOPT WWOPT XOPT XXOPT YOPT YYOPT ZOPT ZZOPT
X%token RROPT BOPT SLOPT HOPT IIOPT
X
X%token AAFLAG CCFLAG DDFLAG EEFLAG EFLAG FFFLAG FFLAG HFLAG IIFLAG LFLAG
X%token LLFLAG MFLAG MMFLAG NFLAG PFLAG PPFLAG RFLAG RRFLAG SFLAG SSFLAG
X%token UFLAG UUFLAG XFLAG XXFLAG
X%token HHFLAG VVFLAG BBFLAG
X
X%type	<psb>		mval strval ifcon conval ifres elseres nameset namelist
X%type	<psb>		doptid eoptid idlist fcond dlist mflags route mdefs
X%type	<psb>		matchaddr matchtok action actionstmt mailerspec mtdef
X%type	<psb>		rwaddr rwtok ftype reftok rword cantok resolution
X%type	<psb>		userspec hword hostid dheader mdefine
X%type	<psb>		catstring catstringlist canval canvaltok
X%type	<ival>		anychar
X%type	<phe>		cdef
X%type	<optval>	optid
X%type	<flgval>	flagid
X%type	<mpval>		mvar
X
X%left COMMA
X%left LPAREN RPAREN
X%nonassoc SCONST
X
X%%
Xconfig		:	/* empty */
X		|	config blockdef
X		|	error blockdef
X		;
X
Xblockdef	:	BIND bindings
X		|	MACRO macdefs
X		|	CLASS classdefs
X		|	OPTIONS optdefs
X		|	PRECEDENCE precdefs
X		|	TRUSTED tlist
X		|	HEADER hdefs
X		|	MAILER mlist
X		|	RULESET rdef
X		|	FIELD fdefs
X		;
X
Xbindings	:	/* empty */
X		|	bindings IDENT ASGN RULESET ICONST SEMI {
X				BindID ($2, $5, ID_RULESET);
X			}
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xmacdefs		:	/* empty */
X		|	macdefs IDENT ASGN mdefine SEMI {
X				EmitDef (def_macro, $2, $4, (char *) NULL);
X			}
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
X/* macro value
X * can be string
X * or ifset()
X * or concat
X */
Xmdefine	        :       mval {
X                        $$ = $1;
X			}
X		|	IFSET LPAREN IDENT COMMA ifres RPAREN {
X				$$ = MakeCond ($3, MacScan($5));
X			}
X		;
Xmval		:	strval				%prec COMMA {
X				$$ = $1;
X			}
X		|	CONCAT LPAREN conval RPAREN {
X				$$ = $3;
X			} 
X		;
X
Xstrval		:	SCONST {
X				$$ = $1;
X			}
X		|	strval SCONST {
X				$$ = ListAppend ($1, $2, (char *) NULL);
X				free ($1);
X			}
X		;
X
X/* conval specifies what can be in a concat() function */
Xconval		:	strval COMMA ifcon {
X				$$ = ListAppend ($1, $3, (char *) NULL);
X				free ($1);
X				free ($3);
X			}
X		|	ifcon COMMA strval {
X				$$ = ListAppend ($1, $3, (char *) NULL);
X				free ($1);
X				free ($3);
X			}
X		|	ifcon {
X				$$ = $1;
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xifcon		:	IFSET LPAREN IDENT COMMA ifres RPAREN {
X				$$ = MakeCond ($3, MacScan($5));
X			}
X		;
X
Xifres		:	mval elseres {
X				if ($2 != NULL) {
X					$$ = ListAppend ($1, $2, "$|");
X					free ($1);
X					free ($2);
X				} else
X					$$ = $1;
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xelseres		:	/* empty */ {
X				$$ = NULL;
X			}
X		|	COMMA mval {
X				$$ = $2;
X			}
X		;
X
Xclassdefs	:	/* empty */ 
X		|	classdefs IDENT ASGN nameset {
X				EmitDef (def_class, $2, $4, (char *) NULL);
X			}
X                | 	classdefs ASM LPAREN SCONST RPAREN SEMI {
X				printf("%s\n",$4);
X                        }
X		|	error
X		;
X
Xnameset		:	LBRACE namelist RBRACE SEMI {
X				$$ = $2;
X			}
X		|	LBRACE RBRACE SEMI {
X				$$ = NULL;
X			}
X		|	LBRACE error RBRACE SEMI {
X				$$ = NULL;
X			}
X		|	READCLASS LPAREN strval RPAREN SEMI {
X				$$ = MakeRStr ($3, (char *) NULL);
X			}
X		|	READCLASS LPAREN strval COMMA strval RPAREN SEMI {
X				$$ = MakeRStr ($3, $5);
X			}
X		|	READCLASS LPAREN error RPAREN SEMI {
X				$$ = NULL;
X			}
X		|	error SEMI {
X				$$ = NULL;
X				yyerrok;
X			}
X		;
X
Xnamelist	:	IDENT {
X				$$ = ListAppend ($1->psb, (char *) NULL, (char *) NULL);
X				RemoveSymbol ($1);
X			}
X		|	strval {
X				$$ = $1;
X			}
X		|	namelist COMMA IDENT {
X				$$ = ListAppend ($1, $3->psb, " ");
X				free ($1);
X				RemoveSymbol ($3);
X			}
X		|	namelist COMMA strval {
X				$$ = ListAppend ($1, $3, " ");
X				free ($1);
X				free ($3);
X			}
X		;
X
Xoptdefs		:	/* empty */
X		|	optdefs optid ASGN strval SEMI {
X				EmitDef (def_option, (struct he *) NULL, ConvOpt ($2), $4);
X			}
X		|	optdefs DOPT ASGN doptid SEMI {
X				EmitDef (def_option, (struct he *) NULL, ConvOpt (opt_d), $4);
X			}
X		|	optdefs EOPT ASGN eoptid SEMI {
X				EmitDef (def_option, (struct he *) NULL, ConvOpt (opt_e), $4);
X			}
X                | 	optdefs ASM LPAREN SCONST RPAREN SEMI {
X				printf("%s\n",$4);
X                        }
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xoptid		:	AAOPT {
X				$$ = opt_A;
X			}
X		|	AOPT {
X				$$ = opt_a;
X			}
X		|	BBOPT {
X				$$ = opt_B;
X			}
X		|	BOPT {
X				$$ = opt_b;
X			}
X		|	CCOPT {
X				$$ = opt_C;
X			}
X		|	COPT {
X				$$ = opt_c;
X			}
X		|	DDOPT {
X				$$ = opt_D;
X			}
X		|	FFOPT {
X				$$ = opt_F;
X			}
X		|	FOPT {
X				$$ = opt_f;
X			}
X		|	GOPT {
X				$$ = opt_g;
X			}
X		|	HOPT {
X				$$ = opt_h;
X			}
X		|	HHOPT {
X				$$ = opt_H;
X			}
X		|	IOPT {
X				$$ = opt_i;
X			}
X		|	IIOPT {
X				$$ = opt_I;
X			}
X		|	LLOPT {
X				$$ = opt_L;
X			}
X		|	MOPT {
X				$$ = opt_m;
X			}
X		|	NNOPT {
X				$$ = opt_N;
X			}
X		|	NOPT {
X				$$ = opt_n;
X			}
X		|	PPOPT {
X				$$ = opt_P;
X			}
X		|	OOPT {
X				$$ = opt_o;
X			}
X		|	QQOPT {
X				$$ = opt_Q;
X			}
X		|	QOPT {
X				$$ = opt_q;
X			}
X		|	ROPT {
X				$$ = opt_r;
X			}
X		|	RROPT {
X				$$ = opt_R;
X			}
X		|	SSOPT {
X				$$ = opt_S;
X			}
X		|	SOPT {
X				$$ = opt_s;
X			}
X		|	TTOPT {
X				$$ = opt_T;
X			}
X		|	TOPT {
X				$$ = opt_t;
X			}
X		|	UOPT {
X				$$ = opt_u;
X			}
X		|	VOPT {
X				$$ = opt_v;
X			}
X		|	WWOPT {
X				$$ = opt_W;
X			}
X		|	XOPT {
X				$$ = opt_x;
X			}
X		|	XXOPT {
X				$$ = opt_X;
X			}
X		|	YOPT {
X				$$ = opt_y;
X			}
X		|	YYOPT {
X				$$ = opt_Y;
X			}
X		|	ZOPT {
X				$$ = opt_z;
X			}
X		|	ZZOPT {
X				$$ = opt_Z;
X			}
X		|	SLOPT {
X				$$ = opt_SL;	/* SLASH .e.g. O/ in IDA */
X			}
X		;
X
Xdoptid		:	DOPTI {
X				$$ = ConvOpt (d_opt_i);
X			}
X		|	DOPTB {
X				$$ = ConvOpt (d_opt_b);
X			}
X		|	DOPTQ {
X				$$ = ConvOpt (d_opt_q);
X			}
X		;
X
Xeoptid		:	EOPTP {
X				$$ = ConvOpt (e_opt_p);
X			}
X		|	EOPTE {
X				$$ = ConvOpt (e_opt_e);
X			}
X		|	EOPTM {
X				$$ = ConvOpt (e_opt_m);
X			}
X		|	EOPTW {
X				$$ = ConvOpt (e_opt_w);
X			}
X		|	EOPTZ {
X				$$ = ConvOpt (e_opt_z);
X			}
X		;
X
Xprecdefs	:	/* empty */
X		|	precdefs IDENT ASGN ICONST SEMI {
X				BindID ($2, $4, ID_PREC);
X				EmitDef (def_prec, $2, (char *) NULL, (char *) NULL);
X			}
X		;
X
Xtlist		:	/* empty */
X		|	tlist LBRACE IDENT idlist RBRACE SEMI {
X				EmitDef (def_trusted, (struct he *) NULL, 
X					 ListAppend ($3->psb, $4, " "), (char *) NULL);
X				free ($4);
X				RemoveSymbol ($3);
X			}
X		|	tlist LBRACE RBRACE SEMI
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xhdefs		:	/* empty */
X		|	hdefs FOR fcond dheader SEMI {
X				EmitDef (def_header, (struct he *) NULL, $3, $4);
X			}
X		|	hdefs FOR fcond LBRACE { Flaglist = $3; } 
X				dheaders RBRACE SEMI
X		|	hdefs DEFINE dlist SEMI {
X				EmitDef (def_header, (struct he *) NULL, (char *) NULL, $3);
X			}
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xfcond		:	LPAREN RPAREN {
X				$$ = NULL;
X			}
X		|	LPAREN mflags RPAREN {
X				$$ = $2;
X			}
X		|	LPAREN error RPAREN {
X				$$ = NULL;
X			}
X		;
X
Xmflags		:	flagid {
X				$$ = ListAppend (ConvFlg ($1), (char *) NULL, (char *) NULL);
X			}
X		|	mflags COMMA flagid {
X				$$ = ListAppend ($1, ConvFlg($3), (char *) NULL);
X				free ($1);
X			}
X		;
X
Xflagid		:	FFLAG {
X				$$ = flg_f;
X			}
X		|	RFLAG {
X				$$ = flg_r;
X			}
X		|	SSFLAG {
X				$$ = flg_S;
X			}
X		|	NFLAG {
X				$$ = flg_n;
X			}
X		|	LFLAG {
X				$$ = flg_l;
X			}
X		|	SFLAG {
X				$$ = flg_s;
X			}
X		|	MFLAG {
X				$$ = flg_m;
X			}
X		|	FFFLAG {
X				$$ = flg_F;
X			}
X		|	DDFLAG {
X				$$ = flg_D;
X			}
X		|	MMFLAG {
X				$$ = flg_M;
X			}
X		|	XFLAG {
X				$$ = flg_x;
X			}
X		|	PPFLAG {
X				$$ = flg_P;
X			}
X		|	UFLAG {
X				$$ = flg_u;
X			}
X		|	HFLAG {
X				$$ = flg_h;
X			}
X		|	AAFLAG {
X				$$ = flg_A;
X			}
X		|	BBFLAG {
X				$$ = flg_B;
X			}
X		|	UUFLAG {
X				$$ = flg_U;
X			}
X		|	EFLAG {
X				$$ = flg_e;
X			}
X		|	XXFLAG {
X				$$ = flg_X;
X			}
X		|	LLFLAG {
X				$$ = flg_L;
X			}
X		|	PFLAG {
X				$$ = flg_p;
X			}
X		|	IIFLAG {
X				$$ = flg_I;
X			}
X		|	CCFLAG {
X				$$ = flg_C;
X			}
X		|	EEFLAG {
X				$$ = flg_E;
X			}
X		|	RRFLAG {
X				$$ = flg_R;
X			}
X		|	HHFLAG {
X				$$ = flg_H;
X			}
X		|	VVFLAG {
X				$$ = flg_V;
X			}
X		;
X
Xdheader		:	/* empty */ {
X				$$ = NULL;
X			}
X		|	DEFINE dlist {
X				$$ = $2;
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xdheaders	:	/* empty */
X		|	dheaders DEFINE dlist SEMI {
X				EmitDef (def_header, (struct he *) NULL, Flaglist, $3);
X			}
X                | 	dheaders ASM LPAREN SCONST RPAREN SEMI {
X				printf("%s\n",$4);
X                        }
X		|	error
X		;
X
Xdlist		:	LPAREN strval COMMA catstringlist RPAREN {
X				$$ = ListAppend ($2, MacScan ($4), " ");
X				free ($2);
X				free ($4);
X			}
X		|	LPAREN error RPAREN {
X				$$ = NULL;
X			}
X		;
X
Xcatstringlist	:	catstring {
X  				$$ = $1;
X			}
X		|	catstring COMMA catstringlist {
X  				$$ = ListAppend( $1, $3, (char *) NULL);
X  				free($1);
X			}
Xcatstring	:	SCONST {
X				$$ = $1;
X			}
X		|	CONCAT LPAREN conval RPAREN {
X				$$ = $3;
X			}
X		|	ifcon {
X				$$ = $1;
X			}
X		;
X
Xmlist		:	/* empty */
X		|	mlist IDENT LBRACE mdefs RBRACE SEMI {
X				EmitDef (def_mailer, $2, $4, (char *) NULL);
X			}
X		|	mlist IDENT LBRACE RBRACE SEMI {
X				EmitDef (def_mailer, $2, (char *) NULL, (char *) NULL);
X			}
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xmdefs		:	mtdef {
X				$$ = $1;
X			}
X		|	mdefs COMMA mtdef {
X				$$ = ListAppend ($1, $3, ", ");
X				free ($1);
X				free ($3);
X			}
X		;	
X
Xmtdef		:	mvar ASGN mval {
X				$$ = ListAppend (ConvMat ($1), MacScan ($3), "=");
X				free ($3);
X			}
X		|	MFLAGS ASGN LBRACE mflags RBRACE {
X				$$ = ListAppend (ConvMat (mat_flags), $4, "=");
X			}
X		|	MSENDER ASGN IDENT {
X				$$ = ListAppend (ConvMat (mat_sender), CheckRS ($3), "=");
X			}
X		|	MSENDER ASGN IDENT SLASH IDENT {
X				$$ = ListAppend(
X				 Tsb = ListAppend (ConvMat(mat_sender), CheckRS ($3), "="),
X				 Tsb1 = ListAppend ("/", CheckRS ($5), (char *) NULL),
X						 (char *) NULL);
X				free (Tsb);
X				free (Tsb1);
X			}
X		|	MRECIPIENT ASGN IDENT {
X				$$ = ListAppend (ConvMat (mat_recipient), CheckRS ($3), "=");
X			}
X		|	MRECIPIENT ASGN IDENT SLASH IDENT {
X				$$ = ListAppend(
X				 Tsb = ListAppend (ConvMat(mat_recipient), CheckRS ($3), "="),
X				 Tsb1 = ListAppend ("/", CheckRS ($5), (char *) NULL),
X						 (char *) NULL);
X				free (Tsb);
X				free (Tsb1);
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xmvar		:	MPATH {
X				$$ = mat_path;
X			}
X		|	MARGV {
X				$$ = mat_argv;
X			}
X		|	MEOL {
X				$$ = mat_eol;
X			}
X		|	MMAXSIZE {
X				$$ = mat_maxsize;
X			}
X		;
X
Xrdef		:	/* empty */
X		|	rdef IDENT { StartRuleset ($2); } rulelist
X		;
X
Xrulelist	:	LBRACE ruledefs RBRACE {
X				RMatch = FALSE;
X			}
X		|	error {
X				RMatch = FALSE;
X			}
X		;
X
Xruledefs	:	/* empty */ {
X				RMatch = TRUE;
X			}
X		|	ruledefs IF LPAREN matchaddr RPAREN actionstmt {
X				EmitDef (def_ruleset, (struct he *) NULL, 
X					 ListAppend ($4, $6, "\t"), (char *) NULL);
X			free ($4);
X			free ($6);
X			}
X                | 	ruledefs ASM LPAREN SCONST RPAREN SEMI {
X				  printf("%s\n",$4);
X                        }
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xmatchaddr	:	/* empty */ {
X				$$ = NULL;
X			}
X		|	matchaddr matchtok {
X				$$ = ListAppend ($1, $2, (char *) NULL);
X				free ($1);
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xmatchtok	:	IDENT {
X				$$ = GetField ($1);
X			}
X		|	anychar {
X				*Cbuf = $1;
X				$$ = ListAppend (Cbuf, (char *) NULL, (char *) NULL);
X			}
X		|	mval {
X				$$ = MacScan ($1);
X			}
X		|	DOLLAR IDENT {
X				Mbuf[1] = MakeMac ($2, ID_MACRO);
X				$$ = ListAppend (Mbuf, (char *) NULL, (char *) NULL);
X			}
X                |       YPALIAS LPAREN matchtok RPAREN {
X		         $$ = ListAppend("${",$3,(char *) NULL);
X/*			 free ($3); */
X		}
X                |       YPPASSWD LPAREN matchtok RPAREN {
X		         $$ = ListAppend("$\"",$3,(char *) NULL);
X		}
X                |       RESOLVED LPAREN matchtok RPAREN {
X		         $$ = ListAppend("$#",$3,(char *) NULL);
X		}
X	;
X
Xactionstmt	:	action LPAREN rwaddr RPAREN SEMI {
X				$$ = ListAppend ($1, $3, (char *) NULL);
X				free ($3);
X			}
X		|	RESOLVE LPAREN resolution RPAREN SEMI {
X				$$ = $3;
X			}
X		|	error SEMI {
X				$$ = NULL;
X				yyerrok;
X			}
X		;
X
Xaction		:	RETRY {
X				$$ = NULL;
X			}
X		|	NEXT {
X				$$ = "$:";
X			}
X		|	RETURN {
X				$$ = "$@";
X			}
X		;
X
Xrwaddr		:	/* empty */ {
X				$$ = NULL;
X			}
X		|	rwaddr rwtok {
X				$$ = ListAppend ($1, $2, (char *) NULL);
X				free ($1);
X			}
X		|	rwaddr IDENT LPAREN rwaddr RPAREN {
X				$$ = ListAppend ($1, (Tsb = MakeRSCall ($2, $4)), (char *) NULL);
X				free ($1);
X				free ($4);
X				free (Tsb);
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xrwtok		:	anychar {
X				*Cbuf = $1;
X				$$ = ListAppend (Cbuf, (char *) NULL, (char *) NULL);
X			}
X		|	mval {
X				$$ = MacScan ($1);
X			}
X		|	cantok {
X				$$ = $1;
X			}
X		|	ALIAS LPAREN reftok  RPAREN {
X				$$ = ListAppend("$(@", $3, "$:$)");
X			}
X		|	ALIAS LPAREN reftok DEFAULT LPAREN rwaddr RPAREN RPAREN {
X				$$ = ListAppend(Tsb = 
X						ListAppend ( "$(@", 
X							    $3, 
X							    (char *)NULL),
X						Tsb1 = ListAppend("$:", $6, "$)" ),
X						(char *) NULL);
X				free (Tsb);
X				free (Tsb1);
X				free ($3);
X				free ($6);
X			}
X		|	reftok {
X				$$ = $1;
X			}
X		|	ifcon {
X				$$ = $1;
X			}
X                |	YPMAP LPAREN IDENT COMMA rwaddr RPAREN {
X				*Cbuf = MakeMac ($3, ID_MACRO);
X				$$ = ListAppend(Tsb = ListAppend ("${", (char *)Cbuf, (char *)NULL),
X						Tsb1 = ListAppend ($5, "$}", (char *) NULL),
X						 (char *) NULL);
X				free (Tsb);
X				free (Tsb1);
X				free ($5);
X			}
X
X                |	PROGRAM LPAREN IDENT COMMA rwaddr RPAREN {
X				*Cbuf = MakeMac ($3, ID_MACRO);
X				$$ = ListAppend(Tsb = ListAppend ("$<", (char *)Cbuf, (char *)NULL),
X						Tsb1 = ListAppend ($5, "", (char *) NULL),
X						 (char *) NULL);
X				free (Tsb);
X				free (Tsb1);
X				free ($5);
X			}
X
X                |	action LPAREN rwaddr RPAREN {
X				$$ = ListAppend ($1, $3, (char *) NULL);
X				free ($3);
X			}
X		;
X
X
Xcantok		:	CANON LPAREN canval RPAREN {
X				$$ = Bracket ($3, TRUE);
X				free ($3);
X			}
X
X                ;
Xcanval		:	canvaltok {
X				$$ = $1;
X			}
X		|	canval canvaltok {
X				$$ = ListAppend ($1, $2, (char *) NULL);
X				free ($1);
X				free ($2);
X			}
X		;
X
Xcanvaltok	:	IDENT {
X				$$ = ListAppend ($1->psb, (char *) NULL, (char *) NULL);
X				RemoveSymbol ($1);
X			}
X		|	SCONST {
X				$$ = ListAppend (MacScan ($1), (char *) NULL, (char *) NULL);
X				free ($1);
X			}
X                |	NEXT LPAREN RPAREN {	/* I Used next earlier, but now use default - because it is clearer syntax */
X				$$ = "$:";
X			}
X                |	NEXT LPAREN canval RPAREN {
X				$$ = ListAppend("$:", $3, (char *)NULL);
X			}
X                |	DEFAULT LPAREN RPAREN {
X				$$ = "$:";
X			}
X                |	DEFAULT LPAREN canval RPAREN {
X				$$ = ListAppend("$:", $3, (char *)NULL);
X			}
X		|	reftok {
X				$$ = $1;
X			}
X		|	SEPCHAR {
X				*Cbuf = $1;
X				$$ = ListAppend (Cbuf, (char *) NULL, (char *) NULL);
X			}
X		|	HOSTNUM LPAREN reftok RPAREN {
X				$$ = Bracket ($3, FALSE);
X				free ($3);
X			}
X		;
X
Xreftok		:	DOLLAR IDENT {
X				Mbuf[1] = MakeMac ($2, ID_MACRO);
X				$$ = ListAppend (Mbuf, (char *) NULL, (char *) NULL);
X			}
X		|	DOLLAR ICONST {
X				$$ = ListAppend (MakePosTok ($2), (char *) NULL, (char *) NULL);
X			}
X                |	EVAL LPAREN IDENT RPAREN {
X				*Cbuf = MakeMac ($3, ID_MACRO);
X				$$ = ListAppend("$&", (char *)Cbuf, (char *)NULL);
X			}
X		;
X
Xanychar		:	SEPCHAR {
X				$$ = $1;
X			}
X		|	COLON {
X				$$ = ':';
X			}
X		|	STAR {
X				$$ = '*';
X			}
X		|	SEMI {
X				$$ = ';';
X			}
X		|	LBRACE {
X				$$ = '{';
X			}
X		|	RBRACE {
X				$$ = '}';
X			}
X		|	COMMA {
X				$$ = ',';
X			}
X		|	SLASH {
X				$$ = '/';
X			}
X		|	ASGN {
X				$$ = '=';
X			}
X		;
X
Xresolution	:	mailerspec COMMA route {
X				$$ = ListAppend ($1, $3, (char *) NULL);
X				free ($1);
X				free ($3);
X			}
X		|	mailerspec {
X			$$ = $1;
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xmailerspec	:	MAILER LPAREN rword RPAREN {
X				$$ = ListAppend ("$#", $3, (char *) NULL);
X			}
X		;
X
Xroute		:	HOST LPAREN hword RPAREN COMMA userspec {
X				$$ = ListAppend (Tsb = ListAppend ("$@", $3, (char *) NULL),
X						 $6, (char *) NULL);
X				free (Tsb);
X
X
X				free ($6);
X			}
X		|	userspec {
X				$$ = $1;
X			}
X		;
X
Xhword		:	hostid {
X				$$ = $1;
X			}
X		|	HOSTNUM LPAREN reftok RPAREN {
X				$$ = Bracket ($3, FALSE);
X				free ($3);
X			}
X		;
X
Xhostid		:	/* empty */ {
X				$$ = NULL;
X			}
X		|	hostid IDENT {
X				$$ = ListAppend ($1, $2->psb, (char *) NULL);
X				RemoveSymbol ($2);
X				free ($1);
X			}
X		|	hostid rwtok {
X				$$ = ListAppend ($1, $2, (char *) NULL);
X				free ($1);
X			}
X		;
X
Xuserspec	:	USER LPAREN rwaddr RPAREN {
X				$$ = ListAppend ("$:", $3, (char *) NULL);
X				free ($3);
X			}
X		;
X
Xrword		:	IDENT {
X				$$ = CheckMailer ($1);
X			}
X		|	reftok {
X				$$ = $1;
X			}
X		;
X
Xfdefs		:	/* empty */
X		|	fdefs IDENT idlist COLON ftype SEMI {
X				AssignType (ListAppend ($2->psb, $3, " "), $5);
X				free ($3);
X			}
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xidlist		:	/* empty */ {
X				$$ = NULL;
X			}
X		|	idlist COMMA IDENT {
X				$$ = ListAppend ($1, $3->psb, " ");
X				free ($1);
X			}
X		;
X
Xftype		:	MATCH LPAREN ICONST RPAREN cdef {
X				$$ = ListAppend (MakeField ($3, $5, FALSE, FALSE), 
X				    		 (char *) NULL, (char *) NULL);
X			}
X		|	MATCH LPAREN ICONST RPAREN MAP IDENT {
X				$$ = ListAppend (MakeField ($3, $6, FALSE, TRUE), 
X				    		 (char *) NULL, (char *) NULL);
X			}
X		|	MATCH HOST {
X				$$ = ListAppend ("$%y", 
X				    		 (char *) NULL, (char *) NULL);
X			}
X		|	MATCH LPAREN ICONST STAR RPAREN {
X				$$ = ListAppend (MakeField ($3, (struct he *) NULL, TRUE, FALSE), 
X						 (char *) NULL, (char *) NULL);
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xcdef		:	/* empty */ {
X				$$ = NULL;
X			}
X		|	IN IDENT {
X				$$ = $2;
X			}
X		;
END_OF_src/parser.y
if test 21605 -ne `wc -c <src/parser.y`; then
    echo shar: \"src/parser.y\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 4 \(of 6\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 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
--
Bruce G. Barnett	barnett@crd.ge.com	uunet!crdgw1!barnett

barnett@grymoire.crd.ge.com (Bruce Barnett) (02/23/91)

#! /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 5 (of 6)."
# Contents:  doc/ease.paper
# Wrapped by barnett@grymoire on Sat Feb 23 01:13:55 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f doc/ease.paper -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"doc/ease.paper\"
else
echo shar: Extracting \"doc/ease.paper\" \(32871 characters\)
sed "s/^X//" >doc/ease.paper <<'END_OF_doc/ease.paper'
X...
X... $Header: /home/kreskin/u0/barnett/Src/Ease/ease/doc/RCS/ease.paper,v 2.0 1990/01/30 12:50:44 jeff Exp barnett $
X... 
X... $Log: ease.paper,v $
X... Revision 2.0  1990/01/30  12:50:44  jeff
X... Baseline version, corresponding to netwide release 2.0.
X...
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.AU
XBruce G. Barnett
X.AI
XGeneral Electric Corporate Research and Development
XSchenectady, NY 12301
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.  
XIn 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
XIt is recommended that you learn \fBEase\fP by converting your current
Xconfiguration file into \fBEase\fP format by using the program
X\fIcfc\fP written by Arnold Robbins and modified by Bruce G. Barnett.
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, it supports C language preprocessor (cpp) commands, which 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)
Xif the program is executed with an option understood by 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 2
XLatest Changes
XThe first two releases of \fBEase\fP provided a good starting point
Xfor managing \fIsendmail\fP  files. However, the translation wasn't
Xperfect. Some editing needed to be done before \fBEase\fB could be
Xused.
XBruce G. Barnett made modifications to Arnold Robbin's \fBEase\fP to
Xsendmail convertor \fIcfc\fP and tested these changes to verify a
X\fIsendmail\fP configuration fle could be translated into \fBEase\fP
Xand back with no errors: at least for the more common versions of
X\fIsendmail\fP.
XIn case this translation is not perfect, \fBEase\fP version 3 supports
Xthe \fIasm("...")\fP command, which passes the contents of the string
Xdirectly to the \fIsendmail.cf\fP file.
XAlso - support for SunOS and Ultrix sendmail were added.
XNew options and flags were added, and well as the \fIypmap\fP (SunOS),
X\fIypalias\fP and \fIyppasswd\fP (Ultrix) functions.
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 \fBEase\fR translator (\fIet\fR). If the command line options include a flag understood by the C language preprocessor (cpp), \fIet\fP automatically 
Xpipes input through \fIcpp\fP.
XThe \fBEase\fR
Xtranslator may be invoked on the command line in one of four ways:
X.TS
Xcenter box ;
Xl l .
X\fIet\fR <options>  <input-file>  <output-file>	[read from a file, write to a file]
X\fIet\fR  <options> <input-file>	[read from a file, write to standard output]
X\fIet\fR  <options> -  <output-file>	[read from standard input, write to a file]
X\fIet\fR <options>	[read from standard input, write to standard output]
X.TE
X.NH
XConclusion
X.PP
X\fBEase\fR is [ed - this information is old] currently in use at the
XPurdue University Computing Center.  Source code for the \fBEase\fR
Xtranslator (\fIet\fR) may be obtained 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,
XAndrew Partan of the Corporation for Open Systems,
Xand
XBruce G. Barnett, of General Electric.
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.
X# Local variables:
X# mode: nroff
X# end:
END_OF_doc/ease.paper
if test 32871 -ne `wc -c <doc/ease.paper`; then
    echo shar: \"doc/ease.paper\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 5 \(of 6\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 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
--
Bruce G. Barnett	barnett@crd.ge.com	uunet!crdgw1!barnett

barnett@grymoire.crd.ge.com (Bruce Barnett) (02/23/91)

#! /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 6 (of 6)."
# Contents:  cfc/cfc.c
# Wrapped by barnett@grymoire on Sat Feb 23 01:13:56 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f cfc/cfc.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"cfc/cfc.c\"
else
echo shar: Extracting \"cfc/cfc.c\" \(39729 characters\)
sed "s/^X//" >cfc/cfc.c <<'END_OF_cfc/cfc.c'
X#ifndef lint
Xstatic char RCSid[] = "$Header: /home/kreskin/u0/barnett/Src/ease/cfc/RCS/cfc.c,v 3.0 1991/02/22 19:33:07 barnett Exp $";
X#endif
X
X/*
X * $Log: cfc.c,v $
X * Revision 3.0  1991/02/22  19:33:07  barnett
X * Many enhancements for IDA and HP sendmail.cf files
X *
X * Revision 2.2  1991/02/21  19:19:34  barnett
X * Fixed several bugs:
X * 	Multiple ifsets on one line
X * 	Better handling of # in comments
X * 	Support for escaping a '* and /' in a comment field
X *
X * Revision 2.1  1990/01/30  11:38:10  jeff
X * Enhancements by Bruce Barnett 89/1/23:
X *    - Added some enhancements for SunOS 4.0 and Ultrix 3.0
X *    - And a log of unusual grammar constructs
X *
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 */
Xint ida = 0;			/* IDA sendmail options  */
Xint sunos  = 0;			/* Special parsing for SunOS - bgb */
Xint DECos  = 0;			/* Special parsing for Ultrix - bgb */
X				/* NOTE: can't use 'ultrix' cause of cpp */
Xint hpos = 0;			/* HP/UX */
X
Xchar *classes = 0;			/* list of classes defined */
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X	extern int getopt ();
X	extern int optind;
X	extern char *optarg;
X	int i,c;
X
X	while ((c = getopt (argc, argv, "icdhusC:")) != EOF) {
X		switch (c) {
X		case 'c':
X			compat = 1;
X			break;
X		case 'u':
X			undoc = 1;
X			break;
X		case 's':
X			sunos = 1;
X			break;
X		case 'd':
X			DECos = 1;
X			break;
X		case 'i':
X			ida = 1;
X			break;
X		case 'h':
X			hpos = 1;
X			break;
X	        case 'C':
X			classes = optarg;
X			break;
X		case '?':
X		default:
X			fprintf (stderr, "usage: %s [ -[ids] ] [ -c ] [ -u ] [-C classes ]\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 version $Revision: 3.0 $*/\n");
X	printf ("/* automatically from a sendmail.cf file                   */\n");
X	printf ("/* It may need to be edited before feeding to ease.        */\n");
X	printf ("/***********************************************************/\n");
X	/* let's generate something that might work */
X	printf ("bind \n");
X	for (i=0;i<=29;i++) 
X	  printf ("\tRULESET_%d = ruleset %d;\n",i,i);
X	/* SunOS uses ruleset 30. Other sendmails only support S0 to S29 */
X	if (sunos)
X	  printf ("\tRULESET_30 = ruleset 30;\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	 * Also class definitions - BGB
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			endruleset ();
X			class ();
X			break;
X		case 'F':
X			endruleset ();
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	register int j;
X	/* try to be semi-intelligent about comments */
X
X	/* if a blank line, keep as a blank line */
X	if (buffer[1] == '\0')
X		printf ("\n");
X	else { /* non-blank comment */
X	    j=1;
X	    printf("/*");
X	    /* print ######## as /********* */
X	    while (buffer[j] == '#') {
X		j++;
X		printf("*");
X	    }
X	    /* print the rest of the line */
X	    while (buffer[j] != '\0') {
X		switch (buffer[j]) {
X		  case '#':
X		    /* convert ### to *** */
X		    if (buffer[j+1] == '\0') {
X			printf("*");
X		    } else if (buffer[j+1] == '#') /* a string of #### */
X		      while (buffer[j] == '#' && buffer[j+1] != '\0') {
X			  printf("*");
X			  j++;
X		      }
X		    else printf("#");
X		    break;
X		  case '*':
X		    if (buffer[j+1] == '/') { 
X			printf("*\\/");
X			j++;
X		    } else printf("*");
X		    break;
X		  default:
X		    printf("%c", buffer[j]);
X		    break;
X		}
X		j++;
X	    } /* end while */
X	    if ( buffer[j-2] == '#' && buffer[j-1] == '#')
X	      printf("*/\n");
X	    else if ( buffer[j-2] != '#' && buffer[j-1] == '#')
X	      printf("*/\n");
X	    else if ( buffer[j-1] == ' ' || buffer[j-1] == '\t')
X	      printf("*/\n");
X	    else 
X	      printf(" */\n");
X	} /* end of non-blank */
X    }
X
X/* ruleset --- name a ruleset */
X
Xruleset ()
X{
X	static int first = 1;
X	register char *cp = buffer + 1;
X	int i;
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		if (classes && *classes ) {
X		    printf("\t/* defining classes %s */\n",classes);
X		    for (i=0;*(classes+i);i++) {
X			printf ("\tany_in_%c : match (1) in %c;\n",*(classes+i),*(classes+i));
X			printf ("\tany_not_in_%c : match (0) in %c;\n",*(classes+i),*(classes+i));
X		    }
X		}
X		/* let's make the default configuration nicer for SunOS - bgb */
X		if (DECos || ida  || hpos ) {
X		    printf ("\tany_in_myhostname : match (1) in c_myname;\n");
X		}
X		if (sunos) {
X/*		    printf ("\tany_in_V : match (1) in V;\n");
X		    printf ("\tany_not_in_V : match (0) in V;\n"); */
X		    printf ("/*\tany_in_map_? : match (1) map ?;\t*/\n");
X		    printf ("/*\tany_not_in_map_? : match (0) map ?;\t*/\n");
X		    printf ("\tany_in_etc_hosts : match  host;\n");
X		    printf ("\tany_in_mydomainname : match (1) in c_mydomain;\n");
X		    printf ("\tany_in_myhostname : match (1) in c_myname;\n");
X		} 
X	}
X
X	printf ("ruleset\n\tRULESET_");
X	while (cp && *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 && *cp && *cp != '\t')
X		cp++;
X	if (!*cp) {
X	    fprintf(stderr,
X		    "Unexpected EOL when expecting right hand side of rule\n");
X	    lhs(buffer+1);
X	    printf("\n\tMissingRightHandSide();\n");
X	    return;
X	}
X	*cp = '\0';
X
X	cp++;
X	while (cp && *cp && *cp == '\t')
X		cp++;
X	cp2 = cp;
X	while (cp && *cp && *cp != '\t')
X		cp++;
X	if (*cp == '\t' && cp[1])
X	{
X		*cp = '\0';
X		com++;
X		cp++;
X		while (cp && *cp && *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	register int open = 0;
X	int	ifset = 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				switch(*++cp) {
X				  case 'w':
X				    if (sunos || ida || DECos ) {
X					printf (" any_in_myhostname ");
X					break;
X				    } /* else fall through */
X				  case 'm':
X				    if (sunos ) {
X					printf (" any_in_mydomainname ");
X					break;
X				    } /* else fall through */
X				    default :
X					printf (" any_in_%c ", *cp);
X				  }
X				break;
X		        case '%' :
X			       /* YP map for SunOS */
X			       if ((cp+1) && sunos && (*(cp +1) == 'y') ) {
X				   printf (" any_in_etc_hosts"); ++cp;
X			       } else {
X				   printf (" any_in_map_%c", *++cp);
X			       }
X			       break;
X			case '~':
X				printf (" any_not_in_%c ", *++cp);
X				break;
X			case '?':
X				printf (" ifset (%s, ", macro (*++cp));
X				conditional++;ifset++;
X				break;
X			case '|':
X				if ( ! conditional) die("lhs - $| without $?");
X				if ( ifset) {
X				    printf("\", \"");
X				} else {
X					fprintf(stderr,"Got $| when not in ifset\n");
X				    putchar (',');
X				}
X				break;
X			case '{':
X				printf("ypalias (");	/* Ultrix */
X				open++;
X				break;
X			case '"':
X				printf("yppasswd (");	/* Ultrix */
X				open++;
X				break;
X			case '.':
X				putchar (')');
X				conditional--;ifset--;
X				break;
X			case '#':
X				/* IDA does something strange with this */
X				printf("resolved(");
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			        /* start a literal - but ignore the first space  */
X				if (*cp != ' ' && ! quoting)	
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	while (open--)
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	char *cp1;
X	register int open = 0;
X	register int conditional = 0;	/* true if in an ifset condition */
X	register int quoting = 0;	/* true if in a string */
X	register int ifset = 0;	/* true if in ifset(), like quoting */
X	register int needconcat = 0;	/* true if an $? on line (lookahead) */
X	register int didconcat = 0;	/* true if did the concat()	*/
X	register int indbm = 0;	/* true if in IDA $( $) construct */
X	register int inalias = 0;	/* true if in IDA $(@ $) construct */
X	int	canon = 0;
X	int	diddefault = 0;
X
X	printf ("\t\t");
X
X	/* Need to handle this line */
X	/* R$+<@$=S>	$:$1<@$2>$?R<$R>$.	*/
X	for(cp1=cp;*cp1;cp1++) {
X	    if (*cp1 == '$' && (cp1+1) && *(cp1+1)== '?')
X	      needconcat = 1;	/* there is an ifset on this line */
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 && ! ifset )
X		    {
X			quoting = 0;
X			putchar ('"');
X		    }
X		  switch (*++cp) {
X		    case '>':
X		      printf ("RULESET_");
X		      for (cp++; cp && *cp && isdigit (*cp); cp++)
X			putchar (*cp);
X		      cp--;
X		      printf (" (");
X		      open++;
X		      break;
X		    case '[':
X		      if (quoting) {
X			  putchar('"');
X			  quoting--;
X		      }
X		      printf (" canon (");
X		      open++; canon++;
X		      break;
X		    case ']':
X		      putchar (')');
X		      open--;
X		      if (diddefault) {
X			  putchar (')');
X			  diddefault--;
X		      }
X		      break;
X		    case '{':
X		      printf ("ypmap (%s, ", macro (*++cp)); /* sunos */
X		      open++;
X		      break;
X		    case '}':
X		      putchar (')');
X		      open--;
X		      break;
X		    case '<':
X		      printf ("program (%s, ", macro (*++cp)); /* HP/UX */
X		      open++;
X		      break;
X		    case '?':
X		      if (didconcat) {
X			  printf ("\",");
X			  needconcat = 0; /* don't need this */
X		      }
X		      printf ("ifset (%s, \"", macro (*++cp));
X		      conditional++;
X		      ifset++;
X		      quoting++;
X		      break;
X		    case '|':
X		      if ( ! conditional) die("rhs - $| without $?");
X		      if ( ifset) {
X			  printf("\", \"");
X		      } else {
X			  fprintf(stderr,"Got $| when not in ifset\n");
X			  putchar (',');
X		      }
X		      break;
X		    case '.':
X		      if (ifset && quoting ) {
X			  putchar('"'); quoting--;
X		      }
X		      if (! ifset ) fprintf(stderr,"Got $. while not in ifset\n");
X		      putchar (')');
X		      if (open) {
X			  putchar(')');
X			  open--;
X		      }
X		      conditional--;
X		      ifset--;
X		      break;
X		    case '#':
X		      parseresolve(cp);
X		      goto out;	/* string is exhausted */
X		      /* break; */
X		    case '@':
X		      if ( ! indbm) {
X			  printf ("return (");
X			  if (needconcat && cp+1 && cp+2 &&
X			      ! ((*(cp+1) == '$') && (*(cp+2) == '?'))){ 
X			      printf ("concat (\"");
X			      open++;didconcat++;
X			  }
X			  open++;
X		      } else {
X			  printf("\", \"");
X		      }
X		      break;
X		    case ':':
X		      if ( canon ) {
X			  printf("default ( ");
X			  canon--;diddefault++;
X		      } else if ( indbm ) {
X			  printf("default ( ");
X			  indbm--;diddefault++;
X		      } else {
X			  printf ("next (");
X			  if (needconcat && cp+1 && cp+2 &&
X			      ! ((*(cp+1) == '$') && (*(cp+2) == '?'))){ 
X			      printf ("concat (\"");
X			      open++;didconcat++;
X			  }
X			  open++;
X		      } 
X		      break;
X		    case '(':
X		      if (*(cp+1) == '@') { /* then IDA alias lookup */
X			  cp++;	/* point past '@' */
X			  printf("alias(");
X			  indbm++;
X			  open++;
X		      } else { /* lookup */
X			  printf("dbm(");
X			  printf("$%s, \"",macro(*cp++));
X		      }
X		      break;
X		    case ')':
X		      printf("))");
X		      open--;
X		      indbm--;
X		      break;
X		    case '&':
X		      printf(" eval(%s) ",macro(*(++cp)));
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 (ifset ) {
X			  if (quoting)
X			    printf ("${%s}", macro (*cp));
X			  else
X			    printf ("$%s", macro (*cp));
X		      } else { /* not not in ifset() */
X			  if (quoting)
X			    printf ("${%s}", macro (*cp));
X			  else 
X			    printf ("$%s", macro (*cp));
X		      }
X		      break;
X		  }
X		  break; 		/* not a character that starts with a $ */
X		default:
X		  if ( ifset  && quoting ) {
X		      putchar(*cp);
X		  } else if (ifset  && ! quoting) {
X		      if ( ispunct (*cp)) {
X			  putchar('"');quoting++;
X		      } 
X		      putchar(*cp); 
X		  } else {	/* not ifset */
X		      if (ispunct (*cp))
X			{
X			    if (quoting )	/* end a literal */
X			      {
X				  quoting = 0;
X				  putchar ('"');
X			      }
X			    /* else
X			       do nothing */
X			} else  {
X			    if (*cp != ' ' && ! quoting)	/* start a literal */
X			      {
X				  quoting = 1;
X				  putchar ('"');
X			      }
X			    /* else
X			       do nothing */
X			}
X		      putchar (*cp);	/* print the character */
X		  }
X		  break;
X	      }
X	  } /* end of for */
Xout:
X	if (quoting)
X		putchar ('"');
X	while (open--)
X		putchar (')');
X	printf (";\n");
X	if (conditional)
X		die ("rhs - $? without $.");
X}
X/* parseresolve - parse this mailer/host/user mess */
Xparseresolve(cp)
Xchar	*cp;
X{
X    int quoting = 0;
X    int open = 0;
X    char *addrops;
X    addrops = ".:;%@!=/[]?#^,<>$"; /* should be defined from input file */
X    printf ("resolve (mailer (");
X/*  if (strncmp (cp+1, "local", 5) == 0
X    || strncmp (cp+1, "error", 5) == 0
X    || strncmp (cp+1, "LOCAL", 5) == 0
X    || strncmp (cp+1, "ERROR", 5) == 0)
X    goto skiphost;
Xloop1:
X*/
X    /* this is a simple parser that scans the right
X       hand side of a $# rule
X       The format is usually
X       "$# mailer $@ host $: user" or
X       "$# mailer $: user"  or
X       "$# mailer $: something with a $macro"  or
X       "$# $M $: user"  or
X       "$# $1 "   (IDA sendmail )
X       
X       Note that there may be special constructs
X       in the host field, i.e.
X       "$1", "[$2]", "$w", or "$K".
X       and in the user field. Esp. in the error mailer:
X       "$1 < @$2 > $4",  or
X       "Never heard of host $2 in domain $m "
X       "$n" which should become -> "$m_daemon"
X       */
X    /* pointing to '#' */
X    cp++;
X    /* output any character not a '$' */
X    while (cp && *cp && *cp != '$' ) {
X	/* skip spaces in the mailer field */
X	if ( *cp != ' ' ) putchar(*cp); 
X	cp++;
X    }
X    if (!cp || !*cp ) goto out;
X    /* currently pointing to a "$" */
X    /* we may now be pointing to:
X       $@ - the host name
X       $: - the user
X       or a macro
X       or nothing?! (*cp == 0);
X       /* don't look at the '$' */
X    cp++;
X    if (!cp || !*cp ) goto out;
X    if (*cp  == ':') goto parseuser;
X    if (*cp != '@' ) {
X	/* must be a macro name */
X	printf ("$%s",macro(*cp++));
X	/* now skip to the $@ */
X	if (!cp || !*cp ) goto out;
X	while (cp && *cp && *cp == ' ') cp++;
X	if (!cp || !*cp ) goto out;
X	if (*cp == '$') cp++; 
X	else 
X	  fprintf(stderr,
X		  "Error: found %c when expecting a '$' on line %d\n",
X		  *cp,line);
X	if (*cp == ':') goto parseuser;
X	if (*cp == '@') cp++;
X	else 
X	  fprintf(stderr,
X		  "Error: found %c when expecting a '@' on line %d\n",
X		  *cp,line);
X    } else {
X	/* I did see the '@' of the $@ */
X	cp++;
X    }
X    /* print host name ($@host ) */
X    printf ("),\n\t\t\t\thost (");
X    for (;cp && *cp;cp++) {
X	if (*cp != '$') { 
X	    putchar (*cp);
X	} else {
X	    /* it might be the $: */
X	    if (!*(cp+1)) goto out;
X	    if ( *(cp+1) == ':') {
X		cp++; /* parseuser expects ':' */
X		goto parseuser;
X	    } else {
X		putchar(*cp++); /* print '$' */
X		printf("%s", macro(*cp)); /* and next */
X	    }
X	}
X    }
X  parseuser:
X    printf ("),\n\t\t\t\tuser (");
X    /* *cp == ':', now look for user = $n */
X    /* maybe *cp == 0 */
X    if ( !*cp ) goto out;
X    if (*cp != ':' ) 
X      fprintf(stderr,
X	      "Expected ':', found '%c' after '$' on line %d\n",*cp,line);
X    /* looking at the user string */
X    quoting = 0;
X    for (cp++; cp && *cp; cp++) {
X	if (quoting ) {
X/*	    if (isalnum(*cp) || isspace(*cp)) { */
X	    if (*cp == '"') {
X		printf("\\\"");	/* print "\" */
X		quoting++;
X	    } else if (*cp == '\\') {
X		printf("\\");	/* print "\" and the next character */
X		putchar(*++cp);
X	    } else if (!index(addrops,*cp))  {	
X		/* not one of those address characters */
X		putchar (*cp);
X	    } else { /* maybe it's a dollar sign? */
X		quoting=0;
X		printf("\" %c",*cp);
X		if (*cp == '$') {
X		    cp++;	/* This may not be used at all - but it can't hurt */
X		    if (*cp == '>' ) { /* IDA sendmail */
X			cp++;
X			printf(" RULESET_");
X			while (cp && *cp && *cp >= '0' && *cp <= '9') putchar(*cp++);
X			printf("(");
X			open++;
X		    } else {
X			printf("%s",macro(*cp));
X		    }
X		}
X	    }
X	} else {	/* not quoting */
X	    if ( *cp == '$' ) {
X		cp++;
X		if (*cp == '>' ) { /* IDA sendmail */
X		    cp++;
X		    printf("retry (RULESET_");
X		    while (cp && *cp && *cp >= '0' && *cp <= '9') putchar(*cp++);
X		    printf("("); open++;
X		    open++;
X		} else {
X		    putchar ('$'); /* print $ */
X		    printf("%s",macro(*cp)); /* and macro */
X		}
X	    } else if (*cp && (index (addrops,*cp))) {
X		putchar(*cp);
X	    } else if (*cp == '"') {
X		printf("\"\\\"");quoting++;	/* print "\" */
X	    } else {
X		quoting = 1;
X		printf(" \"%c",*cp);
X	    } 
X	} /* end of quoting/not quoting */
X    }
X    if (quoting) printf("\"");
X  out:
X    while (open--) printf(")");
X    printf ("))");
X} /* end parseresolve () */
X/* def --- define a macro */
X
Xdef ()
X{
X	register char *mac = buffer + 1, *value = buffer + 2;
X	register int conditional = 0;
X	register int concat = 0;
X	register int quote = 0;
X	register int ifset = 0;
X	
X
X	printf ("macro\n\t%s = ", macro (*mac));
X/*	fprintf(stderr,"mac=%c, value=%s\n",*mac,value); */
X
X/* This is tricky, we want the form:
X *
X *	Dq$g$?x$x$.
X * to become
X *  macro
X *       m_defaddr = concat ("${m_sreladdr}", ifset (m_sname," (${m_sname})"));
X * and
X *      Dq$?x$x $.<$g>
X * to become
X *  macro
X *       m_defaddr = concat (ifset (m_sname," (${m_sname})"),"<${m_sreladdr}>" );
X *
X * One problem is the form 
X *	Dq$?x$x <$g>$|$g$.
X *
X *
X */
X	concat = 0;
X	quote = 0;
X	conditional = 0;
X	ifset = 0;
X	if (! *value ) printf("\"\""); /* unusual error - just print " and let
X			               the end of the loop after the while 
X			               clean it up */
X	while (*value)
X	{
X		switch (*value) {
X		case '$':
X			switch (*++value) {
X			/* $:$?E$1%$2.dnet<@$E.LOCAL>$3$|$1<@$2.dnet>$3$. 
X			   Dq$?x$x <$g>$|$g$.
X			   Dq$?x$!x <$g>$|$g$.
X			   */
X			case '?':
X			        /* Another special case %$&*! 
X			         * if the start of the string is $?, 
X				 * but the end is NOT $., then we need a concat
X				 */
X			        if (*(value+strlen(value)-1) == '.' &&
X			            *(value+strlen(value)-2) == '$') {
X				    /* just use ifset with no concat */
X				    printf ("ifset (%s, ", macro (*++value));
X				    conditional++;ifset++;
X				    /* Still need a quote character,
X				       next characters might be a $!x */
X				    if ((*(value+1) == '$') && (*(value+2) == '!')) {
X					value++;value++;
X					printf("\"${quote(%s)} ",macro(*++value));
X					quote++;
X				    } else {
X					printf("\"");quote++;
X				    }
X				} else {
X				    printf ("concat( ifset (%s, \"", macro (*++value));
X				    conditional++;quote++;concat++;ifset++;
X				}
X				break;
X			case '|':
X				if ( ! conditional) die("def - $| without $?");
X				if ( ifset) {
X				    printf("\", \"");
X				} else {
X					fprintf(stderr,"Got $| when not in ifset\n");
X				    putchar (',');
X				}
X				break;
X			case '.':
X				if (quote) {
X				    putchar('"');quote--;
X				}
X				putchar (')');
X				conditional--;ifset--;
X				/* not EOL, must be in concat(ifset( ,) */
X				if (*(value+1)) putchar(','); 
X				break;
X	  	        case '!':	/* IDA sendmail  - this code never gets executed */
X				printf("quote("); concat++;
X				break;
X		        default:
X			/* see if *(value+1) == '$' and *(value+2) == '?' */
X				if (!concat && (strlen(value)>2) 
X				    && (*(value+1) == '$')
X				    && (*(value+2) == '?')) {
X				    printf ("concat (\"${%s}\", ", macro (*value));
X				    /* I'm gonna need a concat */
X				    concat++;
X				} else {
X				    if (!quote) {
X					printf("\"${%s}", macro (*value));
X					quote++;
X				    } else {
X					printf ("${%s}", macro (*value));
X				    }
X				}
X				break;
X			}
X			break;
X	        case '"' :
X		        if (quote) {
X			    printf ("\\\"");
X			} else {
X			    printf("\"\\\"");
X			    quote++;
X			}
X			break;
X		default:
X			if ( ! quote ) {
X			    putchar('"');
X			    quote++;
X			}
X			putchar (*value);
X			break;
X		}
X		value++;
X	}
X	if ( quote ) putchar('"');
X	if (concat) {
X	    putchar (')');
X	    concat--;
X	}
X	printf (";\n");
X	if (conditional)
X		die ("def - $? without $.");
X}
X
X/* class --- define a class list */
X
Xclass ()
X{
X	register char *name = buffer + 1, *value = buffer + 2;
X	int  havepunct;
X	char *s;
X
X
X	printf ("class\n\t");
X	  switch (name[0]) {
X	    case 'w' : 	printf("c_myname"); break;
X	    case 'm' : 	if (sunos) { printf("c_mydomain"); break; }
X	      /* fall through if not SunOS */
X	    default:	printf("%c",name[0]);
X	  }
X
X	printf (" = { ");
X
X	while (value && *value && isspace (*value))
X		value++;
X
X	/* a class may be a series of punctuation characters e.g. IDA */
X	/* also watch for spaces on the end of a line and avoid ',)' */
X
X	while (value && *value)
X	{
X	    /* get first field */
X	    /* look for first space or EOL */
X	    for (s=value,havepunct=0;*s && ! isspace (*s);s++)
X	      if (ispunct(*s)) havepunct = 1;
X
X	    /* field is from *value to *s  
X	       if there is a punctuation char, havepunt == 1 */
X	    if (havepunct) putchar('"');
X	    while (value < s ) {
X		if (*value == '"') putchar('\\');	 /* escape quotes */
X		if (*value == '$' ) printf ("${%s}", macro (*++value));
X		else putchar(*value);
X		value++;
X	    }
X	    if (havepunct) putchar('"');
X	    /* if not EOL, put a comma there 
X	       but watch out for extra spaces..... 
X
X	       so scan over spaces, then look at the next character.
X	       If not EOL, print ", ". */
X
X	       while (value && *value && isspace(*value)) value++;
X	       if (*value && !isspace(*value)) printf (", ");
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 && *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 != '=') cp++; cp++
X#define value()		for (; cp && *cp && *cp != ','; cp++) putchar (*cp); cp++
X
Xloop:
X	while (cp && *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		/* IDA has ruleset/ruleset */
X		for (; *cp && *cp != ',' && *cp != '/'; cp++) 
X		  putchar (*cp); 
X		if (ida && cp && (*cp == '/' )) {
X		    putchar (*cp++);
X		    printf("RULESET_");
X		    value ();
X		} else {
X		    cp++ ;
X		}
X		break;
X
X	case 'S':
X		skipname ();
X		printf ("Sender = RULESET_");
X		/* IDA has ruleset/ruleset */
X		for (; *cp && *cp != ',' && *cp != '/'; cp++) 
X		  putchar (*cp); 
X		if (ida && cp && (*cp == '/' )) {
X		    putchar (*cp++);
X		    printf("RULESET_");
X		    value ();
X		} else {
X		    cp++ ;
X		}
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	register int concat = 0;
X	register int quote = 0;
X	register int ifset = 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 != '?'; 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	/* skip over any spaces */
X	while ( cp && *cp && isspace(*cp)) cp++;
X        /* but if we are now at the end of the line, we must fake
X	   an entry for "" */
X	if ( cp && *cp ) printf ("\", ");  /* don't print next " yet, see if it is a concat */
X	else if (cp && ! *cp ) printf("\", \"\"");
X	else if (!cp) {
X	    printf("\"");
X	    fprintf(stderr,"I didn't expect this!\n");
X	}
X
X	quote = concat = conditional = ifset = 0;
Xbody:
X	while (cp && *cp)
X	{
X		switch (*cp) {
X		case '$':
X			switch (*++cp) {
X			case '?':
X			    /* if we are not in a concat, then start one */
X			    if ( ! concat ) {
X				printf("concat (");
X				concat++;
X			    }  else { /* we are in one */
X				if (quote) {
X				    printf("\"");quote--;
X				}
X				printf("), concat (");
X			    }
X			    if (quote) {
X				printf("\",");quote--;
X			    }
X			    printf ("ifset (%s, \"", macro (*++cp));
X			    conditional++; quote++;ifset++;
X			    break;
X			case '|':
X				if ( ! conditional) die("header - $| without $?");
X				if ( ifset) {
X				    printf("\", \"");
X				} else {
X					fprintf(stderr,"Got $| when not in ifset\n");
X				    putchar (',');
X				}
X			    break;
X			case '.':
X			    if (quote) {
X				putchar('"');quote--;
X			    }
X			    putchar (')');
X			    conditional--;ifset--;
X			    if (concat) {
X				/* this is messy - There may be more than one $? on a line */
X
X				if (cp+1) { /* if there is more on the line */
X				    printf(", ");
X				}
X			    }
X			    break;
X			default: /* a $<letter> */
X			/* see if *(cp+1) == '$' and *(cp+2) == '?' */
X			    if (!concat && (strlen(cp)>2) 
X				&& (*(cp+1) == '$')
X				&& (*(cp+2) == '?')) {
X				printf ("concat (\"${%s}\", ", macro (*cp));
X				/* I'm gonna need a concat */
X				concat++;
X			    } else {
X				if (!quote) {
X				    printf("\"${%s}", macro (*cp));
X				    quote++;
X				} else {
X				    printf ("${%s}", macro (*cp));
X				}
X			    }
X			    break;
X			}
X			break;
X	        case '"' :
X			printf ("\\\"");
X			break;
X		default:
X			if ( ! quote ) {
X			    putchar('"');
X			    quote++;
X			}
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			if ( ! quote ) {
X			    putchar('"');
X			    quote++;
X			}
X			printf ("\\\n");
X			cp = buffer + 1;
X
X			goto body;
X		}
X		else
X			ungets (buffer);
X	}
X	else
X		ungets ((char *) NULL);
X
X	if ( quote ) {
X	    putchar('"'); 
X	}
X	if (concat) {
X	    putchar(')');
X	    concat--;
X	}
X	printf (");\n");
X
X	if (flags)
X		printf ("\t};\n");
X
X	if (conditional)
X		die ("header translation  problem: $? without $.");
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	if ( *cp && *cp == ' ') cp++; /* skip over spaces in the begining */
X	while (cp && *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/* it may also be a blank 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 'k':	/* The official domain name for this site */
X		return ("m_uucpname");	/* IDA */
X
X	case 'l':	/* The format of the UNIX from line */
X		return ("m_ufrom");
X
X	case 'm':	/* The Domain Name (SunOS) */
X		if (sunos) {
X		    return ("m_domain");
X		} else {
X		    buf[0] = c;
X		    return (buf);
X		}
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        case '"':	/* you can get a quote charater in some macro definitions */
X		return ("\\\"");
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 'H':	return ("f_mail11");	/* Ultrix 3.0 */
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	case 'B':	return ("f_bsmtp"); /* IDA sendmail */
X	case 'V':	return ("f_relativize"); /* IDA sendmail */
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 'b':	return ("o_maxempty"); /* SunOS 4.0 */
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 'h':	return ("o_maxhops");	/* SunOS 4.0 */
X	case 'i':	return ("o_skipd");
X	case 'I':	return ("o_nameserver");	/* HP/UX */
X/*	case 'K':		Keyed Database (IDA) */
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 'R':	return ("o_nfs");	/* SunOS 4.0 */
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':	if (sunos ) return ("o_aliasfile"); else docompat ("o_newproc");
X	case 'y':	docompat ("o_recipfactor");
X	case 'z':	docompat ("o_prifactor");
X	case 'Z':	docompat ("o_waitfactor");
X	case '/':	return ("o_envelope");	/* IDA */
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_cfc/cfc.c
if test 39729 -ne `wc -c <cfc/cfc.c`; then
    echo shar: \"cfc/cfc.c\" unpacked with wrong size!
fi
chmod +x cfc/cfc.c
# end of overwriting check
fi
echo shar: End of archive 6 \(of 6\).
cp /dev/null ark6isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 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
--
Bruce G. Barnett	barnett@crd.ge.com	uunet!crdgw1!barnett