Ease 3.0: High Level Language for Sendmail (Part 6 of 6)

Bruce Barnett barnett at grymoire.crd.ge.com
Sat Feb 23 18:19:20 AEST 1991


#! /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 at 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 at 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 at crd.ge.com	uunet!crdgw1!barnett



More information about the Alt.sources mailing list