v13i030: New version of .cf compiler

Rich Salz rsalz at bbn.com
Wed Feb 10 10:19:37 AEST 1988


Submitted-by: "Arnold D. Robbins" <arnold at EMORYU1.ARPA>
Posting-number: Volume 13, Issue 30
Archive-name: cfc

[  CFC is a program that turns sendmail.cf files into almost directly-
   readable EASE language files.  I wrote the Makefile and just slipped
   it into the shar.  --r$ ]

Rich,
    I think the only BSD-ism is the use of index.

Arnold Robbins
The (wounded and bleeding) slayer of Sendmail dragons

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	cfc.1
#	cfc.c
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(some number of characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
all:		cfc cfc.1
install:	all
	@echo install according to local conventions.
cfc:		cfc.c
	$(CC) $(CFLAGS) -o cfc cfc.c
SHAR_EOF
fi # end of overwriting check

echo shar: extracting "'cfc.1'" '(3162 characters)'
if test -f 'cfc.1'
then
	echo shar: will not over-write existing file "'cfc.1'"
else
cat << \SHAR_EOF > 'cfc.1'
...
... $Header: cfc.1,v 1.3 88/01/21 16:23:21 arnold Locked $
... 
... $Log:	cfc.1,v $
... Revision 1.3  88/01/21  16:23:21  arnold
... Some typo fixes.
... 
... Revision 1.2  87/04/08  10:21:47  arnold
... Small bug fixes, compatibility option added, also warnings for
... unrecognized flags and options. ADR.
... 
... Revision 1.1  87/02/16  15:25:32  arnold
... Initial revision
... 
...
.TH CFC 8 local
.SH NAME
cfc \- Sendmail cf file compiler
.SH SYNOPSIS
.B cfc
[
.B \-c
] <
.I sendmail.cf-file
>
.I ease-source-file
.SH DESCRIPTION
.I Cfc
is a filter that reads a raw
.IR sendmail (8)
configuration file on its standard input, and produces almost useable
.IR ease (1)
source on its standard output.
.P
It is designed as a conversion tool, to translate an existing
.B sendmail.cf
file into
.I ease
with the idea that all future work will be done in
.IR ease .
.P
.I Cfc
passes all comments through to the output, and converts all predefined
.I sendmail
macros, options, option values, and mailer flags into the names used by
.IR ease .
.P
Once it is through, the user need only spend some time in a good screen
editor doing the following:
.RS
.P
Changing the RULESET_n names into more descriptive names, and
adding ruleset bindings.
.P
Applying quoting to necessary string literals, principally in the
definitions of headers. The
.I ease
documentation on header formats should be consulted.
.P
Adding new field names.
.I Cfc
just uses very generic field names, everywhere, when names like ``user,''
``host,'' and ``relay'' might be more descriptive.
.P
Miscellanious formatting.
.I Cfc
introduces tabs on its own, as well as often passing through tabs
from the
.I sendmail
input.
It will also print a header for each different type of line, e.g. if the
input had seven
.B O
(option) lines, there will be seven option blocks.
These are usually succesive, and can therefore be merged.
Finally, the block close on rulesets often comes after the comments that
precede the next ruleset or mailer specification.
.RE
.P
In short,
.I cfc
does over 90% of the tedious work of translating a
.B sendmail.cf
into
.I ease
format.
The rest of the work can be done in a day or less.
Suprisingly, the combination of
.I cfc
and
.I ease
can find bugs in a current
.B sendmail.cf
file!
.P
.I Cfc takes one option,
.BR \-c ,
which indicates it should run in 4.2BSD compatibility mode.
In this case, options and mailer flags which are new in the 4.3BSD
version of
.I sendmail
will not be recognized.
.\" .SH FILES
.SH SEE ALSO
.I "Sendmail Installation and Operation Guide"
by Eric Allman
(SMM:7 in the 4.3 BSD UNIX System Manager's Manual),
.I "Ease: A Configuration Language for Sendmail"
by James S. Schoner,
.IR sendmail (8),
.IR ease (1).
.SH DIAGNOSTICS
``\c
.IR Routine :
malformed input line
.IR line :
fatal error''
for input it doesn't understand.
.I Routine
is the name of the routine in
.I cfc
which choked, and
.I line
is the line number in the input.
.SH BUGS
Only recognizes continuation lines (lines that begin with a \s-1TAB\s+1)
for header (H) and mailer (M) definitions.
.SH AUTHOR
.nf
Arnold Robbins
Emory University Computing Center
arnold at emory.edu
.fi
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'cfc.c'" '(20180 characters)'
if test -f 'cfc.c'
then
	echo shar: will not over-write existing file "'cfc.c'"
else
cat << \SHAR_EOF > 'cfc.c'
#ifndef lint
static char RCSid[] = "$Header: cfc.c,v 1.5 88/01/21 16:18:13 root Locked $";
#endif

/*
 * $Log:	cfc.c,v $
 * Revision 1.5  88/01/21  16:18:13  root
 * Eliminated Rutgers-ism, linted, smartened Mailer Argv handling. ADR.
 * 
 * Revision 1.4  88/01/21  15:57:52  root
 * Added the 'y' factor; missed it last time. ADR.
 * 
 * Revision 1.3  87/04/08  10:23:02  root
 * Small bug fixes, compatibility option added, also warnings for
 * unrecognized flags and options. ADR.
 * 
 * Revision 1.2  87/02/18  15:26:39  root
 * Fix to recognize multidigit ruleset numbers in $> (calls) in RHS. ADR.
 * 
 * Revision 1.1  87/02/16  15:25:00  arnold
 * Initial revision
 * 
 * Revision 1.1  87/02/16  15:25:00  arnold
 * Initial revision
 * 
 */

/*
 * cfc.c
 *
 * Sendmail cf file compiler.
 * Reads a raw sendmail.cf file and produces ease source.
 *
 * There are very few comments in this source. You will need both the
 * "Sendmail Installation and Operation Guide" and the paper on Ease
 * to really understand this.
 *
 * Arnold Robbins
 * Emory University Computing Center
 * 2/87
 */

#include <stdio.h>
#include <ctype.h>

char buffer[BUFSIZ];
int line = 0;
int inruleset = 0;

extern char *macro ();		/* convert sendmail to ease macro names */
extern char *mflags ();		/* convert sendmail to ease mailer flag names */
extern char *optionname ();	/* convert sendmail to ease option names */
extern char *delivoption ();	/* delivery options */
extern char *handle_option ();	/* handling options */

extern char *ngets ();		/* buffered gets () routine */
extern void ungets ();		/* put a buffer back for getting */

#define endruleset()	if (inruleset) { inruleset = 0; printf ("\t}\n"); }

int compat = 0;			/* complain about new 4.3 options & flags */

main (argc, argv)
int argc;
char **argv;
{
	if (argc > 1)
	{
		if (strcmp (argv[1], "-c") == 0)
			compat = 1;
		else
		{
			fprintf (stderr, "usage: %s [ -c ]\n", argv[0]);
			fprintf (stderr, "illegal argument '%s' ignored\n",
					argv[1]);
		}
	}

	printf ("/******************************************************/\n");
	printf ("/* This ease file generated by cfc from a sendmail.cf */\n");
	printf ("/* file. It must be edited by hand before being fed   */\n");
	printf ("/* to ease!                                           */\n");
	printf ("/******************************************************/\n");
	printf ("\n\nbind\n\t/* RULESET BINDINGS GO HERE (cfc) */\n\n");

	/*
	 * For perfection, everything but the comment and rule cases
	 * should do an endruleset (), but practically speaking, it is
	 * usually only the mailer new ruleset definitions that end a
	 * previous ruleset. Occasionally a macro, too.
	 */

	while (ngets (buffer) != NULL)
	{
		line++;
		switch (buffer[0]) {
		case '#':
			comment ();
			continue;	/* skip code to end ruleset */
		case 'S':
			endruleset ();
			ruleset ();
			continue;	/* skip code to end ruleset */
		case 'R':
			rule ();
			continue;	/* skip code to end ruleset */
		case 'D':
			endruleset ();
			def ();
			break;
		case 'C':
			class ();
			break;
		case 'F':
			fileclass ();
			break;
		case 'M':
			endruleset ();
			mailer ();
			break;
		case 'H':
			header ();
			break;
		case 'O':
			option ();
			break;
		case 'T':
			trusted ();
			break;
		case 'P':
			precedence ();
			break;
		default:
			other ();
			continue;	/* skip code to end ruleset */
		}
		endruleset ();
	}
	endruleset ();		/* just in case */
	exit (0);
	/*NOTREACHED*/
}

/* comment --- produce a comment */

comment ()
{
	static char format[] = "/* %s */\n";
	register int i = strlen (buffer) - 1;

	/* try to be semi-intelligent about comments */

	if (buffer[1] == '\0')
		printf ("\n");
	else if (isspace (buffer[1]) && buffer[i] != '#')
	{
		for (i = 1; isspace (buffer[i]); i++)
			;
		printf (format, buffer + i);
	}
	else
		printf (format, buffer);
}

/* ruleset --- name a ruleset */

ruleset ()
{
	static int first = 1;
	register char *cp = buffer + 1;

	if (first)
	{
		first = 0;
		printf ("\n/* These are sample field definitons (cfc) */\n");
		printf ("\nfield\n\tzero_or_more : match (0*);\n");
		printf ("\tone_or_more : match (1*);\n");
		printf ("\texactly_one : match (1);\n");
		printf ("\tany_in_? : match (1) in ?;\n");
		printf ("\tany_not_in_? : match (0) in ?;\n\n");
	}

	printf ("ruleset\n\tRULESET_");
	while (*cp && ! isspace (*cp))
	{
		putchar (*cp);
		cp++;
	}

	printf (" {");
	if (*cp)
		printf ("\t/* %s */", cp);
	putchar ('\n');
	inruleset++;
}

/* rule --- print out a rule */

rule ()
{
	register char *cp = buffer + 1;
	register char *cp2;
	register int com = 0;

	/* first, split it up into LHS, RHS, COMMENT */

	while (*cp != '\t')
		cp++;
	*cp = '\0';

	cp++;
	while (*cp == '\t')
		cp++;
	cp2 = cp;
	while (*cp && *cp != '\t')
		cp++;
	if (*cp == '\t' && cp[1])
	{
		*cp = '\0';
		com++;
		cp++;
		while (*cp == '\t')
			cp++;
	}

	/* now print */
	lhs (buffer + 1);	/* left hand side */
	if (com)
		printf ("\t/* %s */", cp);
	putchar ('\n');
	rhs (cp2);		/* right hand side */
}

/* lhs --- left hand side of a production */

lhs (text)
char *text;
{
	register char *cp = text;
	register int conditional = 0;
	register int quoting = 0;

	printf ("\tif (");
	for (; *cp; cp++)
	{
		switch (*cp) {
		case '$':
			if (quoting)
			{
				quoting = 0;
				putchar ('"');
			}
			switch (*++cp) {
			case '*':
				printf (" zero_or_more ");
				break;
			case '+':
				printf (" one_or_more ");
				break;
			case '-':
				printf (" exactly_one ");
				break;
			case '=':
				printf (" any_in_%c ", *++cp);
				break;
			case '~':
				printf (" any_not_in_%c ", *++cp);
				break;
			case '?':
				printf (" ifset (%s, ", macro (*++cp));
				conditional++;
				break;
			case '|':
				printf (", ");
				break;
			case '.':
				putchar (')');
				conditional--;
				break;
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
				printf ("$%c", *cp);
				break;
			default:
				if (quoting)
					printf ("${%s}", macro (*cp));
				else
					printf ("$%s", macro (*cp));
				break;
			}
			break;
		default:
			if (ispunct (*cp))
			{
				if (quoting)	/* end a literal */
				{
					quoting = 0;
					putchar ('"');
				}
				/* else
					do nothing */
			}
			else
			{
				if (! quoting)	/* start a literal */
				{
					quoting = 1;
					putchar ('"');
				}
				/* else
					do nothing */
			}
			putchar (*cp);	/* print the character */
			break;
		}
	}
	if (quoting)
		putchar ('"');
	if (conditional)
		die ("lhs");
	printf (")");
}

/* rhs --- right hand side of a production */

rhs (text)
char *text;
{
	register char *cp = text;
	char *index ();
	register int open = 0;
	register int conditional = 0;
	register int quoting = 0;

	printf ("\t\t");

	if (*cp == '$' && index ("#@:", cp[1]) != NULL)
		;	/* not the default */
	else
	{
		printf ("retry (");
		open++;
	}

	for (; *cp; cp++)
	{
		switch (*cp) {
		case '$':
			if (quoting)
			{
				quoting = 0;
				putchar ('"');
			}
			switch (*++cp) {
			case '>':
				printf ("RULESET_");
				for (cp++; *cp && isdigit (*cp); cp++)
					putchar (*cp);
				cp--;
				printf (" (");
				open++;
				break;
			case '[':
				printf ("canon (");
				open++;
				break;
			case ']':
				putchar (')');
				open--;
				break;
			case '?':
				printf ("ifset (%s, ", macro (*++cp));
				conditional++;
				break;
			case '|':
				putchar (',');
				break;
			case '.':
				putchar (')');
				conditional--;
				break;
			case '#':
				printf ("resolve (mailer (");
				if (strncmp (cp+1, "local$", 6) == 0
					|| strncmp (cp+1, "error$", 6) == 0)
					goto skiphost;
			loop1:
				for (cp++; *cp != '$'; cp++)
					putchar (*cp);
				cp++;
				if (*cp != '@')
				{
					printf ("$%c", *cp);
					goto loop1;
				}
				printf ("),\n\t\t\t\thost (");
			skiphost:
			loop2:
				for (cp++; *cp != '$'; cp++)
					putchar (*cp);
				cp++;
				if (*cp != ':')
				{
					printf ("$%c", *cp);
					goto loop2;
				}
				printf ("),\n\t\t\t\tuser (");
				for (cp++; *cp; cp++)
					putchar (*cp);
				printf ("))");
				goto out;	/* string is exhausted */
				/* break; */
			case '@':
				printf ("return (");
				open++;
				break;
			case ':':
				printf ("next (");
				open++;
				break;
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
				printf ("$%c", *cp);
				break;
			default:
				if (quoting)
					printf ("${%s}", macro (*cp));
				else
					printf ("$%s", macro (*cp));
				break;
			}
			break;
		default:
			if (ispunct (*cp))
			{
				if (quoting)	/* end a literal */
				{
					quoting = 0;
					putchar ('"');
				}
				/* else
					do nothing */
			}
			else
			{
				if (! quoting)	/* start a literal */
				{
					quoting = 1;
					putchar ('"');
				}
				/* else
					do nothing */
			}
			putchar (*cp);	/* print the character */
			break;
		}
	}
out:
	if (quoting)
		putchar ('"');
	while (open--)
		putchar (')');
	printf (";\n");
	if (conditional)
		die ("rhs");
}

/* def --- define a macro */

def ()
{
	register char *mac = buffer + 1, *value = buffer + 2;
	register int conditional = 0;

	printf ("macro\n\t%s = \"", macro (*mac));

	while (*value)
	{
		switch (*value) {
		case '$':
			switch (*++value) {
			case '?':
				printf ("ifset (%s, ", macro (*++value));
				conditional++;
				break;
			case '|':
				putchar (',');
				break;
			case '.':
				putchar (')');
				conditional--;
				break;
			default:
				printf ("${%s}", macro (*value));
				break;
			}
			break;
		default:
			putchar (*value);
			break;
		}
		value++;
	}
	printf ("\";\n");
	if (conditional)
		die ("def");
}

/* class --- define a class list */

class ()
{
	register char *name = buffer + 1, *value = buffer + 2;

	printf ("class\n\t%c = { ", *name);

	while (*value && isspace (*value))
		value++;

	while (*value)
	{
		if (isspace (*value))
		{
			printf (", ");
			while (isspace (*value))
				value++;
			value--;	/* cancel loop */
		}
		else
			putchar (*value);
		value++;
	}
	printf (" };\n");
}

/* fileclass --- define a class that is to be read from a file */

fileclass ()
{
	register char *name = buffer + 1, *value = buffer + 2;

	printf ("class\n\t%c = readclass (\"", *name);
	for (; *value && !isspace (*value); value++)
		putchar (*value);
	putchar ('"');
	while (*value && isspace (*value))
		value++;
	if (*value)
		printf (", \"%s\"", value);
	printf (");\n");
}

/* mailer --- convert a mailer specification */

mailer ()
{
	register char *cp = buffer + 1;

	printf ("mailer\n\t");
	for (; *cp != ','; cp++)
		putchar (*cp);
	cp++;
	printf (" {\n");	/* just did mailer name */

#define skipname()	cp++; while (*cp != '=') cp++; cp++
#define value()		for (; *cp && *cp != ','; cp++) putchar (*cp); cp++

loop:
	while (*cp && isspace (*cp))
		cp++;

	printf ("\t\t");
	switch (*cp) {
	case 'A':
		skipname ();
		printf ("Argv = \"");
		for (; *cp && *cp != ','; cp++)
		{
			if (*cp == '$')	/* XXX: assume no conditionals */
				printf ("${%s}", macro (*++cp));
			else if (*cp == '"')
				printf ("\\\"");
			else
				putchar (*cp);
		}
		cp++;	/* do manually what value does */
		putchar ('"');
		break;

	case 'E':
		skipname ();
		printf ("Eol = \"");
		value ();
		putchar ('"');
		break;

	case 'F':
		skipname ();
		printf ("Flags = { ");
		for (; *cp && *cp != ','; cp++)
		{
			printf ("%s", mflags (*cp));
			if (cp[1] && cp[1] != ',')
				printf (", ");
		}
		cp++;	/* do manually what value does */
		printf (" }");
		break;

	case 'M':
		skipname ();
		printf ("Maxsize = \"");
		value ();
		putchar ('"');
		break;

	case 'P':
		skipname ();
		printf ("Path = \"");
		value ();
		putchar ('"');
		break;

	case 'R':
		skipname ();
		printf ("Recipient = RULESET_");
		value ();
		break;

	case 'S':
		skipname ();
		printf ("Sender = RULESET_");
		value ();
		break;

	case '\0':
		goto done;
	}

	if (cp[-1] && cp[-1] == ',')
	{
		printf (",\n");
		goto loop;
	}
	else
		putchar ('\n');

done:
	/* handle continuation lines */
	if (ngets (buffer) != NULL)
	{
		line++;
		if (buffer[0] == '\t')
		{
			cp = buffer;
			goto loop;
		}
		else
			ungets (buffer);
	}
	else
		ungets ((char *) NULL);
	
	printf ("\t};\n");

#undef value
#undef skipname
}

/* header --- define sendmail headers */

header ()
{
	register char *cp = buffer + 1;
	register int flags = 0;
	register int conditional = 0;

	printf ("header\n\t");
	if (*cp == '?')		/* header for mailers  with these flags */
	{
		flags++;
		printf ("for (");
		for (cp++; *cp != '?'; cp++)
		{
			printf ("%s", mflags (*cp));
			if (cp[1] != '?')
				putchar (',');
		}
		printf (") {\n\t\t");
		cp++;	/* skip final '?' */
	}

	printf ("define (\"");
	for (; *cp && ! isspace (*cp); cp++)
		putchar (*cp);
	printf ("\", \"");

body:
	while (*cp)
	{
		switch (*cp) {
		case '$':
			switch (*++cp) {
			case '?':
				printf ("ifset (%s, ", macro (*++cp));
				conditional++;
				break;
			case '|':
				putchar (',');
				break;
			case '.':
				putchar (')');
				conditional--;
				break;
			default:
				printf ("${%s}", macro (*cp));
				break;
			}
			break;
		default:
			putchar (*cp);
			break;
		}
		cp++;
	}

	/* handle continuation lines */
	if (ngets (buffer) != NULL)
	{
		line++;
		if (buffer[0] == '\t')
		{
			printf ("\\\n");
			cp = buffer + 1;
			goto body;
		}
		else
			ungets (buffer);
	}
	else
		ungets ((char *) NULL);

	printf ("\");\n");

	if (flags)
		printf ("\t};\n");

	if (conditional)
		die ("header");
}

/* option --- translate a sendmail option to an ease option */

option ()
{
	register char *name = buffer + 1, *value = buffer + 2;

	printf ("options\n\t");
	if (*name == 'd')		/* delivery */
		printf ("o_delivery = %s;\n", delivoption (*value));
	else if (*name == 'e')		/* handling */
		printf ("o_handling = %s;\n", handle_option (*value));
	else
		printf ("%s = \"%s\";\n", optionname (*name), value);
}

/* trusted --- define the list of trusted users */

trusted ()
{
	register char *cp = buffer + 1;

	while (*cp)
	{
		if (isspace (*cp))
			*cp = ',';
		cp++;
	}
	printf ("trusted\n\t{ %s };\n", buffer+1);
}

/* precedence --- define the precedence of a message class */

precedence ()
{
	register char *cp = buffer + 1;

	printf ("precedence\n\t");
	for (; *cp && *cp != '='; cp++)
		putchar (*cp);
	printf (" = %s;\n", ++cp);
}

/* other --- not a sendmail control line */

other ()
{
	printf ("%s\n", buffer);
}

die (routine)
char *routine;
{
	fprintf (stderr, "%s: malformed input line %d: fatal error\n",
			routine, line);
	exit (1);
}

/* macro --- return name for sendmail predefined macro */

char *macro (c)
char c;
{
	static char buf[2] = { '\0', '\0' };

	switch (c) {
	case 'a':	/* The origination date in Arpanet format */
		return ("m_odate");

	case 'b':	/* The current date in Arpanet format */
		return ("m_adate");

	case 'c':	/* The hop count */
		return ("m_hops");

	case 'd':	/* The date in UNIX (ctime) format */
		return ("m_udate");

	case 'e':	/* The SMTP entry message */
		return ("m_smtp");

	case 'f':	/* The sender (from) address */
		return ("m_saddr");

	case 'g':	/* The sender address relative to the recipient */
		return ("m_sreladdr");

	case 'h':	/* The recipient host */
		return ("m_rhost");

	case 'i':	/* The queue id */
		return ("m_qid");

	case 'j':	/* The official domain name for this site */
		return ("m_oname");

	case 'l':	/* The format of the UNIX from line */
		return ("m_ufrom");

	case 'n':	/* The name of the daemon (for error messages) */
		return ("m_daemon");

	case 'o':	/* The set of "operators" in addresses */
		return ("m_addrops");

	case 'p':	/* Sendmail's pid */
		return ("m_pid");

	case 'q':	/* The default format of sender address */
		return ("m_defaddr");

	case 'r':	/* Protocol used */
		return ("m_protocol");

	case 's':	/* Sender's host name */
		return ("m_shostname");

	case 't':	/* A numeric representation of the current time */
		return ("m_ctime");

	case 'u':	/* The recipient user */
		return ("m_ruser");

	case 'v':	/* The version number of sendmail */
		return ("m_version");

	case 'w':	/* The hostname of this site */
		return ("m_sitename");

	case 'x':	/* The full name of the sender */
		return ("m_sname");

	case 'y':	/* The id of the sender's tty */
		return ("m_stty");

	case 'z':	/* The home directory of the recipient */
		return ("m_rhdir");

	default:
		buf[0] = c;
		return (buf);
	}
}

#define docompat(val)	if (compat) goto warn; else return (val)

/* mflags --- convert sendmail mailer flags to ease names */

char *mflags (c)
char c;
{
	static char buf[2] = { '\0', '\0' };

	switch (c) {
	case 'f':	return ("f_ffrom");
	case 'r':	return ("f_rfrom");
	case 'S':	return ("f_noreset");
	case 'n':	return ("f_noufrom");
	case 'l':	return ("f_locm");
	case 's':	return ("f_strip"); 
	case 'm':	return ("f_mult");
	case 'F':	return ("f_from");
	case 'D':	return ("f_date");
	case 'M':	return ("f_mesg");
	case 'x':	return ("f_full");	
	case 'P':	return ("f_return");	
	case 'u':	return ("f_upperu");	
	case 'h':	return ("f_upperh");	
	case 'A':	return ("f_arpa");	
	case 'U':	return ("f_ufrom");	
	case 'e':	return ("f_expensive");	
	case 'X':	return ("f_dot");	
	case 'L':	return ("f_llimit");	
	case 'p':	return ("f_retsmtp");	
	case 'I':	return ("f_smtp");	
	case 'C':	return ("f_addrw");	
	case 'E':	docompat ("f_escape");
	default:
	warn:
		fprintf (stderr,
			"warning: non standard mailer flag '%c' on line %d\n",
				c, line);
		buf[0] = c;
		return buf;
	}
}

/* optionname --- convert sendmail options to ease names */

char *optionname (c)
char c;
{
	static char buf[2] = { '\0', '\0' };

	switch (c) {
	case 'A':	return ("o_alias");
	case 'a':	return ("o_ewait");
	case 'B':	return ("o_bsub");
	case 'c':	return ("o_qwait");
	case 'd':	return ("o_delivery");
	case 'D':	return ("o_rebuild");
	case 'e':	return ("o_handling");
	case 'F':	return ("o_tmode");
	case 'f':	return ("o_usave");
	case 'g':	return ("o_gid");
	case 'H':	return ("o_fsmtp");
	case 'i':	return ("o_skipd");
	case 'L':	return ("o_slog");
	case 'm':	return ("o_rsend");
	case 'N':	return ("o_dnet");
	case 'o':	return ("o_hformat");
	case 'Q':	return ("o_qdir");
	case 'q':	docompat ("o_qfactor");
	case 'r':	return ("o_tread");
	case 'S':	return ("o_flog");
	case 's':	return ("o_safe");
	case 'T':	return ("o_qtimeout");
	case 't':	return ("o_timezone");
	case 'u':	return ("o_dmuid");
	case 'v':	return ("o_verbose");
	case 'W':	return ("o_wizpass");
	case 'x':	return ("o_loadq");
	case 'X':	return ("o_loadnc");
	case 'Y':	docompat ("o_newproc");
	case 'y':	docompat ("o_recipfactor");
	case 'Z':	docompat ("o_prifactor");
	case 'z':	docompat ("o_waitfactor");
	default:
	warn:
		fprintf (stderr,
			"warning: non standard option '%c' on line %d\n",
				c, line);
		buf[0] = c;
		return buf;
	}
}

/* delivoption --- convert sendmail delivery option value to ease name */

char *delivoption (c)
char c;
{
	static char buf[2] = { '\0', '\0' };

	switch (c) {
	case 'i':	return ("d_interactive");
	case 'b':	return ("d_background");
	case 'q':	return ("d_queue");
	default:
		fprintf (stderr,
	"warning: non standard delivery option '%c' on line %d\n", c, line);
		buf[0] = c;
		return buf;
	}
}

/* handle_option --- convert sendmail handling option value to ease name */

char *handle_option (c)
char c;
{
	static char buf[2] = { '\0', '\0' };

	switch (c) {
	case 'p':	return ("h_print");
	case 'q':	return ("h_exit");
	case 'm':	return ("h_mail");
	case 'w':	return ("h_write");
	case 'e':	return ("h_mailz");
	default:
		fprintf (stderr,
	"warning: non standard handling option '%c' on line %d\n", c, line);
		buf[0] = c;
		return buf;
	}
}

/*
 * "buffered" i/o routines. These are necessary since
 * mail headers may have continuation lines, and we can't see if
 * a continuation line is there without getting it. If it isn't,
 * just put it back.
 */

int saved = 0;
char *saveb = NULL;

/* ngets --- get a line of input from either saved buffer or stdin */

char *ngets (bp)
char *bp;
{
	if (! saved)
		return (gets (bp));

	saved = 0;
	bp = saveb;
	saveb = NULL;
	return (bp);
}

/* ungets --- put a buffer back on the input, so to speak */

void ungets (bp)
char *bp;
{
	saved = 1;
	saveb = bp;
	line--;
}
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0


-- 
For comp.sources.unix stuff, mail to sources at uunet.uu.net.



More information about the Comp.sources.unix mailing list